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