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