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