Remove warnings in the lttv/module/text directory v2
[lttv.git] / lttv / modules / text / depanalysis.c
CommitLineData
8c108c1c
PMF
1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2008 Pierre-Marc Fournier
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
c7cb53d7
YB
22#define _GNU_SOURCE
23#include <stdio.h>
8c108c1c
PMF
24
25#include <lttv/lttv.h>
26#include <lttv/option.h>
27#include <lttv/module.h>
28#include <lttv/hook.h>
29#include <lttv/attribute.h>
30#include <lttv/iattribute.h>
31#include <lttv/stats.h>
32#include <lttv/filter.h>
33#include <lttv/print.h>
34#include <ltt/ltt.h>
35#include <ltt/event.h>
36#include <ltt/trace.h>
c7cb53d7 37
8c108c1c
PMF
38#include <glib.h>
39#include <stdlib.h>
40
41#include "sstack.h"
42
43static LttvHooks
44 *before_traceset,
45 *after_traceset,
8c108c1c
PMF
46 *event_hook;
47
48static int depanalysis_range_pid = -1;
49static int depanalysis_range_pid_searching = -1;
50static int depanalysis_use_time=0;
51static int depanalysis_event_limit = -1;
55cd92ee 52static int a_print_simple_summary = 0;
8c108c1c
PMF
53static LttTime depanalysis_time1, depanalysis_time2;
54static char *arg_t1_str,*arg_t2_str;
55static int statedump_finished = 0;
56
57
58struct llev_state_info_irq {
59 int irq;
60};
61
62struct llev_state_info_softirq {
63 int softirq;
64};
65
66struct llev_state_info_syscall {
67 int syscall_id;
68
69 int substate;
70
71 void *private;
72};
73
74struct llev_state_info_syscall__open {
75 GQuark filename;
76};
77
78struct llev_state_info_syscall__read {
79 GQuark filename;
80};
81
82struct llev_state_info_syscall__poll {
83 GQuark filename;
84};
85
86struct llev_state_info_preempted {
87 int prev_state;
88};
89
90struct hlev_state_info_blocked {
91 int syscall_id;
92 unsigned char trap; /* flag */
93 int substate;
94
95 /* Garray of pointers to struct process_state that reflect the
96 * low-level state stack when respectively entering and exiting the blocked
97 * state.
98 */
99 GArray *llev_state_entry;
100 GArray *llev_state_exit;
101
102 int pid_exit; /* FIXME: it's not pretty to have this here; find this info elsewhere */
103 LttTime time_woken;
104
105 void *private;
106};
107
108struct hlev_state_info_blocked__open {
109 GQuark filename;
110};
111
112struct hlev_state_info_blocked__read {
113 GQuark filename;
114};
115
116struct hlev_state_info_blocked__poll {
117 GQuark filename;
118};
119
120struct hlev_state_info_interrupted_irq {
121 int irq;
122};
123
124struct hlev_state_info_interrupted_softirq {
125 int softirq;
126};
127
128struct summary_tree_node {
129 char *name;
130 GHashTable *children;
131 LttTime duration;
132 GArray *episodes;
133 int id_for_episodes;
134};
135
136struct state_info {
137 char name[40];
138 int size_priv;
139 char *tree_path[6];
140};
141
142struct state_info llev_state_infos[] = {
143 { "UNKNOWN", 0, { NULL } },
144 { "RUNNING", 0, { NULL } },
145 { "SYSCALL", sizeof(struct llev_state_info_syscall), { NULL } },
146 { "IRQ", sizeof(struct llev_state_info_irq), { NULL } },
147 { "SOFTIRQ", sizeof(struct llev_state_info_softirq), { NULL } },
148 { "TRAP", 0, { NULL } },
149 { "PREEMPTED", sizeof(struct llev_state_info_preempted), { NULL } },
150};
151
152struct state_info hlev_state_infos[] = {
153 { "UNKNOWN", 0, { "Total", "Unknown", NULL } },
154 { "RUNNING", 0, { "Total", "Working", NULL } },
155 { "BLOCKED", sizeof(struct hlev_state_info_blocked), { "Total", "Blocked", NULL } },
156 { "INTERRUPTED_IRQ", sizeof(struct hlev_state_info_interrupted_irq), { "Total", "Interrupted", "IRQ", NULL } },
157 { "INTERRUPTED_SOFTIRQ", sizeof(struct hlev_state_info_interrupted_softirq), { "Total", "Interrupted", "SoftIRQ", NULL } },
158 { "INTERRUPTED_CPU", 0, { "Total", "Interrupted", "Preempted", NULL } },
159 { "INTERRUPTED_POST_BLOCK", 0, { "Total", "Interrupted", "Waiting schedule after blocking", NULL } },
160};
161
162enum llev_state {
163 LLEV_UNKNOWN=0,
164 LLEV_RUNNING,
165 LLEV_SYSCALL,
166 LLEV_IRQ,
167 LLEV_SOFTIRQ,
168 LLEV_TRAP,
169 LLEV_PREEMPTED,
170};
171
172enum llev_syscall_substate {
173 LLEV_SYSCALL__UNDEFINED,
174 LLEV_SYSCALL__OPEN,
175 LLEV_SYSCALL__READ,
176 LLEV_SYSCALL__POLL,
177};
178
179enum hlev_event {
180 HLEV_EVENT_TRY_WAKEUP=0,
181};
182
183enum hlev_state {
184 HLEV_UNKNOWN=0,
185 HLEV_RUNNING,
186 HLEV_BLOCKED,
187 HLEV_INTERRUPTED_IRQ,
188 HLEV_INTERRUPTED_SOFTIRQ,
189 HLEV_INTERRUPTED_CPU,
190 HLEV_INTERRUPTED_POST_BLOCK,
191};
192
193enum hlev_state_blocked {
194 HLEV_BLOCKED__UNDEFINED,
195 HLEV_BLOCKED__OPEN,
196 HLEV_BLOCKED__READ,
197 HLEV_BLOCKED__POLL,
198};
199
200struct sstack_event {
201 int event_type;
202 void *private;
203};
204
205struct try_wakeup_event {
206 int pid; /* this sould be more precise avec pid may be reused */
207 LttTime time;
208 struct process *waker;
209};
210
211struct process_state {
212 int bstate;
213 int cause_type;
214 void *private;
215
216 LttTime time_begin;
217 LttTime time_end;
218};
219
220struct process_with_state {
221 struct process *process;
222 struct process_state state;
223};
224
225#define PROCESS_STATE_STACK_SIZE 10
226struct process {
227 int pid;
228 GQuark name;
229 int parent;
230
231 struct sstack *stack;
232 struct process_state *llev_state_stack[PROCESS_STATE_STACK_SIZE];
233 int stack_current;
234 struct process_state *hlev_state;
235 GArray *hlev_history;
236};
237
238static inline void *old_process_state_private_data(struct process *p)
239{
240 return p->llev_state_stack[p->stack_current]->private;
241}
242
243static inline struct process_state *process_find_state(struct process *p, enum llev_state st)
244{
245 int i;
246
247 for(i=p->stack->array->len-1; i>=0; i--) {
248 struct sstack_item *item = g_array_index(p->stack->array, struct sstack_item *, i);
249
250 struct process_with_state *pwstate = item->data_val;
251 if(pwstate->state.bstate == st) {
252 return &pwstate->state;
253 }
254 }
255
256 return NULL;
257}
258
259static int find_pos_in_stack(enum llev_state lls, struct process *p)
260{
261 int i;
262 for(i=p->stack_current; i>=0; i--) {
263 if(p->llev_state_stack[i]->bstate == lls)
264 return i;
265 }
266
267 return -1;
268}
269
270static struct process_state *find_in_stack(enum llev_state lls, struct process *p)
271{
272 int result;
273
274 result = find_pos_in_stack(lls, p);
275
276 if(result >= 0)
277 return p->llev_state_stack[result];
278 else
279 return NULL;
280
281}
282
283/* called back from sstack on deletion of a data_val which is
284 * a struct process_with_state
285 */
286
287static void delete_data_val(struct process_with_state *pwstate)
288{
289 // FIXME: Free this also
290 //g_free(pwstate->state.private);
291
292 // FIXME: this is really ugly. Don't free the pwstate if the state is LLEV_RUNNING.
293 // LLEV_RUNNING is a special case that's being processed and deleted immediately after
294 // being inserted on the sstack, to prevent state begin accumulated because it couldn't
295 // be processed before the end of the trace. If we free the state, we get invalid memory
296 // reads when looking at it on the state_stack.
297 //if(pwstate->state.bstate != LLEV_RUNNING)
298 // g_free(pwstate);
299}
300
b1d18041
PMF
301inline void print_time(LttTime t)
302{
303 //printf("%lu.%lu", t.tv_sec, t.tv_nsec);
304 double f;
305 f = (double)t.tv_sec + ((double)t.tv_nsec)/1000000000.0;
306 printf("%.9f", f);
307}
308
8c108c1c
PMF
309static struct sstack_item *prepare_push_item(struct process *p, enum llev_state st, LttTime t)
310{
311 struct process_with_state *pwstate = g_malloc(sizeof(struct process_with_state));
312 struct sstack_item *item;
313
314 int wait_for_pop = 0;
315
316 if(st == LLEV_SYSCALL) {
317 /* We need to push LLEV_SYSCALL as wait_for_pop because it depends on some of
318 * its children. If we don't do this, it's going to get processed immediately
319 * by the sstack and we might miss some details about it that will come later.
320 */
321 wait_for_pop = 1;
322 }
323
324 item = sstack_item_new_push(wait_for_pop);
325
326 //printf("pushing in context of %d\n", p->pid);
327
328 pwstate->process = p;
329 pwstate->state.bstate = st;
330 pwstate->state.time_begin = t;
331 pwstate->state.private = g_malloc(llev_state_infos[st].size_priv);
332
333 item->data_val = pwstate;
b1d18041
PMF
334 item->delete_data_val = (void (*)(void*))delete_data_val;
335
336 return item;
8c108c1c
PMF
337}
338
339static void *item_private(struct sstack_item *item)
340{
341 struct process_with_state *pwstate = item->data_val;
342 return pwstate->state.private;
343}
344
345static void commit_item(struct process *p, struct sstack_item *item)
346{
347 sstack_add_item(p->stack, item);
348}
349
350static void old_process_push_llev_state(struct process *p, struct process_state *pstate)
351{
352 if(++p->stack_current >= PROCESS_STATE_STACK_SIZE) {
353 fprintf(stderr, "depanalysis: internal process stack overflow\n");
354 abort();
355 }
356
357 p->llev_state_stack[p->stack_current] = pstate;
358}
359
360static void live_complete_process_push_llev_state(struct process *p, enum llev_state st, LttTime t)
361{
362 struct process_state *pstate = g_malloc(sizeof(struct process_state));
363
364 pstate->bstate = st;
365 pstate->time_begin = t;
366 pstate->private = g_malloc(llev_state_infos[st].size_priv);
367
368 old_process_push_llev_state(p, pstate);
369}
370
371static void prepare_pop_item_commit_nocheck(struct process *p, enum llev_state st, LttTime t)
372{
373 struct process_with_state *pwstate;
374 struct sstack_item *item = sstack_item_new_pop();
375
376 int push_idx;
377
378 if(p->stack->pushes->len > 0)
379 push_idx = g_array_index(p->stack->pushes, int, p->stack->pushes->len-1);
380 else
381 push_idx = -1;
382
383 if(push_idx >= 0) {
384 pwstate = g_array_index(p->stack->array, struct sstack_item *, push_idx)->data_val;
385 pwstate->process = p;
386 pwstate->state.time_end = t;
387 item->data_val = pwstate;
388 /* don't set delete_data_val because we use the same pwstate as push, and we don't want to free it twice */
389 }
390 else {
391
392 pwstate = g_malloc(sizeof(struct process_with_state));
393 pwstate->process = p;
394 item->data_val = pwstate;
395 pwstate->state.time_end = t;
396 pwstate->state.bstate = st;
397 }
398
399 sstack_add_item(p->stack, item);
400
401}
402
403static void prepare_pop_item_commit(struct process *p, enum llev_state st, LttTime t)
404{
405 struct process_with_state *pwstate;
8c108c1c
PMF
406
407 int push_idx;
408
409 if(p->stack->pushes->len > 0)
410 push_idx = g_array_index(p->stack->pushes, int, p->stack->pushes->len-1);
411 else
412 push_idx = -1;
413
414 if(push_idx >= 0) {
415 /* FIXME: ugly workaround for kernel bug that generates two kernel_arch_syscall_exit on fork.
416 * The bug only occurs upon creation of new processes. But these processes always have
417 * a LLEV_RUNNING at index 0. */
418 if(push_idx >= p->stack->array->len)
419 return;
420
421 pwstate = g_array_index(p->stack->array, struct sstack_item *, push_idx)->data_val;
422
423 if(pwstate->state.bstate != st) {
424 /* FIXME: ugly workaround for kernel bug that generates two kernel_arch_syscall_exit on fork */
425 if(st != LLEV_SYSCALL) {
426 printf("bad pop! at ");
427 print_time(t);
428 printf("\n");
429 print_stack(p->stack);
430 abort();
431 }
432 else {
433 /* case where we have a double syscall_exit */
434 return;
435 }
436 }
437 }
438
439 prepare_pop_item_commit_nocheck(p, st, t);
440}
441
442
443static int try_pop_blocked_llev_preempted(struct process *p, LttTime t)
444{
445 int push_idx;
446 struct process_with_state *pwstate;
447
448 if(p->stack->pushes->len > 0)
449 push_idx = g_array_index(p->stack->pushes, int, p->stack->pushes->len-1);
450 else
451 push_idx = -1;
452
453 if(push_idx >= 0) {
454 pwstate = g_array_index(p->stack->array, struct sstack_item *, push_idx)->data_val;
455
456 if(!(pwstate->state.bstate == LLEV_PREEMPTED && ((struct llev_state_info_preempted *)pwstate->state.private)->prev_state > 0)) {
55cd92ee 457 //printf("double try wake up\n");
8c108c1c
PMF
458 return 0;
459 }
460 }
461
462 prepare_pop_item_commit_nocheck(p, LLEV_PREEMPTED, t);
463 return 1;
464}
465
466static void old_process_pop_llev_state(struct process *p, struct process_state *pstate)
467{
468 /* Ensure we are really popping the current state */
469 /* FIXME: pstate->bstate is uninitialized? */
470 // Commenting because it does not work. The way things work now, this check cannot work.
471 //if(p->llev_state_stack[p->stack_current]->bstate != LLEV_UNKNOWN && p->llev_state_stack[p->stack_current]->bstate != pstate->bstate) {
472 // printf("ERROR! bad pop!\n");
473 // abort();
474 //}
475
476 /* Actually change the that position */
477 if(p->stack_current >= 0)
478 p->stack_current--;
479
480 /* If stack empty, we must put something in it */
481 if(p->stack_current == -1) {
482 if(pstate->bstate == LLEV_SYSCALL) {
483 //process_push_llev_state(p, LLEV_RUNNING, pstate->time_end);
484 live_complete_process_push_llev_state(p, LLEV_RUNNING, pstate->time_end);
485 }
486 else {
487 live_complete_process_push_llev_state(p, LLEV_UNKNOWN, pstate->time_end);
488 }
489 }
490}
491
492static GHashTable *process_hash_table;
493static GHashTable *syscall_table;
494static GHashTable *irq_table;
495static GHashTable *softirq_table;
496
497/* Insert the hooks before and after each trace and tracefile, and for each
498 event. Print a global header. */
499
500static FILE *a_file;
501
502static GString *a_string;
503
504static gboolean write_traceset_header(void *hook_data, void *call_data)
505{
8c108c1c 506 g_info("Traceset header");
c7cb53d7 507
8c108c1c
PMF
508 return FALSE;
509}
510
b1d18041 511GArray *oldstyle_stack_to_garray(struct process_state **oldstyle_stack, int current)
8c108c1c
PMF
512{
513 GArray *retval;
514 int i;
515
b1d18041 516 retval = g_array_new(FALSE, FALSE, sizeof(struct process_state *));
8c108c1c
PMF
517
518 for(i=0; i<current; i++) {
519 g_array_append_val(retval, oldstyle_stack[i]);
520 }
521
522 return retval;
523}
524
525static void update_hlev_state(struct process *p, LttTime t)
526{
527 int i;
528
c7cb53d7 529 enum hlev_state new_hlev = 0;
8c108c1c
PMF
530
531 for(i=p->stack_current; i>=0; i--) {
532 enum llev_state st;
533 st = p->llev_state_stack[i]->bstate;
534
535 if(st == LLEV_RUNNING || st == LLEV_TRAP || st == LLEV_SYSCALL) {
536 new_hlev = HLEV_RUNNING;
537 break;
538 }
539 else if(st == LLEV_IRQ) {
540 new_hlev = HLEV_INTERRUPTED_IRQ;
541 break;
542 }
543 else if(st == LLEV_SOFTIRQ) {
544 new_hlev = HLEV_INTERRUPTED_SOFTIRQ;
545 break;
546 }
547 else if(st == LLEV_PREEMPTED) {
548 int prev_state = ((struct llev_state_info_preempted *) old_process_state_private_data(p))->prev_state;
549
550 if(prev_state == 0) {
551 new_hlev = HLEV_INTERRUPTED_CPU;
552 }
553 else if(prev_state == -1) {
554 new_hlev = HLEV_INTERRUPTED_POST_BLOCK;
555 }
556 else {
557 new_hlev = HLEV_BLOCKED;
558 }
559 break;
560 }
561 else if(st == LLEV_UNKNOWN) {
562 new_hlev = HLEV_UNKNOWN;
563 break;
564 }
565 else {
566 abort();
567 }
568 }
569
570 /* If no state change, do nothing */
571 if(p->hlev_state != NULL && new_hlev == p->hlev_state->bstate) {
572 return;
573 }
574
575 p->hlev_state->time_end = t;
576 /* This check is here because we initially put HLEV_UNKNOWN as hlev state, but in the case
577 * of processes newly created, it is immediately replaced by HLEV_BLOCKED. In order to avoid
578 * having a UNKNOWN state of duration 0 in the summary, we don't add it. This isn't as elegant
579 * as it ought to be.
580 */
581 if(ltt_time_compare(p->hlev_state->time_begin, p->hlev_state->time_end) != 0)
582 g_array_append_val(p->hlev_history, p->hlev_state);
583 p->hlev_state = g_malloc(sizeof(struct process_state));
584 p->hlev_state->bstate = new_hlev;
585 p->hlev_state->time_begin = t;
586 p->hlev_state->private = g_malloc(hlev_state_infos[new_hlev].size_priv);
587
588 //printf("depanalysis: now at hlev state %s\n", hlev_state_infos[new_hlev].name);
589
590 /* Set private data */
591 switch(p->hlev_state->bstate) {
592 case HLEV_UNKNOWN:
593 break;
594 case HLEV_RUNNING:
595 break;
596 case HLEV_BLOCKED: {
597 struct hlev_state_info_blocked *hlev_blocked_private = p->hlev_state->private;
8c108c1c
PMF
598 int syscall_pos = find_pos_in_stack(LLEV_SYSCALL, p);
599 int trap_pos = find_pos_in_stack(LLEV_TRAP, p);
600
601 /* init vals */
602 hlev_blocked_private->syscall_id = 1;
603 hlev_blocked_private->trap = 0;
c7cb53d7 604 hlev_blocked_private->pid_exit = 0;
8c108c1c
PMF
605 hlev_blocked_private->substate = HLEV_BLOCKED__UNDEFINED;
606 hlev_blocked_private->private = NULL;
607 hlev_blocked_private->llev_state_entry = oldstyle_stack_to_garray(p->llev_state_stack, p->stack_current);
608 hlev_blocked_private->llev_state_exit = NULL;
609
610 //g_assert(syscall_pos >= 0 || trap_pos >= 0);
611
612 if(trap_pos > syscall_pos) {
613 hlev_blocked_private->trap = 1;
614 }
615
616 /* initial value, may be changed below */
617 hlev_blocked_private->substate = HLEV_BLOCKED__UNDEFINED;
618
619 if(syscall_pos >= 0) {
620 struct process_state *ps = p->llev_state_stack[syscall_pos];
621 struct llev_state_info_syscall *llev_syscall_private = (struct llev_state_info_syscall *) ps->private;
622 hlev_blocked_private->syscall_id = llev_syscall_private->syscall_id;
623
624 if(llev_syscall_private->substate == LLEV_SYSCALL__OPEN) {
625 struct llev_state_info_syscall__open *llev_syscall_open_private;
626 struct hlev_state_info_blocked__open *hlev_blocked_open_private;
627 llev_syscall_open_private = llev_syscall_private->private;
628 hlev_blocked_private->substate = HLEV_BLOCKED__OPEN;
629 hlev_blocked_open_private = g_malloc(sizeof(struct hlev_state_info_blocked__open));
630 hlev_blocked_private->private = hlev_blocked_open_private;
631 hlev_blocked_open_private->filename = llev_syscall_open_private->filename;
632
633 //printf("depanalysis: blocked in an open!\n");
634 }
635 else if(llev_syscall_private->substate == LLEV_SYSCALL__READ) {
636 struct llev_state_info_syscall__read *llev_syscall_read_private;
637 struct hlev_state_info_blocked__read *hlev_blocked_read_private;
638 llev_syscall_read_private = llev_syscall_private->private;
639 hlev_blocked_private->substate = HLEV_BLOCKED__READ;
640 hlev_blocked_read_private = g_malloc(sizeof(struct hlev_state_info_blocked__read));
641 hlev_blocked_private->private = hlev_blocked_read_private;
642 hlev_blocked_read_private->filename = llev_syscall_read_private->filename;
643
644 //printf("depanalysis: blocked in a read!\n");
645 }
646 else if(llev_syscall_private->substate == LLEV_SYSCALL__POLL) {
647 struct llev_state_info_syscall__poll *llev_syscall_poll_private;
648 struct hlev_state_info_blocked__poll *hlev_blocked_poll_private;
649 llev_syscall_poll_private = llev_syscall_private->private;
650 hlev_blocked_private->substate = HLEV_BLOCKED__POLL;
651 hlev_blocked_poll_private = g_malloc(sizeof(struct hlev_state_info_blocked__poll));
652 hlev_blocked_private->private = hlev_blocked_poll_private;
653 hlev_blocked_poll_private->filename = llev_syscall_poll_private->filename;
654
655 //printf("depanalysis: blocked in a read!\n");
656 }
657 }
658 else {
659 hlev_blocked_private->syscall_id = -1;
660 }
661
662 break;
663 }
664 case HLEV_INTERRUPTED_IRQ: {
665 struct hlev_state_info_interrupted_irq *sinfo = p->hlev_state->private;
666 struct process_state *ps = find_in_stack(LLEV_IRQ, p);
667 if(ps == NULL)
668 abort();
669 else
670 sinfo->irq = ((struct llev_state_info_irq *) ps->private)->irq;
671 break;
672 }
673 case HLEV_INTERRUPTED_SOFTIRQ: {
674 struct hlev_state_info_interrupted_softirq *sinfo = p->hlev_state->private;
675 struct process_state *ps = find_in_stack(LLEV_SOFTIRQ, p);
676 if(ps == NULL)
677 abort();
678 else
679 sinfo->softirq = ((struct llev_state_info_softirq *) ps->private)->softirq;
680 break;
681 }
682 default:
683 break;
684 };
685}
686
687static gint compare_summary_tree_node_times(gconstpointer a, gconstpointer b)
688{
689 struct summary_tree_node *n1 = (struct summary_tree_node *) a;
690 struct summary_tree_node *n2 = (struct summary_tree_node *) b;
691
692 return ltt_time_compare(n2->duration, n1->duration);
693}
694
695/* Print an item of the simple summary tree, and recurse, printing its children.
696 *
697 * If depth == -1, this is the root: we don't print a label, we only recurse into
698 * the children.
699 */
700
701static void print_summary_item(struct summary_tree_node *node, int depth)
702{
703 GList *vals;
704
705 if(depth >= 0) {
c7cb53d7
YB
706 printf("\t%*s (",
707 (unsigned int)strlen(node->name)+2*depth,
708 node->name);
8c108c1c
PMF
709 print_time(node->duration);
710 printf(") <%d>\n", node->id_for_episodes);
711 }
712
713 if(!node->children)
714 return;
715
716 vals = g_hash_table_get_values(node->children);
717
718 /* sort the values */
719 vals = g_list_sort(vals, compare_summary_tree_node_times);
720
721 while(vals) {
722 print_summary_item((struct summary_tree_node *)vals->data, depth+1);
723 vals = vals->next;
724 }
725
726 /* we must free the list returned by g_hash_table_get_values() */
727 g_list_free(vals);
728}
729
730static inline void print_irq(int irq)
731{
c7cb53d7 732 printf("IRQ %d [%s]", irq, g_quark_to_string((GQuark)(unsigned long)g_hash_table_lookup(irq_table, &irq)));
8c108c1c
PMF
733}
734
735static inline void print_softirq(int softirq)
736{
c7cb53d7 737 printf("SoftIRQ %d [%s]", softirq, g_quark_to_string((GQuark)(unsigned long)g_hash_table_lookup(softirq_table, &softirq)));
8c108c1c
PMF
738}
739
740static inline void print_pid(int pid)
741{
742 struct process *event_process_info = g_hash_table_lookup(process_hash_table, &pid);
743
c7cb53d7 744 const char *pname;
8c108c1c
PMF
745
746 if(event_process_info == NULL)
747 pname = "?";
748 else
749 pname = g_quark_to_string(event_process_info->name);
750 printf("%d [%s]", pid, pname);
751}
752
753static void modify_path_with_private(GArray *path, struct process_state *pstate)
754{
8c108c1c
PMF
755 char *tmps;
756
757 // FIXME: fix this leak
758 switch(pstate->bstate) {
759 case HLEV_INTERRUPTED_IRQ:
c7cb53d7 760 asprintf(&tmps, "IRQ %d [%s]", ((struct hlev_state_info_interrupted_irq *)pstate->private)->irq, g_quark_to_string((GQuark)(unsigned long)g_hash_table_lookup(irq_table, &((struct hlev_state_info_interrupted_irq *)pstate->private)->irq)));
8c108c1c
PMF
761 g_array_append_val(path, tmps);
762 break;
763 case HLEV_INTERRUPTED_SOFTIRQ:
c7cb53d7 764 asprintf(&tmps, "SoftIRQ %d [%s]", ((struct hlev_state_info_interrupted_softirq *)pstate->private)->softirq, g_quark_to_string((GQuark)(unsigned long)g_hash_table_lookup(softirq_table, &((struct hlev_state_info_interrupted_softirq *)pstate->private)->softirq)));
8c108c1c
PMF
765 g_array_append_val(path, tmps);
766 break;
767 case HLEV_BLOCKED: {
768 struct hlev_state_info_blocked *hlev_blocked_private = (struct hlev_state_info_blocked *)pstate->private;
769
770 if(hlev_blocked_private->trap) {
771 char *ptr = "Trap";
772 g_array_append_val(path, ptr);
773 }
774
775 if(hlev_blocked_private->syscall_id == -1) {
776 char *ptr = "Userspace";
777 g_array_append_val(path, ptr);
778 }
779 else {
c7cb53d7 780 asprintf(&tmps, "Syscall %d [%s]", hlev_blocked_private->syscall_id, g_quark_to_string((GQuark)(unsigned long)g_hash_table_lookup(syscall_table, &hlev_blocked_private->syscall_id)));
8c108c1c
PMF
781 g_array_append_val(path, tmps);
782 }
783
784 if(((struct hlev_state_info_blocked *)pstate->private)->substate == HLEV_BLOCKED__OPEN) {
c7cb53d7 785 const char *str = g_quark_to_string(((struct hlev_state_info_blocked__open *)((struct hlev_state_info_blocked *)pstate->private)->private)->filename);
8c108c1c
PMF
786 g_array_append_val(path, str);
787 }
788 else if(((struct hlev_state_info_blocked *)pstate->private)->substate == HLEV_BLOCKED__READ) {
789 char *str;
790 asprintf(&str, "%s", g_quark_to_string(((struct hlev_state_info_blocked__read *)((struct hlev_state_info_blocked *)pstate->private)->private)->filename));
791 g_array_append_val(path, str);
792 /* FIXME: this must be freed at some point */
793 //free(str);
794 }
795 else if(((struct hlev_state_info_blocked *)pstate->private)->substate == HLEV_BLOCKED__POLL) {
796 char *str;
797 asprintf(&str, "%s", g_quark_to_string(((struct hlev_state_info_blocked__poll *)((struct hlev_state_info_blocked *)pstate->private)->private)->filename));
798 g_array_append_val(path, str);
799 /* FIXME: this must be freed at some point */
800 //free(str);
801 }
802 break;
803 }
804 };
805}
806
807void print_stack_garray_horizontal(GArray *stack)
808{
809 /* FIXME: this function doesn't work if we delete the states as we process them because we
810 * try to read those states here to print the low level stack.
811 */
812 int i;
813
814 for(i=0; i<stack->len; i++) {
815 struct process_state *pstate = g_array_index(stack, struct process_state *, i);
816 printf("%s", llev_state_infos[pstate->bstate].name);
817
818 if(pstate->bstate == LLEV_SYSCALL) {
819 struct llev_state_info_syscall *llev_syscall_private = pstate->private;
c7cb53d7 820 printf(" %d [%s]", llev_syscall_private->syscall_id, g_quark_to_string((GQuark)(unsigned long)g_hash_table_lookup(syscall_table, &llev_syscall_private->syscall_id)));
8c108c1c
PMF
821 }
822
823 printf(", ");
824
825 }
826}
827
828static int dicho_search_state_ending_after(struct process *p, LttTime t)
829{
830 int under = 0;
831 int over = p->hlev_history->len-1;
832 struct process_state *pstate;
833 int result;
834
835 if(over < 1)
836 return -1;
837
838 /* If the last element is smaller or equal than the time we are searching for,
839 * no match
840 */
841 pstate = g_array_index(p->hlev_history, struct process_state *, over);
842 if(ltt_time_compare(pstate->time_end, t) <= 0) {
843 return -1;
844 }
845 /* no need to check for the equal case */
846
847 pstate = g_array_index(p->hlev_history, struct process_state *, under);
848 result = ltt_time_compare(pstate->time_end, t);
849 if(result >= 1) {
850 /* trivial match at the first element if it is greater or equal
851 * than the time we want
852 */
853 return under;
854 }
855
856 while(1) {
857 int dicho;
858
859 dicho = (under+over)/2;
860 pstate = g_array_index(p->hlev_history, struct process_state *, dicho);
861 result = ltt_time_compare(pstate->time_end, t);
862
863 if(result == -1) {
864 under = dicho;
865 }
866 else if(result == 1) {
867 over = dicho;
868 }
869 else {
870 /* exact match */
871 return dicho+1;
872 }
873
874 if(over-under == 1) {
875 /* we have converged */
876 return over;
877 }
878 }
879
880}
881
882/* FIXME: this shouldn't be based on pids in case of reuse
883 * FIXME: should add a list of processes used to avoid loops
884 */
885
886static struct process_state *find_state_ending_after(int pid, LttTime t)
887{
888 struct process *p;
889 int result;
890
891
892 p = g_hash_table_lookup(process_hash_table, &pid);
893 if(!p)
894 return NULL;
895
896 result = dicho_search_state_ending_after(p, t);
897
898 if(result == -1)
899 return NULL;
900 else
901 return g_array_index(p->hlev_history, struct process_state *, result);
902}
903
8d308134
MD
904static void print_indent(int offset)
905{
906 if (offset > 2) {
907 int i;
908
909 printf("%*s", 8, "");
910 for (i = 3; i < offset; i++) {
911 printf("|");
912 printf("%*s", 4, "");
913 }
914 } else
915 printf("%*s", 4*offset, "");
916}
917
8c108c1c
PMF
918static void print_delay_pid(int pid, LttTime t1, LttTime t2, int offset)
919{
920 struct process *p;
921 int i;
922
923 p = g_hash_table_lookup(process_hash_table, &pid);
924 if(!p)
925 return;
926
927 i = dicho_search_state_ending_after(p, t1);
928 for(; i<p->hlev_history->len; i++) {
929 struct process_state *pstate = g_array_index(p->hlev_history, struct process_state *, i);
930 if(ltt_time_compare(pstate->time_end, t2) > 0)
931 break;
932
933 if(pstate->bstate == HLEV_BLOCKED) {
934 struct hlev_state_info_blocked *state_private_blocked;
935 state_private_blocked = pstate->private;
936 struct process_state *state_unblocked;
937
8d308134
MD
938 print_indent(offset);
939 printf("--> Blocked in ");
8c108c1c
PMF
940 print_stack_garray_horizontal(state_private_blocked->llev_state_entry);
941
942 printf("(times: ");
943 print_time(pstate->time_begin);
944 printf("-");
945 print_time(pstate->time_end);
946
947 printf(", dur: %f)\n", 1e-9*ltt_time_to_double(ltt_time_sub(pstate->time_end, pstate->time_begin)));
948
949 state_unblocked = find_state_ending_after(state_private_blocked->pid_exit, state_private_blocked->time_woken);
950 if(state_unblocked) {
951 if(state_unblocked->bstate == HLEV_INTERRUPTED_IRQ) {
952 struct hlev_state_info_interrupted_irq *priv = state_unblocked->private;
953 /* if in irq or softirq, we don't care what the waking process was doing because they are asynchroneous events */
8d308134
MD
954 print_indent(offset);
955 printf("--- Woken up by an IRQ: ");
8c108c1c
PMF
956 print_irq(priv->irq);
957 printf("\n");
958 }
959 else if(state_unblocked->bstate == HLEV_INTERRUPTED_SOFTIRQ) {
960 struct hlev_state_info_interrupted_softirq *priv = state_unblocked->private;
8d308134
MD
961 print_indent(offset);
962 printf("--- Woken up by a SoftIRQ: ");
8c108c1c
PMF
963 print_softirq(priv->softirq);
964 printf("\n");
965 }
966 else {
967 LttTime t1prime=t1;
968 LttTime t2prime=t2;
969
970 if(ltt_time_compare(t1prime, pstate->time_begin) < 0)
971 t1prime = pstate->time_begin;
972 if(ltt_time_compare(t2prime, pstate->time_end) > 0)
973 t2prime = pstate->time_end;
974
975 print_delay_pid(state_private_blocked->pid_exit, t1prime, t2prime, offset+1);
8d308134
MD
976 print_indent(offset);
977 printf("--- Woken up in context of ");
8c108c1c
PMF
978 print_pid(state_private_blocked->pid_exit);
979 if(state_private_blocked->llev_state_exit) {
980 print_stack_garray_horizontal(state_private_blocked->llev_state_exit);
981 }
982 else {
983 }
984 printf(" in high-level state %s", hlev_state_infos[state_unblocked->bstate].name);
985 printf("\n");
986 }
987 }
988 else {
8d308134 989 print_indent(offset);
8c108c1c
PMF
990 printf("Weird... cannot find in what state the waker (%d) was\n", state_private_blocked->pid_exit);
991 }
992
993
994 //print_delay_pid(state_private_blocked->pid_exit, pstate->time_start, pstate->time_end);
995 //printf("\t\t Woken up in context of %d: ", state_private_blocked->pid_exit);
996 //if(state_private_blocked->llev_state_exit) {
997 // print_stack_garray_horizontal(state_private_blocked->llev_state_exit);
998 // printf("here3 (%d)\n", state_private_blocked->llev_state_exit->len);
999 //}
1000 //else
1001 // printf("the private_blocked %p had a null exit stack\n", state_private_blocked);
1002 //printf("\n");
1003 }
1004 }
1005}
1006
1007static void print_range_critical_path(int process, LttTime t1, LttTime t2)
1008{
1009 printf("Critical path for requested range:\n");
1010 printf("Final process is %d\n", process);
1011 print_delay_pid(process, t1, t2, 2);
1012}
1013
8d308134
MD
1014/*
1015 * output legend example:
1016 *
1017 * --> Blocked in RUNNING, SYSCALL NNN [syscall_name]
1018 * | ---> Blocked in RUNNING, SYSCALL NNN [syscall_name]
1019 * | | --> Blocked in RUNNING, SYSCALL [syscall_name]
1020 * | | --- Woken up by an IRQ: IRQ 0 [timer]
1021 * | --- Woken up in context of PID [appname] in high-level state RUNNING
1022 * --- Woken up in context of PID [appname] in high-level state RUNNING
1023 */
1024
8c108c1c
PMF
1025static void print_process_critical_path_summary()
1026{
1027 struct process *pinfo;
1028 GList *pinfos;
8c108c1c
PMF
1029
1030 pinfos = g_hash_table_get_values(process_hash_table);
1031 if(pinfos == NULL) {
1032 fprintf(stderr, "error: no process found\n");
1033 return;
1034 }
1035
1036 printf("Process Critical Path Summary:\n");
1037
1038 for(;;) {
8c108c1c
PMF
1039
1040 pinfo = (struct process *)pinfos->data;
55cd92ee
MD
1041 if (depanalysis_range_pid_searching != -1 && pinfo->pid != depanalysis_range_pid_searching)
1042 goto next_iter;
8c108c1c
PMF
1043 printf("\tProcess %d [%s]\n", pinfo->pid, g_quark_to_string(pinfo->name));
1044
1045 if(pinfo->hlev_history->len < 1)
1046 goto next_iter;
1047
1048 print_delay_pid(pinfo->pid, g_array_index(pinfo->hlev_history, struct process_state *, 0)->time_begin, g_array_index(pinfo->hlev_history, struct process_state *, pinfo->hlev_history->len - 1)->time_end, 2);
1049
1050 next_iter:
1051
1052 if(pinfos->next)
1053 pinfos = pinfos->next;
1054 else
1055 break;
1056 }
1057}
1058
1059gint compare_states_length(gconstpointer a, gconstpointer b)
1060{
1061 struct process_state **s1 = (struct process_state **)a;
1062 struct process_state **s2 = (struct process_state **)b;
1063 gint val;
1064
1065 val = ltt_time_compare(ltt_time_sub((*s2)->time_end, (*s2)->time_begin), ltt_time_sub((*s1)->time_end, (*s1)->time_begin));
1066 return val;
1067}
1068
55cd92ee 1069static void print_simple_summary(void)
8c108c1c
PMF
1070{
1071 struct process *pinfo;
1072 GList *pinfos;
1073 GList *pinfos_first;
1074 int i,j;
1075 int id_for_episodes = 0;
1076
55cd92ee
MD
1077 if (!a_print_simple_summary)
1078 return;
1079
8c108c1c
PMF
1080 /* we save all the nodes here to print the episodes table quickly */
1081 GArray *all_nodes = g_array_new(FALSE, FALSE, sizeof(struct summary_tree_node *));
1082
1083 pinfos_first = g_hash_table_get_values(process_hash_table);
1084 if(pinfos_first == NULL) {
1085 fprintf(stderr, "error: no processes found\n");
1086 return;
1087 }
1088 pinfos = pinfos_first;
1089
1090 printf("Simple summary:\n");
1091
1092 /* For each process */
1093 for(;;) {
1094 struct summary_tree_node base_node = { children: NULL, name: "Root" };
1095
8c108c1c
PMF
1096 pinfo = (struct process *)pinfos->data;
1097 printf("\tProcess %d [%s]\n", pinfo->pid, g_quark_to_string(pinfo->name));
1098
1099 /* For each state in the process history */
1100 for(i=0; i<pinfo->hlev_history->len; i++) {
1101 struct process_state *pstate = g_array_index(pinfo->hlev_history, struct process_state *, i);
1102 struct summary_tree_node *node_cur = &base_node;
1103 GArray *tree_path_garray;
1104
1105 /* Modify the path based on private data */
1106 tree_path_garray = g_array_new(FALSE, FALSE, sizeof(char *));
1107 {
1108 int count=0;
1109 char **tree_path_cur2 = hlev_state_infos[pstate->bstate].tree_path;
1110 while(*tree_path_cur2) {
1111 count++;
1112 tree_path_cur2++;
1113 }
1114 g_array_append_vals(tree_path_garray, hlev_state_infos[pstate->bstate].tree_path, count);
1115 }
1116 modify_path_with_private(tree_path_garray, pstate);
1117
1118 /* Walk the path, adding the nodes to the summary */
1119 for(j=0; j<tree_path_garray->len; j++) {
1120 struct summary_tree_node *newnode;
1121 GQuark componentquark;
1122
1123 /* Have a path component we must follow */
1124 if(!node_cur->children) {
1125 /* must create the hash table for the children */
1126 node_cur->children = g_hash_table_new(g_int_hash, g_int_equal);
1127 }
1128
1129 /* try to get the node for the next component */
1130 componentquark = g_quark_from_string(g_array_index(tree_path_garray, char *, j));
1131 newnode = g_hash_table_lookup(node_cur->children, &componentquark);
1132 if(newnode == NULL) {
1133 newnode = g_malloc(sizeof(struct summary_tree_node));
1134 newnode->children = NULL;
1135 newnode->name = g_array_index(tree_path_garray, char *, j);
1136 newnode->duration = ltt_time_zero;
1137 newnode->id_for_episodes = id_for_episodes++;
1138 newnode->episodes = g_array_new(FALSE, FALSE, sizeof(struct process_state *));
1139 g_hash_table_insert(node_cur->children, &componentquark, newnode);
1140
1141 g_array_append_val(all_nodes, newnode);
1142 }
1143 node_cur = newnode;
1144
1145 node_cur->duration = ltt_time_add(node_cur->duration, ltt_time_sub(pstate->time_end, pstate->time_begin));
1146 g_array_append_val(node_cur->episodes, pstate);
1147 }
1148 }
1149
1150 /* print the summary */
1151 print_summary_item(&base_node, -1);
1152
1153 printf("\n");
1154
1155 if(pinfos->next)
1156 pinfos = pinfos->next;
1157 else
1158 break;
1159 }
1160
1161 printf("\n");
1162
1163 printf("Episode list\n");
1164 pinfos = pinfos_first;
1165
1166 /* For all the nodes of the Simple summary tree */
1167 for(i=0; i<all_nodes->len; i++) {
1168 struct summary_tree_node *node = (struct summary_tree_node *)g_array_index(all_nodes, struct summary_tree_node *, i);
1169
1170 /* Sort the episodes from longest to shortest */
1171 g_array_sort(node->episodes, compare_states_length);
1172
1173 printf("\tNode id: <%d>\n", node->id_for_episodes);
1174 /* For each episode of the node */
1175 for(j=0; j<node->episodes->len; j++) {
1176 struct process_state *st = g_array_index(node->episodes, struct process_state *, j);
1177
1178 printf("\t\t");
1179 print_time(st->time_begin);
1180 printf("-");
1181 print_time(st->time_end);
1182 printf(" (%f)\n", 1e-9*ltt_time_to_double(ltt_time_sub(st->time_end,st->time_begin)));
1183 }
1184 }
1185}
1186
1187static void print_simple_summary_pid_range(int pid, LttTime t1, LttTime t2)
1188{
1189 struct process *pinfo;
1190 int i,j;
1191 int id_for_episodes = 0;
1192
1193 /* we save all the nodes here to print the episodes table quickly */
1194 GArray *all_nodes = g_array_new(FALSE, FALSE, sizeof(struct summary_tree_node *));
1195
1196 pinfo = g_hash_table_lookup(process_hash_table, &pid);
1197
1198 {
1199 struct summary_tree_node base_node = { children: NULL, name: "Root" };
1200
8c108c1c
PMF
1201 printf("\tProcess %d [%s]\n", pinfo->pid, g_quark_to_string(pinfo->name));
1202
1203 /* For each state in the process history */
1204 for(i=0; i<pinfo->hlev_history->len; i++) {
1205 struct process_state *pstate = g_array_index(pinfo->hlev_history, struct process_state *, i);
1206 struct summary_tree_node *node_cur = &base_node;
1207 GArray *tree_path_garray;
1208
1209 if(ltt_time_compare(pstate->time_end, t1) < 0)
1210 continue;
1211
1212 if(ltt_time_compare(pstate->time_end, t2) > 0)
1213 break;
1214
1215 /* Modify the path based on private data */
1216 tree_path_garray = g_array_new(FALSE, FALSE, sizeof(char *));
1217 {
1218 int count=0;
1219 char **tree_path_cur2 = hlev_state_infos[pstate->bstate].tree_path;
1220 while(*tree_path_cur2) {
1221 count++;
1222 tree_path_cur2++;
1223 }
1224 g_array_append_vals(tree_path_garray, hlev_state_infos[pstate->bstate].tree_path, count);
1225 }
1226 modify_path_with_private(tree_path_garray, pstate);
1227
1228 /* Walk the path, adding the nodes to the summary */
1229 for(j=0; j<tree_path_garray->len; j++) {
1230 struct summary_tree_node *newnode;
1231 GQuark componentquark;
1232
1233 /* Have a path component we must follow */
1234 if(!node_cur->children) {
1235 /* must create the hash table for the children */
1236 node_cur->children = g_hash_table_new(g_int_hash, g_int_equal);
1237 }
1238
1239 /* try to get the node for the next component */
1240 componentquark = g_quark_from_string(g_array_index(tree_path_garray, char *, j));
1241 newnode = g_hash_table_lookup(node_cur->children, &componentquark);
1242 if(newnode == NULL) {
1243 newnode = g_malloc(sizeof(struct summary_tree_node));
1244 newnode->children = NULL;
1245 newnode->name = g_array_index(tree_path_garray, char *, j);
1246 newnode->duration = ltt_time_zero;
1247 newnode->id_for_episodes = id_for_episodes++;
1248 newnode->episodes = g_array_new(FALSE, FALSE, sizeof(struct process_state *));
1249 g_hash_table_insert(node_cur->children, &componentquark, newnode);
1250
1251 g_array_append_val(all_nodes, newnode);
1252 }
1253 node_cur = newnode;
1254
1255 node_cur->duration = ltt_time_add(node_cur->duration, ltt_time_sub(pstate->time_end, pstate->time_begin));
1256 g_array_append_val(node_cur->episodes, pstate);
1257 }
1258 }
1259
1260 /* print the summary */
1261 print_summary_item(&base_node, -1);
1262
1263 printf("\n");
1264 }
1265
1266 printf("\n");
1267
1268 printf("Episode list\n");
1269
1270 /* For all the nodes of the Simple summary tree */
1271 for(i=0; i<all_nodes->len; i++) {
1272 struct summary_tree_node *node = (struct summary_tree_node *)g_array_index(all_nodes, struct summary_tree_node *, i);
1273
1274 /* Sort the episodes from longest to shortest */
1275 g_array_sort(node->episodes, compare_states_length);
1276
1277 printf("\tNode id: <%d>\n", node->id_for_episodes);
1278 /* For each episode of the node */
1279 for(j=0; j<node->episodes->len; j++) {
1280 struct process_state *st = g_array_index(node->episodes, struct process_state *, j);
1281
1282 printf("\t\t");
1283 print_time(st->time_begin);
1284 printf("-");
1285 print_time(st->time_end);
1286 printf(" (%f)\n", 1e-9*ltt_time_to_double(ltt_time_sub(st->time_end,st->time_begin)));
1287 }
1288 }
1289}
1290
1291static void flush_process_sstacks(void)
1292{
1293 GList *pinfos;
1294
1295 pinfos = g_hash_table_get_values(process_hash_table);
1296 while(pinfos) {
1297 struct process *pinfo = (struct process *)pinfos->data;
1298
1299 sstack_force_flush(pinfo->stack);
1300
1301 pinfos = pinfos->next;
1302 }
1303
1304 g_list_free(pinfos);
1305}
1306
1307struct family_item {
1308 int pid;
1309 LttTime creation;
1310};
1311
1312void print_range_reports(int pid, LttTime t1, LttTime t2)
1313{
1314 GArray *family = g_array_new(FALSE, FALSE, sizeof(struct family_item));
1315 int i;
1316
1317 /* reconstruct the parental sequence */
1318 for(;;) {
1319 struct process *pinfo;
1320 struct family_item fi;
1321 LttTime cur_beg;
1322
1323 pinfo = g_hash_table_lookup(process_hash_table, &pid);
1324 if(pinfo == NULL)
1325 abort();
1326
1327 fi.pid = pid;
1328 cur_beg = g_array_index(pinfo->hlev_history, struct process_state *, 0)->time_begin;
1329 fi.creation = cur_beg;
1330 g_array_append_val(family, fi);
1331
1332 if(ltt_time_compare(cur_beg, t1) == -1) {
1333 /* current pid starts before the interesting time */
1334 break;
1335 }
1336 if(pinfo->parent == -1) {
1337 printf("unable to go back, we don't know the parent of %d\n", fi.pid);
1338 abort();
1339 }
1340 /* else, we go on */
1341 pid = pinfo->parent;
1342
1343 }
1344
1345 printf("Simple summary for range:\n");
1346 for(i=family->len-1; i>=0; i--) {
1347 LttTime iter_t1, iter_t2;
1348 int iter_pid = g_array_index(family, struct family_item, i).pid;
1349
1350 if(i == family->len-1)
1351 iter_t1 = t1;
1352 else
1353 iter_t1 = g_array_index(family, struct family_item, i).creation;
1354
1355 if(i == 0)
1356 iter_t2 = t2;
1357 else
1358 iter_t2 = g_array_index(family, struct family_item, i-1).creation;
1359
c7cb53d7 1360 printf("This section of summary concerns pid %d between ", iter_pid);
8c108c1c
PMF
1361 print_time(iter_t1);
1362 printf(" and ");
1363 print_time(iter_t2);
1364 printf(".\n");
1365 print_simple_summary_pid_range(iter_pid, iter_t1, iter_t2);
1366 }
1367 print_range_critical_path(depanalysis_range_pid, t1, t2);
1368}
1369
1370static gboolean write_traceset_footer(void *hook_data, void *call_data)
1371{
c7cb53d7 1372 g_info("depanalysis traceset footer");
8c108c1c
PMF
1373
1374 /* After processing all the events, we need to flush the sstacks
1375 * because some unfinished states may remain in them. We want them
1376 * event though there are incomplete.
1377 */
1378 flush_process_sstacks();
1379
1380 /* print the reports */
1381 print_simple_summary();
1382 print_process_critical_path_summary();
8c108c1c 1383 if(depanalysis_use_time == 3) {
55cd92ee 1384 printf("depanalysis_use_time = %d\n", depanalysis_use_time);
8c108c1c
PMF
1385 if(depanalysis_range_pid == -1 && depanalysis_range_pid_searching >= 0)
1386 depanalysis_range_pid = depanalysis_range_pid_searching;
1387
1388 if(depanalysis_range_pid >= 0) {
1389 print_range_reports(depanalysis_range_pid, depanalysis_time1, depanalysis_time2);
1390 }
1391 else
1392 printf("range critical path: could not find the end of the range\n");
1393 }
1394
1395 return FALSE;
1396}
1397
8c108c1c
PMF
1398
1399static int write_event_content(void *hook_data, void *call_data)
1400{
8c108c1c
PMF
1401
1402 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1403
1404 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1405
1406 LttEvent *e;
1407
1408 guint cpu = tfs->cpu;
1409 LttvTraceState *ts = (LttvTraceState*)tfc->t_context;
1410 LttvProcessState *process = ts->running_process[cpu];
1411
1412 e = ltt_tracefile_get_event(tfc->tf);
1413
1414 lttv_event_to_string(e, a_string, TRUE, 1, tfs);
1415
1416// if(a_state) {
1417 g_string_append_printf(a_string, " %s ",
1418 g_quark_to_string(process->state->s));
1419// }
1420
1421 g_string_append_printf(a_string,"\n");
1422
1423 fputs(a_string->str, a_file);
1424 return FALSE;
1425}
1426
1427static int field_get_value_int(struct LttEvent *e, struct marker_info *info, GQuark f)
1428{
1429 struct marker_field *marker_field;
1430 int found=0;
1431
1432 for_each_marker_field(marker_field, info) {
1433 if (marker_field->name == f) {
1434 found = 1;
1435 break;
1436 }
1437 }
1438 g_assert(found);
1439 return ltt_event_get_long_unsigned(e, marker_field);
1440}
1441
1442static char *field_get_value_string(struct LttEvent *e, struct marker_info *info, GQuark f)
1443{
1444 struct marker_field *marker_field;
1445 int found=0;
1446
1447 for_each_marker_field(marker_field, info) {
1448 if (marker_field->name == f) {
1449 found = 1;
1450 break;
1451 }
1452 }
1453 g_assert(found);
1454 return ltt_event_get_string(e, marker_field);
1455}
1456
c7cb53d7 1457void process_delayed_stack_action(void *arg, struct sstack_item *item)
8c108c1c 1458{
c7cb53d7 1459 struct process *pinfo = (struct process *)arg;
8c108c1c
PMF
1460 //printf("processing delayed stack action on pid %d at ", pinfo->pid);
1461 //if(((struct process_with_state *) item->data_val)->state.time_begin.tv_nsec == 987799696)
1462 // printf("HERE!!!\n");
1463 //print_time(((struct process_with_state *) item->data_val)->state.time_begin);
1464 //printf("\n");
1465 //printf("stack before:\n");
1466 //print_stack(pinfo->stack);
1467
1468 if(item->data_type == SSTACK_TYPE_PUSH) {
1469 struct process_with_state *pwstate = item->data_val;
1470 //printf("pushing\n");
1471 old_process_push_llev_state(pinfo, &pwstate->state);
1472 update_hlev_state(pinfo, pwstate->state.time_begin);
1473 }
1474 else if(item->data_type == SSTACK_TYPE_POP) {
1475 struct process_with_state *pwstate = item->data_val;
1476 //printf("popping\n");
1477 old_process_pop_llev_state(pinfo, &pwstate->state);
1478 update_hlev_state(pinfo, pwstate->state.time_end);
1479 }
1480 else if(item->data_type == SSTACK_TYPE_EVENT) {
1481 struct sstack_event *se = item->data_val;
1482 if(se->event_type == HLEV_EVENT_TRY_WAKEUP) {
1483 /* FIXME: should change hlev event from BLOCKED to INTERRUPTED CPU when receiving TRY_WAKEUP */
1484 struct try_wakeup_event *twe = se->private;
1485
1486 /* FIXME: maybe do some more rigorous checking here */
1487 if(pinfo->hlev_state->bstate == HLEV_BLOCKED) {
1488 struct hlev_state_info_blocked *hlev_blocked_private = pinfo->hlev_state->private;
1489
1490 hlev_blocked_private->pid_exit = twe->pid;
1491 hlev_blocked_private->time_woken = twe->time;
1492 hlev_blocked_private->llev_state_exit = oldstyle_stack_to_garray(twe->waker->llev_state_stack, twe->waker->stack_current);
1493 //printf("set a non null exit stack on %p, and stack size is %d\n", hlev_blocked_private, hlev_blocked_private->llev_state_exit->len);
1494
1495 /*
1496 if(p->stack_current >= 0 && p->llev_state_stack[p->stack_current]->bstate == LLEV_PREEMPTED) {
1497 old_process_pop_llev_state(pinfo, p->llev_state_stack[p->stack_current]);
1498 update_hlev_state(pinfo
1499 old_process_push_llev_state
1500 }*/
1501
1502 }
1503 }
1504 }
1505
1506 //printf("stack after:\n");
1507 //print_stack(pinfo->stack);
1508}
1509
1510static struct process *get_or_init_process_info(struct LttEvent *e, GQuark name, int pid, int *new)
1511{
c7cb53d7
YB
1512 //gconstpointer val;
1513 gpointer val;
8c108c1c
PMF
1514
1515 val = g_hash_table_lookup(process_hash_table, &pid);
1516 if(val == NULL) {
1517 struct process *pinfo;
1518 int i;
1519
1520 /* Initialize new pinfo for newly discovered process */
1521 pinfo = g_malloc(sizeof(struct process));
1522 pinfo->pid = pid;
1523 pinfo->parent = -1; /* unknown parent */
1524 pinfo->hlev_history = g_array_new(FALSE, FALSE, sizeof(struct process_state *));
1525 pinfo->stack = sstack_new();
1526 pinfo->stack_current=-1;
1527 pinfo->stack->process_func = process_delayed_stack_action;
1528 pinfo->stack->process_func_arg = pinfo;
1529 for(i=0; i<PROCESS_STATE_STACK_SIZE; i++) {
1530 pinfo->llev_state_stack[i] = g_malloc(sizeof(struct process_state));
1531 }
1532
1533 pinfo->hlev_state = g_malloc(sizeof(struct process_state));
1534 pinfo->hlev_state->bstate = HLEV_UNKNOWN;
1535 pinfo->hlev_state->time_begin = e->event_time;
1536 pinfo->hlev_state->private = NULL;
1537
1538 /* set the name */
1539 pinfo->name = name;
1540
1541 g_hash_table_insert(process_hash_table, &pinfo->pid, pinfo);
1542 if(new)
1543 *new = 1;
1544 return pinfo;
1545 }
1546 else {
1547 if(new)
1548 *new = 0;
1549 return val;
1550
1551 }
1552}
1553
1554static int differentiate_swappers(int pid, LttEvent *e)
1555{
1556 if(pid == 0)
1557 return pid+e->tracefile->cpu_num+2000000;
1558 else
1559 return pid;
1560}
1561
1562static int process_event(void *hook_data, void *call_data)
1563{
1564 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1565 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1566 LttEvent *e;
1567 struct marker_info *info;
1568
1569 /* Extract data from event structures and state */
1570 guint cpu = tfs->cpu;
1571 LttvTraceState *ts = (LttvTraceState*)tfc->t_context;
1572 LttvProcessState *process = ts->running_process[cpu];
8c108c1c
PMF
1573 struct process *pinfo;
1574
1575 e = ltt_tracefile_get_event(tfs->parent.tf);
1576
1577 info = marker_get_info_from_id(tfc->tf->mdata, e->event_id);
1578
1579 //if(depanalysis_use_time && (ltt_time_compare(e->timestamp, arg_t1) == -1 || ltt_time_compare(e->timestamp, arg_t2) == 1)) {
1580 // return;
1581 //}
1582 /* Set the pid for the dependency analysis at each event, until we are passed the range. */
1583 if(depanalysis_use_time == 3) {
1584 if(ltt_time_compare(e->event_time, depanalysis_time2) <= 0) {
1585 depanalysis_range_pid = process->pid;
1586 }
1587 else {
1588 /* Should stop processing and print results */
1589 }
1590 }
1591
1592 /* Code to limit the event count */
1593 if(depanalysis_event_limit > 0) {
1594 depanalysis_event_limit--;
1595 }
1596 else if(depanalysis_event_limit == 0) {
1597 write_traceset_footer(hook_data, call_data);
1598 printf("exit due to event limit reached\n");
1599 exit(0);
1600 }
1601
1602 /* write event like textDump for now, for debugging purposes */
1603 //write_event_content(hook_data, call_data);
1604
1605 if(tfc->tf->name == LTT_CHANNEL_SYSCALL_STATE && info->name == LTT_EVENT_SYS_CALL_TABLE) {
1606 GQuark q;
1607 int *pint = g_malloc(sizeof(int));
1608
1609 *pint = field_get_value_int(e, info, LTT_FIELD_ID);
1610 q = g_quark_from_string(field_get_value_string(e, info, LTT_FIELD_SYMBOL));
c7cb53d7 1611 g_hash_table_insert(syscall_table, pint, (gpointer)(unsigned long)q);
8c108c1c
PMF
1612 }
1613 else if(tfc->tf->name == LTT_CHANNEL_IRQ_STATE && info->name == LTT_EVENT_LIST_INTERRUPT) {
1614 GQuark q;
1615 int *pint = g_malloc(sizeof(int));
1616
1617 *pint = field_get_value_int(e, info, LTT_FIELD_IRQ_ID);
1618 q = g_quark_from_string(field_get_value_string(e, info, LTT_FIELD_ACTION));
c7cb53d7 1619 g_hash_table_insert(irq_table, pint, (gpointer)(unsigned long)q);
8c108c1c
PMF
1620 }
1621 else if(tfc->tf->name == LTT_CHANNEL_SOFTIRQ_STATE && info->name == LTT_EVENT_SOFTIRQ_VEC) {
1622 GQuark q;
1623 int *pint = g_malloc(sizeof(int));
1624
1625 *pint = field_get_value_int(e, info, LTT_FIELD_ID);
1626 q = g_quark_from_string(field_get_value_string(e, info, LTT_FIELD_SYMBOL));
c7cb53d7 1627 g_hash_table_insert(softirq_table, pint, (gpointer)(unsigned long)q);
8c108c1c
PMF
1628 }
1629
1630
1631 /* Only look at events after the statedump is finished.
1632 * Before that, the pids in the LttvProcessState are not reliable
1633 */
1634 if(statedump_finished == 0) {
1635 if(tfc->tf->name == LTT_CHANNEL_GLOBAL_STATE && info->name == LTT_EVENT_STATEDUMP_END)
1636 statedump_finished = 1;
1637 else
1638 return FALSE;
1639
1640 }
1641
1642 pinfo = get_or_init_process_info(e, process->name, differentiate_swappers(process->pid, e), NULL);
1643
1644 /* the state machine
1645 * Process the event in the context of each process
1646 */
1647
1648 if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_IRQ_ENTRY) {
1649 struct process *event_process_info = pinfo;
1650 struct sstack_item *item;
1651
1652 item = prepare_push_item(event_process_info, LLEV_IRQ, e->event_time);
1653 ((struct llev_state_info_irq *) item_private(item))->irq = field_get_value_int(e, info, LTT_FIELD_IRQ_ID);
1654 commit_item(event_process_info, item);
1655 }
1656 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_IRQ_EXIT) {
1657 struct process *event_process_info = pinfo;
1658
1659 prepare_pop_item_commit(event_process_info, LLEV_IRQ, e->event_time);
1660 }
1661 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_SCHED_SCHEDULE) {
1662 int next_pid = field_get_value_int(e, info, LTT_FIELD_NEXT_PID);
1663 int prev_pid = field_get_value_int(e, info, LTT_FIELD_PREV_PID);
1664 if(next_pid != 0) {
1665 struct process *event_process_info = get_or_init_process_info(e, process->name, differentiate_swappers(next_pid, e), NULL);
1666 prepare_pop_item_commit(event_process_info, LLEV_PREEMPTED, e->event_time);
1667 }
1668 if(prev_pid != 0) {
1669 struct sstack_item *item;
1670 struct process *event_process_info = get_or_init_process_info(e, process->name, differentiate_swappers(prev_pid, e), NULL);
1671
1672 item = prepare_push_item(event_process_info, LLEV_PREEMPTED, e->event_time);
1673 ((struct llev_state_info_preempted *) item_private(item))->prev_state = field_get_value_int(e, info, LTT_FIELD_PREV_STATE);
1674 commit_item(event_process_info, item);
1675 }
1676 }
1677 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_TRAP_ENTRY) {
1678 struct process *event_process_info = pinfo;
1679 struct sstack_item *item;
1680
1681 item = prepare_push_item(event_process_info, LLEV_TRAP, e->event_time);
1682 commit_item(event_process_info, item);
1683 }
1684 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_TRAP_EXIT) {
1685 struct process *event_process_info = pinfo;
1686
1687 prepare_pop_item_commit(event_process_info, LLEV_TRAP, e->event_time);
1688 }
1689 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_SYSCALL_ENTRY) {
1690 struct process *event_process_info = pinfo;
1691 struct sstack_item *item;
1692
1693 item = prepare_push_item(event_process_info, LLEV_SYSCALL, e->event_time);
1694 ((struct llev_state_info_syscall *) item_private(item))->syscall_id = field_get_value_int(e, info, LTT_FIELD_SYSCALL_ID);
1695 ((struct llev_state_info_syscall *) item_private(item))->substate = LLEV_SYSCALL__UNDEFINED;
1696 commit_item(event_process_info, item);
1697 }
1698 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_SYSCALL_EXIT) {
1699 struct process *event_process_info = pinfo;
1700
1701 prepare_pop_item_commit(event_process_info, LLEV_SYSCALL, e->event_time);
1702 }
1703 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_SOFT_IRQ_ENTRY) {
1704 struct process *event_process_info = pinfo;
1705 struct sstack_item *item;
1706
1707 item = prepare_push_item(event_process_info, LLEV_SOFTIRQ, e->event_time);
1708 ((struct llev_state_info_softirq *) item_private(item))->softirq = field_get_value_int(e, info, LTT_FIELD_SOFT_IRQ_ID);
1709 commit_item(event_process_info, item);
1710 }
1711 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_SOFT_IRQ_EXIT) {
1712 struct process *event_process_info = pinfo;
1713
1714 prepare_pop_item_commit(event_process_info, LLEV_SOFTIRQ, e->event_time);
1715 }
1716 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_PROCESS_FORK) {
1717 int pid = differentiate_swappers(field_get_value_int(e, info, LTT_FIELD_CHILD_PID), e);
c7cb53d7 1718 struct process *event_process_info = get_or_init_process_info(e, process->name, pid, NULL);
8c108c1c
PMF
1719 struct sstack_item *item;
1720
1721 event_process_info->parent = process->pid;
1722 //printf("At ");
1723 //print_time(e->event_time);
1724 //printf(", fork in process %d (%s), creating child %d\n", differentiate_swappers(process->pid, e), g_quark_to_string(process->name), pid);
1725
1726 item = prepare_push_item(event_process_info, LLEV_RUNNING, e->event_time);
1727 commit_item(event_process_info, item);
1728 item = prepare_push_item(event_process_info, LLEV_SYSCALL, e->event_time);
1729 /* FIXME: this sets fork() as syscall, it's pretty inelegant */
1730 ((struct llev_state_info_syscall *) item_private(item))->syscall_id = 57;
1731 ((struct llev_state_info_syscall *) item_private(item))->substate = LLEV_SYSCALL__UNDEFINED;
1732 commit_item(event_process_info, item);
1733
1734 item = prepare_push_item(event_process_info, LLEV_PREEMPTED, e->event_time);
1735 /* Consider fork as BLOCKED */
1736 ((struct llev_state_info_preempted *) item_private(item))->prev_state = 1;
1737 commit_item(event_process_info, item);
1738
1739 //printf("process %d now has a stack of height %d\n", differentiate_swappers(process->pid, e), get_or_init_process_info(e, process->name, differentiate_swappers(process->pid, cpu), NULL)->stack_current-1);
1740
1741 }
1742 else if(tfc->tf->name == LTT_CHANNEL_FS && info->name == LTT_EVENT_EXEC) {
1743 struct process *event_process_info = pinfo;
1744
1745 guint cpu = tfs->cpu;
1746 LttvProcessState *process_state = ts->running_process[cpu];
1747 event_process_info->name = process_state->name;
1748 }
1749 else if(tfc->tf->name == LTT_CHANNEL_FS && info->name == LTT_EVENT_OPEN) {
1750 struct process_state *pstate = process_find_state(pinfo, LLEV_SYSCALL);
1751 struct llev_state_info_syscall *llev_syscall_private;
1752 struct llev_state_info_syscall__open *llev_syscall_open_private;
1753
1754 /* TODO: this is too easy */
1755 if(pstate == NULL)
1756 goto next_iter;
1757
1758 llev_syscall_private = (struct llev_state_info_syscall *)pstate->private;
1759
1760 //printf("depanalysis: found an open with state %d in pid %d\n", pstate->bstate, process->pid);
1761 if(pstate->bstate == LLEV_UNKNOWN)
1762 goto next_iter;
1763
1764 g_assert(pstate->bstate == LLEV_SYSCALL);
1765 g_assert(llev_syscall_private->substate == LLEV_SYSCALL__UNDEFINED);
1766
1767 llev_syscall_private->substate = LLEV_SYSCALL__OPEN;
1768 //printf("setting substate LLEV_SYSCALL__OPEN on syscall_private %p\n", llev_syscall_private);
1769 llev_syscall_private->private = g_malloc(sizeof(struct llev_state_info_syscall__open));
1770 llev_syscall_open_private = llev_syscall_private->private;
1771
1772 llev_syscall_open_private->filename = g_quark_from_string(field_get_value_string(e, info, LTT_FIELD_FILENAME));
1773
1774 }
1775 else if(tfc->tf->name == LTT_CHANNEL_FS && info->name == LTT_EVENT_READ) {
1776 struct process_state *pstate = process_find_state(pinfo, LLEV_SYSCALL);
1777 struct llev_state_info_syscall *llev_syscall_private;
1778 struct llev_state_info_syscall__read *llev_syscall_read_private;
1779 GQuark pfileq;
1780 int fd;
1781
1782 /* TODO: this is too easy */
1783 if(pstate == NULL)
1784 goto next_iter;
1785
1786 llev_syscall_private = (struct llev_state_info_syscall *)pstate->private;
1787
1788 //printf("depanalysis: found an read with state %d in pid %d\n", pstate->bstate, process->pid);
1789 if(pstate->bstate == LLEV_UNKNOWN)
1790 goto next_iter;
1791
1792 g_assert(pstate->bstate == LLEV_SYSCALL);
1793 g_assert(llev_syscall_private->substate == LLEV_SYSCALL__UNDEFINED);
1794
1795 llev_syscall_private->substate = LLEV_SYSCALL__READ;
1796 //printf("setting substate LLEV_SYSCALL__READ on syscall_private %p\n", llev_syscall_private);
1797 llev_syscall_private->private = g_malloc(sizeof(struct llev_state_info_syscall__read));
1798 llev_syscall_read_private = llev_syscall_private->private;
1799
1800 fd = field_get_value_int(e, info, LTT_FIELD_FD);
c7cb53d7 1801 pfileq = (GQuark)(unsigned long)g_hash_table_lookup(process->fds, &fd);
8c108c1c
PMF
1802 if(pfileq) {
1803 llev_syscall_read_private->filename = pfileq;
1804 }
1805 else {
1806 char *tmp;
1807 asprintf(&tmp, "Unknown filename, fd %d", fd);
1808 llev_syscall_read_private->filename = g_quark_from_string(tmp);
1809 free(tmp);
1810 }
1811 }
1812 else if(tfc->tf->name == LTT_CHANNEL_FS && info->name == LTT_EVENT_POLL_EVENT) {
1813 struct process_state *pstate = process_find_state(pinfo, LLEV_SYSCALL);
1814 struct llev_state_info_syscall *llev_syscall_private;
1815 struct llev_state_info_syscall__poll *llev_syscall_poll_private;
1816 GQuark pfileq;
1817 int fd;
1818
1819 /* TODO: this is too easy */
1820 if(pstate == NULL)
1821 goto next_iter;
1822
1823 llev_syscall_private = (struct llev_state_info_syscall *)pstate->private;
1824
1825 //printf("depanalysis: found an poll with state %d in pid %d\n", pstate->bstate, process->pid);
1826 if(pstate->bstate == LLEV_UNKNOWN)
1827 goto next_iter;
1828
1829 /* poll doesn't have a single event that gives the syscall args. instead, there can be an arbitrary
1830 * number of fs_pollfd or fd_poll_event events
1831 * We use the fd_poll_event event, which occurs for each fd that had activity causing a return of the poll()
1832 * For now we only use the first.
1833 * We should do something about this. FIXME
1834 */
1835 if(llev_syscall_private->substate == LLEV_SYSCALL__POLL)
1836 goto next_iter;
1837
1838 g_assert(pstate->bstate == LLEV_SYSCALL);
1839 g_assert(llev_syscall_private->substate == LLEV_SYSCALL__UNDEFINED);
1840
1841 llev_syscall_private->substate = LLEV_SYSCALL__POLL;
1842 //printf("setting substate LLEV_SYSCALL__POLL on syscall_private %p\n", llev_syscall_private);
1843 llev_syscall_private->private = g_malloc(sizeof(struct llev_state_info_syscall__poll));
1844 llev_syscall_poll_private = llev_syscall_private->private;
1845
1846 fd = field_get_value_int(e, info, LTT_FIELD_FD);
c7cb53d7 1847 pfileq = (GQuark)(unsigned long)g_hash_table_lookup(process->fds, &fd);
8c108c1c
PMF
1848 if(pfileq) {
1849 llev_syscall_poll_private->filename = pfileq;
1850 }
1851 else {
1852 char *tmp;
1853 asprintf(&tmp, "Unknown filename, fd %d", fd);
1854 llev_syscall_poll_private->filename = g_quark_from_string(tmp);
1855 free(tmp);
1856 }
1857 }
1858 else if(tfc->tf->name == LTT_CHANNEL_KERNEL && info->name == LTT_EVENT_SCHED_TRY_WAKEUP) {
1859 struct sstack_event *se = g_malloc(sizeof(struct sstack_event));
1860 struct try_wakeup_event *twe = g_malloc(sizeof(struct try_wakeup_event));
1861 struct sstack_item *item = sstack_item_new_event();
1862 int target = field_get_value_int(e, info, LTT_FIELD_PID);
1863 struct process *target_pinfo;
1864 int result;
1865
1866 se->event_type = HLEV_EVENT_TRY_WAKEUP;
1867 se->private = twe;
1868 //printf("pushing try wake up event in context of %d\n", pinfo->pid);
1869
1870 twe->pid = differentiate_swappers(process->pid, e);
1871 twe->time = e->event_time;
1872 twe->waker = pinfo;
1873
1874 /* FIXME: the target could not yet have an entry in the hash table, we would then lose data */
1875 target_pinfo = g_hash_table_lookup(process_hash_table, &target);
1876 if(!target_pinfo)
1877 goto next_iter;
1878
1879 item->data_val = se;
b1d18041 1880 item->delete_data_val = (void (*)(void *))delete_data_val;
8c108c1c
PMF
1881
1882 sstack_add_item(target_pinfo->stack, item);
1883
1884 /* Now pop the blocked schedule out of the target */
1885 result = try_pop_blocked_llev_preempted(target_pinfo, e->event_time);
1886
1887 if(result) {
1888 struct sstack_item *item;
1889 struct process *event_process_info = target_pinfo;
1890
1891 item = prepare_push_item(event_process_info, LLEV_PREEMPTED, e->event_time);
1892 ((struct llev_state_info_preempted *) item_private(item))->prev_state = -1; /* special value meaning post-block sched out */
1893 commit_item(event_process_info, item);
1894 }
1895
1896 }
1897
1898 next_iter:
8c108c1c
PMF
1899 return FALSE;
1900}
1901
1902void print_sstack_private(struct sstack_item *item)
1903{
1904 struct process_with_state *pwstate = item->data_val;
1905
1906 if(pwstate && item->data_type == SSTACK_TYPE_PUSH)
1907 printf("\tstate: %s", llev_state_infos[pwstate->state.bstate].name);
1908
1909 printf(" (");
1910 print_time(pwstate->state.time_begin);
1911 printf("-");
1912 print_time(pwstate->state.time_end);
1913 printf("\n");
1914
1915}
1916
1917static LttTime ltt_time_from_string(const char *str)
1918{
1919 LttTime retval;
1920
1921 char *decdot = strchr(str, '.');
1922
1923 if(decdot) {
1924 *decdot = '\0';
1925 retval.tv_nsec = atol(decdot+1);
1926 }
1927 else {
1928 retval.tv_nsec = 0;
1929 }
1930
1931 retval.tv_sec = atol(str);
1932
1933 return retval;
1934}
1935
1936static void arg_t1(void *hook_data)
1937{
1938 printf("arg_t1\n");
1939 depanalysis_use_time |= 1;
1940 depanalysis_time1 = ltt_time_from_string(arg_t1_str);
1941}
1942
1943static void arg_t2(void *hook_data)
1944{
1945 depanalysis_use_time |= 2;
1946 depanalysis_time2 = ltt_time_from_string(arg_t2_str);
1947}
1948
1949static void arg_pid(void *hook_data)
1950{
1951}
1952
1953static void arg_limit(void *hook_data)
1954{
1955}
1956
55cd92ee
MD
1957static void arg_sum(void *hook_data)
1958{
1959}
1960
8c108c1c
PMF
1961static void init()
1962{
1963 gboolean result;
1964
1965 print_sstack_item_data = print_sstack_private;
1966
1967 LttvAttributeValue value;
1968
1969 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
1970
1971 a_file = stdout;
1972
1973 lttv_option_add("dep-time-start", 0, "dependency analysis time of analysis start", "time",
1974 LTTV_OPT_STRING, &arg_t1_str, arg_t1, NULL);
1975 lttv_option_add("dep-time-end", 0, "dependency analysis time of analysis end", "time",
1976 LTTV_OPT_STRING, &arg_t2_str, arg_t2, NULL);
1977 lttv_option_add("dep-pid", 0, "dependency analysis pid", "pid",
1978 LTTV_OPT_INT, &depanalysis_range_pid_searching, arg_pid, NULL);
1979 lttv_option_add("limit-events", 0, "dependency limit event count", "count",
1980 LTTV_OPT_INT, &depanalysis_event_limit, arg_limit, NULL);
55cd92ee
MD
1981 lttv_option_add("print-summary", 0, "print simple summary", "sum",
1982 LTTV_OPT_INT, &a_print_simple_summary, arg_sum, NULL);
8c108c1c
PMF
1983
1984 process_hash_table = g_hash_table_new(g_int_hash, g_int_equal);
1985 syscall_table = g_hash_table_new(g_int_hash, g_int_equal);
1986 irq_table = g_hash_table_new(g_int_hash, g_int_equal);
1987 softirq_table = g_hash_table_new(g_int_hash, g_int_equal);
1988
1989 a_string = g_string_new("");
1990
1991 result = lttv_iattribute_find_by_path(attributes, "hooks/event",
1992 LTTV_POINTER, &value);
1993 g_assert(result);
1994 event_hook = *(value.v_pointer);
1995 g_assert(event_hook);
1996 lttv_hooks_add(event_hook, process_event, NULL, LTTV_PRIO_DEFAULT);
1997
8c108c1c
PMF
1998 result = lttv_iattribute_find_by_path(attributes, "hooks/traceset/before",
1999 LTTV_POINTER, &value);
2000 g_assert(result);
2001 before_traceset = *(value.v_pointer);
2002 g_assert(before_traceset);
2003 lttv_hooks_add(before_traceset, write_traceset_header, NULL,
2004 LTTV_PRIO_DEFAULT);
2005
2006 result = lttv_iattribute_find_by_path(attributes, "hooks/traceset/after",
2007 LTTV_POINTER, &value);
2008 g_assert(result);
2009 after_traceset = *(value.v_pointer);
2010 g_assert(after_traceset);
2011 lttv_hooks_add(after_traceset, write_traceset_footer, NULL,
2012 LTTV_PRIO_DEFAULT);
2013}
2014
2015static void destroy()
2016{
2017 lttv_option_remove("dep-time-start");
2018 lttv_option_remove("dep-time-end");
2019 lttv_option_remove("dep-pid");
2020 lttv_option_remove("limit-events");
55cd92ee 2021 lttv_option_remove("print-summary");
8c108c1c
PMF
2022
2023 g_hash_table_destroy(process_hash_table);
2024 g_hash_table_destroy(syscall_table);
2025 g_hash_table_destroy(irq_table);
2026 g_hash_table_destroy(softirq_table);
2027
2028 g_string_free(a_string, TRUE);
2029
2030 lttv_hooks_remove_data(event_hook, write_event_content, NULL);
c7cb53d7 2031
8c108c1c
PMF
2032 lttv_hooks_remove_data(before_traceset, write_traceset_header, NULL);
2033 lttv_hooks_remove_data(after_traceset, write_traceset_footer, NULL);
2034}
2035
2036LTTV_MODULE("depanalysis", "Dependency analysis test", \
2037 "Produce a dependency analysis of a trace", \
2038 init, destroy, "stats", "batchAnalysis", "option", "print")
2039
This page took 0.113697 seconds and 4 git commands to generate.