continue implementation of cpu resource
[lttv.git] / ltt / branches / poly / lttv / lttv / state.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <lttv/lttv.h>
24 #include <lttv/module.h>
25 #include <lttv/state.h>
26 #include <ltt/facility.h>
27 #include <ltt/trace.h>
28 #include <ltt/event.h>
29 #include <ltt/type.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 /* Comment :
34 * Mathieu Desnoyers
35 * usertrace is there only to be able to update the current CPU of the
36 * usertraces when there is a schedchange. it is a way to link the ProcessState
37 * to the associated usertrace. Link only created upon thread creation.
38 *
39 * The cpu id is necessary : it gives us back the current ProcessState when we
40 * are considering data from the usertrace.
41 */
42
43 #define PREALLOCATED_EXECUTION_STACK 10
44
45 /* Facilities Quarks */
46
47 GQuark
48 LTT_FACILITY_KERNEL,
49 LTT_FACILITY_KERNEL_ARCH,
50 LTT_FACILITY_LIST,
51 LTT_FACILITY_FS,
52 LTT_FACILITY_USER_GENERIC;
53
54 /* Events Quarks */
55
56 GQuark
57 LTT_EVENT_SYSCALL_ENTRY,
58 LTT_EVENT_SYSCALL_EXIT,
59 LTT_EVENT_TRAP_ENTRY,
60 LTT_EVENT_TRAP_EXIT,
61 LTT_EVENT_IRQ_ENTRY,
62 LTT_EVENT_IRQ_EXIT,
63 LTT_EVENT_SOFT_IRQ_ENTRY,
64 LTT_EVENT_SOFT_IRQ_EXIT,
65 LTT_EVENT_SCHED_SCHEDULE,
66 LTT_EVENT_PROCESS_FORK,
67 LTT_EVENT_KTHREAD_CREATE,
68 LTT_EVENT_PROCESS_EXIT,
69 LTT_EVENT_PROCESS_FREE,
70 LTT_EVENT_EXEC,
71 LTT_EVENT_PROCESS_STATE,
72 LTT_EVENT_STATEDUMP_END,
73 LTT_EVENT_FUNCTION_ENTRY,
74 LTT_EVENT_FUNCTION_EXIT,
75 LTT_EVENT_THREAD_BRAND;
76
77 /* Fields Quarks */
78
79 GQuark
80 LTT_FIELD_SYSCALL_ID,
81 LTT_FIELD_TRAP_ID,
82 LTT_FIELD_IRQ_ID,
83 LTT_FIELD_SOFT_IRQ_ID,
84 LTT_FIELD_PREV_PID,
85 LTT_FIELD_NEXT_PID,
86 LTT_FIELD_PREV_STATE,
87 LTT_FIELD_PARENT_PID,
88 LTT_FIELD_CHILD_PID,
89 LTT_FIELD_PID,
90 LTT_FIELD_TGID,
91 LTT_FIELD_CHILD_TGID,
92 LTT_FIELD_FILENAME,
93 LTT_FIELD_NAME,
94 LTT_FIELD_TYPE,
95 LTT_FIELD_MODE,
96 LTT_FIELD_SUBMODE,
97 LTT_FIELD_STATUS,
98 LTT_FIELD_THIS_FN,
99 LTT_FIELD_CALL_SITE;
100
101 LttvExecutionMode
102 LTTV_STATE_MODE_UNKNOWN,
103 LTTV_STATE_USER_MODE,
104 LTTV_STATE_SYSCALL,
105 LTTV_STATE_TRAP,
106 LTTV_STATE_IRQ,
107 LTTV_STATE_SOFT_IRQ;
108
109 LttvExecutionSubmode
110 LTTV_STATE_SUBMODE_UNKNOWN,
111 LTTV_STATE_SUBMODE_NONE;
112
113 LttvProcessStatus
114 LTTV_STATE_UNNAMED,
115 LTTV_STATE_WAIT_FORK,
116 LTTV_STATE_WAIT_CPU,
117 LTTV_STATE_EXIT,
118 LTTV_STATE_ZOMBIE,
119 LTTV_STATE_WAIT,
120 LTTV_STATE_RUN,
121 LTTV_STATE_DEAD;
122
123 GQuark
124 LTTV_STATE_UNBRANDED;
125
126 LttvProcessType
127 LTTV_STATE_USER_THREAD,
128 LTTV_STATE_KERNEL_THREAD;
129
130 LttvCPUMode
131 LTTV_CPU_UNKNOWN,
132 LTTV_CPU_IDLE,
133 LTTV_CPU_BUSY,
134 LTTV_CPU_IRQ,
135 LTTV_CPU_TRAP;
136
137 static GQuark
138 LTTV_STATE_TRACEFILES,
139 LTTV_STATE_PROCESSES,
140 LTTV_STATE_PROCESS,
141 LTTV_STATE_RUNNING_PROCESS,
142 LTTV_STATE_EVENT,
143 LTTV_STATE_SAVED_STATES,
144 LTTV_STATE_SAVED_STATES_TIME,
145 LTTV_STATE_TIME,
146 LTTV_STATE_HOOKS,
147 LTTV_STATE_NAME_TABLES,
148 LTTV_STATE_TRACE_STATE_USE_COUNT;
149
150 static void create_max_time(LttvTraceState *tcs);
151
152 static void get_max_time(LttvTraceState *tcs);
153
154 static void free_max_time(LttvTraceState *tcs);
155
156 static void create_name_tables(LttvTraceState *tcs);
157
158 static void get_name_tables(LttvTraceState *tcs);
159
160 static void free_name_tables(LttvTraceState *tcs);
161
162 static void free_saved_state(LttvTraceState *tcs);
163
164 static void lttv_state_free_process_table(GHashTable *processes);
165
166 static void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
167 GPtrArray *quarktable);
168
169 void lttv_state_save(LttvTraceState *self, LttvAttribute *container)
170 {
171 LTTV_TRACE_STATE_GET_CLASS(self)->state_save(self, container);
172 }
173
174
175 void lttv_state_restore(LttvTraceState *self, LttvAttribute *container)
176 {
177 LTTV_TRACE_STATE_GET_CLASS(self)->state_restore(self, container);
178 }
179
180
181 void lttv_state_state_saved_free(LttvTraceState *self,
182 LttvAttribute *container)
183 {
184 LTTV_TRACE_STATE_GET_CLASS(self)->state_saved_free(self, container);
185 }
186
187
188 guint process_hash(gconstpointer key)
189 {
190 guint pid = ((const LttvProcessState *)key)->pid;
191 return (pid>>8 ^ pid>>4 ^ pid>>2 ^ pid) ;
192 }
193
194
195 /* If the hash table hash function is well distributed,
196 * the process_equal should compare different pid */
197 gboolean process_equal(gconstpointer a, gconstpointer b)
198 {
199 const LttvProcessState *process_a, *process_b;
200 gboolean ret = TRUE;
201
202 process_a = (const LttvProcessState *)a;
203 process_b = (const LttvProcessState *)b;
204
205 if(likely(process_a->pid != process_b->pid)) ret = FALSE;
206 else if(likely(process_a->pid == 0 &&
207 process_a->cpu != process_b->cpu)) ret = FALSE;
208
209 return ret;
210 }
211
212 static void delete_usertrace(gpointer key, gpointer value, gpointer user_data)
213 {
214 g_tree_destroy((GTree*)value);
215 }
216
217 static void lttv_state_free_usertraces(GHashTable *usertraces)
218 {
219 g_hash_table_foreach(usertraces, delete_usertrace, NULL);
220 g_hash_table_destroy(usertraces);
221 }
222
223
224
225 static void
226 restore_init_state(LttvTraceState *self)
227 {
228 guint i, nb_cpus;
229
230 LttvTracefileState *tfcs;
231
232 LttTime start_time, end_time;
233
234 /* Free the process tables */
235 if(self->processes != NULL) lttv_state_free_process_table(self->processes);
236 if(self->usertraces != NULL) lttv_state_free_usertraces(self->usertraces);
237 self->processes = g_hash_table_new(process_hash, process_equal);
238 self->usertraces = g_hash_table_new(g_direct_hash, g_direct_equal);
239 self->nb_event = 0;
240
241 /* Seek time to beginning */
242 // Mathieu : fix : don't seek traceset here : causes inconsistency in seek
243 // closest. It's the tracecontext job to seek the trace to the beginning
244 // anyway : the init state might be used at the middle of the trace as well...
245 //g_tree_destroy(self->parent.ts_context->pqueue);
246 //self->parent.ts_context->pqueue = g_tree_new(compare_tracefile);
247
248 ltt_trace_time_span_get(self->parent.t, &start_time, &end_time);
249
250 //lttv_process_trace_seek_time(&self->parent, ltt_time_zero);
251
252 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
253
254 /* Put the per cpu running_process to beginning state : process 0. */
255 for(i=0; i< nb_cpus; i++) {
256 LttvExecutionState *es;
257 self->running_process[i] = lttv_state_create_process(self, NULL, i, 0, 0,
258 LTTV_STATE_UNNAMED, &start_time);
259 /* We are not sure is it's a kernel thread or normal thread, put the
260 * bottom stack state to unknown */
261 self->running_process[i]->execution_stack =
262 g_array_set_size(self->running_process[i]->execution_stack, 1);
263 es = self->running_process[i]->state =
264 &g_array_index(self->running_process[i]->execution_stack,
265 LttvExecutionState, 0);
266 es->t = LTTV_STATE_MODE_UNKNOWN;
267 es->s = LTTV_STATE_UNNAMED;
268
269 //self->running_process[i]->state->s = LTTV_STATE_RUN;
270 self->running_process[i]->cpu = i;
271 }
272
273 #if 0
274 nb_tracefile = self->parent.tracefiles->len;
275
276 for(i = 0 ; i < nb_tracefile ; i++) {
277 tfcs =
278 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
279 LttvTracefileContext*, i));
280 ltt_trace_time_span_get(self->parent.t, &tfcs->parent.timestamp, NULL);
281 // tfcs->saved_position = 0;
282 tfcs->process = lttv_state_create_process(tfcs, NULL,0);
283 tfcs->process->state->s = LTTV_STATE_RUN;
284 tfcs->process->last_cpu = tfcs->cpu_name;
285 tfcs->process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfcs)->tf);
286 }
287 #endif //0
288 }
289
290 //static LttTime time_zero = {0,0};
291
292 static gint compare_usertraces(gconstpointer a, gconstpointer b,
293 gpointer user_data)
294 {
295 const LttTime *t1 = (const LttTime *)a;
296 const LttTime *t2 = (const LttTime *)b;
297
298 return ltt_time_compare(*t1, *t2);
299 }
300
301 static void free_usertrace_key(gpointer data)
302 {
303 g_free(data);
304 }
305
306 #define MAX_STRING_LEN 4096
307
308 static void
309 state_load_saved_states(LttvTraceState *tcs)
310 {
311 FILE *fp;
312 GPtrArray *quarktable;
313 char *trace_path;
314 char path[PATH_MAX];
315 guint count;
316 guint i;
317 tcs->has_precomputed_states = FALSE;
318 GQuark q;
319 gchar *string;
320 gint hdr;
321 gchar buf[MAX_STRING_LEN];
322 guint len;
323
324 trace_path = g_quark_to_string(ltt_trace_name(tcs->parent.t));
325 strncpy(path, trace_path, PATH_MAX-1);
326 count = strnlen(trace_path, PATH_MAX-1);
327 // quarktable : open, test
328 strncat(path, "/precomputed/quarktable", PATH_MAX-count-1);
329 fp = fopen(path, "r");
330 if(!fp) return;
331 quarktable = g_ptr_array_sized_new(4096);
332
333 /* Index 0 is null */
334 hdr = fgetc(fp);
335 if(hdr == EOF) return;
336 g_assert(hdr == HDR_QUARKS);
337 q = 1;
338 do {
339 hdr = fgetc(fp);
340 if(hdr == EOF) break;
341 g_assert(hdr == HDR_QUARK);
342 g_ptr_array_set_size(quarktable, q+1);
343 i=0;
344 while(1) {
345 fread(&buf[i], sizeof(gchar), 1, fp);
346 if(buf[i] == '\0' || feof(fp)) break;
347 i++;
348 }
349 len = strnlen(buf, MAX_STRING_LEN-1);
350 g_ptr_array_index (quarktable, q) = g_new(gchar, len+1);
351 strncpy(g_ptr_array_index (quarktable, q), buf, len+1);
352 q++;
353 } while(1);
354
355 fclose(fp);
356
357 // saved_states : open, test
358 strncpy(path, trace_path, PATH_MAX-1);
359 count = strnlen(trace_path, PATH_MAX-1);
360 strncat(path, "/precomputed/states", PATH_MAX-count-1);
361 fp = fopen(path, "r");
362 if(!fp) return;
363
364 hdr = fgetc(fp);
365 if(hdr != HDR_TRACE) goto end;
366
367 lttv_trace_states_read_raw(tcs, fp, quarktable);
368
369 tcs->has_precomputed_states = TRUE;
370
371 end:
372 fclose(fp);
373
374 /* Free the quarktable */
375 for(i=0; i<quarktable->len; i++) {
376 string = g_ptr_array_index (quarktable, i);
377 g_free(string);
378 }
379 g_ptr_array_free(quarktable, TRUE);
380 return;
381 }
382
383 static void
384 init(LttvTracesetState *self, LttvTraceset *ts)
385 {
386 guint i, j, nb_trace, nb_tracefile, nb_cpu;
387
388 LttvTraceContext *tc;
389
390 LttvTraceState *tcs;
391
392 LttvTracefileState *tfcs;
393
394 LttvAttributeValue v;
395
396 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
397 init((LttvTracesetContext *)self, ts);
398
399 nb_trace = lttv_traceset_number(ts);
400 for(i = 0 ; i < nb_trace ; i++) {
401 tc = self->parent.traces[i];
402 tcs = LTTV_TRACE_STATE(tc);
403 tcs->save_interval = LTTV_STATE_SAVE_INTERVAL;
404 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
405 LTTV_UINT, &v);
406 (*v.v_uint)++;
407
408 if(*(v.v_uint) == 1) {
409 create_name_tables(tcs);
410 create_max_time(tcs);
411 }
412 get_name_tables(tcs);
413 get_max_time(tcs);
414
415 nb_tracefile = tc->tracefiles->len;
416 nb_cpu = ltt_trace_get_num_cpu(tc->t);
417 tcs->processes = NULL;
418 tcs->usertraces = NULL;
419 tcs->running_process = g_new(LttvProcessState*, nb_cpu);
420 /* init cpu resource stuff */
421 tcs->cpu_states = g_new(LttvCPUState, nb_cpu);
422 for(j = 0; j<nb_cpu; j++) {
423 tcs->cpu_states[j].mode_stack = g_array_new(FALSE, FALSE, sizeof(LttvCPUMode));
424 g_assert(tcs->cpu_states[j].mode_stack != NULL);
425 }
426
427 restore_init_state(tcs);
428 for(j = 0 ; j < nb_tracefile ; j++) {
429 tfcs =
430 LTTV_TRACEFILE_STATE(g_array_index(tc->tracefiles,
431 LttvTracefileContext*, j));
432 tfcs->tracefile_name = ltt_tracefile_name(tfcs->parent.tf);
433 tfcs->cpu = ltt_tracefile_cpu(tfcs->parent.tf);
434 tfcs->cpu_state = &(tcs->cpu_states[tfcs->cpu]);
435 if(ltt_tracefile_tid(tfcs->parent.tf) != 0) {
436 /* It's a Usertrace */
437 guint tid = ltt_tracefile_tid(tfcs->parent.tf);
438 GTree *usertrace_tree = (GTree*)g_hash_table_lookup(tcs->usertraces,
439 (gconstpointer)tid);
440 if(!usertrace_tree) {
441 usertrace_tree = g_tree_new_full(compare_usertraces,
442 NULL, free_usertrace_key, NULL);
443 g_hash_table_insert(tcs->usertraces,
444 (gpointer)tid, usertrace_tree);
445 }
446 LttTime *timestamp = g_new(LttTime, 1);
447 *timestamp = ltt_interpolate_time_from_tsc(tfcs->parent.tf,
448 ltt_tracefile_creation(tfcs->parent.tf));
449 g_tree_insert(usertrace_tree, timestamp, tfcs);
450 }
451 }
452
453 /* See if the trace has saved states */
454 state_load_saved_states(tcs);
455 }
456 }
457
458 static void
459 fini(LttvTracesetState *self)
460 {
461 guint i, nb_trace;
462
463 LttvTraceState *tcs;
464
465 LttvTracefileState *tfcs;
466
467 LttvAttributeValue v;
468
469 nb_trace = lttv_traceset_number(LTTV_TRACESET_CONTEXT(self)->ts);
470 for(i = 0 ; i < nb_trace ; i++) {
471 tcs = (LttvTraceState *)(LTTV_TRACESET_CONTEXT(self)->traces[i]);
472 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_TRACE_STATE_USE_COUNT,
473 LTTV_UINT, &v);
474
475 g_assert(*(v.v_uint) != 0);
476 (*v.v_uint)--;
477
478 if(*(v.v_uint) == 0) {
479 free_name_tables(tcs);
480 free_max_time(tcs);
481 free_saved_state(tcs);
482 }
483 g_free(tcs->running_process);
484 tcs->running_process = NULL;
485 lttv_state_free_process_table(tcs->processes);
486 lttv_state_free_usertraces(tcs->usertraces);
487 tcs->processes = NULL;
488 tcs->usertraces = NULL;
489 }
490 LTTV_TRACESET_CONTEXT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
491 fini((LttvTracesetContext *)self);
492 }
493
494
495 static LttvTracesetContext *
496 new_traceset_context(LttvTracesetContext *self)
497 {
498 return LTTV_TRACESET_CONTEXT(g_object_new(LTTV_TRACESET_STATE_TYPE, NULL));
499 }
500
501
502 static LttvTraceContext *
503 new_trace_context(LttvTracesetContext *self)
504 {
505 return LTTV_TRACE_CONTEXT(g_object_new(LTTV_TRACE_STATE_TYPE, NULL));
506 }
507
508
509 static LttvTracefileContext *
510 new_tracefile_context(LttvTracesetContext *self)
511 {
512 return LTTV_TRACEFILE_CONTEXT(g_object_new(LTTV_TRACEFILE_STATE_TYPE, NULL));
513 }
514
515
516 /* Write the process state of the trace */
517
518 static void write_process_state(gpointer key, gpointer value,
519 gpointer user_data)
520 {
521 LttvProcessState *process;
522
523 LttvExecutionState *es;
524
525 FILE *fp = (FILE *)user_data;
526
527 guint i;
528 guint64 address;
529
530 process = (LttvProcessState *)value;
531 fprintf(fp,
532 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\">\n",
533 process, process->pid, process->tgid, process->ppid,
534 g_quark_to_string(process->type),
535 process->creation_time.tv_sec,
536 process->creation_time.tv_nsec,
537 process->insertion_time.tv_sec,
538 process->insertion_time.tv_nsec,
539 g_quark_to_string(process->name),
540 g_quark_to_string(process->brand),
541 process->cpu);
542
543 for(i = 0 ; i < process->execution_stack->len; i++) {
544 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
545 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
546 g_quark_to_string(es->t), g_quark_to_string(es->n),
547 es->entry.tv_sec, es->entry.tv_nsec);
548 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
549 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
550 }
551
552 for(i = 0 ; i < process->user_stack->len; i++) {
553 address = &g_array_index(process->user_stack, guint64, i);
554 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n",
555 address);
556 }
557
558 if(process->usertrace) {
559 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
560 g_quark_to_string(process->usertrace->tracefile_name),
561 process->usertrace->cpu);
562 }
563
564
565 fprintf(fp, " </PROCESS>\n");
566 }
567
568
569 void lttv_state_write(LttvTraceState *self, LttTime t, FILE *fp)
570 {
571 guint i, nb_tracefile, nb_block, offset;
572 guint64 tsc;
573
574 LttvTracefileState *tfcs;
575
576 LttTracefile *tf;
577
578 LttEventPosition *ep;
579
580 guint nb_cpus;
581
582 ep = ltt_event_position_new();
583
584 fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
585
586 g_hash_table_foreach(self->processes, write_process_state, fp);
587
588 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
589 for(i=0;i<nb_cpus;i++) {
590 fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
591 i, self->running_process[i]->pid);
592 }
593
594 nb_tracefile = self->parent.tracefiles->len;
595
596 for(i = 0 ; i < nb_tracefile ; i++) {
597 tfcs =
598 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
599 LttvTracefileContext*, i));
600 fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
601 tfcs->parent.timestamp.tv_sec,
602 tfcs->parent.timestamp.tv_nsec);
603 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
604 if(e == NULL) fprintf(fp,"/>\n");
605 else {
606 ltt_event_position(e, ep);
607 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
608 fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
609 tsc);
610 }
611 }
612 g_free(ep);
613 fprintf(fp,"</PROCESS_STATE>\n");
614 }
615
616
617 static void write_process_state_raw(gpointer key, gpointer value,
618 gpointer user_data)
619 {
620 LttvProcessState *process;
621
622 LttvExecutionState *es;
623
624 FILE *fp = (FILE *)user_data;
625
626 guint i;
627 guint64 address;
628
629 process = (LttvProcessState *)value;
630 fputc(HDR_PROCESS, fp);
631 //fwrite(&header, sizeof(header), 1, fp);
632 //fprintf(fp, "%s", g_quark_to_string(process->type));
633 //fputc('\0', fp);
634 fwrite(&process->type, sizeof(process->type), 1, fp);
635 //fprintf(fp, "%s", g_quark_to_string(process->name));
636 //fputc('\0', fp);
637 fwrite(&process->name, sizeof(process->name), 1, fp);
638 //fprintf(fp, "%s", g_quark_to_string(process->brand));
639 //fputc('\0', fp);
640 fwrite(&process->brand, sizeof(process->brand), 1, fp);
641 fwrite(&process->pid, sizeof(process->pid), 1, fp);
642 fwrite(&process->tgid, sizeof(process->tgid), 1, fp);
643 fwrite(&process->ppid, sizeof(process->ppid), 1, fp);
644 fwrite(&process->cpu, sizeof(process->cpu), 1, fp);
645 fwrite(&process->creation_time, sizeof(process->creation_time), 1, fp);
646 fwrite(&process->insertion_time, sizeof(process->insertion_time), 1, fp);
647
648 #if 0
649 fprintf(fp,
650 " <PROCESS CORE=%p PID=%u TGID=%u PPID=%u TYPE=\"%s\" CTIME_S=%lu CTIME_NS=%lu ITIME_S=%lu ITIME_NS=%lu NAME=\"%s\" BRAND=\"%s\" CPU=\"%u\" PROCESS_TYPE=%u>\n",
651 process, process->pid, process->tgid, process->ppid,
652 g_quark_to_string(process->type),
653 process->creation_time.tv_sec,
654 process->creation_time.tv_nsec,
655 process->insertion_time.tv_sec,
656 process->insertion_time.tv_nsec,
657 g_quark_to_string(process->name),
658 g_quark_to_string(process->brand),
659 process->cpu);
660 #endif //0
661
662 for(i = 0 ; i < process->execution_stack->len; i++) {
663 es = &g_array_index(process->execution_stack, LttvExecutionState, i);
664
665 fputc(HDR_ES, fp);
666 //fprintf(fp, "%s", g_quark_to_string(es->t));
667 //fputc('\0', fp);
668 fwrite(&es->t, sizeof(es->t), 1, fp);
669 //fprintf(fp, "%s", g_quark_to_string(es->n));
670 //fputc('\0', fp);
671 fwrite(&es->n, sizeof(es->n), 1, fp);
672 //fprintf(fp, "%s", g_quark_to_string(es->s));
673 //fputc('\0', fp);
674 fwrite(&es->s, sizeof(es->s), 1, fp);
675 fwrite(&es->entry, sizeof(es->entry), 1, fp);
676 fwrite(&es->change, sizeof(es->change), 1, fp);
677 fwrite(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
678 #if 0
679 fprintf(fp, " <ES MODE=\"%s\" SUBMODE=\"%s\" ENTRY_S=%lu ENTRY_NS=%lu",
680 g_quark_to_string(es->t), g_quark_to_string(es->n),
681 es->entry.tv_sec, es->entry.tv_nsec);
682 fprintf(fp, " CHANGE_S=%lu CHANGE_NS=%lu STATUS=\"%s\"/>\n",
683 es->change.tv_sec, es->change.tv_nsec, g_quark_to_string(es->s));
684 #endif //0
685 }
686
687 for(i = 0 ; i < process->user_stack->len; i++) {
688 address = &g_array_index(process->user_stack, guint64, i);
689 fputc(HDR_USER_STACK, fp);
690 fwrite(&address, sizeof(address), 1, fp);
691 #if 0
692 fprintf(fp, " <USER_STACK ADDRESS=\"%llu\"/>\n",
693 address);
694 #endif //0
695 }
696
697 if(process->usertrace) {
698 fputc(HDR_USERTRACE, fp);
699 //fprintf(fp, "%s", g_quark_to_string(process->usertrace->tracefile_name));
700 //fputc('\0', fp);
701 fwrite(&process->usertrace->tracefile_name,
702 sizeof(process->usertrace->tracefile_name), 1, fp);
703 fwrite(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
704 #if 0
705 fprintf(fp, " <USERTRACE NAME=\"%s\" CPU=%u\n/>",
706 g_quark_to_string(process->usertrace->tracefile_name),
707 process->usertrace->cpu);
708 #endif //0
709 }
710
711 }
712
713
714 void lttv_state_write_raw(LttvTraceState *self, LttTime t, FILE *fp)
715 {
716 guint i, nb_tracefile, nb_block, offset;
717 guint64 tsc;
718
719 LttvTracefileState *tfcs;
720
721 LttTracefile *tf;
722
723 LttEventPosition *ep;
724
725 guint nb_cpus;
726
727 ep = ltt_event_position_new();
728
729 //fprintf(fp,"<PROCESS_STATE TIME_S=%lu TIME_NS=%lu>\n", t.tv_sec, t.tv_nsec);
730 fputc(HDR_PROCESS_STATE, fp);
731 fwrite(&t, sizeof(t), 1, fp);
732
733 g_hash_table_foreach(self->processes, write_process_state_raw, fp);
734
735 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
736 for(i=0;i<nb_cpus;i++) {
737 fputc(HDR_CPU, fp);
738 fwrite(&i, sizeof(i), 1, fp); /* cpu number */
739 fwrite(&self->running_process[i]->pid,
740 sizeof(self->running_process[i]->pid), 1, fp);
741 //fprintf(fp," <CPU NUM=%u RUNNING_PROCESS=%u>\n",
742 // i, self->running_process[i]->pid);
743 }
744
745 nb_tracefile = self->parent.tracefiles->len;
746
747 for(i = 0 ; i < nb_tracefile ; i++) {
748 tfcs =
749 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
750 LttvTracefileContext*, i));
751 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
752 // tfcs->parent.timestamp.tv_sec,
753 // tfcs->parent.timestamp.tv_nsec);
754 fputc(HDR_TRACEFILE, fp);
755 fwrite(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
756 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
757 * position following : end of trace */
758 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
759 if(e != NULL) {
760 ltt_event_position(e, ep);
761 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
762 //fprintf(fp, " BLOCK=%u OFFSET=%u TSC=%llu/>\n", nb_block, offset,
763 // tsc);
764 fwrite(&nb_block, sizeof(nb_block), 1, fp);
765 fwrite(&offset, sizeof(offset), 1, fp);
766 fwrite(&tsc, sizeof(tsc), 1, fp);
767 }
768 }
769 g_free(ep);
770 }
771
772
773 /* Read process state from a file */
774
775 /* Called because a HDR_PROCESS was found */
776 static void read_process_state_raw(LttvTraceState *self, FILE *fp,
777 GPtrArray *quarktable)
778 {
779 LttvExecutionState *es;
780 LttvProcessState *process, *parent_process;
781 LttvProcessState tmp;
782 GQuark tmpq;
783
784 guint i;
785 guint64 *address;
786 guint cpu;
787
788 /* TODO : check return value */
789 fread(&tmp.type, sizeof(tmp.type), 1, fp);
790 fread(&tmp.name, sizeof(tmp.name), 1, fp);
791 fread(&tmp.brand, sizeof(tmp.brand), 1, fp);
792 fread(&tmp.pid, sizeof(tmp.pid), 1, fp);
793 fread(&tmp.tgid, sizeof(tmp.tgid), 1, fp);
794 fread(&tmp.ppid, sizeof(tmp.ppid), 1, fp);
795 fread(&tmp.cpu, sizeof(tmp.cpu), 1, fp);
796 fread(&tmp.creation_time, sizeof(tmp.creation_time), 1, fp);
797 fread(&tmp.insertion_time, sizeof(tmp.insertion_time), 1, fp);
798
799 if(tmp.pid == 0) {
800 process = lttv_state_find_process(self, tmp.cpu, tmp.pid);
801 } else {
802 /* We must link to the parent */
803 parent_process = lttv_state_find_process_or_create(self, ANY_CPU, tmp.ppid,
804 &ltt_time_zero);
805 process = lttv_state_find_process(self, ANY_CPU, tmp.pid);
806 if(process == NULL) {
807 process = lttv_state_create_process(self, parent_process, tmp.cpu,
808 tmp.pid, tmp.tgid,
809 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name)),
810 &tmp.creation_time);
811 }
812 }
813 process->insertion_time = tmp.insertion_time;
814 process->creation_time = tmp.creation_time;
815 process->type = g_quark_from_string(
816 (gchar*)g_ptr_array_index(quarktable, tmp.type));
817 process->tgid = tmp.tgid;
818 process->ppid = tmp.ppid;
819 process->brand = g_quark_from_string(
820 (gchar*)g_ptr_array_index(quarktable, tmp.brand));
821 process->name =
822 g_quark_from_string((gchar*)g_ptr_array_index(quarktable, tmp.name));
823
824
825 do {
826 if(feof(fp) || ferror(fp)) goto end_loop;
827
828 gint hdr = fgetc(fp);
829 if(hdr == EOF) goto end_loop;
830
831 switch(hdr) {
832 case HDR_ES:
833 process->execution_stack =
834 g_array_set_size(process->execution_stack,
835 process->execution_stack->len + 1);
836 es = &g_array_index(process->execution_stack, LttvExecutionState,
837 process->execution_stack->len-1);
838 process->state = es;
839
840 fread(&es->t, sizeof(es->t), 1, fp);
841 es->t = g_quark_from_string(
842 (gchar*)g_ptr_array_index(quarktable, es->t));
843 fread(&es->n, sizeof(es->n), 1, fp);
844 es->n = g_quark_from_string(
845 (gchar*)g_ptr_array_index(quarktable, es->n));
846 fread(&es->s, sizeof(es->s), 1, fp);
847 es->s = g_quark_from_string(
848 (gchar*)g_ptr_array_index(quarktable, es->s));
849 fread(&es->entry, sizeof(es->entry), 1, fp);
850 fread(&es->change, sizeof(es->change), 1, fp);
851 fread(&es->cum_cpu_time, sizeof(es->cum_cpu_time), 1, fp);
852 break;
853 case HDR_USER_STACK:
854 process->user_stack = g_array_set_size(process->user_stack,
855 process->user_stack->len + 1);
856 address = &g_array_index(process->user_stack, guint64,
857 process->user_stack->len-1);
858 fread(address, sizeof(address), 1, fp);
859 process->current_function = *address;
860 break;
861 case HDR_USERTRACE:
862 fread(&tmpq, sizeof(tmpq), 1, fp);
863 fread(&process->usertrace->cpu, sizeof(process->usertrace->cpu), 1, fp);
864 break;
865 default:
866 ungetc(hdr, fp);
867 goto end_loop;
868 };
869 } while(1);
870 end_loop:
871 return;
872 }
873
874
875 /* Called because a HDR_PROCESS_STATE was found */
876 /* Append a saved state to the trace states */
877 void lttv_state_read_raw(LttvTraceState *self, FILE *fp, GPtrArray *quarktable)
878 {
879 guint i, nb_tracefile, nb_block, offset;
880 guint64 tsc;
881 LttvTracefileState *tfcs;
882
883 LttEventPosition *ep;
884
885 guint nb_cpus;
886
887 int hdr;
888
889 LttTime t;
890
891 LttvAttribute *saved_states_tree, *saved_state_tree;
892
893 LttvAttributeValue value;
894 GTree *pqueue = self->parent.ts_context->pqueue;
895 ep = ltt_event_position_new();
896
897 restore_init_state(self);
898
899 fread(&t, sizeof(t), 1, fp);
900
901 do {
902 if(feof(fp) || ferror(fp)) goto end_loop;
903 hdr = fgetc(fp);
904 if(hdr == EOF) goto end_loop;
905
906 switch(hdr) {
907 case HDR_PROCESS:
908 /* Call read_process_state_raw */
909 read_process_state_raw(self, fp, quarktable);
910 break;
911 case HDR_TRACEFILE:
912 case HDR_TRACESET:
913 case HDR_TRACE:
914 case HDR_QUARKS:
915 case HDR_QUARK:
916 case HDR_ES:
917 case HDR_USER_STACK:
918 case HDR_USERTRACE:
919 case HDR_PROCESS_STATE:
920 case HDR_CPU:
921 ungetc(hdr, fp);
922 goto end_loop;
923 break;
924 default:
925 g_error("Error while parsing saved state file : unknown data header %d",
926 hdr);
927 };
928 } while(1);
929 end_loop:
930
931 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
932 for(i=0;i<nb_cpus;i++) {
933 int cpu_num;
934 hdr = fgetc(fp);
935 g_assert(hdr == HDR_CPU);
936 fread(&cpu_num, sizeof(cpu_num), 1, fp); /* cpu number */
937 g_assert(i == cpu_num);
938 fread(&self->running_process[i]->pid,
939 sizeof(self->running_process[i]->pid), 1, fp);
940 }
941
942 nb_tracefile = self->parent.tracefiles->len;
943
944 for(i = 0 ; i < nb_tracefile ; i++) {
945 tfcs =
946 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
947 LttvTracefileContext*, i));
948 // fprintf(fp, " <TRACEFILE TIMESTAMP_S=%lu TIMESTAMP_NS=%lu",
949 // tfcs->parent.timestamp.tv_sec,
950 // tfcs->parent.timestamp.tv_nsec);
951 g_tree_remove(pqueue, &tfcs->parent);
952 hdr = fgetc(fp);
953 g_assert(hdr == HDR_TRACEFILE);
954 fread(&tfcs->parent.timestamp, sizeof(tfcs->parent.timestamp), 1, fp);
955 /* Note : if timestamp if LTT_TIME_INFINITE, there will be no
956 * position following : end of trace */
957 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) != 0) {
958 fread(&nb_block, sizeof(nb_block), 1, fp);
959 fread(&offset, sizeof(offset), 1, fp);
960 fread(&tsc, sizeof(tsc), 1, fp);
961 ltt_event_position_set(ep, tfcs->parent.tf, nb_block, offset, tsc);
962 gint ret = ltt_tracefile_seek_position(tfcs->parent.tf, ep);
963 g_assert(ret == 0);
964 g_tree_insert(pqueue, &tfcs->parent, &tfcs->parent);
965 }
966 }
967 g_free(ep);
968
969 saved_states_tree = lttv_attribute_find_subdir(self->parent.t_a,
970 LTTV_STATE_SAVED_STATES);
971 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
972 value = lttv_attribute_add(saved_states_tree,
973 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
974 *(value.v_gobject) = (GObject *)saved_state_tree;
975 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
976 *(value.v_time) = t;
977 lttv_state_save(self, saved_state_tree);
978 g_debug("Saving state at time %lu.%lu", t.tv_sec,
979 t.tv_nsec);
980
981 *(self->max_time_state_recomputed_in_seek) = t;
982
983 }
984
985 /* Called when a HDR_TRACE is found */
986 void lttv_trace_states_read_raw(LttvTraceState *tcs, FILE *fp,
987 GPtrArray *quarktable)
988 {
989 int hdr;
990
991 do {
992 if(feof(fp) || ferror(fp)) goto end_loop;
993 hdr = fgetc(fp);
994 if(hdr == EOF) goto end_loop;
995
996 switch(hdr) {
997 case HDR_PROCESS_STATE:
998 /* Call read_process_state_raw */
999 lttv_state_read_raw(tcs, fp, quarktable);
1000 break;
1001 case HDR_TRACEFILE:
1002 case HDR_TRACESET:
1003 case HDR_TRACE:
1004 case HDR_QUARKS:
1005 case HDR_QUARK:
1006 case HDR_ES:
1007 case HDR_USER_STACK:
1008 case HDR_USERTRACE:
1009 case HDR_PROCESS:
1010 case HDR_CPU:
1011 g_error("Error while parsing saved state file :"
1012 " unexpected data header %d",
1013 hdr);
1014 break;
1015 default:
1016 g_error("Error while parsing saved state file : unknown data header %d",
1017 hdr);
1018 };
1019 } while(1);
1020 end_loop:
1021 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
1022 restore_init_state(tcs);
1023 lttv_process_trace_seek_time(tcs, ltt_time_zero);
1024 return;
1025 }
1026
1027
1028
1029 /* Copy each process from an existing hash table to a new one */
1030
1031 static void copy_process_state(gpointer key, gpointer value,gpointer user_data)
1032 {
1033 LttvProcessState *process, *new_process;
1034
1035 GHashTable *new_processes = (GHashTable *)user_data;
1036
1037 guint i;
1038
1039 process = (LttvProcessState *)value;
1040 new_process = g_new(LttvProcessState, 1);
1041 *new_process = *process;
1042 new_process->execution_stack = g_array_sized_new(FALSE, FALSE,
1043 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1044 new_process->execution_stack =
1045 g_array_set_size(new_process->execution_stack,
1046 process->execution_stack->len);
1047 for(i = 0 ; i < process->execution_stack->len; i++) {
1048 g_array_index(new_process->execution_stack, LttvExecutionState, i) =
1049 g_array_index(process->execution_stack, LttvExecutionState, i);
1050 }
1051 new_process->state = &g_array_index(new_process->execution_stack,
1052 LttvExecutionState, new_process->execution_stack->len - 1);
1053 new_process->user_stack = g_array_sized_new(FALSE, FALSE,
1054 sizeof(guint64), 0);
1055 new_process->user_stack =
1056 g_array_set_size(new_process->user_stack,
1057 process->user_stack->len);
1058 for(i = 0 ; i < process->user_stack->len; i++) {
1059 g_array_index(new_process->user_stack, guint64, i) =
1060 g_array_index(process->user_stack, guint64, i);
1061 }
1062 new_process->current_function = process->current_function;
1063 g_hash_table_insert(new_processes, new_process, new_process);
1064 }
1065
1066
1067 static GHashTable *lttv_state_copy_process_table(GHashTable *processes)
1068 {
1069 GHashTable *new_processes = g_hash_table_new(process_hash, process_equal);
1070
1071 g_hash_table_foreach(processes, copy_process_state, new_processes);
1072 return new_processes;
1073 }
1074
1075
1076 /* The saved state for each trace contains a member "processes", which
1077 stores a copy of the process table, and a member "tracefiles" with
1078 one entry per tracefile. Each tracefile has a "process" member pointing
1079 to the current process and a "position" member storing the tracefile
1080 position (needed to seek to the current "next" event. */
1081
1082 static void state_save(LttvTraceState *self, LttvAttribute *container)
1083 {
1084 guint i, nb_tracefile, nb_cpus;
1085
1086 LttvTracefileState *tfcs;
1087
1088 LttvAttribute *tracefiles_tree, *tracefile_tree;
1089
1090 guint *running_process;
1091
1092 LttvAttributeType type;
1093
1094 LttvAttributeValue value;
1095
1096 LttvAttributeName name;
1097
1098 LttEventPosition *ep;
1099
1100 tracefiles_tree = lttv_attribute_find_subdir(container,
1101 LTTV_STATE_TRACEFILES);
1102
1103 value = lttv_attribute_add(container, LTTV_STATE_PROCESSES,
1104 LTTV_POINTER);
1105 *(value.v_pointer) = lttv_state_copy_process_table(self->processes);
1106
1107 /* Add the currently running processes array */
1108 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1109 running_process = g_new(guint, nb_cpus);
1110 for(i=0;i<nb_cpus;i++) {
1111 running_process[i] = self->running_process[i]->pid;
1112 }
1113 value = lttv_attribute_add(container, LTTV_STATE_RUNNING_PROCESS,
1114 LTTV_POINTER);
1115 *(value.v_pointer) = running_process;
1116
1117 g_info("State save");
1118
1119 nb_tracefile = self->parent.tracefiles->len;
1120
1121 for(i = 0 ; i < nb_tracefile ; i++) {
1122 tfcs =
1123 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1124 LttvTracefileContext*, i));
1125 tracefile_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
1126 value = lttv_attribute_add(tracefiles_tree, i,
1127 LTTV_GOBJECT);
1128 *(value.v_gobject) = (GObject *)tracefile_tree;
1129 #if 0
1130 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_PROCESS,
1131 LTTV_UINT);
1132 *(value.v_uint) = tfcs->process->pid;
1133 #endif //0
1134 value = lttv_attribute_add(tracefile_tree, LTTV_STATE_EVENT,
1135 LTTV_POINTER);
1136 /* Only save the position if the tfs has not infinite time. */
1137 //if(!g_tree_lookup(self->parent.ts_context->pqueue, &tfcs->parent)
1138 // && current_tfcs != tfcs) {
1139 if(ltt_time_compare(tfcs->parent.timestamp, ltt_time_infinite) == 0) {
1140 *(value.v_pointer) = NULL;
1141 } else {
1142 LttEvent *e = ltt_tracefile_get_event(tfcs->parent.tf);
1143 ep = ltt_event_position_new();
1144 ltt_event_position(e, ep);
1145 *(value.v_pointer) = ep;
1146
1147 guint nb_block, offset;
1148 guint64 tsc;
1149 LttTracefile *tf;
1150 ltt_event_position_get(ep, &tf, &nb_block, &offset, &tsc);
1151 g_info("Block %u offset %u tsc %llu time %lu.%lu", nb_block, offset,
1152 tsc,
1153 tfcs->parent.timestamp.tv_sec, tfcs->parent.timestamp.tv_nsec);
1154 }
1155 }
1156 }
1157
1158
1159 static void state_restore(LttvTraceState *self, LttvAttribute *container)
1160 {
1161 guint i, nb_tracefile, pid, nb_cpus;
1162
1163 LttvTracefileState *tfcs;
1164
1165 LttvAttribute *tracefiles_tree, *tracefile_tree;
1166
1167 guint *running_process;
1168
1169 LttvAttributeType type;
1170
1171 LttvAttributeValue value;
1172
1173 LttvAttributeName name;
1174
1175 gboolean is_named;
1176
1177 LttEventPosition *ep;
1178
1179 LttvTracesetContext *tsc = self->parent.ts_context;
1180
1181 tracefiles_tree = lttv_attribute_find_subdir(container,
1182 LTTV_STATE_TRACEFILES);
1183
1184 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1185 &value);
1186 g_assert(type == LTTV_POINTER);
1187 lttv_state_free_process_table(self->processes);
1188 self->processes = lttv_state_copy_process_table(*(value.v_pointer));
1189
1190 /* Add the currently running processes array */
1191 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1192 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1193 &value);
1194 g_assert(type == LTTV_POINTER);
1195 running_process = *(value.v_pointer);
1196 for(i=0;i<nb_cpus;i++) {
1197 pid = running_process[i];
1198 self->running_process[i] = lttv_state_find_process(self, i, pid);
1199 g_assert(self->running_process[i] != NULL);
1200 }
1201
1202
1203 nb_tracefile = self->parent.tracefiles->len;
1204
1205 //g_tree_destroy(tsc->pqueue);
1206 //tsc->pqueue = g_tree_new(compare_tracefile);
1207
1208 for(i = 0 ; i < nb_tracefile ; i++) {
1209 tfcs =
1210 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1211 LttvTracefileContext*, i));
1212 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1213 g_assert(type == LTTV_GOBJECT);
1214 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1215 #if 0
1216 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_PROCESS,
1217 &value);
1218 g_assert(type == LTTV_UINT);
1219 pid = *(value.v_uint);
1220 tfcs->process = lttv_state_find_process_or_create(tfcs, pid);
1221 #endif //0
1222 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1223 &value);
1224 g_assert(type == LTTV_POINTER);
1225 //g_assert(*(value.v_pointer) != NULL);
1226 ep = *(value.v_pointer);
1227 g_assert(tfcs->parent.t_context != NULL);
1228
1229 LttvTracefileContext *tfc = LTTV_TRACEFILE_CONTEXT(tfcs);
1230 g_tree_remove(tsc->pqueue, tfc);
1231
1232 if(ep != NULL) {
1233 g_assert(ltt_tracefile_seek_position(tfc->tf, ep) == 0);
1234 tfc->timestamp = ltt_event_time(ltt_tracefile_get_event(tfc->tf));
1235 g_assert(ltt_time_compare(tfc->timestamp, ltt_time_infinite) != 0);
1236 g_tree_insert(tsc->pqueue, tfc, tfc);
1237 g_info("Restoring state for a tf at time %lu.%lu", tfc->timestamp.tv_sec, tfc->timestamp.tv_nsec);
1238 } else {
1239 tfc->timestamp = ltt_time_infinite;
1240 }
1241 }
1242 }
1243
1244
1245 static void state_saved_free(LttvTraceState *self, LttvAttribute *container)
1246 {
1247 guint i, nb_tracefile, nb_cpus;
1248
1249 LttvTracefileState *tfcs;
1250
1251 LttvAttribute *tracefiles_tree, *tracefile_tree;
1252
1253 guint *running_process;
1254
1255 LttvAttributeType type;
1256
1257 LttvAttributeValue value;
1258
1259 LttvAttributeName name;
1260
1261 gboolean is_named;
1262
1263 LttEventPosition *ep;
1264
1265 tracefiles_tree = lttv_attribute_find_subdir(container,
1266 LTTV_STATE_TRACEFILES);
1267 g_object_ref(G_OBJECT(tracefiles_tree));
1268 lttv_attribute_remove_by_name(container, LTTV_STATE_TRACEFILES);
1269
1270 type = lttv_attribute_get_by_name(container, LTTV_STATE_PROCESSES,
1271 &value);
1272 g_assert(type == LTTV_POINTER);
1273 lttv_state_free_process_table(*(value.v_pointer));
1274 *(value.v_pointer) = NULL;
1275 lttv_attribute_remove_by_name(container, LTTV_STATE_PROCESSES);
1276
1277 /* Free running processes array */
1278 nb_cpus = ltt_trace_get_num_cpu(self->parent.t);
1279 type = lttv_attribute_get_by_name(container, LTTV_STATE_RUNNING_PROCESS,
1280 &value);
1281 g_assert(type == LTTV_POINTER);
1282 running_process = *(value.v_pointer);
1283 g_free(running_process);
1284
1285 nb_tracefile = self->parent.tracefiles->len;
1286
1287 for(i = 0 ; i < nb_tracefile ; i++) {
1288 tfcs =
1289 LTTV_TRACEFILE_STATE(g_array_index(self->parent.tracefiles,
1290 LttvTracefileContext*, i));
1291 type = lttv_attribute_get(tracefiles_tree, i, &name, &value, &is_named);
1292 g_assert(type == LTTV_GOBJECT);
1293 tracefile_tree = *((LttvAttribute **)(value.v_gobject));
1294
1295 type = lttv_attribute_get_by_name(tracefile_tree, LTTV_STATE_EVENT,
1296 &value);
1297 g_assert(type == LTTV_POINTER);
1298 if(*(value.v_pointer) != NULL) g_free(*(value.v_pointer));
1299 }
1300 g_object_unref(G_OBJECT(tracefiles_tree));
1301 }
1302
1303
1304 static void free_saved_state(LttvTraceState *self)
1305 {
1306 guint i, nb;
1307
1308 LttvAttributeType type;
1309
1310 LttvAttributeValue value;
1311
1312 LttvAttributeName name;
1313
1314 gboolean is_named;
1315
1316 LttvAttribute *saved_states;
1317
1318 saved_states = lttv_attribute_find_subdir(self->parent.t_a,
1319 LTTV_STATE_SAVED_STATES);
1320
1321 nb = lttv_attribute_get_number(saved_states);
1322 for(i = 0 ; i < nb ; i++) {
1323 type = lttv_attribute_get(saved_states, i, &name, &value, &is_named);
1324 g_assert(type == LTTV_GOBJECT);
1325 state_saved_free(self, *((LttvAttribute **)value.v_gobject));
1326 }
1327
1328 lttv_attribute_remove_by_name(self->parent.t_a, LTTV_STATE_SAVED_STATES);
1329 }
1330
1331
1332 static void
1333 create_max_time(LttvTraceState *tcs)
1334 {
1335 LttvAttributeValue v;
1336
1337 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1338 LTTV_POINTER, &v);
1339 g_assert(*(v.v_pointer) == NULL);
1340 *(v.v_pointer) = g_new(LttTime,1);
1341 *((LttTime *)*(v.v_pointer)) = ltt_time_zero;
1342 }
1343
1344
1345 static void
1346 get_max_time(LttvTraceState *tcs)
1347 {
1348 LttvAttributeValue v;
1349
1350 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1351 LTTV_POINTER, &v);
1352 g_assert(*(v.v_pointer) != NULL);
1353 tcs->max_time_state_recomputed_in_seek = (LttTime *)*(v.v_pointer);
1354 }
1355
1356
1357 static void
1358 free_max_time(LttvTraceState *tcs)
1359 {
1360 LttvAttributeValue v;
1361
1362 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_SAVED_STATES_TIME,
1363 LTTV_POINTER, &v);
1364 g_free(*(v.v_pointer));
1365 *(v.v_pointer) = NULL;
1366 }
1367
1368
1369 typedef struct _LttvNameTables {
1370 // FIXME GQuark *eventtype_names;
1371 GQuark *syscall_names;
1372 guint nb_syscalls;
1373 GQuark *trap_names;
1374 guint nb_traps;
1375 GQuark *irq_names;
1376 guint nb_irqs;
1377 GQuark *soft_irq_names;
1378 guint nb_softirqs;
1379 } LttvNameTables;
1380
1381
1382 static void
1383 create_name_tables(LttvTraceState *tcs)
1384 {
1385 int i, nb;
1386
1387 GQuark f_name, e_name;
1388
1389 LttvTraceHook h;
1390
1391 LttvTraceHookByFacility *thf;
1392
1393 LttEventType *et;
1394
1395 LttType *t;
1396
1397 GString *fe_name = g_string_new("");
1398
1399 LttvNameTables *name_tables = g_new(LttvNameTables, 1);
1400
1401 LttvAttributeValue v;
1402
1403 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1404 LTTV_POINTER, &v);
1405 g_assert(*(v.v_pointer) == NULL);
1406 *(v.v_pointer) = name_tables;
1407 #if 0 // Use iteration over the facilities_by_name and then list all event
1408 // types of each facility
1409 nb = ltt_trace_eventtype_number(tcs->parent.t);
1410 name_tables->eventtype_names = g_new(GQuark, nb);
1411 for(i = 0 ; i < nb ; i++) {
1412 et = ltt_trace_eventtype_get(tcs->parent.t, i);
1413 e_name = ltt_eventtype_name(et);
1414 f_name = ltt_facility_name(ltt_eventtype_facility(et));
1415 g_string_printf(fe_name, "%s.%s", f_name, e_name);
1416 name_tables->eventtype_names[i] = g_quark_from_string(fe_name->str);
1417 }
1418 #endif //0
1419 if(!lttv_trace_find_hook(tcs->parent.t,
1420 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
1421 LTT_FIELD_SYSCALL_ID, 0, 0,
1422 NULL, NULL, &h)) {
1423
1424 thf = lttv_trace_hook_get_first(&h);
1425
1426 t = ltt_field_type(thf->f1);
1427 nb = ltt_type_element_number(t);
1428
1429 lttv_trace_hook_destroy(&h);
1430
1431 name_tables->syscall_names = g_new(GQuark, nb);
1432 name_tables->nb_syscalls = nb;
1433
1434 for(i = 0 ; i < nb ; i++) {
1435 name_tables->syscall_names[i] = ltt_enum_string_get(t, i);
1436 if(!name_tables->syscall_names[i]) {
1437 GString *string = g_string_new("");
1438 g_string_printf(string, "syscall %u", i);
1439 name_tables->syscall_names[i] = g_quark_from_string(string->str);
1440 g_string_free(string, TRUE);
1441 }
1442 }
1443
1444 //name_tables->syscall_names = g_new(GQuark, 256);
1445 //for(i = 0 ; i < 256 ; i++) {
1446 // g_string_printf(fe_name, "syscall %d", i);
1447 // name_tables->syscall_names[i] = g_quark_from_string(fe_name->str);
1448 //}
1449 } else {
1450 name_tables->syscall_names = NULL;
1451 name_tables->nb_syscalls = 0;
1452 }
1453
1454 if(!lttv_trace_find_hook(tcs->parent.t, LTT_FACILITY_KERNEL_ARCH,
1455 LTT_EVENT_TRAP_ENTRY,
1456 LTT_FIELD_TRAP_ID, 0, 0,
1457 NULL, NULL, &h)) {
1458
1459 thf = lttv_trace_hook_get_first(&h);
1460
1461 t = ltt_field_type(thf->f1);
1462 //nb = ltt_type_element_number(t);
1463
1464 lttv_trace_hook_destroy(&h);
1465
1466 /*
1467 name_tables->trap_names = g_new(GQuark, nb);
1468 for(i = 0 ; i < nb ; i++) {
1469 name_tables->trap_names[i] = g_quark_from_string(
1470 ltt_enum_string_get(t, i));
1471 }
1472 */
1473 name_tables->nb_traps = 256;
1474 name_tables->trap_names = g_new(GQuark, 256);
1475 for(i = 0 ; i < 256 ; i++) {
1476 g_string_printf(fe_name, "trap %d", i);
1477 name_tables->trap_names[i] = g_quark_from_string(fe_name->str);
1478 }
1479 } else {
1480 name_tables->trap_names = NULL;
1481 name_tables->nb_traps = 0;
1482 }
1483
1484 if(!lttv_trace_find_hook(tcs->parent.t,
1485 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
1486 LTT_FIELD_IRQ_ID, 0, 0,
1487 NULL, NULL, &h)) {
1488
1489 thf = lttv_trace_hook_get_first(&h);
1490
1491 t = ltt_field_type(thf->f1);
1492 //nb = ltt_type_element_number(t);
1493
1494 lttv_trace_hook_destroy(&h);
1495
1496 /*
1497 name_tables->irq_names = g_new(GQuark, nb);
1498 for(i = 0 ; i < nb ; i++) {
1499 name_tables->irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1500 }
1501 */
1502
1503 name_tables->nb_irqs = 256;
1504 name_tables->irq_names = g_new(GQuark, 256);
1505 for(i = 0 ; i < 256 ; i++) {
1506 g_string_printf(fe_name, "irq %d", i);
1507 name_tables->irq_names[i] = g_quark_from_string(fe_name->str);
1508 }
1509 } else {
1510 name_tables->nb_irqs = 0;
1511 name_tables->irq_names = NULL;
1512 }
1513 /*
1514 name_tables->soft_irq_names = g_new(GQuark, nb);
1515 for(i = 0 ; i < nb ; i++) {
1516 name_tables->soft_irq_names[i] = g_quark_from_string(ltt_enum_string_get(t, i));
1517 }
1518 */
1519
1520 name_tables->nb_softirqs = 256;
1521 name_tables->soft_irq_names = g_new(GQuark, 256);
1522 for(i = 0 ; i < 256 ; i++) {
1523 g_string_printf(fe_name, "softirq %d", i);
1524 name_tables->soft_irq_names[i] = g_quark_from_string(fe_name->str);
1525 }
1526
1527
1528 g_string_free(fe_name, TRUE);
1529 }
1530
1531
1532 static void
1533 get_name_tables(LttvTraceState *tcs)
1534 {
1535 LttvNameTables *name_tables;
1536
1537 LttvAttributeValue v;
1538
1539 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1540 LTTV_POINTER, &v);
1541 g_assert(*(v.v_pointer) != NULL);
1542 name_tables = (LttvNameTables *)*(v.v_pointer);
1543 //tcs->eventtype_names = name_tables->eventtype_names;
1544 tcs->syscall_names = name_tables->syscall_names;
1545 tcs->nb_syscalls = name_tables->nb_syscalls;
1546 tcs->trap_names = name_tables->trap_names;
1547 tcs->nb_traps = name_tables->nb_traps;
1548 tcs->irq_names = name_tables->irq_names;
1549 tcs->soft_irq_names = name_tables->soft_irq_names;
1550 tcs->nb_irqs = name_tables->nb_irqs;
1551 tcs->nb_softirqs = name_tables->nb_softirqs;
1552 }
1553
1554
1555 static void
1556 free_name_tables(LttvTraceState *tcs)
1557 {
1558 LttvNameTables *name_tables;
1559
1560 LttvAttributeValue v;
1561
1562 lttv_attribute_find(tcs->parent.t_a, LTTV_STATE_NAME_TABLES,
1563 LTTV_POINTER, &v);
1564 name_tables = (LttvNameTables *)*(v.v_pointer);
1565 *(v.v_pointer) = NULL;
1566
1567 // g_free(name_tables->eventtype_names);
1568 if(name_tables->syscall_names) g_free(name_tables->syscall_names);
1569 if(name_tables->trap_names) g_free(name_tables->trap_names);
1570 if(name_tables->irq_names) g_free(name_tables->irq_names);
1571 if(name_tables->soft_irq_names) g_free(name_tables->soft_irq_names);
1572 if(name_tables) g_free(name_tables);
1573 }
1574
1575 #ifdef HASH_TABLE_DEBUG
1576
1577 static void test_process(gpointer key, gpointer value, gpointer user_data)
1578 {
1579 LttvProcessState *process = (LttvProcessState *)value;
1580
1581 /* Test for process corruption */
1582 guint stack_len = process->execution_stack->len;
1583 }
1584
1585 static void hash_table_check(GHashTable *table)
1586 {
1587 g_hash_table_foreach(table, test_process, NULL);
1588 }
1589
1590
1591 #endif
1592
1593 /* clears the stack and sets the state passed as argument */
1594 static void cpu_set_base_mode(LttvCPUState *cpust, LttvCPUMode state)
1595 {
1596 g_array_set_size(cpust->mode_stack, 1);
1597 ((GQuark *)cpust->mode_stack->data)[0] = state;
1598 }
1599
1600 static void cpu_push_mode(LttvCPUState *cpust, LttvCPUMode state)
1601 {
1602 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len + 1);
1603 ((GQuark *)cpust->mode_stack->data)[cpust->mode_stack->len - 1] = state;
1604 }
1605
1606 static void cpu_pop_mode(LttvCPUState *cpust)
1607 {
1608 if(cpust->mode_stack->len == 1)
1609 cpu_set_base_mode(cpust, LTTV_CPU_UNKNOWN);
1610 else
1611 g_array_set_size(cpust->mode_stack, cpust->mode_stack->len - 1);
1612 }
1613
1614 static void push_state(LttvTracefileState *tfs, LttvExecutionMode t,
1615 guint state_id)
1616 {
1617 LttvExecutionState *es;
1618
1619 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1620 guint cpu = tfs->cpu;
1621
1622 #ifdef HASH_TABLE_DEBUG
1623 hash_table_check(ts->processes);
1624 #endif
1625 LttvProcessState *process = ts->running_process[cpu];
1626
1627 guint depth = process->execution_stack->len;
1628
1629 process->execution_stack =
1630 g_array_set_size(process->execution_stack, depth + 1);
1631 /* Keep in sync */
1632 process->state =
1633 &g_array_index(process->execution_stack, LttvExecutionState, depth - 1);
1634
1635 es = &g_array_index(process->execution_stack, LttvExecutionState, depth);
1636 es->t = t;
1637 es->n = state_id;
1638 es->entry = es->change = tfs->parent.timestamp;
1639 es->cum_cpu_time = ltt_time_zero;
1640 es->s = process->state->s;
1641 process->state = es;
1642 }
1643
1644 /* pop state
1645 * return 1 when empty, else 0 */
1646 int lttv_state_pop_state_cleanup(LttvProcessState *process,
1647 LttvTracefileState *tfs)
1648 {
1649 guint cpu = tfs->cpu;
1650 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1651
1652 guint depth = process->execution_stack->len;
1653
1654 if(depth == 1){
1655 return 1;
1656 }
1657
1658 process->execution_stack =
1659 g_array_set_size(process->execution_stack, depth - 1);
1660 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1661 depth - 2);
1662 process->state->change = tfs->parent.timestamp;
1663
1664 return 0;
1665 }
1666
1667 static void pop_state(LttvTracefileState *tfs, LttvExecutionMode t)
1668 {
1669 guint cpu = tfs->cpu;
1670 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
1671 LttvProcessState *process = ts->running_process[cpu];
1672
1673 guint depth = process->execution_stack->len;
1674
1675 if(process->state->t != t){
1676 g_info("Different execution mode type (%lu.%09lu): ignore it\n",
1677 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1678 g_info("process state has %s when pop_int is %s\n",
1679 g_quark_to_string(process->state->t),
1680 g_quark_to_string(t));
1681 g_info("{ %u, %u, %s, %s, %s }\n",
1682 process->pid,
1683 process->ppid,
1684 g_quark_to_string(process->name),
1685 g_quark_to_string(process->brand),
1686 g_quark_to_string(process->state->s));
1687 return;
1688 }
1689
1690 if(depth == 1){
1691 g_info("Trying to pop last state on stack (%lu.%09lu): ignore it\n",
1692 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
1693 return;
1694 }
1695
1696 process->execution_stack =
1697 g_array_set_size(process->execution_stack, depth - 1);
1698 process->state = &g_array_index(process->execution_stack, LttvExecutionState,
1699 depth - 2);
1700 process->state->change = tfs->parent.timestamp;
1701 }
1702
1703 struct search_result {
1704 const LttTime *time; /* Requested time */
1705 LttTime *best; /* Best result */
1706 };
1707
1708 static gint search_usertrace(gconstpointer a, gconstpointer b)
1709 {
1710 const LttTime *elem_time = (const LttTime*)a;
1711 /* Explicit non const cast */
1712 struct search_result *res = (struct search_result *)b;
1713
1714 if(ltt_time_compare(*elem_time, *(res->time)) < 0) {
1715 /* The usertrace was created before the schedchange */
1716 /* Get larger keys */
1717 return 1;
1718 } else if(ltt_time_compare(*elem_time, *(res->time)) >= 0) {
1719 /* The usertrace was created after the schedchange time */
1720 /* Get smaller keys */
1721 if(res->best) {
1722 if(ltt_time_compare(*elem_time, *res->best) < 0) {
1723 res->best = elem_time;
1724 }
1725 } else {
1726 res->best = elem_time;
1727 }
1728 return -1;
1729 }
1730 return 0;
1731 }
1732
1733 static LttvTracefileState *ltt_state_usertrace_find(LttvTraceState *tcs,
1734 guint pid, const LttTime *timestamp)
1735 {
1736 LttvTracefileState *tfs = NULL;
1737 struct search_result res;
1738 /* Find the usertrace associated with a pid and time interval.
1739 * Search in the usertraces by PID (within a hash) and then, for each
1740 * corresponding element of the array, find the first one with creation
1741 * timestamp the lowest, but higher or equal to "timestamp". */
1742 res.time = timestamp;
1743 res.best = NULL;
1744 GTree *usertrace_tree = g_hash_table_lookup(tcs->usertraces, (gpointer)pid);
1745 if(usertrace_tree) {
1746 g_tree_search(usertrace_tree, search_usertrace, &res);
1747 if(res.best)
1748 tfs = g_tree_lookup(usertrace_tree, res.best);
1749 }
1750
1751 return tfs;
1752 }
1753
1754
1755 LttvProcessState *
1756 lttv_state_create_process(LttvTraceState *tcs, LttvProcessState *parent,
1757 guint cpu, guint pid, guint tgid, GQuark name, const LttTime *timestamp)
1758 {
1759 LttvProcessState *process = g_new(LttvProcessState, 1);
1760
1761 LttvExecutionState *es;
1762
1763 LttvTraceContext *tc = (LttvTraceContext*)tcs;
1764
1765 char buffer[128];
1766
1767 process->pid = pid;
1768 process->tgid = tgid;
1769 process->cpu = cpu;
1770 process->name = name;
1771 process->brand = LTTV_STATE_UNBRANDED;
1772 //process->last_cpu = tfs->cpu_name;
1773 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1774 process->type = LTTV_STATE_USER_THREAD;
1775 process->usertrace = ltt_state_usertrace_find(tcs, pid, timestamp);
1776 process->current_function = 0; //function 0x0 by default.
1777
1778 g_info("Process %u, core %p", process->pid, process);
1779 g_hash_table_insert(tcs->processes, process, process);
1780
1781 if(parent) {
1782 process->ppid = parent->pid;
1783 process->creation_time = *timestamp;
1784 }
1785
1786 /* No parent. This process exists but we are missing all information about
1787 its creation. The birth time is set to zero but we remember the time of
1788 insertion */
1789
1790 else {
1791 process->ppid = 0;
1792 process->creation_time = ltt_time_zero;
1793 }
1794
1795 process->insertion_time = *timestamp;
1796 sprintf(buffer,"%d-%lu.%lu",pid, process->creation_time.tv_sec,
1797 process->creation_time.tv_nsec);
1798 process->pid_time = g_quark_from_string(buffer);
1799 process->cpu = cpu;
1800 //process->last_cpu = tfs->cpu_name;
1801 //process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)tfs)->tf);
1802 process->execution_stack = g_array_sized_new(FALSE, FALSE,
1803 sizeof(LttvExecutionState), PREALLOCATED_EXECUTION_STACK);
1804 process->execution_stack = g_array_set_size(process->execution_stack, 2);
1805 es = process->state = &g_array_index(process->execution_stack,
1806 LttvExecutionState, 0);
1807 es->t = LTTV_STATE_USER_MODE;
1808 es->n = LTTV_STATE_SUBMODE_NONE;
1809 es->entry = *timestamp;
1810 //g_assert(timestamp->tv_sec != 0);
1811 es->change = *timestamp;
1812 es->cum_cpu_time = ltt_time_zero;
1813 es->s = LTTV_STATE_RUN;
1814
1815 es = process->state = &g_array_index(process->execution_stack,
1816 LttvExecutionState, 1);
1817 es->t = LTTV_STATE_SYSCALL;
1818 es->n = LTTV_STATE_SUBMODE_NONE;
1819 es->entry = *timestamp;
1820 //g_assert(timestamp->tv_sec != 0);
1821 es->change = *timestamp;
1822 es->cum_cpu_time = ltt_time_zero;
1823 es->s = LTTV_STATE_WAIT_FORK;
1824
1825 /* Allocate an empty function call stack. If it's empty, use 0x0. */
1826 process->user_stack = g_array_sized_new(FALSE, FALSE,
1827 sizeof(guint64), 0);
1828
1829 return process;
1830 }
1831
1832 LttvProcessState *lttv_state_find_process(LttvTraceState *ts, guint cpu,
1833 guint pid)
1834 {
1835 LttvProcessState key;
1836 LttvProcessState *process;
1837
1838 key.pid = pid;
1839 key.cpu = cpu;
1840 process = g_hash_table_lookup(ts->processes, &key);
1841 return process;
1842 }
1843
1844 LttvProcessState *
1845 lttv_state_find_process_or_create(LttvTraceState *ts, guint cpu, guint pid,
1846 const LttTime *timestamp)
1847 {
1848 LttvProcessState *process = lttv_state_find_process(ts, cpu, pid);
1849 LttvExecutionState *es;
1850
1851 /* Put ltt_time_zero creation time for unexisting processes */
1852 if(unlikely(process == NULL)) {
1853 process = lttv_state_create_process(ts,
1854 NULL, cpu, pid, 0, LTTV_STATE_UNNAMED, timestamp);
1855 /* We are not sure is it's a kernel thread or normal thread, put the
1856 * bottom stack state to unknown */
1857 process->execution_stack =
1858 g_array_set_size(process->execution_stack, 1);
1859 process->state = es =
1860 &g_array_index(process->execution_stack, LttvExecutionState, 0);
1861 es->t = LTTV_STATE_MODE_UNKNOWN;
1862 es->s = LTTV_STATE_UNNAMED;
1863 }
1864 return process;
1865 }
1866
1867 /* FIXME : this function should be called when we receive an event telling that
1868 * release_task has been called in the kernel. In happens generally when
1869 * the parent waits for its child terminaison, but may also happen in special
1870 * cases in the child's exit : when the parent ignores its children SIGCCHLD or
1871 * has the flag SA_NOCLDWAIT. It can also happen when the child is part
1872 * of a killed thread ground, but isn't the leader.
1873 */
1874 static void exit_process(LttvTracefileState *tfs, LttvProcessState *process)
1875 {
1876 LttvTraceState *ts = LTTV_TRACE_STATE(tfs->parent.t_context);
1877 LttvProcessState key;
1878
1879 key.pid = process->pid;
1880 key.cpu = process->cpu;
1881 g_hash_table_remove(ts->processes, &key);
1882 g_array_free(process->execution_stack, TRUE);
1883 g_array_free(process->user_stack, TRUE);
1884 g_free(process);
1885 }
1886
1887
1888 static void free_process_state(gpointer key, gpointer value,gpointer user_data)
1889 {
1890 g_array_free(((LttvProcessState *)value)->execution_stack, TRUE);
1891 g_array_free(((LttvProcessState *)value)->user_stack, TRUE);
1892 g_free(value);
1893 }
1894
1895
1896 static void lttv_state_free_process_table(GHashTable *processes)
1897 {
1898 g_hash_table_foreach(processes, free_process_state, NULL);
1899 g_hash_table_destroy(processes);
1900 }
1901
1902
1903 static gboolean syscall_entry(void *hook_data, void *call_data)
1904 {
1905 LttvTracefileState *s = (LttvTracefileState *)call_data;
1906 guint cpu = s->cpu;
1907 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1908 LttvProcessState *process = ts->running_process[cpu];
1909 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1910 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1911 LttField *f = thf->f1;
1912
1913 LttvExecutionSubmode submode;
1914
1915 guint nb_syscalls = ((LttvTraceState *)(s->parent.t_context))->nb_syscalls;
1916 guint syscall = ltt_event_get_unsigned(e, f);
1917
1918 if(syscall < nb_syscalls) {
1919 submode = ((LttvTraceState *)(s->parent.t_context))->syscall_names[
1920 syscall];
1921 } else {
1922 /* Fixup an incomplete syscall table */
1923 GString *string = g_string_new("");
1924 g_string_printf(string, "syscall %u", syscall);
1925 submode = g_quark_from_string(string->str);
1926 g_string_free(string, TRUE);
1927 }
1928 /* There can be no system call from PID 0 : unknown state */
1929 if(process->pid != 0)
1930 push_state(s, LTTV_STATE_SYSCALL, submode);
1931 return FALSE;
1932 }
1933
1934
1935 static gboolean syscall_exit(void *hook_data, void *call_data)
1936 {
1937 LttvTracefileState *s = (LttvTracefileState *)call_data;
1938 guint cpu = s->cpu;
1939 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
1940 LttvProcessState *process = ts->running_process[cpu];
1941
1942 /* There can be no system call from PID 0 : unknown state */
1943 if(process->pid != 0)
1944 pop_state(s, LTTV_STATE_SYSCALL);
1945 return FALSE;
1946 }
1947
1948
1949 static gboolean trap_entry(void *hook_data, void *call_data)
1950 {
1951 LttvTracefileState *s = (LttvTracefileState *)call_data;
1952 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1953 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1954 LttField *f = thf->f1;
1955
1956 LttvExecutionSubmode submode;
1957
1958 guint64 nb_traps = ((LttvTraceState *)(s->parent.t_context))->nb_traps;
1959 guint64 trap = ltt_event_get_long_unsigned(e, f);
1960
1961 if(trap < nb_traps) {
1962 submode = ((LttvTraceState *)(s->parent.t_context))->trap_names[trap];
1963 } else {
1964 /* Fixup an incomplete trap table */
1965 GString *string = g_string_new("");
1966 g_string_printf(string, "trap %llu", trap);
1967 submode = g_quark_from_string(string->str);
1968 g_string_free(string, TRUE);
1969 }
1970
1971 push_state(s, LTTV_STATE_TRAP, submode);
1972
1973 /* update cpu status */
1974 cpu_push_mode(s->cpu_state, LTTV_CPU_TRAP);
1975
1976 return FALSE;
1977 }
1978
1979 static gboolean trap_exit(void *hook_data, void *call_data)
1980 {
1981 LttvTracefileState *s = (LttvTracefileState *)call_data;
1982
1983 pop_state(s, LTTV_STATE_TRAP);
1984
1985 /* update cpu status */
1986 cpu_pop_mode(s->cpu_state);
1987
1988 return FALSE;
1989 }
1990
1991 static gboolean irq_entry(void *hook_data, void *call_data)
1992 {
1993 LttvTracefileState *s = (LttvTracefileState *)call_data;
1994 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
1995 guint8 fac_id = ltt_event_facility_id(e);
1996 guint8 ev_id = ltt_event_eventtype_id(e);
1997 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
1998 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
1999 g_assert(thf->f1 != NULL);
2000 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2001 LttField *f = thf->f1;
2002
2003 LttvExecutionSubmode submode;
2004 guint64 irq = ltt_event_get_long_unsigned(e, f);
2005 guint64 nb_irqs = ((LttvTraceState *)(s->parent.t_context))->nb_irqs;
2006 GString *string;
2007
2008 if(irq < nb_irqs) {
2009 submode = ((LttvTraceState *)(s->parent.t_context))->irq_names[irq];
2010 } else {
2011 /* Fixup an incomplete irq table */
2012 GString *string = g_string_new("");
2013 g_string_printf(string, "irq %llu", irq);
2014 submode = g_quark_from_string(string->str);
2015 g_string_free(string, TRUE);
2016 }
2017
2018 /* Do something with the info about being in user or system mode when int? */
2019 push_state(s, LTTV_STATE_IRQ, submode);
2020
2021 /* update cpu status */
2022 cpu_push_mode(s->cpu_state, LTTV_CPU_IRQ);
2023
2024 return FALSE;
2025 }
2026
2027 static gboolean soft_irq_exit(void *hook_data, void *call_data)
2028 {
2029 LttvTracefileState *s = (LttvTracefileState *)call_data;
2030
2031 pop_state(s, LTTV_STATE_SOFT_IRQ);
2032 return FALSE;
2033 }
2034
2035
2036
2037 static gboolean irq_exit(void *hook_data, void *call_data)
2038 {
2039 LttvTracefileState *s = (LttvTracefileState *)call_data;
2040
2041 pop_state(s, LTTV_STATE_IRQ);
2042
2043 /* update cpu status */
2044 cpu_pop_mode(s->cpu_state);
2045
2046 return FALSE;
2047 }
2048
2049 static gboolean soft_irq_entry(void *hook_data, void *call_data)
2050 {
2051 LttvTracefileState *s = (LttvTracefileState *)call_data;
2052 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2053 guint8 fac_id = ltt_event_facility_id(e);
2054 guint8 ev_id = ltt_event_eventtype_id(e);
2055 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2056 // g_assert(lttv_trace_hook_get_first((LttvTraceHook *)hook_data)->f1 != NULL);
2057 g_assert(thf->f1 != NULL);
2058 // g_assert(thf == lttv_trace_hook_get_first((LttvTraceHook *)hook_data));
2059 LttField *f = thf->f1;
2060
2061 LttvExecutionSubmode submode;
2062 guint64 softirq = ltt_event_get_long_unsigned(e, f);
2063 guint64 nb_softirqs = ((LttvTraceState *)(s->parent.t_context))->nb_softirqs;
2064 GString *string;
2065
2066 if(softirq < nb_softirqs) {
2067 submode = ((LttvTraceState *)(s->parent.t_context))->soft_irq_names[softirq];
2068 } else {
2069 /* Fixup an incomplete irq table */
2070 GString *string = g_string_new("");
2071 g_string_printf(string, "softirq %llu", softirq);
2072 submode = g_quark_from_string(string->str);
2073 g_string_free(string, TRUE);
2074 }
2075
2076 /* Do something with the info about being in user or system mode when int? */
2077 push_state(s, LTTV_STATE_SOFT_IRQ, submode);
2078 return FALSE;
2079 }
2080
2081 static void push_function(LttvTracefileState *tfs, guint64 funcptr)
2082 {
2083 guint64 *new_func;
2084
2085 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2086 guint cpu = tfs->cpu;
2087 LttvProcessState *process = ts->running_process[cpu];
2088
2089 guint depth = process->user_stack->len;
2090
2091 process->user_stack =
2092 g_array_set_size(process->user_stack, depth + 1);
2093
2094 new_func = &g_array_index(process->user_stack, guint64, depth);
2095 *new_func = funcptr;
2096 process->current_function = funcptr;
2097 }
2098
2099 static void pop_function(LttvTracefileState *tfs, guint64 funcptr)
2100 {
2101 guint cpu = tfs->cpu;
2102 LttvTraceState *ts = (LttvTraceState*)tfs->parent.t_context;
2103 LttvProcessState *process = ts->running_process[cpu];
2104
2105 if(process->current_function != funcptr){
2106 g_info("Different functions (%lu.%09lu): ignore it\n",
2107 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2108 g_info("process state has %llu when pop_function is %llu\n",
2109 process->current_function, funcptr);
2110 g_info("{ %u, %u, %s, %s, %s }\n",
2111 process->pid,
2112 process->ppid,
2113 g_quark_to_string(process->name),
2114 g_quark_to_string(process->brand),
2115 g_quark_to_string(process->state->s));
2116 return;
2117 }
2118 guint depth = process->user_stack->len;
2119
2120 if(depth == 0){
2121 g_info("Trying to pop last function on stack (%lu.%09lu): ignore it\n",
2122 tfs->parent.timestamp.tv_sec, tfs->parent.timestamp.tv_nsec);
2123 return;
2124 }
2125
2126 process->user_stack =
2127 g_array_set_size(process->user_stack, depth - 1);
2128 process->current_function =
2129 g_array_index(process->user_stack, guint64, depth - 2);
2130 }
2131
2132
2133 static gboolean function_entry(void *hook_data, void *call_data)
2134 {
2135 LttvTracefileState *s = (LttvTracefileState *)call_data;
2136 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2137 guint8 fac_id = ltt_event_facility_id(e);
2138 guint8 ev_id = ltt_event_eventtype_id(e);
2139 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2140 g_assert(thf->f1 != NULL);
2141 LttField *f = thf->f1;
2142 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2143
2144 push_function(s, funcptr);
2145 return FALSE;
2146 }
2147
2148 static gboolean function_exit(void *hook_data, void *call_data)
2149 {
2150 LttvTracefileState *s = (LttvTracefileState *)call_data;
2151 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2152 guint8 fac_id = ltt_event_facility_id(e);
2153 guint8 ev_id = ltt_event_eventtype_id(e);
2154 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2155 g_assert(thf->f1 != NULL);
2156 LttField *f = thf->f1;
2157 guint64 funcptr = ltt_event_get_long_unsigned(e, f);
2158
2159 LttvExecutionSubmode submode;
2160
2161 pop_function(s, funcptr);
2162 return FALSE;
2163 }
2164
2165 static gboolean schedchange(void *hook_data, void *call_data)
2166 {
2167 LttvTracefileState *s = (LttvTracefileState *)call_data;
2168 guint cpu = s->cpu;
2169 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2170 LttvProcessState *process = ts->running_process[cpu];
2171 LttvProcessState *old_process = ts->running_process[cpu];
2172
2173 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2174 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2175 guint pid_in, pid_out;
2176 gint64 state_out;
2177
2178 pid_out = ltt_event_get_unsigned(e, thf->f1);
2179 pid_in = ltt_event_get_unsigned(e, thf->f2);
2180 state_out = ltt_event_get_long_int(e, thf->f3);
2181
2182 if(likely(process != NULL)) {
2183
2184 /* We could not know but it was not the idle process executing.
2185 This should only happen at the beginning, before the first schedule
2186 event, and when the initial information (current process for each CPU)
2187 is missing. It is not obvious how we could, after the fact, compensate
2188 the wrongly attributed statistics. */
2189
2190 //This test only makes sense once the state is known and if there is no
2191 //missing events. We need to silently ignore schedchange coming after a
2192 //process_free, or it causes glitches. (FIXME)
2193 //if(unlikely(process->pid != pid_out)) {
2194 // g_assert(process->pid == 0);
2195 //}
2196 if(process->pid == 0
2197 && process->state->t == LTTV_STATE_MODE_UNKNOWN) {
2198 if(pid_out == 0) {
2199 /* Scheduling out of pid 0 at beginning of the trace :
2200 * we know for sure it is in syscall mode at this point. */
2201 g_assert(process->execution_stack->len == 1);
2202 process->state->t = LTTV_STATE_SYSCALL;
2203 process->state->s = LTTV_STATE_WAIT;
2204 process->state->change = s->parent.timestamp;
2205 process->state->entry = s->parent.timestamp;
2206 }
2207 } else {
2208 if(unlikely(process->state->s == LTTV_STATE_EXIT)) {
2209 process->state->s = LTTV_STATE_ZOMBIE;
2210 process->state->change = s->parent.timestamp;
2211 } else {
2212 if(unlikely(state_out == 0)) process->state->s = LTTV_STATE_WAIT_CPU;
2213 else process->state->s = LTTV_STATE_WAIT;
2214 process->state->change = s->parent.timestamp;
2215 }
2216
2217 if(state_out == 32 || state_out == 128)
2218 exit_process(s, process); /* EXIT_DEAD || TASK_DEAD */
2219 /* see sched.h for states */
2220 }
2221 }
2222 process = ts->running_process[cpu] =
2223 lttv_state_find_process_or_create(
2224 (LttvTraceState*)s->parent.t_context,
2225 cpu, pid_in,
2226 &s->parent.timestamp);
2227 process->state->s = LTTV_STATE_RUN;
2228 process->cpu = cpu;
2229 if(process->usertrace)
2230 process->usertrace->cpu = cpu;
2231 // process->last_cpu_index = ltt_tracefile_num(((LttvTracefileContext*)s)->tf);
2232 process->state->change = s->parent.timestamp;
2233
2234 /* update cpu status */
2235 if(pid_in == 0)
2236 cpu_set_base_mode(s->cpu_state, LTTV_CPU_IDLE);
2237 else
2238 cpu_set_base_mode(s->cpu_state, LTTV_CPU_BUSY);
2239
2240 return FALSE;
2241 }
2242
2243 static gboolean process_fork(void *hook_data, void *call_data)
2244 {
2245 LttvTracefileState *s = (LttvTracefileState *)call_data;
2246 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2247 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2248 guint parent_pid;
2249 guint child_pid; /* In the Linux Kernel, there is one PID per thread. */
2250 guint child_tgid; /* tgid in the Linux kernel is the "real" POSIX PID. */
2251 LttvProcessState *zombie_process;
2252 guint cpu = s->cpu;
2253 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2254 LttvProcessState *process = ts->running_process[cpu];
2255 LttvProcessState *child_process;
2256
2257 /* Parent PID */
2258 parent_pid = ltt_event_get_unsigned(e, thf->f1);
2259
2260 /* Child PID */
2261 child_pid = ltt_event_get_unsigned(e, thf->f2);
2262 s->parent.target_pid = child_pid;
2263
2264 /* Child TGID */
2265 if(thf->f3) child_tgid = ltt_event_get_unsigned(e, thf->f3);
2266 else child_tgid = 0;
2267
2268 /* Mathieu : it seems like the process might have been scheduled in before the
2269 * fork, and, in a rare case, might be the current process. This might happen
2270 * in a SMP case where we don't have enough precision on the clocks.
2271 *
2272 * Test reenabled after precision fixes on time. (Mathieu) */
2273 #if 0
2274 zombie_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2275
2276 if(unlikely(zombie_process != NULL)) {
2277 /* Reutilisation of PID. Only now we are sure that the old PID
2278 * has been released. FIXME : should know when release_task happens instead.
2279 */
2280 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2281 guint i;
2282 for(i=0; i< num_cpus; i++) {
2283 g_assert(zombie_process != ts->running_process[i]);
2284 }
2285
2286 exit_process(s, zombie_process);
2287 }
2288 #endif //0
2289 g_assert(process->pid != child_pid);
2290 // FIXME : Add this test in the "known state" section
2291 // g_assert(process->pid == parent_pid);
2292 child_process = lttv_state_find_process(ts, ANY_CPU, child_pid);
2293 if(child_process == NULL) {
2294 child_process = lttv_state_create_process(ts, process, cpu,
2295 child_pid, child_tgid,
2296 LTTV_STATE_UNNAMED, &s->parent.timestamp);
2297 } else {
2298 /* The process has already been created : due to time imprecision between
2299 * multiple CPUs : it has been scheduled in before creation. Note that we
2300 * shouldn't have this kind of imprecision.
2301 *
2302 * Simply put a correct parent.
2303 */
2304 g_assert(0); /* This is a problematic case : the process has been created
2305 before the fork event */
2306 child_process->ppid = process->pid;
2307 child_process->tgid = child_tgid;
2308 }
2309 g_assert(child_process->name == LTTV_STATE_UNNAMED);
2310 child_process->name = process->name;
2311 child_process->brand = process->brand;
2312
2313 return FALSE;
2314 }
2315
2316 /* We stamp a newly created process as kernel_thread.
2317 * The thread should not be running yet. */
2318 static gboolean process_kernel_thread(void *hook_data, void *call_data)
2319 {
2320 LttvTracefileState *s = (LttvTracefileState *)call_data;
2321 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2322 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2323 guint pid;
2324 guint cpu = s->cpu;
2325 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2326 LttvProcessState *process;
2327 LttvExecutionState *es;
2328
2329 /* PID */
2330 pid = (guint)ltt_event_get_long_unsigned(e, thf->f1);
2331 s->parent.target_pid = pid;
2332
2333 process = lttv_state_find_process_or_create(ts, ANY_CPU, pid,
2334 &ltt_time_zero);
2335 process->execution_stack =
2336 g_array_set_size(process->execution_stack, 1);
2337 es = process->state =
2338 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2339 es->t = LTTV_STATE_SYSCALL;
2340 process->type = LTTV_STATE_KERNEL_THREAD;
2341
2342 return FALSE;
2343 }
2344
2345 static gboolean process_exit(void *hook_data, void *call_data)
2346 {
2347 LttvTracefileState *s = (LttvTracefileState *)call_data;
2348 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2349 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2350 LttField *f;
2351 guint pid;
2352 guint cpu = s->cpu;
2353 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2354 LttvProcessState *process; // = ts->running_process[cpu];
2355
2356 pid = ltt_event_get_unsigned(e, thf->f1);
2357 s->parent.target_pid = pid;
2358
2359 // FIXME : Add this test in the "known state" section
2360 // g_assert(process->pid == pid);
2361
2362 process = lttv_state_find_process(ts, ANY_CPU, pid);
2363 if(likely(process != NULL)) {
2364 process->state->s = LTTV_STATE_EXIT;
2365 }
2366 return FALSE;
2367 }
2368
2369 static gboolean process_free(void *hook_data, void *call_data)
2370 {
2371 LttvTracefileState *s = (LttvTracefileState *)call_data;
2372 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2373 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2374 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2375 guint release_pid;
2376 LttvProcessState *process;
2377
2378 /* PID of the process to release */
2379 release_pid = ltt_event_get_unsigned(e, thf->f1);
2380 s->parent.target_pid = release_pid;
2381
2382 g_assert(release_pid != 0);
2383
2384 process = lttv_state_find_process(ts, ANY_CPU, release_pid);
2385
2386 if(likely(process != NULL)) {
2387 /* release_task is happening at kernel level : we can now safely release
2388 * the data structure of the process */
2389 //This test is fun, though, as it may happen that
2390 //at time t : CPU 0 : process_free
2391 //at time t+150ns : CPU 1 : schedule out
2392 //Clearly due to time imprecision, we disable it. (Mathieu)
2393 //If this weird case happen, we have no choice but to put the
2394 //Currently running process on the cpu to 0.
2395 //I re-enable it following time precision fixes. (Mathieu)
2396 //Well, in the case where an process is freed by a process on another CPU
2397 //and still scheduled, it happens that this is the schedchange that will
2398 //drop the last reference count. Do not free it here!
2399 guint num_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2400 guint i;
2401 for(i=0; i< num_cpus; i++) {
2402 //g_assert(process != ts->running_process[i]);
2403 if(process == ts->running_process[i]) {
2404 //ts->running_process[i] = lttv_state_find_process(ts, i, 0);
2405 break;
2406 }
2407 }
2408 if(i == num_cpus) /* process is not scheduled */
2409 exit_process(s, process);
2410 }
2411
2412 return FALSE;
2413 }
2414
2415
2416 static gboolean process_exec(void *hook_data, void *call_data)
2417 {
2418 LttvTracefileState *s = (LttvTracefileState *)call_data;
2419 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2420 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2421 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2422 //gchar *name;
2423 guint cpu = s->cpu;
2424 LttvProcessState *process = ts->running_process[cpu];
2425
2426 #if 0//how to use a sequence that must be transformed in a string
2427 /* PID of the process to release */
2428 guint64 name_len = ltt_event_field_element_number(e, thf->f1);
2429 //name = ltt_event_get_string(e, thf->f1);
2430 LttField *child = ltt_event_field_element_select(e, thf->f1, 0);
2431 gchar *name_begin =
2432 (gchar*)(ltt_event_data(e)+ltt_event_field_offset(e, child));
2433 gchar *null_term_name = g_new(gchar, name_len+1);
2434 memcpy(null_term_name, name_begin, name_len);
2435 null_term_name[name_len] = '\0';
2436 process->name = g_quark_from_string(null_term_name);
2437 #endif //0
2438
2439 process->name = g_quark_from_string(ltt_event_get_string(e, thf->f1));
2440 process->brand = LTTV_STATE_UNBRANDED;
2441 //g_free(null_term_name);
2442 return FALSE;
2443 }
2444
2445 static gboolean thread_brand(void *hook_data, void *call_data)
2446 {
2447 LttvTracefileState *s = (LttvTracefileState *)call_data;
2448 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2449 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2450 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2451 gchar *name;
2452 guint cpu = s->cpu;
2453 LttvProcessState *process = ts->running_process[cpu];
2454
2455 name = ltt_event_get_string(e, thf->f1);
2456 process->brand = g_quark_from_string(name);
2457
2458 return FALSE;
2459 }
2460
2461 static void fix_process(gpointer key, gpointer value,
2462 gpointer user_data)
2463 {
2464 LttvProcessState *process;
2465 LttvExecutionState *es;
2466 process = (LttvProcessState *)value;
2467 LttvTracefileContext *tfc = (LttvTracefileContext *)user_data;
2468 LttTime *timestamp = (LttTime*)user_data;
2469
2470 if(process->type == LTTV_STATE_KERNEL_THREAD) {
2471 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2472 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2473 es->t = LTTV_STATE_SYSCALL;
2474 es->n = LTTV_STATE_SUBMODE_NONE;
2475 es->entry = *timestamp;
2476 es->change = *timestamp;
2477 es->cum_cpu_time = ltt_time_zero;
2478 if(es->s == LTTV_STATE_UNNAMED)
2479 es->s = LTTV_STATE_WAIT;
2480 }
2481 } else {
2482 es = &g_array_index(process->execution_stack, LttvExecutionState, 0);
2483 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2484 es->t = LTTV_STATE_USER_MODE;
2485 es->n = LTTV_STATE_SUBMODE_NONE;
2486 es->entry = *timestamp;
2487 //g_assert(timestamp->tv_sec != 0);
2488 es->change = *timestamp;
2489 es->cum_cpu_time = ltt_time_zero;
2490 if(es->s == LTTV_STATE_UNNAMED)
2491 es->s = LTTV_STATE_RUN;
2492
2493 if(process->execution_stack->len == 1) {
2494 /* Still in bottom unknown mode, means never did a system call
2495 * May be either in user mode, syscall mode, running or waiting.*/
2496 /* FIXME : we may be tagging syscall mode when being user mode */
2497 process->execution_stack =
2498 g_array_set_size(process->execution_stack, 2);
2499 es = process->state = &g_array_index(process->execution_stack,
2500 LttvExecutionState, 1);
2501 es->t = LTTV_STATE_SYSCALL;
2502 es->n = LTTV_STATE_SUBMODE_NONE;
2503 es->entry = *timestamp;
2504 //g_assert(timestamp->tv_sec != 0);
2505 es->change = *timestamp;
2506 es->cum_cpu_time = ltt_time_zero;
2507 if(es->s == LTTV_STATE_WAIT_FORK)
2508 es->s = LTTV_STATE_WAIT;
2509 }
2510 }
2511 }
2512 }
2513
2514 static gboolean statedump_end(void *hook_data, void *call_data)
2515 {
2516 LttvTracefileState *s = (LttvTracefileState *)call_data;
2517 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2518 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2519 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2520 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2521
2522 /* For all processes */
2523 /* if kernel thread, if stack[0] is unknown, set to syscall mode, wait */
2524 /* else, if stack[0] is unknown, set to user mode, running */
2525
2526 g_hash_table_foreach(ts->processes, fix_process, &tfc->timestamp);
2527 }
2528
2529 static gboolean enum_process_state(void *hook_data, void *call_data)
2530 {
2531 LttvTracefileState *s = (LttvTracefileState *)call_data;
2532 LttEvent *e = ltt_tracefile_get_event(s->parent.tf);
2533 //It's slow : optimise later by doing this before reading trace.
2534 LttEventType *et = ltt_event_eventtype(e);
2535 //
2536 LttvTraceHookByFacility *thf = (LttvTraceHookByFacility *)hook_data;
2537 guint parent_pid;
2538 guint pid;
2539 guint tgid;
2540 gchar * command;
2541 guint cpu = s->cpu;
2542 LttvTraceState *ts = (LttvTraceState*)s->parent.t_context;
2543 LttvProcessState *process = ts->running_process[cpu];
2544 LttvProcessState *parent_process;
2545 LttField *f4, *f5, *f6, *f7, *f8;
2546 GQuark type, mode, submode, status;
2547 LttvExecutionState *es;
2548 guint i, nb_cpus;
2549
2550 /* PID */
2551 pid = ltt_event_get_unsigned(e, thf->f1);
2552 s->parent.target_pid = pid;
2553
2554 /* Parent PID */
2555 parent_pid = ltt_event_get_unsigned(e, thf->f2);
2556
2557 /* Command name */
2558 command = ltt_event_get_string(e, thf->f3);
2559
2560 /* type */
2561 f4 = ltt_eventtype_field_by_name(et, LTT_FIELD_TYPE);
2562 type = ltt_enum_string_get(ltt_field_type(f4),
2563 ltt_event_get_unsigned(e, f4));
2564
2565 /* mode */
2566 f5 = ltt_eventtype_field_by_name(et, LTT_FIELD_MODE);
2567 mode = ltt_enum_string_get(ltt_field_type(f5),
2568 ltt_event_get_unsigned(e, f5));
2569
2570 /* submode */
2571 f6 = ltt_eventtype_field_by_name(et, LTT_FIELD_SUBMODE);
2572 submode = ltt_enum_string_get(ltt_field_type(f6),
2573 ltt_event_get_unsigned(e, f6));
2574
2575 /* status */
2576 f7 = ltt_eventtype_field_by_name(et, LTT_FIELD_STATUS);
2577 status = ltt_enum_string_get(ltt_field_type(f7),
2578 ltt_event_get_unsigned(e, f7));
2579
2580 /* TGID */
2581 f8 = ltt_eventtype_field_by_name(et, LTT_FIELD_TGID);
2582 if(f8) tgid = ltt_event_get_unsigned(e, f8);
2583 else tgid = 0;
2584
2585
2586 if(pid == 0) {
2587 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2588 for(i=0; i<nb_cpus; i++) {
2589 process = lttv_state_find_process(ts, i, pid);
2590 g_assert(process != NULL);
2591
2592 process->ppid = parent_pid;
2593 process->tgid = tgid;
2594 process->name = g_quark_from_string(command);
2595 es =
2596 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2597 process->type = LTTV_STATE_KERNEL_THREAD;
2598 }
2599
2600 } else {
2601 /* The process might exist if a process was forked while performing the
2602 * state dump. */
2603 process = lttv_state_find_process(ts, ANY_CPU, pid);
2604 if(process == NULL) {
2605 parent_process = lttv_state_find_process(ts, ANY_CPU, parent_pid);
2606 process = lttv_state_create_process(ts, parent_process, cpu,
2607 pid, tgid, g_quark_from_string(command),
2608 &s->parent.timestamp);
2609
2610 /* Keep the stack bottom : a running user mode */
2611 /* Disabled because of inconsistencies in the current statedump states. */
2612 if(type == LTTV_STATE_KERNEL_THREAD) {
2613 /* Only keep the bottom
2614 * FIXME Kernel thread : can be in syscall or interrupt or trap. */
2615 /* Will cause expected trap when in fact being syscall (even after end of
2616 * statedump event)
2617 * Will cause expected interrupt when being syscall. (only before end of
2618 * statedump event) */
2619 // This will cause a "popping last state on stack, ignoring it."
2620 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2621 es = process->state = &g_array_index(process->execution_stack,
2622 LttvExecutionState, 0);
2623 process->type = LTTV_STATE_KERNEL_THREAD;
2624 es->t = LTTV_STATE_MODE_UNKNOWN;
2625 es->s = LTTV_STATE_UNNAMED;
2626 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2627 #if 0
2628 es->t = LTTV_STATE_SYSCALL;
2629 es->s = status;
2630 es->n = submode;
2631 #endif //0
2632 } else {
2633 /* User space process :
2634 * bottom : user mode
2635 * either currently running or scheduled out.
2636 * can be scheduled out because interrupted in (user mode or in syscall)
2637 * or because of an explicit call to the scheduler in syscall. Note that
2638 * the scheduler call comes after the irq_exit, so never in interrupt
2639 * context. */
2640 // temp workaround : set size to 1 : only have user mode bottom of stack.
2641 // will cause g_info message of expected syscall mode when in fact being
2642 // in user mode. Can also cause expected trap when in fact being user
2643 // mode in the event of a page fault reenabling interrupts in the handler.
2644 // Expected syscall and trap can also happen after the end of statedump
2645 // This will cause a "popping last state on stack, ignoring it."
2646 process->execution_stack = g_array_set_size(process->execution_stack, 1);
2647 es = process->state = &g_array_index(process->execution_stack,
2648 LttvExecutionState, 0);
2649 es->t = LTTV_STATE_MODE_UNKNOWN;
2650 es->s = LTTV_STATE_UNNAMED;
2651 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2652 #if 0
2653 es->t = LTTV_STATE_USER_MODE;
2654 es->s = status;
2655 es->n = submode;
2656 #endif //0
2657 }
2658 #if 0
2659 /* UNKNOWN STATE */
2660 {
2661 es = process->state = &g_array_index(process->execution_stack,
2662 LttvExecutionState, 1);
2663 es->t = LTTV_STATE_MODE_UNKNOWN;
2664 es->s = LTTV_STATE_UNNAMED;
2665 es->n = LTTV_STATE_SUBMODE_UNKNOWN;
2666 }
2667 #endif //0
2668 } else {
2669 /* The process has already been created :
2670 * Probably was forked while dumping the process state or
2671 * was simply scheduled in prior to get the state dump event.
2672 */
2673 process->ppid = parent_pid;
2674 process->tgid = tgid;
2675 process->name = g_quark_from_string(command);
2676 process->type = type;
2677 es =
2678 &g_array_index(process->execution_stack, LttvExecutionState, 0);
2679 #if 0
2680 if(es->t == LTTV_STATE_MODE_UNKNOWN) {
2681 if(type == LTTV_STATE_KERNEL_THREAD)
2682 es->t = LTTV_STATE_SYSCALL;
2683 else
2684 es->t = LTTV_STATE_USER_MODE;
2685 }
2686 #endif //0
2687 /* Don't mess around with the stack, it will eventually become
2688 * ok after the end of state dump. */
2689 }
2690 }
2691
2692 return FALSE;
2693 }
2694
2695 gint lttv_state_hook_add_event_hooks(void *hook_data, void *call_data)
2696 {
2697 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2698
2699 lttv_state_add_event_hooks(tss);
2700
2701 return 0;
2702 }
2703
2704 void lttv_state_add_event_hooks(LttvTracesetState *self)
2705 {
2706 LttvTraceset *traceset = self->parent.ts;
2707
2708 guint i, j, k, l, nb_trace, nb_tracefile;
2709
2710 LttvTraceState *ts;
2711
2712 LttvTracefileState *tfs;
2713
2714 GArray *hooks;
2715
2716 LttvTraceHookByFacility *thf;
2717
2718 LttvTraceHook *hook;
2719
2720 LttvAttributeValue val;
2721
2722 gint ret;
2723 gint hn;
2724
2725 nb_trace = lttv_traceset_number(traceset);
2726 for(i = 0 ; i < nb_trace ; i++) {
2727 ts = (LttvTraceState *)self->parent.traces[i];
2728
2729 /* Find the eventtype id for the following events and register the
2730 associated by id hooks. */
2731
2732 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 19);
2733 hooks = g_array_set_size(hooks, 19); // Max possible number of hooks.
2734 hn = 0;
2735
2736 ret = lttv_trace_find_hook(ts->parent.t,
2737 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_ENTRY,
2738 LTT_FIELD_SYSCALL_ID, 0, 0,
2739 syscall_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2740 if(ret) hn--;
2741
2742 ret = lttv_trace_find_hook(ts->parent.t,
2743 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_SYSCALL_EXIT,
2744 0, 0, 0,
2745 syscall_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2746 if(ret) hn--;
2747
2748 ret = lttv_trace_find_hook(ts->parent.t,
2749 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_ENTRY,
2750 LTT_FIELD_TRAP_ID, 0, 0,
2751 trap_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2752 if(ret) hn--;
2753
2754 ret = lttv_trace_find_hook(ts->parent.t,
2755 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_TRAP_EXIT,
2756 0, 0, 0,
2757 trap_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2758 if(ret) hn--;
2759
2760 ret = lttv_trace_find_hook(ts->parent.t,
2761 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
2762 LTT_FIELD_IRQ_ID, 0, 0,
2763 irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2764 if(ret) hn--;
2765
2766 ret = lttv_trace_find_hook(ts->parent.t,
2767 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
2768 0, 0, 0,
2769 irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2770 if(ret) hn--;
2771
2772 ret = lttv_trace_find_hook(ts->parent.t,
2773 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_ENTRY,
2774 LTT_FIELD_SOFT_IRQ_ID, 0, 0,
2775 soft_irq_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2776 if(ret) hn--;
2777
2778 ret = lttv_trace_find_hook(ts->parent.t,
2779 LTT_FACILITY_KERNEL, LTT_EVENT_SOFT_IRQ_EXIT,
2780 0, 0, 0,
2781 soft_irq_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2782 if(ret) hn--;
2783
2784 ret = lttv_trace_find_hook(ts->parent.t,
2785 LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE,
2786 LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE,
2787 schedchange, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2788 if(ret) hn--;
2789
2790 ret = lttv_trace_find_hook(ts->parent.t,
2791 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FORK,
2792 LTT_FIELD_PARENT_PID, LTT_FIELD_CHILD_PID, LTT_FIELD_CHILD_TGID,
2793 process_fork, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2794 if(ret) hn--;
2795
2796 ret = lttv_trace_find_hook(ts->parent.t,
2797 LTT_FACILITY_KERNEL_ARCH, LTT_EVENT_KTHREAD_CREATE,
2798 LTT_FIELD_PID, 0, 0,
2799 process_kernel_thread, NULL, &g_array_index(hooks, LttvTraceHook,
2800 hn++));
2801 if(ret) hn--;
2802
2803 ret = lttv_trace_find_hook(ts->parent.t,
2804 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_EXIT,
2805 LTT_FIELD_PID, 0, 0,
2806 process_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2807 if(ret) hn--;
2808
2809 ret = lttv_trace_find_hook(ts->parent.t,
2810 LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_FREE,
2811 LTT_FIELD_PID, 0, 0,
2812 process_free, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2813 if(ret) hn--;
2814
2815 ret = lttv_trace_find_hook(ts->parent.t,
2816 LTT_FACILITY_FS, LTT_EVENT_EXEC,
2817 LTT_FIELD_FILENAME, 0, 0,
2818 process_exec, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2819 if(ret) hn--;
2820
2821 ret = lttv_trace_find_hook(ts->parent.t,
2822 LTT_FACILITY_USER_GENERIC, LTT_EVENT_THREAD_BRAND,
2823 LTT_FIELD_NAME, 0, 0,
2824 thread_brand, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2825 if(ret) hn--;
2826
2827 /* statedump-related hooks */
2828 ret = lttv_trace_find_hook(ts->parent.t,
2829 LTT_FACILITY_LIST, LTT_EVENT_PROCESS_STATE,
2830 LTT_FIELD_PID, LTT_FIELD_PARENT_PID, LTT_FIELD_NAME,
2831 enum_process_state, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2832 if(ret) hn--;
2833
2834 ret = lttv_trace_find_hook(ts->parent.t,
2835 LTT_FACILITY_LIST, LTT_EVENT_STATEDUMP_END,
2836 0, 0, 0,
2837 statedump_end, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2838 if(ret) hn--;
2839
2840 ret = lttv_trace_find_hook(ts->parent.t,
2841 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_ENTRY,
2842 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2843 function_entry, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2844 if(ret) hn--;
2845
2846 ret = lttv_trace_find_hook(ts->parent.t,
2847 LTT_FACILITY_USER_GENERIC, LTT_EVENT_FUNCTION_EXIT,
2848 LTT_FIELD_THIS_FN, LTT_FIELD_CALL_SITE, 0,
2849 function_exit, NULL, &g_array_index(hooks, LttvTraceHook, hn++));
2850 if(ret) hn--;
2851
2852 hooks = g_array_set_size(hooks, hn);
2853
2854 /* Add these hooks to each event_by_id hooks list */
2855
2856 nb_tracefile = ts->parent.tracefiles->len;
2857
2858 for(j = 0 ; j < nb_tracefile ; j++) {
2859 tfs =
2860 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2861 LttvTracefileContext*, j));
2862
2863 for(k = 0 ; k < hooks->len ; k++) {
2864 hook = &g_array_index(hooks, LttvTraceHook, k);
2865 for(l=0;l<hook->fac_list->len;l++) {
2866 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2867 lttv_hooks_add(
2868 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2869 thf->h,
2870 thf,
2871 LTTV_PRIO_STATE);
2872 }
2873 }
2874 }
2875 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2876 *(val.v_pointer) = hooks;
2877 }
2878 }
2879
2880 gint lttv_state_hook_remove_event_hooks(void *hook_data, void *call_data)
2881 {
2882 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
2883
2884 lttv_state_remove_event_hooks(tss);
2885
2886 return 0;
2887 }
2888
2889 void lttv_state_remove_event_hooks(LttvTracesetState *self)
2890 {
2891 LttvTraceset *traceset = self->parent.ts;
2892
2893 guint i, j, k, l, nb_trace, nb_tracefile;
2894
2895 LttvTraceState *ts;
2896
2897 LttvTracefileState *tfs;
2898
2899 GArray *hooks;
2900
2901 LttvTraceHook *hook;
2902
2903 LttvTraceHookByFacility *thf;
2904
2905 LttvAttributeValue val;
2906
2907 nb_trace = lttv_traceset_number(traceset);
2908 for(i = 0 ; i < nb_trace ; i++) {
2909 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
2910
2911 lttv_attribute_find(ts->parent.a, LTTV_STATE_HOOKS, LTTV_POINTER, &val);
2912 hooks = *(val.v_pointer);
2913
2914 /* Remove these hooks from each event_by_id hooks list */
2915
2916 nb_tracefile = ts->parent.tracefiles->len;
2917
2918 for(j = 0 ; j < nb_tracefile ; j++) {
2919 tfs =
2920 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
2921 LttvTracefileContext*, j));
2922
2923 for(k = 0 ; k < hooks->len ; k++) {
2924 hook = &g_array_index(hooks, LttvTraceHook, k);
2925 for(l=0;l<hook->fac_list->len;l++) {
2926 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
2927
2928 lttv_hooks_remove_data(
2929 lttv_hooks_by_id_find(tfs->parent.event_by_id, thf->id),
2930 thf->h,
2931 thf);
2932 }
2933 }
2934 }
2935 for(k = 0 ; k < hooks->len ; k++)
2936 lttv_trace_hook_destroy(&g_array_index(hooks, LttvTraceHook, k));
2937 g_array_free(hooks, TRUE);
2938 }
2939 }
2940
2941 static gboolean state_save_event_hook(void *hook_data, void *call_data)
2942 {
2943 guint *event_count = (guint*)hook_data;
2944
2945 /* Only save at LTTV_STATE_SAVE_INTERVAL */
2946 if(likely((*event_count)++ < LTTV_STATE_SAVE_INTERVAL))
2947 return FALSE;
2948 else
2949 *event_count = 0;
2950
2951 LttvTracefileState *self = (LttvTracefileState *)call_data;
2952
2953 LttvTracefileState *tfcs;
2954
2955 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
2956
2957 LttEventPosition *ep;
2958
2959 guint i;
2960
2961 LttTracefile *tf;
2962
2963 LttvAttribute *saved_states_tree, *saved_state_tree;
2964
2965 LttvAttributeValue value;
2966
2967 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
2968 LTTV_STATE_SAVED_STATES);
2969 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
2970 value = lttv_attribute_add(saved_states_tree,
2971 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
2972 *(value.v_gobject) = (GObject *)saved_state_tree;
2973 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
2974 *(value.v_time) = self->parent.timestamp;
2975 lttv_state_save(tcs, saved_state_tree);
2976 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
2977 self->parent.timestamp.tv_nsec);
2978
2979 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
2980
2981 return FALSE;
2982 }
2983
2984 static gboolean state_save_after_trace_hook(void *hook_data, void *call_data)
2985 {
2986 LttvTraceState *tcs = (LttvTraceState *)(call_data);
2987
2988 *(tcs->max_time_state_recomputed_in_seek) = tcs->parent.time_span.end_time;
2989
2990 return FALSE;
2991 }
2992
2993 guint lttv_state_current_cpu(LttvTracefileState *tfs)
2994 {
2995 return tfs->cpu;
2996 }
2997
2998
2999
3000 #if 0
3001 static gboolean block_start(void *hook_data, void *call_data)
3002 {
3003 LttvTracefileState *self = (LttvTracefileState *)call_data;
3004
3005 LttvTracefileState *tfcs;
3006
3007 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3008
3009 LttEventPosition *ep;
3010
3011 guint i, nb_block, nb_event, nb_tracefile;
3012
3013 LttTracefile *tf;
3014
3015 LttvAttribute *saved_states_tree, *saved_state_tree;
3016
3017 LttvAttributeValue value;
3018
3019 ep = ltt_event_position_new();
3020
3021 nb_tracefile = tcs->parent.tracefiles->len;
3022
3023 /* Count the number of events added since the last block end in any
3024 tracefile. */
3025
3026 for(i = 0 ; i < nb_tracefile ; i++) {
3027 tfcs =
3028 LTTV_TRACEFILE_STATE(&g_array_index(tcs->parent.tracefiles,
3029 LttvTracefileContext, i));
3030 ltt_event_position(tfcs->parent.e, ep);
3031 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3032 tcs->nb_event += nb_event - tfcs->saved_position;
3033 tfcs->saved_position = nb_event;
3034 }
3035 g_free(ep);
3036
3037 if(tcs->nb_event >= tcs->save_interval) {
3038 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3039 LTTV_STATE_SAVED_STATES);
3040 saved_state_tree = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
3041 value = lttv_attribute_add(saved_states_tree,
3042 lttv_attribute_get_number(saved_states_tree), LTTV_GOBJECT);
3043 *(value.v_gobject) = (GObject *)saved_state_tree;
3044 value = lttv_attribute_add(saved_state_tree, LTTV_STATE_TIME, LTTV_TIME);
3045 *(value.v_time) = self->parent.timestamp;
3046 lttv_state_save(tcs, saved_state_tree);
3047 tcs->nb_event = 0;
3048 g_debug("Saving state at time %lu.%lu", self->parent.timestamp.tv_sec,
3049 self->parent.timestamp.tv_nsec);
3050 }
3051 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3052 return FALSE;
3053 }
3054 #endif //0
3055
3056 #if 0
3057 static gboolean block_end(void *hook_data, void *call_data)
3058 {
3059 LttvTracefileState *self = (LttvTracefileState *)call_data;
3060
3061 LttvTraceState *tcs = (LttvTraceState *)(self->parent.t_context);
3062
3063 LttTracefile *tf;
3064
3065 LttEventPosition *ep;
3066
3067 guint nb_block, nb_event;
3068
3069 ep = ltt_event_position_new();
3070 ltt_event_position(self->parent.e, ep);
3071 ltt_event_position_get(ep, &nb_block, &nb_event, &tf);
3072 tcs->nb_event += nb_event - self->saved_position + 1;
3073 self->saved_position = 0;
3074 *(tcs->max_time_state_recomputed_in_seek) = self->parent.timestamp;
3075 g_free(ep);
3076
3077 return FALSE;
3078 }
3079 #endif //0
3080 #if 0
3081 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3082 {
3083 LttvTraceset *traceset = self->parent.ts;
3084
3085 guint i, j, nb_trace, nb_tracefile;
3086
3087 LttvTraceState *ts;
3088
3089 LttvTracefileState *tfs;
3090
3091 LttvTraceHook hook_start, hook_end;
3092
3093 nb_trace = lttv_traceset_number(traceset);
3094 for(i = 0 ; i < nb_trace ; i++) {
3095 ts = (LttvTraceState *)self->parent.traces[i];
3096
3097 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3098 NULL, NULL, block_start, &hook_start);
3099 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3100 NULL, NULL, block_end, &hook_end);
3101
3102 nb_tracefile = ts->parent.tracefiles->len;
3103
3104 for(j = 0 ; j < nb_tracefile ; j++) {
3105 tfs =
3106 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3107 LttvTracefileContext, j));
3108 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3109 hook_start.id), hook_start.h, NULL, LTTV_PRIO_STATE);
3110 lttv_hooks_add(lttv_hooks_by_id_find(tfs->parent.event_by_id,
3111 hook_end.id), hook_end.h, NULL, LTTV_PRIO_STATE);
3112 }
3113 }
3114 }
3115 #endif //0
3116
3117 void lttv_state_save_add_event_hooks(LttvTracesetState *self)
3118 {
3119 LttvTraceset *traceset = self->parent.ts;
3120
3121 guint i, j, nb_trace, nb_tracefile;
3122
3123 LttvTraceState *ts;
3124
3125 LttvTracefileState *tfs;
3126
3127
3128 nb_trace = lttv_traceset_number(traceset);
3129 for(i = 0 ; i < nb_trace ; i++) {
3130
3131 ts = (LttvTraceState *)self->parent.traces[i];
3132 nb_tracefile = ts->parent.tracefiles->len;
3133
3134 if(ts->has_precomputed_states) continue;
3135
3136 guint *event_count = g_new(guint, 1);
3137 *event_count = 0;
3138
3139 for(j = 0 ; j < nb_tracefile ; j++) {
3140 tfs =
3141 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3142 LttvTracefileContext*, j));
3143 lttv_hooks_add(tfs->parent.event,
3144 state_save_event_hook,
3145 event_count,
3146 LTTV_PRIO_STATE);
3147
3148 }
3149 }
3150
3151 lttv_process_traceset_begin(&self->parent,
3152 NULL, NULL, NULL, NULL, NULL);
3153
3154 }
3155
3156 gint lttv_state_save_hook_add_event_hooks(void *hook_data, void *call_data)
3157 {
3158 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3159
3160 lttv_state_save_add_event_hooks(tss);
3161
3162 return 0;
3163 }
3164
3165
3166 #if 0
3167 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3168 {
3169 LttvTraceset *traceset = self->parent.ts;
3170
3171 guint i, j, nb_trace, nb_tracefile;
3172
3173 LttvTraceState *ts;
3174
3175 LttvTracefileState *tfs;
3176
3177 LttvTraceHook hook_start, hook_end;
3178
3179 nb_trace = lttv_traceset_number(traceset);
3180 for(i = 0 ; i < nb_trace ; i++) {
3181 ts = LTTV_TRACE_STATE(self->parent.traces[i]);
3182
3183 lttv_trace_find_hook(ts->parent.t, "core","block_start",NULL,
3184 NULL, NULL, block_start, &hook_start);
3185
3186 lttv_trace_find_hook(ts->parent.t, "core","block_end",NULL,
3187 NULL, NULL, block_end, &hook_end);
3188
3189 nb_tracefile = ts->parent.tracefiles->len;
3190
3191 for(j = 0 ; j < nb_tracefile ; j++) {
3192 tfs =
3193 LTTV_TRACEFILE_STATE(&g_array_index(ts->parent.tracefiles,
3194 LttvTracefileContext, j));
3195 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3196 tfs->parent.event_by_id, hook_start.id), hook_start.h, NULL);
3197 lttv_hooks_remove_data(lttv_hooks_by_id_find(
3198 tfs->parent.event_by_id, hook_end.id), hook_end.h, NULL);
3199 }
3200 }
3201 }
3202 #endif //0
3203
3204 void lttv_state_save_remove_event_hooks(LttvTracesetState *self)
3205 {
3206 LttvTraceset *traceset = self->parent.ts;
3207
3208 guint i, j, nb_trace, nb_tracefile;
3209
3210 LttvTraceState *ts;
3211
3212 LttvTracefileState *tfs;
3213
3214 LttvHooks *after_trace = lttv_hooks_new();
3215
3216 lttv_hooks_add(after_trace,
3217 state_save_after_trace_hook,
3218 NULL,
3219 LTTV_PRIO_STATE);
3220
3221
3222 lttv_process_traceset_end(&self->parent,
3223 NULL, after_trace, NULL, NULL, NULL);
3224
3225 lttv_hooks_destroy(after_trace);
3226
3227 nb_trace = lttv_traceset_number(traceset);
3228 for(i = 0 ; i < nb_trace ; i++) {
3229
3230 ts = (LttvTraceState *)self->parent.traces[i];
3231 nb_tracefile = ts->parent.tracefiles->len;
3232
3233 if(ts->has_precomputed_states) continue;
3234
3235 guint *event_count = NULL;
3236
3237 for(j = 0 ; j < nb_tracefile ; j++) {
3238 tfs =
3239 LTTV_TRACEFILE_STATE(g_array_index(ts->parent.tracefiles,
3240 LttvTracefileContext*, j));
3241 event_count = lttv_hooks_remove(tfs->parent.event,
3242 state_save_event_hook);
3243 }
3244 if(event_count) g_free(event_count);
3245 }
3246 }
3247
3248 gint lttv_state_save_hook_remove_event_hooks(void *hook_data, void *call_data)
3249 {
3250 LttvTracesetState *tss = (LttvTracesetState*)(call_data);
3251
3252 lttv_state_save_remove_event_hooks(tss);
3253
3254 return 0;
3255 }
3256
3257 void lttv_state_traceset_seek_time_closest(LttvTracesetState *self, LttTime t)
3258 {
3259 LttvTraceset *traceset = self->parent.ts;
3260
3261 guint i, nb_trace;
3262
3263 int min_pos, mid_pos, max_pos;
3264
3265 guint call_rest = 0;
3266
3267 LttvTraceState *tcs;
3268
3269 LttvAttributeValue value;
3270
3271 LttvAttributeType type;
3272
3273 LttvAttributeName name;
3274
3275 gboolean is_named;
3276
3277 LttvAttribute *saved_states_tree, *saved_state_tree, *closest_tree;
3278
3279 //g_tree_destroy(self->parent.pqueue);
3280 //self->parent.pqueue = g_tree_new(compare_tracefile);
3281
3282 g_info("Entering seek_time_closest for time %lu.%lu", t.tv_sec, t.tv_nsec);
3283
3284 nb_trace = lttv_traceset_number(traceset);
3285 for(i = 0 ; i < nb_trace ; i++) {
3286 tcs = (LttvTraceState *)self->parent.traces[i];
3287
3288 if(ltt_time_compare(t, *(tcs->max_time_state_recomputed_in_seek)) < 0) {
3289 saved_states_tree = lttv_attribute_find_subdir(tcs->parent.t_a,
3290 LTTV_STATE_SAVED_STATES);
3291 min_pos = -1;
3292
3293 if(saved_states_tree) {
3294 max_pos = lttv_attribute_get_number(saved_states_tree) - 1;
3295 mid_pos = max_pos / 2;
3296 while(min_pos < max_pos) {
3297 type = lttv_attribute_get(saved_states_tree, mid_pos, &name, &value,
3298 &is_named);
3299 g_assert(type == LTTV_GOBJECT);
3300 saved_state_tree = *((LttvAttribute **)(value.v_gobject));
3301 type = lttv_attribute_get_by_name(saved_state_tree, LTTV_STATE_TIME,
3302 &value);
3303 g_assert(type == LTTV_TIME);
3304 if(ltt_time_compare(*(value.v_time), t) < 0) {
3305 min_pos = mid_pos;
3306 closest_tree = saved_state_tree;
3307 }
3308 else max_pos = mid_pos - 1;
3309
3310 mid_pos = (min_pos + max_pos + 1) / 2;
3311 }
3312 }
3313
3314 /* restore the closest earlier saved state */
3315 if(min_pos != -1) {
3316 lttv_state_restore(tcs, closest_tree);
3317 call_rest = 1;
3318 }
3319
3320 /* There is no saved state, yet we want to have it. Restart at T0 */
3321 else {
3322 restore_init_state(tcs);
3323 lttv_process_trace_seek_time(&(tcs->parent), ltt_time_zero);
3324 }
3325 }
3326 /* We want to seek quickly without restoring/updating the state */
3327 else {
3328 restore_init_state(tcs);
3329 lttv_process_trace_seek_time(&(tcs->parent), t);
3330 }
3331 }
3332 if(!call_rest) g_info("NOT Calling restore");
3333 }
3334
3335
3336 static void
3337 traceset_state_instance_init (GTypeInstance *instance, gpointer g_class)
3338 {
3339 }
3340
3341
3342 static void
3343 traceset_state_finalize (LttvTracesetState *self)
3344 {
3345 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACESET_CONTEXT_TYPE))->
3346 finalize(G_OBJECT(self));
3347 }
3348
3349
3350 static void
3351 traceset_state_class_init (LttvTracesetContextClass *klass)
3352 {
3353 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3354
3355 gobject_class->finalize = (void (*)(GObject *self)) traceset_state_finalize;
3356 klass->init = (void (*)(LttvTracesetContext *self, LttvTraceset *ts))init;
3357 klass->fini = (void (*)(LttvTracesetContext *self))fini;
3358 klass->new_traceset_context = new_traceset_context;
3359 klass->new_trace_context = new_trace_context;
3360 klass->new_tracefile_context = new_tracefile_context;
3361 }
3362
3363
3364 GType
3365 lttv_traceset_state_get_type(void)
3366 {
3367 static GType type = 0;
3368 if (type == 0) {
3369 static const GTypeInfo info = {
3370 sizeof (LttvTracesetStateClass),
3371 NULL, /* base_init */
3372 NULL, /* base_finalize */
3373 (GClassInitFunc) traceset_state_class_init, /* class_init */
3374 NULL, /* class_finalize */
3375 NULL, /* class_data */
3376 sizeof (LttvTracesetState),
3377 0, /* n_preallocs */
3378 (GInstanceInitFunc) traceset_state_instance_init, /* instance_init */
3379 NULL /* value handling */
3380 };
3381
3382 type = g_type_register_static (LTTV_TRACESET_CONTEXT_TYPE, "LttvTracesetStateType",
3383 &info, 0);
3384 }
3385 return type;
3386 }
3387
3388
3389 static void
3390 trace_state_instance_init (GTypeInstance *instance, gpointer g_class)
3391 {
3392 }
3393
3394
3395 static void
3396 trace_state_finalize (LttvTraceState *self)
3397 {
3398 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACE_CONTEXT_TYPE))->
3399 finalize(G_OBJECT(self));
3400 }
3401
3402
3403 static void
3404 trace_state_class_init (LttvTraceStateClass *klass)
3405 {
3406 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3407
3408 gobject_class->finalize = (void (*)(GObject *self)) trace_state_finalize;
3409 klass->state_save = state_save;
3410 klass->state_restore = state_restore;
3411 klass->state_saved_free = state_saved_free;
3412 }
3413
3414
3415 GType
3416 lttv_trace_state_get_type(void)
3417 {
3418 static GType type = 0;
3419 if (type == 0) {
3420 static const GTypeInfo info = {
3421 sizeof (LttvTraceStateClass),
3422 NULL, /* base_init */
3423 NULL, /* base_finalize */
3424 (GClassInitFunc) trace_state_class_init, /* class_init */
3425 NULL, /* class_finalize */
3426 NULL, /* class_data */
3427 sizeof (LttvTraceState),
3428 0, /* n_preallocs */
3429 (GInstanceInitFunc) trace_state_instance_init, /* instance_init */
3430 NULL /* value handling */
3431 };
3432
3433 type = g_type_register_static (LTTV_TRACE_CONTEXT_TYPE,
3434 "LttvTraceStateType", &info, 0);
3435 }
3436 return type;
3437 }
3438
3439
3440 static void
3441 tracefile_state_instance_init (GTypeInstance *instance, gpointer g_class)
3442 {
3443 }
3444
3445
3446 static void
3447 tracefile_state_finalize (LttvTracefileState *self)
3448 {
3449 G_OBJECT_CLASS(g_type_class_peek(LTTV_TRACEFILE_CONTEXT_TYPE))->
3450 finalize(G_OBJECT(self));
3451 }
3452
3453
3454 static void
3455 tracefile_state_class_init (LttvTracefileStateClass *klass)
3456 {
3457 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3458
3459 gobject_class->finalize = (void (*)(GObject *self)) tracefile_state_finalize;
3460 }
3461
3462
3463 GType
3464 lttv_tracefile_state_get_type(void)
3465 {
3466 static GType type = 0;
3467 if (type == 0) {
3468 static const GTypeInfo info = {
3469 sizeof (LttvTracefileStateClass),
3470 NULL, /* base_init */
3471 NULL, /* base_finalize */
3472 (GClassInitFunc) tracefile_state_class_init, /* class_init */
3473 NULL, /* class_finalize */
3474 NULL, /* class_data */
3475 sizeof (LttvTracefileState),
3476 0, /* n_preallocs */
3477 (GInstanceInitFunc) tracefile_state_instance_init, /* instance_init */
3478 NULL /* value handling */
3479 };
3480
3481 type = g_type_register_static (LTTV_TRACEFILE_CONTEXT_TYPE,
3482 "LttvTracefileStateType", &info, 0);
3483 }
3484 return type;
3485 }
3486
3487
3488 static void module_init()
3489 {
3490 LTTV_STATE_UNNAMED = g_quark_from_string("UNNAMED");
3491 LTTV_STATE_UNBRANDED = g_quark_from_string("UNBRANDED");
3492 LTTV_STATE_MODE_UNKNOWN = g_quark_from_string("MODE_UNKNOWN");
3493 LTTV_STATE_USER_MODE = g_quark_from_string("USER_MODE");
3494 LTTV_STATE_SYSCALL = g_quark_from_string("SYSCALL");
3495 LTTV_STATE_TRAP = g_quark_from_string("TRAP");
3496 LTTV_STATE_IRQ = g_quark_from_string("IRQ");
3497 LTTV_STATE_SOFT_IRQ = g_quark_from_string("SOFTIRQ");
3498 LTTV_STATE_SUBMODE_UNKNOWN = g_quark_from_string("UNKNOWN");
3499 LTTV_STATE_SUBMODE_NONE = g_quark_from_string("NONE");
3500 LTTV_STATE_WAIT_FORK = g_quark_from_string("WAIT_FORK");
3501 LTTV_STATE_WAIT_CPU = g_quark_from_string("WAIT_CPU");
3502 LTTV_STATE_EXIT = g_quark_from_string("EXIT");
3503 LTTV_STATE_ZOMBIE = g_quark_from_string("ZOMBIE");
3504 LTTV_STATE_WAIT = g_quark_from_string("WAIT");
3505 LTTV_STATE_RUN = g_quark_from_string("RUN");
3506 LTTV_STATE_DEAD = g_quark_from_string("DEAD");
3507 LTTV_STATE_USER_THREAD = g_quark_from_string("USER_THREAD");
3508 LTTV_STATE_KERNEL_THREAD = g_quark_from_string("KERNEL_THREAD");
3509 LTTV_STATE_TRACEFILES = g_quark_from_string("tracefiles");
3510 LTTV_STATE_PROCESSES = g_quark_from_string("processes");
3511 LTTV_STATE_PROCESS = g_quark_from_string("process");
3512 LTTV_STATE_RUNNING_PROCESS = g_quark_from_string("running_process");
3513 LTTV_STATE_EVENT = g_quark_from_string("event");
3514 LTTV_STATE_SAVED_STATES = g_quark_from_string("saved states");
3515 LTTV_STATE_SAVED_STATES_TIME = g_quark_from_string("saved states time");
3516 LTTV_STATE_TIME = g_quark_from_string("time");
3517 LTTV_STATE_HOOKS = g_quark_from_string("saved state hooks");
3518 LTTV_STATE_NAME_TABLES = g_quark_from_string("name tables");
3519 LTTV_STATE_TRACE_STATE_USE_COUNT =
3520 g_quark_from_string("trace_state_use_count");
3521
3522
3523 LTT_FACILITY_KERNEL = g_quark_from_string("kernel");
3524 LTT_FACILITY_KERNEL_ARCH = g_quark_from_string("kernel_arch");
3525 LTT_FACILITY_FS = g_quark_from_string("fs");
3526 LTT_FACILITY_LIST = g_quark_from_string("list");
3527 LTT_FACILITY_USER_GENERIC = g_quark_from_string("user_generic");
3528
3529
3530 LTT_EVENT_SYSCALL_ENTRY = g_quark_from_string("syscall_entry");
3531 LTT_EVENT_SYSCALL_EXIT = g_quark_from_string("syscall_exit");
3532 LTT_EVENT_TRAP_ENTRY = g_quark_from_string("trap_entry");
3533 LTT_EVENT_TRAP_EXIT = g_quark_from_string("trap_exit");
3534 LTT_EVENT_IRQ_ENTRY = g_quark_from_string("irq_entry");
3535 LTT_EVENT_IRQ_EXIT = g_quark_from_string("irq_exit");
3536 LTT_EVENT_SOFT_IRQ_ENTRY = g_quark_from_string("soft_irq_entry");
3537 LTT_EVENT_SOFT_IRQ_EXIT = g_quark_from_string("soft_irq_exit");
3538 LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule");
3539 LTT_EVENT_PROCESS_FORK = g_quark_from_string("process_fork");
3540 LTT_EVENT_KTHREAD_CREATE = g_quark_from_string("kthread_create");
3541 LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit");
3542 LTT_EVENT_PROCESS_FREE = g_quark_from_string("process_free");
3543 LTT_EVENT_EXEC = g_quark_from_string("exec");
3544 LTT_EVENT_PROCESS_STATE = g_quark_from_string("process_state");
3545 LTT_EVENT_STATEDUMP_END = g_quark_from_string("statedump_end");
3546 LTT_EVENT_FUNCTION_ENTRY = g_quark_from_string("function_entry");
3547 LTT_EVENT_FUNCTION_EXIT = g_quark_from_string("function_exit");
3548 LTT_EVENT_THREAD_BRAND = g_quark_from_string("thread_brand");
3549
3550
3551 LTT_FIELD_SYSCALL_ID = g_quark_from_string("syscall_id");
3552 LTT_FIELD_TRAP_ID = g_quark_from_string("trap_id");
3553 LTT_FIELD_IRQ_ID = g_quark_from_string("irq_id");
3554 LTT_FIELD_SOFT_IRQ_ID = g_quark_from_string("softirq_id");
3555 LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid");
3556 LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid");
3557 LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state");
3558 LTT_FIELD_PARENT_PID = g_quark_from_string("parent_pid");
3559 LTT_FIELD_CHILD_PID = g_quark_from_string("child_pid");
3560 LTT_FIELD_PID = g_quark_from_string("pid");
3561 LTT_FIELD_TGID = g_quark_from_string("tgid");
3562 LTT_FIELD_CHILD_TGID = g_quark_from_string("child_tgid");
3563 LTT_FIELD_FILENAME = g_quark_from_string("filename");
3564 LTT_FIELD_NAME = g_quark_from_string("name");
3565 LTT_FIELD_TYPE = g_quark_from_string("type");
3566 LTT_FIELD_MODE = g_quark_from_string("mode");
3567 LTT_FIELD_SUBMODE = g_quark_from_string("submode");
3568 LTT_FIELD_STATUS = g_quark_from_string("status");
3569 LTT_FIELD_THIS_FN = g_quark_from_string("this_fn");
3570 LTT_FIELD_CALL_SITE = g_quark_from_string("call_site");
3571
3572 LTTV_CPU_UNKNOWN = g_quark_from_string("unknown");
3573 LTTV_CPU_IDLE = g_quark_from_string("idle");
3574 LTTV_CPU_BUSY = g_quark_from_string("busy");
3575 LTTV_CPU_IRQ = g_quark_from_string("irq");
3576 LTTV_CPU_TRAP = g_quark_from_string("trap");
3577 }
3578
3579 static void module_destroy()
3580 {
3581 }
3582
3583
3584 LTTV_MODULE("state", "State computation", \
3585 "Update the system state, possibly saving it at intervals", \
3586 module_init, module_destroy)
3587
3588
3589
This page took 0.105684 seconds and 5 git commands to generate.