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