1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <[email protected]>
4 *
5 */
6
7 /** FIXME: Convert numbers based on machine and file */
8 #define _LARGEFILE64_SOURCE
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #ifndef NO_AUDIT
13 #include <libaudit.h>
14 #endif
15 #include "trace-local.h"
16 #include "trace-hash.h"
17 #include "trace-hash-local.h"
18 #include "list.h"
19
20 #include <linux/time64.h>
21
22 #ifdef WARN_NO_AUDIT
23 # warning "lib audit not found, using raw syscalls " \
24 "(install audit-libs-devel(for fedora) or libaudit-dev(for debian/ubuntu) and try again)"
25 #endif
26
27 #define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWP"
28 #define TASK_STATE_MAX 1024
29
30 #define task_from_item(item) container_of(item, struct task_data, hash)
31 #define start_from_item(item) container_of(item, struct start_data, hash)
32 #define event_from_item(item) container_of(item, struct event_hash, hash)
33 #define stack_from_item(item) container_of(item, struct stack_data, hash)
34 #define group_from_item(item) container_of(item, struct group_data, hash)
35 #define event_data_from_item(item) container_of(item, struct event_data, hash)
36
nsecs_per_sec(unsigned long long ts)37 static unsigned long long nsecs_per_sec(unsigned long long ts)
38 {
39 return ts / NSEC_PER_SEC;
40 }
41
mod_to_usec(unsigned long long ts)42 static unsigned long long mod_to_usec(unsigned long long ts)
43 {
44 return ((ts % NSEC_PER_SEC) + NSEC_PER_USEC / 2) / NSEC_PER_USEC;
45 }
46
47 struct handle_data;
48 struct event_hash;
49 struct event_data;
50
51 typedef void (*event_data_print)(struct trace_seq *s, struct event_hash *hash);
52 typedef int (*handle_event_func)(struct handle_data *h, unsigned long long pid,
53 struct event_data *data,
54 struct tep_record *record, int cpu);
55
56 enum event_data_type {
57 EVENT_TYPE_UNDEFINED,
58 EVENT_TYPE_STACK,
59 EVENT_TYPE_SCHED_SWITCH,
60 EVENT_TYPE_WAKEUP,
61 EVENT_TYPE_FUNC,
62 EVENT_TYPE_SYSCALL,
63 EVENT_TYPE_IRQ,
64 EVENT_TYPE_SOFTIRQ,
65 EVENT_TYPE_SOFTIRQ_RAISE,
66 EVENT_TYPE_PROCESS_EXEC,
67 EVENT_TYPE_USER_MATE,
68 };
69
70 struct event_data {
71 struct trace_hash_item hash;
72 int id;
73 int trace;
74 struct tep_event *event;
75
76 struct event_data *end;
77 struct event_data *start;
78
79 struct tep_format_field *pid_field;
80 struct tep_format_field *start_match_field; /* match with start */
81 struct tep_format_field *end_match_field; /* match with end */
82 struct tep_format_field *data_field; /* optional */
83
84 event_data_print print_func;
85 handle_event_func handle_event;
86 void *private;
87 int migrate; /* start/end pairs can migrate cpus */
88 int global; /* use global tasks */
89 enum event_data_type type;
90 };
91
92 struct stack_data {
93 struct trace_hash_item hash;
94 unsigned long long count;
95 unsigned long long time;
96 unsigned long long time_min;
97 unsigned long long ts_min;
98 unsigned long long time_max;
99 unsigned long long ts_max;
100 unsigned long long time_avg;
101 unsigned long size;
102 char caller[];
103 };
104
105 struct stack_holder {
106 unsigned long size;
107 void *caller;
108 struct tep_record *record;
109 };
110
111 struct start_data {
112 struct trace_hash_item hash;
113 struct event_data *event_data;
114 struct list_head list;
115 struct task_data *task;
116 unsigned long long timestamp;
117 unsigned long long search_val;
118 unsigned long long val;
119 int cpu;
120
121 struct stack_holder stack;
122 };
123
124 struct event_hash {
125 struct trace_hash_item hash;
126 struct event_data *event_data;
127 unsigned long long search_val;
128 unsigned long long val;
129 unsigned long long count;
130 unsigned long long time_total;
131 unsigned long long time_avg;
132 unsigned long long time_max;
133 unsigned long long ts_max;
134 unsigned long long time_min;
135 unsigned long long ts_min;
136 unsigned long long time_std;
137 unsigned long long last_time;
138
139 struct trace_hash stacks;
140 };
141
142 struct group_data {
143 struct trace_hash_item hash;
144 char *comm;
145 struct trace_hash event_hash;
146 };
147
148 struct task_data {
149 struct trace_hash_item hash;
150 int pid;
151 int sleeping;
152
153 char *comm;
154
155 struct trace_hash start_hash;
156 struct trace_hash event_hash;
157
158 struct task_data *proxy;
159 struct start_data *last_start;
160 struct event_hash *last_event;
161 struct tep_record *last_stack;
162 struct handle_data *handle;
163 struct group_data *group;
164 };
165
166 struct cpu_info {
167 int current;
168 };
169
170 struct sched_switch_data {
171 struct tep_format_field *prev_state;
172 int match_state;
173 };
174
175 struct handle_data {
176 struct handle_data *next;
177 struct tracecmd_input *handle;
178 struct tep_handle *pevent;
179
180 struct trace_hash events;
181 struct trace_hash group_hash;
182
183 struct cpu_info **cpu_data;
184
185 struct tep_format_field *common_pid;
186 struct tep_format_field *wakeup_comm;
187 struct tep_format_field *switch_prev_comm;
188 struct tep_format_field *switch_next_comm;
189
190 struct sched_switch_data sched_switch_blocked;
191 struct sched_switch_data sched_switch_preempt;
192
193 struct trace_hash task_hash;
194 struct list_head *cpu_starts;
195 struct list_head migrate_starts;
196
197 struct task_data *global_task;
198 struct task_data *global_percpu_tasks;
199
200 int cpus;
201 };
202
203 static struct handle_data *handles;
204 static struct event_data *stacktrace_event;
205 static bool merge_like_comms = false;
206
trace_profile_set_merge_like_comms(void)207 void trace_profile_set_merge_like_comms(void)
208 {
209 merge_like_comms = true;
210 }
211
212 static struct start_data *
add_start(struct task_data * task,struct event_data * event_data,struct tep_record * record,unsigned long long search_val,unsigned long long val)213 add_start(struct task_data *task,
214 struct event_data *event_data, struct tep_record *record,
215 unsigned long long search_val, unsigned long long val)
216 {
217 struct start_data *start;
218
219 start = malloc(sizeof(*start));
220 if (!start)
221 return NULL;
222 memset(start, 0, sizeof(*start));
223 start->hash.key = trace_hash(search_val);
224 start->search_val = search_val;
225 start->val = val;
226 start->timestamp = record->ts;
227 start->event_data = event_data;
228 start->cpu = record->cpu;
229 start->task = task;
230 trace_hash_add(&task->start_hash, &start->hash);
231 if (event_data->migrate)
232 list_add(&start->list, &task->handle->migrate_starts);
233 else
234 list_add(&start->list, &task->handle->cpu_starts[record->cpu]);
235 return start;
236 }
237
238 struct event_data_match {
239 struct event_data *event_data;
240 unsigned long long search_val;
241 unsigned long long val;
242 };
243
match_start(struct trace_hash_item * item,void * data)244 static int match_start(struct trace_hash_item *item, void *data)
245 {
246 struct start_data *start = start_from_item(item);
247 struct event_data_match *edata = data;
248
249 return start->event_data == edata->event_data &&
250 start->search_val == edata->search_val;
251 }
252
match_event(struct trace_hash_item * item,void * data)253 static int match_event(struct trace_hash_item *item, void *data)
254 {
255 struct event_data_match *edata = data;
256 struct event_hash *event = event_from_item(item);
257
258 return event->event_data == edata->event_data &&
259 event->search_val == edata->search_val &&
260 event->val == edata->val;
261 }
262
263 static struct event_hash *
find_event_hash(struct task_data * task,struct event_data_match * edata)264 find_event_hash(struct task_data *task, struct event_data_match *edata)
265 {
266 struct event_hash *event_hash;
267 struct trace_hash_item *item;
268 unsigned long long key;
269
270 key = (unsigned long)edata->event_data +
271 (unsigned long)edata->search_val +
272 (unsigned long)edata->val;
273 key = trace_hash(key);
274 item = trace_hash_find(&task->event_hash, key, match_event, edata);
275 if (item)
276 return event_from_item(item);
277
278 event_hash = malloc(sizeof(*event_hash));
279 if (!event_hash)
280 return NULL;
281 memset(event_hash, 0, sizeof(*event_hash));
282
283 event_hash->event_data = edata->event_data;
284 event_hash->search_val = edata->search_val;
285 event_hash->val = edata->val;
286 event_hash->hash.key = key;
287 trace_hash_init(&event_hash->stacks, 32);
288
289 trace_hash_add(&task->event_hash, &event_hash->hash);
290
291 return event_hash;
292 }
293
294 static struct event_hash *
find_start_event_hash(struct task_data * task,struct event_data * event_data,struct start_data * start)295 find_start_event_hash(struct task_data *task, struct event_data *event_data,
296 struct start_data *start)
297 {
298 struct event_data_match edata;
299
300 edata.event_data = event_data;
301 edata.search_val = start->search_val;
302 edata.val = start->val;
303
304 return find_event_hash(task, &edata);
305 }
306
307 static struct start_data *
find_start(struct task_data * task,struct event_data * event_data,unsigned long long search_val)308 find_start(struct task_data *task, struct event_data *event_data,
309 unsigned long long search_val)
310 {
311 unsigned long long key = trace_hash(search_val);
312 struct event_data_match edata;
313 void *data = &edata;
314 struct trace_hash_item *item;
315 struct start_data *start;
316
317 edata.event_data = event_data;
318 edata.search_val = search_val;
319
320 item = trace_hash_find(&task->start_hash, key, match_start, data);
321 if (!item)
322 return NULL;
323
324 start = start_from_item(item);
325 return start;
326 }
327
328 struct stack_match {
329 void *caller;
330 unsigned long size;
331 };
332
match_stack(struct trace_hash_item * item,void * data)333 static int match_stack(struct trace_hash_item *item, void *data)
334 {
335 struct stack_data *stack = stack_from_item(item);
336 struct stack_match *match = data;
337
338 if (match->size != stack->size)
339 return 0;
340
341 return memcmp(stack->caller, match->caller, stack->size) == 0;
342 }
343
344
add_event_stack(struct event_hash * event_hash,void * caller,unsigned long size,unsigned long long time,unsigned long long ts)345 static void add_event_stack(struct event_hash *event_hash,
346 void *caller, unsigned long size,
347 unsigned long long time, unsigned long long ts)
348 {
349 unsigned long long key;
350 struct stack_data *stack;
351 struct stack_match match;
352 struct trace_hash_item *item;
353 int i;
354
355 match.caller = caller;
356 match.size = size;
357
358 if (size < sizeof(int))
359 die("Stack size of less than sizeof(int)??");
360
361 for (key = 0, i = 0; i <= size - sizeof(int); i += sizeof(int))
362 key += trace_hash(*(int *)(caller + i));
363
364 item = trace_hash_find(&event_hash->stacks, key, match_stack, &match);
365 if (!item) {
366 stack = malloc(sizeof(*stack) + size);
367 if (!stack) {
368 warning("Could not allocate stack");
369 return;
370 }
371 memset(stack, 0, sizeof(*stack));
372 memcpy(&stack->caller, caller, size);
373 stack->size = size;
374 stack->hash.key = key;
375 trace_hash_add(&event_hash->stacks, &stack->hash);
376 } else
377 stack = stack_from_item(item);
378
379 stack->count++;
380 stack->time += time;
381 if (stack->count == 1 || time < stack->time_min) {
382 stack->time_min = time;
383 stack->ts_min = ts;
384 }
385 if (time > stack->time_max) {
386 stack->time_max = time;
387 stack->ts_max = ts;
388 }
389 }
390
free_start(struct start_data * start)391 static void free_start(struct start_data *start)
392 {
393 if (start->task->last_start == start)
394 start->task->last_start = NULL;
395 if (start->stack.record)
396 tracecmd_free_record(start->stack.record);
397 trace_hash_del(&start->hash);
398 list_del(&start->list);
399 free(start);
400 }
401
402 static struct event_hash *
add_and_free_start(struct task_data * task,struct start_data * start,struct event_data * event_data,unsigned long long ts)403 add_and_free_start(struct task_data *task, struct start_data *start,
404 struct event_data *event_data, unsigned long long ts)
405 {
406 struct event_hash *event_hash;
407 long long delta;
408
409 delta = ts - start->timestamp;
410
411 /*
412 * It's possible on a live trace, because of timestamps being
413 * different on different CPUs, we can go back in time. When
414 * that happens, just zero out the delta.
415 */
416 if (delta < 0)
417 delta = 0;
418
419 event_hash = find_start_event_hash(task, event_data, start);
420 if (!event_hash)
421 return NULL;
422 event_hash->count++;
423 event_hash->time_total += delta;
424 event_hash->last_time = delta;
425
426 if (delta > event_hash->time_max) {
427 event_hash->time_max = delta;
428 event_hash->ts_max = ts;
429 }
430
431 if (event_hash->count == 1 || delta < event_hash->time_min) {
432 event_hash->time_min = delta;
433 event_hash->ts_min = ts;
434 }
435
436 if (start->stack.record) {
437 unsigned long size;
438 void *caller;
439
440 size = start->stack.size;
441 caller = start->stack.caller;
442
443 add_event_stack(event_hash, caller, size, delta,
444 start->stack.record->ts);
445 tracecmd_free_record(start->stack.record);
446 start->stack.record = NULL;
447 }
448
449 free_start(start);
450
451 return event_hash;
452 }
453
454 static struct event_hash *
find_and_update_start(struct task_data * task,struct event_data * event_data,unsigned long long ts,unsigned long long search_val)455 find_and_update_start(struct task_data *task, struct event_data *event_data,
456 unsigned long long ts, unsigned long long search_val)
457 {
458 struct start_data *start;
459
460 start = find_start(task, event_data, search_val);
461 if (!start)
462 return NULL;
463 return add_and_free_start(task, start, event_data, ts);
464 }
465
match_task(struct trace_hash_item * item,void * data)466 static int match_task(struct trace_hash_item *item, void *data)
467 {
468 struct task_data *task = task_from_item(item);
469 int pid = *(unsigned long *)data;
470
471 return task->pid == pid;
472 }
473
init_task(struct handle_data * h,struct task_data * task)474 static void init_task(struct handle_data *h, struct task_data *task)
475 {
476 task->handle = h;
477
478 trace_hash_init(&task->start_hash, 16);
479 trace_hash_init(&task->event_hash, 32);
480 }
481
482 static struct task_data *
add_task(struct handle_data * h,int pid)483 add_task(struct handle_data *h, int pid)
484 {
485 unsigned long long key = trace_hash(pid);
486 struct task_data *task;
487
488 task = malloc(sizeof(*task));
489 if (!task) {
490 warning("Could not allocate task");
491 return NULL;
492 }
493 memset(task, 0, sizeof(*task));
494
495 task->pid = pid;
496 task->hash.key = key;
497 trace_hash_add(&h->task_hash, &task->hash);
498
499 init_task(h, task);
500
501 return task;
502 }
503
504 static struct task_data *
find_task(struct handle_data * h,int pid)505 find_task(struct handle_data *h, int pid)
506 {
507 unsigned long long key = trace_hash(pid);
508 struct trace_hash_item *item;
509 static struct task_data *last_task;
510 void *data = (unsigned long *)&pid;
511
512 if (last_task && last_task->pid == pid)
513 return last_task;
514
515 item = trace_hash_find(&h->task_hash, key, match_task, data);
516
517 if (item)
518 last_task = task_from_item(item);
519 else
520 last_task = add_task(h, pid);
521
522 return last_task;
523 }
524
match_group(struct trace_hash_item * item,void * data)525 static int match_group(struct trace_hash_item *item, void *data)
526 {
527 struct group_data *group = group_from_item(item);
528
529 return strcmp(group->comm, (char *)data) == 0;
530 }
531
532
533 static void
add_task_comm(struct task_data * task,struct tep_format_field * field,struct tep_record * record)534 add_task_comm(struct task_data *task, struct tep_format_field *field,
535 struct tep_record *record)
536 {
537 const char *comm;
538
539 task->comm = malloc(field->size + 1);
540 if (!task->comm) {
541 warning("Could not allocate task comm");
542 return;
543 }
544 comm = record->data + field->offset;
545 memcpy(task->comm, comm, field->size);
546 task->comm[field->size] = 0;
547 }
548
549 /* Account for tasks that don't have starts */
account_task(struct task_data * task,struct event_data * event_data,struct tep_record * record)550 static void account_task(struct task_data *task, struct event_data *event_data,
551 struct tep_record *record)
552 {
553 struct event_data_match edata;
554 struct event_hash *event_hash;
555 struct task_data *proxy = NULL;
556 unsigned long long search_val = 0;
557 unsigned long long val = 0;
558 unsigned long long pid;
559
560 /*
561 * If an event has the pid_field set, then find that task for
562 * this event instead. Let this task proxy for it to handle
563 * stack traces on this event.
564 */
565 if (event_data->pid_field) {
566 tep_read_number_field(event_data->pid_field,
567 record->data, &pid);
568 proxy = task;
569 task = find_task(task->handle, pid);
570 if (!task)
571 return;
572 proxy->proxy = task;
573 }
574
575 /*
576 * If data_field is defined, use that for val,
577 * if the start_field is defined, use that for search_val.
578 */
579 if (event_data->data_field) {
580 tep_read_number_field(event_data->data_field,
581 record->data, &val);
582 }
583 if (event_data->start_match_field) {
584 tep_read_number_field(event_data->start_match_field,
585 record->data, &search_val);
586 }
587
588 edata.event_data = event_data;
589 edata.search_val = val;
590 edata.val = val;
591
592 event_hash = find_event_hash(task, &edata);
593 if (!event_hash) {
594 warning("failed to allocate event_hash");
595 return;
596 }
597
598 event_hash->count++;
599 task->last_event = event_hash;
600 }
601
602 static struct task_data *
find_event_task(struct handle_data * h,struct event_data * event_data,struct tep_record * record,unsigned long long pid)603 find_event_task(struct handle_data *h, struct event_data *event_data,
604 struct tep_record *record, unsigned long long pid)
605 {
606 if (event_data->global) {
607 if (event_data->migrate)
608 return h->global_task;
609 else
610 return &h->global_percpu_tasks[record->cpu];
611 }
612
613 /* If pid_field is defined, use that to find the task */
614 if (event_data->pid_field)
615 tep_read_number_field(event_data->pid_field,
616 record->data, &pid);
617 return find_task(h, pid);
618 }
619
620 static struct task_data *
handle_end_event(struct handle_data * h,struct event_data * event_data,struct tep_record * record,int pid)621 handle_end_event(struct handle_data *h, struct event_data *event_data,
622 struct tep_record *record, int pid)
623 {
624 struct event_hash *event_hash;
625 struct task_data *task;
626 unsigned long long val;
627
628 task = find_event_task(h, event_data, record, pid);
629 if (!task)
630 return NULL;
631
632 tep_read_number_field(event_data->start_match_field, record->data,
633 &val);
634 event_hash = find_and_update_start(task, event_data->start, record->ts, val);
635 task->last_start = NULL;
636 task->last_event = event_hash;
637
638 return task;
639 }
640
641 static struct task_data *
handle_start_event(struct handle_data * h,struct event_data * event_data,struct tep_record * record,unsigned long long pid)642 handle_start_event(struct handle_data *h, struct event_data *event_data,
643 struct tep_record *record, unsigned long long pid)
644 {
645 struct start_data *start;
646 struct task_data *task;
647 unsigned long long val;
648
649 task = find_event_task(h, event_data, record, pid);
650 if (!task)
651 return NULL;
652
653 tep_read_number_field(event_data->end_match_field, record->data,
654 &val);
655 start = add_start(task, event_data, record, val, val);
656 if (!start) {
657 warning("Failed to allocate start of task");
658 return NULL;
659 }
660
661 task->last_start = start;
662 task->last_event = NULL;
663
664 return task;
665 }
666
handle_event_data(struct handle_data * h,unsigned long long pid,struct event_data * event_data,struct tep_record * record,int cpu)667 static int handle_event_data(struct handle_data *h,
668 unsigned long long pid,
669 struct event_data *event_data,
670 struct tep_record *record, int cpu)
671 {
672 struct task_data *task = NULL;
673
674 /* If this is the end of a event pair (start is set) */
675 if (event_data->start)
676 task = handle_end_event(h, event_data, record, pid);
677
678 /* If this is the start of a event pair (end is set) */
679 if (event_data->end) {
680 task = handle_start_event(h, event_data, record, pid);
681 /* handle_start_event only returns NULL on error */
682 if (!task)
683 return -1;
684 }
685
686 if (!task) {
687 task = find_task(h, pid);
688 if (!task)
689 return -1;
690 task->proxy = NULL;
691 task->last_start = NULL;
692 task->last_event = NULL;
693 account_task(task, event_data, record);
694 }
695
696 return 0;
697 }
698
handle_missed_events(struct handle_data * h,int cpu)699 static void handle_missed_events(struct handle_data *h, int cpu)
700 {
701 struct start_data *start;
702 struct start_data *n;
703
704 /* Clear all starts on this CPU */
705 list_for_each_entry_safe(start, n, &h->cpu_starts[cpu], list) {
706 free_start(start);
707 }
708
709 /* Now clear all starts whose events can migrate */
710 list_for_each_entry_safe(start, n, &h->migrate_starts, list) {
711 free_start(start);
712 }
713 }
714
match_event_data(struct trace_hash_item * item,void * data)715 static int match_event_data(struct trace_hash_item *item, void *data)
716 {
717 struct event_data *event_data = event_data_from_item(item);
718 int id = (int)(unsigned long)data;
719
720 return event_data->id == id;
721 }
722
723 static struct event_data *
find_event_data(struct handle_data * h,int id)724 find_event_data(struct handle_data *h, int id)
725 {
726 struct trace_hash_item *item;
727 unsigned long long key = trace_hash(id);
728 void *data = (void *)(unsigned long)id;
729
730 item = trace_hash_find(&h->events, key, match_event_data, data);
731 if (item)
732 return event_data_from_item(item);
733 return NULL;
734 }
735
trace_profile_record(struct tracecmd_input * handle,struct tep_record * record)736 static void trace_profile_record(struct tracecmd_input *handle,
737 struct tep_record *record)
738 {
739 static struct handle_data *last_handle;
740 struct tep_record *stack_record;
741 struct event_data *event_data;
742 struct task_data *task;
743 struct handle_data *h;
744 struct tep_handle *pevent;
745 unsigned long long pid;
746 int cpu = record->cpu;
747 int id;
748
749 if (last_handle && last_handle->handle == handle)
750 h = last_handle;
751 else {
752 for (h = handles; h; h = h->next) {
753 if (h->handle == handle)
754 break;
755 }
756 if (!h)
757 die("Handle not found?");
758 last_handle = h;
759 }
760
761 if (record->missed_events)
762 handle_missed_events(h, cpu);
763
764 pevent = h->pevent;
765
766 id = tep_data_type(pevent, record);
767
768 event_data = find_event_data(h, id);
769
770 if (!event_data)
771 return;
772
773
774 /* Get this current PID */
775 tep_read_number_field(h->common_pid, record->data, &pid);
776
777 task = find_task(h, pid);
778 if (!task)
779 return;
780 stack_record = task->last_stack;
781
782 if (event_data->handle_event)
783 event_data->handle_event(h, pid, event_data, record, cpu);
784 else
785 handle_event_data(h, pid, event_data, record, cpu);
786
787 /* If the last stack hasn't changed, free it */
788 if (stack_record && task->last_stack == stack_record) {
789 tracecmd_free_record(stack_record);
790 task->last_stack = NULL;
791 }
792 }
793
794 static struct event_data *
add_event(struct handle_data * h,const char * system,const char * event_name,enum event_data_type type)795 add_event(struct handle_data *h, const char *system, const char *event_name,
796 enum event_data_type type)
797 {
798 struct event_data *event_data;
799 struct tep_event *event;
800
801 event = tep_find_event_by_name(h->pevent, system, event_name);
802 if (!event)
803 return NULL;
804
805 if (!h->common_pid) {
806 h->common_pid = tep_find_common_field(event, "common_pid");
807 if (!h->common_pid)
808 die("No 'common_pid' found in event");
809 }
810
811 event_data = malloc(sizeof(*event_data));
812 if (!event_data) {
813 warning("Could not allocate event_data");
814 return NULL;
815 }
816 memset(event_data, 0, sizeof(*event_data));
817 event_data->id = event->id;
818 event_data->event = event;
819 event_data->type = type;
820 event_data->hash.key = trace_hash(event_data->event->id);
821
822 trace_hash_add(&h->events, &event_data->hash);
823
824 return event_data;
825 }
826
827 static void
mate_events(struct handle_data * h,struct event_data * start,const char * pid_field,const char * end_match_field,struct event_data * end,const char * start_match_field,int migrate,int global)828 mate_events(struct handle_data *h, struct event_data *start,
829 const char *pid_field, const char *end_match_field,
830 struct event_data *end, const char *start_match_field,
831 int migrate, int global)
832 {
833 start->end = end;
834 end->start = start;
835
836 if (pid_field) {
837 start->pid_field = tep_find_field(start->event, pid_field);
838 if (!start->pid_field)
839 die("Event: %s does not have field %s",
840 start->event->name, pid_field);
841 }
842
843 /* Field to match with end */
844 start->end_match_field = tep_find_field(start->event, end_match_field);
845 if (!start->end_match_field)
846 die("Event: %s does not have field %s",
847 start->event->name, end_match_field);
848
849 /* Field to match with start */
850 end->start_match_field = tep_find_field(end->event, start_match_field);
851 if (!end->start_match_field)
852 die("Event: %s does not have field %s",
853 end->event->name, start_match_field);
854
855 start->migrate = migrate;
856 start->global = global;
857 end->migrate = migrate;
858 end->global = global;
859 }
860
861 /**
862 * tracecmd_mate_events - match events to profile against
863 * @handle: The input handle where the events exist.
864 * @start_event: The event that starts the transaction
865 * @pid_field: Use this over common_pid (may be NULL to use common_pid)
866 * @end_match_field: The field that matches the end events @start_match_field
867 * @end_event: The event that ends the transaction
868 * @start_match_field: The end event field that matches start's @end_match_field
869 * @migrate: Can the transaction switch CPUs? 1 for yes, 0 for no
870 * @global: The events are global and not per task
871 */
tracecmd_mate_events(struct tracecmd_input * handle,struct tep_event * start_event,const char * pid_field,const char * end_match_field,struct tep_event * end_event,const char * start_match_field,int migrate,int global)872 void tracecmd_mate_events(struct tracecmd_input *handle,
873 struct tep_event *start_event,
874 const char *pid_field, const char *end_match_field,
875 struct tep_event *end_event,
876 const char *start_match_field,
877 int migrate, int global)
878 {
879 struct handle_data *h;
880 struct event_data *start;
881 struct event_data *end;
882
883 for (h = handles; h; h = h->next) {
884 if (h->handle == handle)
885 break;
886 }
887 if (!h)
888 die("Handle not found for trace profile");
889
890 start = add_event(h, start_event->system, start_event->name,
891 EVENT_TYPE_USER_MATE);
892
893 end = add_event(h, end_event->system, end_event->name,
894 EVENT_TYPE_USER_MATE);
895
896 if (!start || !end)
897 return;
898
899 mate_events(h, start, pid_field, end_match_field, end, start_match_field,
900 migrate, global);
901 }
902
func_print(struct trace_seq * s,struct event_hash * event_hash)903 static void func_print(struct trace_seq *s, struct event_hash *event_hash)
904 {
905 const char *func;
906
907 func = tep_find_function(event_hash->event_data->event->tep,
908 event_hash->val);
909 if (func)
910 trace_seq_printf(s, "func: %s()", func);
911 else
912 trace_seq_printf(s, "func: 0x%llx", event_hash->val);
913 }
914
syscall_print(struct trace_seq * s,struct event_hash * event_hash)915 static void syscall_print(struct trace_seq *s, struct event_hash *event_hash)
916 {
917 #ifndef NO_AUDIT
918 const char *name = NULL;
919 int machine;
920
921 machine = audit_detect_machine();
922 if (machine < 0)
923 goto fail;
924 name = audit_syscall_to_name(event_hash->val, machine);
925 if (!name)
926 goto fail;
927 trace_seq_printf(s, "syscall:%s", name);
928 return;
929 fail:
930 #endif
931 trace_seq_printf(s, "%s:%d", event_hash->event_data->event->name,
932 (int)event_hash->val);
933 }
934
935 /* From Linux include/linux/interrupt.h */
936 #define SOFTIRQS \
937 C(HI), \
938 C(TIMER), \
939 C(NET_TX), \
940 C(NET_RX), \
941 C(BLOCK), \
942 C(BLOCK_IOPOLL), \
943 C(TASKLET), \
944 C(SCHED), \
945 C(HRTIMER), \
946 C(RCU), \
947 C(NR),
948
949 #undef C
950 #define C(a) a##_SOFTIRQ
951
952 enum { SOFTIRQS };
953
954 #undef C
955 #define C(a) #a
956
957 static const char *softirq_map[] = { SOFTIRQS };
958
softirq_print(struct trace_seq * s,struct event_hash * event_hash)959 static void softirq_print(struct trace_seq *s, struct event_hash *event_hash)
960 {
961 int softirq = (int)event_hash->val;
962
963 if (softirq < NR_SOFTIRQ)
964 trace_seq_printf(s, "%s:%s", event_hash->event_data->event->name,
965 softirq_map[softirq]);
966 else
967 trace_seq_printf(s, "%s:%d", event_hash->event_data->event->name,
968 softirq);
969 }
970
sched_switch_print(struct trace_seq * s,struct event_hash * event_hash)971 static void sched_switch_print(struct trace_seq *s, struct event_hash *event_hash)
972 {
973 const char states[] = TASK_STATE_TO_CHAR_STR;
974 int i;
975
976 trace_seq_printf(s, "%s:", event_hash->event_data->event->name);
977
978 if (event_hash->val) {
979 int val = event_hash->val;
980
981 for (i = 0; val && i < sizeof(states) - 1; i++, val >>= 1) {
982 if (val & 1)
983 trace_seq_putc(s, states[i+1]);
984 }
985 } else
986 trace_seq_putc(s, 'R');
987 }
988
handle_sched_switch_event(struct handle_data * h,unsigned long long pid,struct event_data * event_data,struct tep_record * record,int cpu)989 static int handle_sched_switch_event(struct handle_data *h,
990 unsigned long long pid,
991 struct event_data *event_data,
992 struct tep_record *record, int cpu)
993 {
994 struct task_data *task;
995 unsigned long long prev_pid;
996 unsigned long long prev_state;
997 unsigned long long next_pid;
998 struct start_data *start;
999
1000 /* pid_field holds prev_pid, data_field holds prev_state */
1001 tep_read_number_field(event_data->pid_field,
1002 record->data, &prev_pid);
1003
1004 tep_read_number_field(event_data->data_field,
1005 record->data, &prev_state);
1006
1007 /* only care about real states */
1008 prev_state &= TASK_STATE_MAX - 1;
1009
1010 /* end_match_field holds next_pid */
1011 tep_read_number_field(event_data->end_match_field,
1012 record->data, &next_pid);
1013
1014 task = find_task(h, prev_pid);
1015 if (!task)
1016 return -1;
1017 if (!task->comm)
1018 add_task_comm(task, h->switch_prev_comm, record);
1019
1020 if (prev_state)
1021 task->sleeping = 1;
1022 else
1023 task->sleeping = 0;
1024
1025 /* task is being scheduled out. prev_state tells why */
1026 start = add_start(task, event_data, record, prev_pid, prev_state);
1027 task->last_start = start;
1028 task->last_event = NULL;
1029
1030 task = find_task(h, next_pid);
1031 if (!task)
1032 return -1;
1033
1034 if (!task->comm)
1035 add_task_comm(task, h->switch_next_comm, record);
1036
1037 /*
1038 * If the next task was blocked, it required a wakeup to
1039 * restart, and there should be one.
1040 * But if it was preempted, we look for the previous sched switch.
1041 * Unfortunately, we have to look for both types of events as
1042 * we do not know why next_pid scheduled out.
1043 *
1044 * event_data->start holds the sched_wakeup event data.
1045 */
1046 find_and_update_start(task, event_data->start, record->ts, next_pid);
1047
1048 /* Look for this task if it was preempted (no wakeup found). */
1049 find_and_update_start(task, event_data, record->ts, next_pid);
1050
1051 return 0;
1052 }
1053
handle_stacktrace_event(struct handle_data * h,unsigned long long pid,struct event_data * event_data,struct tep_record * record,int cpu)1054 static int handle_stacktrace_event(struct handle_data *h,
1055 unsigned long long pid,
1056 struct event_data *event_data,
1057 struct tep_record *record, int cpu)
1058 {
1059 struct task_data *orig_task;
1060 struct task_data *proxy;
1061 struct task_data *task;
1062 unsigned long long size;
1063 struct event_hash *event_hash;
1064 struct start_data *start;
1065 void *caller;
1066
1067 task = find_task(h, pid);
1068 if (!task)
1069 return -1;
1070
1071 if (task->last_stack) {
1072 tracecmd_free_record(task->last_stack);
1073 task->last_stack = NULL;
1074 }
1075
1076 if ((proxy = task->proxy)) {
1077 task->proxy = NULL;
1078 orig_task = task;
1079 task = proxy;
1080 }
1081
1082 if (!task->last_start && !task->last_event) {
1083 /*
1084 * Save this stack in case function graph needs it.
1085 * Need the original task, not a proxy.
1086 */
1087 if (proxy)
1088 task = orig_task;
1089 tracecmd_record_ref(record);
1090 task->last_stack = record;
1091 return 0;
1092 }
1093
1094 /*
1095 * start_match_field holds the size.
1096 * data_field holds the caller location.
1097 */
1098 size = record->size - event_data->data_field->offset;
1099 caller = record->data + event_data->data_field->offset;
1100
1101 /*
1102 * If there's a "start" then don't add the stack until
1103 * it finds a matching "end".
1104 */
1105 if ((start = task->last_start)) {
1106 tracecmd_record_ref(record);
1107 start->stack.record = record;
1108 start->stack.size = size;
1109 start->stack.caller = caller;
1110 task->last_start = NULL;
1111 task->last_event = NULL;
1112 return 0;
1113 }
1114
1115 event_hash = task->last_event;
1116 task->last_event = NULL;
1117
1118 add_event_stack(event_hash, caller, size, event_hash->last_time,
1119 record->ts);
1120
1121 return 0;
1122 }
1123
handle_fgraph_entry_event(struct handle_data * h,unsigned long long pid,struct event_data * event_data,struct tep_record * record,int cpu)1124 static int handle_fgraph_entry_event(struct handle_data *h,
1125 unsigned long long pid,
1126 struct event_data *event_data,
1127 struct tep_record *record, int cpu)
1128 {
1129 unsigned long long size;
1130 struct start_data *start;
1131 struct task_data *task;
1132 void *caller;
1133
1134 task = handle_start_event(h, event_data, record, pid);
1135 if (!task)
1136 return -1;
1137
1138 /*
1139 * If a stack trace hasn't been used for a previous task,
1140 * then it could be a function trace that we can use for
1141 * the function graph. But stack traces come before the function
1142 * graph events (unfortunately). So we need to attach the previous
1143 * stack trace (if there is one) to this start event.
1144 */
1145 if (task->last_stack) {
1146 start = task->last_start;
1147 record = task->last_stack;
1148 size = record->size - stacktrace_event->data_field->offset;
1149 caller = record->data + stacktrace_event->data_field->offset;
1150 start->stack.record = record;
1151 start->stack.size = size;
1152 start->stack.caller = caller;
1153 task->last_stack = NULL;
1154 task->last_event = NULL;
1155 }
1156
1157 /* Do not map stacks after this event to this event */
1158 task->last_start = NULL;
1159
1160 return 0;
1161 }
1162
handle_fgraph_exit_event(struct handle_data * h,unsigned long long pid,struct event_data * event_data,struct tep_record * record,int cpu)1163 static int handle_fgraph_exit_event(struct handle_data *h,
1164 unsigned long long pid,
1165 struct event_data *event_data,
1166 struct tep_record *record, int cpu)
1167 {
1168 struct task_data *task;
1169
1170 task = handle_end_event(h, event_data, record, pid);
1171 if (!task)
1172 return -1;
1173 /* Do not match stacks with function graph exit events */
1174 task->last_event = NULL;
1175
1176 return 0;
1177 }
1178
handle_process_exec(struct handle_data * h,unsigned long long pid,struct event_data * event_data,struct tep_record * record,int cpu)1179 static int handle_process_exec(struct handle_data *h,
1180 unsigned long long pid,
1181 struct event_data *event_data,
1182 struct tep_record *record, int cpu)
1183 {
1184 struct task_data *task;
1185 unsigned long long val;
1186
1187 /* Task has execed, remove the comm for it */
1188 if (event_data->data_field) {
1189 tep_read_number_field(event_data->data_field,
1190 record->data, &val);
1191 pid = val;
1192 }
1193
1194 task = find_task(h, pid);
1195 if (!task)
1196 return -1;
1197
1198 free(task->comm);
1199 task->comm = NULL;
1200
1201 return 0;
1202 }
1203
handle_sched_wakeup_event(struct handle_data * h,unsigned long long pid,struct event_data * event_data,struct tep_record * record,int cpu)1204 static int handle_sched_wakeup_event(struct handle_data *h,
1205 unsigned long long pid,
1206 struct event_data *event_data,
1207 struct tep_record *record, int cpu)
1208 {
1209 struct task_data *proxy;
1210 struct task_data *task = NULL;
1211 struct start_data *start;
1212 unsigned long long success;
1213
1214 proxy = find_task(h, pid);
1215 if (!proxy)
1216 return -1;
1217
1218 /* If present, data_field holds "success" */
1219 if (event_data->data_field) {
1220 tep_read_number_field(event_data->data_field,
1221 record->data, &success);
1222
1223 /* If not a successful wakeup, ignore this */
1224 if (!success)
1225 return 0;
1226 }
1227
1228 tep_read_number_field(event_data->pid_field,
1229 record->data, &pid);
1230
1231 task = find_task(h, pid);
1232 if (!task)
1233 return -1;
1234
1235 if (!task->comm)
1236 add_task_comm(task, h->wakeup_comm, record);
1237
1238 /* if the task isn't sleeping, then ignore the wake up */
1239 if (!task->sleeping) {
1240 /* Ignore any following stack traces */
1241 proxy->proxy = NULL;
1242 proxy->last_start = NULL;
1243 proxy->last_event = NULL;
1244 return 0;
1245 }
1246
1247 /* It's being woken up */
1248 task->sleeping = 0;
1249
1250 /*
1251 * We need the stack trace to be hooked to the woken up
1252 * task, not the waker.
1253 */
1254 proxy->proxy = task;
1255
1256 /* There should be a blocked schedule out of this task */
1257 find_and_update_start(task, event_data->start, record->ts, pid);
1258
1259 /* Set this up for timing how long the wakeup takes */
1260 start = add_start(task, event_data, record, pid, pid);
1261 task->last_event = NULL;
1262 task->last_start = start;
1263
1264 return 0;
1265 }
1266
trace_init_profile(struct tracecmd_input * handle,struct hook_list * hook,int global)1267 void trace_init_profile(struct tracecmd_input *handle, struct hook_list *hook,
1268 int global)
1269 {
1270 struct tep_handle *pevent = tracecmd_get_tep(handle);
1271 struct tep_format_field **fields;
1272 struct handle_data *h;
1273 struct event_data *event_data;
1274 struct event_data *sched_switch;
1275 struct event_data *sched_wakeup;
1276 struct event_data *irq_entry;
1277 struct event_data *irq_exit;
1278 struct event_data *softirq_entry;
1279 struct event_data *softirq_exit;
1280 struct event_data *softirq_raise;
1281 struct event_data *fgraph_entry;
1282 struct event_data *fgraph_exit;
1283 struct event_data *syscall_enter;
1284 struct event_data *syscall_exit;
1285 struct event_data *process_exec;
1286 struct event_data *start_event;
1287 struct event_data *end_event;
1288 struct tep_event **events;
1289 int ret;
1290 int i;
1291
1292 tracecmd_set_show_data_func(handle, trace_profile_record);
1293 h = malloc(sizeof(*h));
1294 if (!h) {
1295 warning("Could not allocate handle");
1296 return;
1297 };
1298 memset(h, 0, sizeof(*h));
1299 h->next = handles;
1300 handles = h;
1301
1302 trace_hash_init(&h->task_hash, 1024);
1303 trace_hash_init(&h->events, 1024);
1304 trace_hash_init(&h->group_hash, 512);
1305
1306 h->handle = handle;
1307 h->pevent = pevent;
1308
1309 h->cpus = tracecmd_cpus(handle);
1310
1311 /*
1312 * For streaming profiling, cpus will not be set up yet.
1313 * In this case, we simply use the number of cpus on the
1314 * system.
1315 */
1316 if (!h->cpus)
1317 h->cpus = tracecmd_count_cpus();
1318
1319 list_head_init(&h->migrate_starts);
1320 h->cpu_starts = malloc(sizeof(*h->cpu_starts) * h->cpus);
1321 if (!h->cpu_starts)
1322 goto free_handle;
1323
1324 for (i = 0; i < h->cpus; i++)
1325 list_head_init(&h->cpu_starts[i]);
1326
1327 h->cpu_data = malloc(h->cpus * sizeof(*h->cpu_data));
1328 if (!h->cpu_data)
1329 goto free_starts;
1330
1331 memset(h->cpu_data, 0, h->cpus * sizeof(h->cpu_data));
1332
1333 h->global_task = malloc(sizeof(struct task_data));
1334 if (!h->global_task)
1335 goto free_data;
1336
1337 memset(h->global_task, 0, sizeof(struct task_data));
1338 init_task(h, h->global_task);
1339 h->global_task->comm = strdup("Global Events");
1340 if (!h->global_task->comm)
1341 die("malloc");
1342 h->global_task->pid = -1;
1343
1344 h->global_percpu_tasks = calloc(h->cpus, sizeof(struct task_data));
1345 if (!h->global_percpu_tasks)
1346 die("malloc");
1347 for (i = 0; i < h->cpus; i++) {
1348 init_task(h, &h->global_percpu_tasks[i]);
1349 ret = asprintf(&h->global_percpu_tasks[i].comm,
1350 "Global CPU[%d] Events", i);
1351 if (ret < 0)
1352 die("malloc");
1353 h->global_percpu_tasks[i].pid = -1 - i;
1354 }
1355
1356 irq_entry = add_event(h, "irq", "irq_handler_entry", EVENT_TYPE_IRQ);
1357 irq_exit = add_event(h, "irq", "irq_handler_exit", EVENT_TYPE_IRQ);
1358 softirq_entry = add_event(h, "irq", "softirq_entry", EVENT_TYPE_SOFTIRQ);
1359 softirq_exit = add_event(h, "irq", "softirq_exit", EVENT_TYPE_SOFTIRQ);
1360 softirq_raise = add_event(h, "irq", "softirq_raise", EVENT_TYPE_SOFTIRQ_RAISE);
1361 sched_wakeup = add_event(h, "sched", "sched_wakeup", EVENT_TYPE_WAKEUP);
1362 sched_switch = add_event(h, "sched", "sched_switch", EVENT_TYPE_SCHED_SWITCH);
1363 fgraph_entry = add_event(h, "ftrace", "funcgraph_entry", EVENT_TYPE_FUNC);
1364 fgraph_exit = add_event(h, "ftrace", "funcgraph_exit", EVENT_TYPE_FUNC);
1365 syscall_enter = add_event(h, "raw_syscalls", "sys_enter", EVENT_TYPE_SYSCALL);
1366 syscall_exit = add_event(h, "raw_syscalls", "sys_exit", EVENT_TYPE_SYSCALL);
1367
1368 process_exec = add_event(h, "sched", "sched_process_exec",
1369 EVENT_TYPE_PROCESS_EXEC);
1370
1371 stacktrace_event = add_event(h, "ftrace", "kernel_stack", EVENT_TYPE_STACK);
1372 if (stacktrace_event) {
1373 stacktrace_event->handle_event = handle_stacktrace_event;
1374
1375 stacktrace_event->data_field = tep_find_field(stacktrace_event->event,
1376 "caller");
1377 if (!stacktrace_event->data_field)
1378 die("Event: %s does not have field caller",
1379 stacktrace_event->event->name);
1380 }
1381
1382 if (process_exec) {
1383 process_exec->handle_event = handle_process_exec;
1384 process_exec->data_field = tep_find_field(process_exec->event,
1385 "old_pid");
1386 }
1387
1388 if (sched_switch) {
1389 sched_switch->handle_event = handle_sched_switch_event;
1390 sched_switch->data_field = tep_find_field(sched_switch->event,
1391 "prev_state");
1392 if (!sched_switch->data_field)
1393 die("Event: %s does not have field prev_state",
1394 sched_switch->event->name);
1395
1396 h->switch_prev_comm = tep_find_field(sched_switch->event,
1397 "prev_comm");
1398 if (!h->switch_prev_comm)
1399 die("Event: %s does not have field prev_comm",
1400 sched_switch->event->name);
1401
1402 h->switch_next_comm = tep_find_field(sched_switch->event,
1403 "next_comm");
1404 if (!h->switch_next_comm)
1405 die("Event: %s does not have field next_comm",
1406 sched_switch->event->name);
1407
1408 sched_switch->print_func = sched_switch_print;
1409 }
1410
1411 if (sched_switch && sched_wakeup) {
1412 mate_events(h, sched_switch, "prev_pid", "next_pid",
1413 sched_wakeup, "pid", 1, 0);
1414 mate_events(h, sched_wakeup, "pid", "pid",
1415 sched_switch, "prev_pid", 1, 0);
1416 sched_wakeup->handle_event = handle_sched_wakeup_event;
1417
1418 /* The 'success' field may or may not be present */
1419 sched_wakeup->data_field = tep_find_field(sched_wakeup->event,
1420 "success");
1421
1422 h->wakeup_comm = tep_find_field(sched_wakeup->event, "comm");
1423 if (!h->wakeup_comm)
1424 die("Event: %s does not have field comm",
1425 sched_wakeup->event->name);
1426 }
1427
1428 if (irq_entry && irq_exit)
1429 mate_events(h, irq_entry, NULL, "irq", irq_exit, "irq", 0, global);
1430
1431 if (softirq_entry)
1432 softirq_entry->print_func = softirq_print;
1433
1434 if (softirq_exit)
1435 softirq_exit->print_func = softirq_print;
1436
1437 if (softirq_raise)
1438 softirq_raise->print_func = softirq_print;
1439
1440 if (softirq_entry && softirq_exit)
1441 mate_events(h, softirq_entry, NULL, "vec", softirq_exit, "vec",
1442 0, global);
1443
1444 if (softirq_entry && softirq_raise)
1445 mate_events(h, softirq_raise, NULL, "vec", softirq_entry, "vec",
1446 0, global);
1447
1448 if (fgraph_entry && fgraph_exit) {
1449 mate_events(h, fgraph_entry, NULL, "func", fgraph_exit, "func", 1, 0);
1450 fgraph_entry->handle_event = handle_fgraph_entry_event;
1451 fgraph_exit->handle_event = handle_fgraph_exit_event;
1452 fgraph_entry->print_func = func_print;
1453 }
1454
1455 if (syscall_enter && syscall_exit) {
1456 mate_events(h, syscall_enter, NULL, "id", syscall_exit, "id", 1, 0);
1457 syscall_enter->print_func = syscall_print;
1458 syscall_exit->print_func = syscall_print;
1459 }
1460
1461 events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
1462 if (!events)
1463 die("malloc");
1464
1465 /* Add some other events */
1466 event_data = add_event(h, "ftrace", "function", EVENT_TYPE_FUNC);
1467 if (event_data) {
1468 event_data->data_field =
1469 tep_find_field(event_data->event, "ip");
1470 }
1471
1472 /* Add any user defined hooks */
1473 for (; hook; hook = hook->next) {
1474 start_event = add_event(h, hook->start_system, hook->start_event,
1475 EVENT_TYPE_USER_MATE);
1476 end_event = add_event(h, hook->end_system, hook->end_event,
1477 EVENT_TYPE_USER_MATE);
1478 if (!start_event) {
1479 warning("Event %s not found", hook->start_event);
1480 continue;
1481 }
1482 if (!end_event) {
1483 warning("Event %s not found", hook->end_event);
1484 continue;
1485 }
1486 mate_events(h, start_event, hook->pid, hook->start_match,
1487 end_event, hook->end_match, hook->migrate,
1488 hook->global);
1489 }
1490
1491 /* Now add any defined event that we haven't processed */
1492 for (i = 0; events[i]; i++) {
1493 event_data = find_event_data(h, events[i]->id);
1494 if (event_data)
1495 continue;
1496
1497 event_data = add_event(h, events[i]->system, events[i]->name,
1498 EVENT_TYPE_UNDEFINED);
1499
1500 fields = tep_event_fields(events[i]);
1501 if (!fields)
1502 die("malloc");
1503
1504 if (fields[0])
1505 event_data->data_field = fields[0];
1506
1507 free(fields);
1508 }
1509 return;
1510
1511 free_data:
1512 free(h->cpu_data);
1513 free_starts:
1514 free(h->cpu_starts);
1515 free_handle:
1516 handles = h->next;
1517 free(h);
1518 warning("Failed handle allocations");
1519 }
1520
output_event_stack(struct tep_handle * pevent,struct stack_data * stack)1521 static void output_event_stack(struct tep_handle *pevent, struct stack_data *stack)
1522 {
1523 int longsize = tep_get_long_size(pevent);
1524 unsigned long long val;
1525 const char *func;
1526 unsigned long long stop = -1ULL;
1527 void *ptr;
1528 int i;
1529
1530 if (longsize < 8)
1531 stop &= (1ULL << (longsize * 8)) - 1;
1532
1533 if (stack->count)
1534 stack->time_avg = stack->time / stack->count;
1535
1536 printf(" <stack> %lld total:%lld min:%lld(ts:%lld.%06lld) max:%lld(ts:%lld.%06lld) avg=%lld\n",
1537 stack->count, stack->time, stack->time_min,
1538 nsecs_per_sec(stack->ts_min), mod_to_usec(stack->ts_min),
1539 stack->time_max,
1540 nsecs_per_sec(stack->ts_max), mod_to_usec(stack->ts_max),
1541 stack->time_avg);
1542
1543 for (i = 0; i < stack->size; i += longsize) {
1544 ptr = stack->caller + i;
1545 switch (longsize) {
1546 case 4:
1547 /* todo, read value from pevent */
1548 val = *(unsigned int *)ptr;
1549 break;
1550 case 8:
1551 val = *(unsigned long long *)ptr;
1552 break;
1553 default:
1554 die("Strange long size %d", longsize);
1555 }
1556 if (val == stop)
1557 break;
1558 func = tep_find_function(pevent, val);
1559 if (func)
1560 printf(" => %s (0x%llx)\n", func, val);
1561 else
1562 printf(" => 0x%llx\n", val);
1563 }
1564 }
1565
1566 struct stack_chain {
1567 struct stack_chain *children;
1568 unsigned long long val;
1569 unsigned long long time;
1570 unsigned long long time_min;
1571 unsigned long long ts_min;
1572 unsigned long long time_max;
1573 unsigned long long ts_max;
1574 unsigned long long time_avg;
1575 unsigned long long count;
1576 int percent;
1577 int nr_children;
1578 };
1579
compare_chains(const void * a,const void * b)1580 static int compare_chains(const void *a, const void *b)
1581 {
1582 const struct stack_chain * A = a;
1583 const struct stack_chain * B = b;
1584
1585 if (A->time > B->time)
1586 return -1;
1587 if (A->time < B->time)
1588 return 1;
1589 /* If stacks don't use time, then use count */
1590 if (A->count > B->count)
1591 return -1;
1592 if (A->count < B->count)
1593 return 1;
1594 return 0;
1595 }
1596
calc_percent(unsigned long long val,unsigned long long total)1597 static int calc_percent(unsigned long long val, unsigned long long total)
1598 {
1599 return (val * 100 + total / 2) / total;
1600 }
1601
stack_overflows(struct stack_data * stack,int longsize,int level)1602 static int stack_overflows(struct stack_data *stack, int longsize, int level)
1603 {
1604 return longsize * level > stack->size - longsize;
1605 }
1606
1607 static unsigned long long
stack_value(struct stack_data * stack,int longsize,int level)1608 stack_value(struct stack_data *stack, int longsize, int level)
1609 {
1610 void *ptr;
1611
1612 ptr = &stack->caller[longsize * level];
1613 return longsize == 8 ? *(u64 *)ptr : *(unsigned *)ptr;
1614 }
1615
1616 static struct stack_chain *
make_stack_chain(struct stack_data ** stacks,int cnt,int longsize,int level,int * nr_children)1617 make_stack_chain(struct stack_data **stacks, int cnt, int longsize, int level,
1618 int *nr_children)
1619 {
1620 struct stack_chain *chain;
1621 unsigned long long total_time = 0;
1622 unsigned long long total_count = 0;
1623 unsigned long long time;
1624 unsigned long long time_min;
1625 unsigned long long ts_min;
1626 unsigned long long time_max;
1627 unsigned long long ts_max;
1628 unsigned long long count;
1629 unsigned long long stop = -1ULL;
1630 int nr_chains = 0;
1631 u64 last = 0;
1632 u64 val;
1633 int start;
1634 int i;
1635 int x;
1636
1637 if (longsize < 8)
1638 stop &= (1ULL << (longsize * 8)) - 1;
1639
1640 /* First find out how many diffs there are */
1641 for (i = 0; i < cnt; i++) {
1642 if (stack_overflows(stacks[i], longsize, level))
1643 continue;
1644
1645 val = stack_value(stacks[i], longsize, level);
1646
1647 if (val == stop)
1648 continue;
1649
1650 if (!nr_chains || val != last)
1651 nr_chains++;
1652 last = val;
1653 }
1654
1655 if (!nr_chains) {
1656 *nr_children = 0;
1657 return NULL;
1658 }
1659
1660 chain = malloc(sizeof(*chain) * nr_chains);
1661 if (!chain) {
1662 warning("Could not allocate chain");
1663 return NULL;
1664 }
1665 memset(chain, 0, sizeof(*chain) * nr_chains);
1666
1667 x = 0;
1668 count = 0;
1669 start = 0;
1670 time = 0;
1671 time_min = 0;
1672 time_max = 0;
1673
1674 for (i = 0; i < cnt; i++) {
1675 if (stack_overflows(stacks[i], longsize, level)) {
1676 start = i+1;
1677 continue;
1678 }
1679
1680 val = stack_value(stacks[i], longsize, level);
1681
1682 if (val == stop) {
1683 start = i+1;
1684 continue;
1685 }
1686
1687 count += stacks[i]->count;
1688 time += stacks[i]->time;
1689 if (stacks[i]->time_max > time_max) {
1690 time_max = stacks[i]->time_max;
1691 ts_max = stacks[i]->ts_max;
1692 }
1693 if (i == start || stacks[i]->time_min < time_min) {
1694 time_min = stacks[i]->time_min;
1695 ts_min = stacks[i]->ts_min;
1696 }
1697 if (i == cnt - 1 ||
1698 stack_overflows(stacks[i+1], longsize, level) ||
1699 val != stack_value(stacks[i+1], longsize, level)) {
1700
1701 total_time += time;
1702 total_count += count;
1703 chain[x].val = val;
1704 chain[x].time_avg = time / count;
1705 chain[x].count = count;
1706 chain[x].time = time;
1707 chain[x].time_min = time_min;
1708 chain[x].ts_min = ts_min;
1709 chain[x].time_max = time_max;
1710 chain[x].ts_max = ts_max;
1711 chain[x].children =
1712 make_stack_chain(&stacks[start], (i - start) + 1,
1713 longsize, level+1,
1714 &chain[x].nr_children);
1715 x++;
1716 start = i + 1;
1717 count = 0;
1718 time = 0;
1719 time_min = 0;
1720 time_max = 0;
1721 }
1722 }
1723
1724 qsort(chain, nr_chains, sizeof(*chain), compare_chains);
1725
1726 *nr_children = nr_chains;
1727
1728 /* Should never happen */
1729 if (!total_time && !total_count)
1730 return chain;
1731
1732
1733 /* Now calculate percentage */
1734 time = 0;
1735 for (i = 0; i < nr_chains; i++) {
1736 if (total_time)
1737 chain[i].percent = calc_percent(chain[i].time, total_time);
1738 /* In case stacks don't have time */
1739 else if (total_count)
1740 chain[i].percent = calc_percent(chain[i].count, total_count);
1741 }
1742
1743 return chain;
1744 }
1745
free_chain(struct stack_chain * chain,int nr_chains)1746 static void free_chain(struct stack_chain *chain, int nr_chains)
1747 {
1748 int i;
1749
1750 if (!chain)
1751 return;
1752
1753 for (i = 0; i < nr_chains; i++)
1754 free_chain(chain[i].children, chain[i].nr_children);
1755
1756 free(chain);
1757 }
1758
1759 #define INDENT 5
1760
print_indent(int level,unsigned long long mask)1761 static void print_indent(int level, unsigned long long mask)
1762 {
1763 char line;
1764 int p;
1765
1766 for (p = 0; p < level + 1; p++) {
1767 if (mask & (1ULL << p))
1768 line = '|';
1769 else
1770 line = ' ';
1771 printf("%*c ", INDENT, line);
1772 }
1773 }
1774
print_chain_func(struct tep_handle * pevent,struct stack_chain * chain)1775 static void print_chain_func(struct tep_handle *pevent, struct stack_chain *chain)
1776 {
1777 unsigned long long val = chain->val;
1778 const char *func;
1779
1780 func = tep_find_function(pevent, val);
1781 if (func)
1782 printf("%s (0x%llx)\n", func, val);
1783 else
1784 printf("0x%llx\n", val);
1785 }
1786
output_chain(struct tep_handle * pevent,struct stack_chain * chain,int level,int nr_chains,unsigned long long * mask)1787 static void output_chain(struct tep_handle *pevent, struct stack_chain *chain, int level,
1788 int nr_chains, unsigned long long *mask)
1789 {
1790 struct stack_chain *child;
1791 int nr_children;
1792 int i;
1793 char line = '|';
1794
1795 if (!nr_chains)
1796 return;
1797
1798 *mask |= (1ULL << (level + 1));
1799 print_indent(level + 1, *mask);
1800 printf("\n");
1801
1802 for (i = 0; i < nr_chains; i++) {
1803
1804 print_indent(level, *mask);
1805
1806 printf("%*c ", INDENT, '+');
1807
1808 if (i == nr_chains - 1) {
1809 *mask &= ~(1ULL << (level + 1));
1810 line = ' ';
1811 }
1812
1813 print_chain_func(pevent, &chain[i]);
1814
1815 print_indent(level, *mask);
1816
1817 printf("%*c ", INDENT, line);
1818 printf(" %d%% (%lld)", chain[i].percent, chain[i].count);
1819 if (chain[i].time)
1820 printf(" time:%lld max:%lld(ts:%lld.%06lld) min:%lld(ts:%lld.%06lld) avg:%lld",
1821 chain[i].time, chain[i].time_max,
1822 nsecs_per_sec(chain[i].ts_max),
1823 mod_to_usec(chain[i].ts_max),
1824 chain[i].time_min,
1825 nsecs_per_sec(chain[i].ts_min),
1826 mod_to_usec(chain[i].ts_min),
1827 chain[i].time_avg);
1828 printf("\n");
1829
1830 for (child = chain[i].children, nr_children = chain[i].nr_children;
1831 child && nr_children == 1;
1832 nr_children = child->nr_children, child = child->children) {
1833 print_indent(level, *mask);
1834 printf("%*c ", INDENT, line);
1835 printf(" ");
1836 print_chain_func(pevent, child);
1837 }
1838
1839 if (child)
1840 output_chain(pevent, child, level+1, nr_children, mask);
1841
1842 print_indent(level + 1, *mask);
1843 printf("\n");
1844 }
1845 *mask &= ~(1ULL << (level + 1));
1846 print_indent(level, *mask);
1847 printf("\n");
1848 }
1849
compare_stacks(const void * a,const void * b)1850 static int compare_stacks(const void *a, const void *b)
1851 {
1852 struct stack_data * const *A = a;
1853 struct stack_data * const *B = b;
1854 unsigned int sa, sb;
1855 int size;
1856 int i;
1857
1858 /* only compare up to the smaller size of the two */
1859 if ((*A)->size > (*B)->size)
1860 size = (*B)->size;
1861 else
1862 size = (*A)->size;
1863
1864 for (i = 0; i < size; i += sizeof(sa)) {
1865 sa = *(unsigned *)&(*A)->caller[i];
1866 sb = *(unsigned *)&(*B)->caller[i];
1867 if (sa > sb)
1868 return 1;
1869 if (sa < sb)
1870 return -1;
1871 }
1872
1873 /* They are the same up to size. Then bigger size wins */
1874 if ((*A)->size > (*B)->size)
1875 return 1;
1876 if ((*A)->size < (*B)->size)
1877 return -1;
1878 return 0;
1879 }
1880
output_stacks(struct tep_handle * pevent,struct trace_hash * stack_hash)1881 static void output_stacks(struct tep_handle *pevent, struct trace_hash *stack_hash)
1882 {
1883 struct trace_hash_item **bucket;
1884 struct trace_hash_item *item;
1885 struct stack_data **stacks;
1886 struct stack_chain *chain;
1887 unsigned long long mask = 0;
1888 int nr_chains;
1889 int longsize = tep_get_long_size(pevent);
1890 int nr_stacks;
1891 int i;
1892
1893 nr_stacks = 0;
1894 trace_hash_for_each_bucket(bucket, stack_hash) {
1895 trace_hash_for_each_item(item, bucket) {
1896 nr_stacks++;
1897 }
1898 }
1899
1900 stacks = malloc(sizeof(*stacks) * nr_stacks);
1901 if (!stacks) {
1902 warning("Could not allocate stacks");
1903 return;
1904 }
1905
1906 nr_stacks = 0;
1907 trace_hash_for_each_bucket(bucket, stack_hash) {
1908 trace_hash_for_each_item(item, bucket) {
1909 stacks[nr_stacks++] = stack_from_item(item);
1910 }
1911 }
1912
1913 qsort(stacks, nr_stacks, sizeof(*stacks), compare_stacks);
1914
1915 chain = make_stack_chain(stacks, nr_stacks, longsize, 0, &nr_chains);
1916
1917 output_chain(pevent, chain, 0, nr_chains, &mask);
1918
1919 if (0)
1920 for (i = 0; i < nr_stacks; i++)
1921 output_event_stack(pevent, stacks[i]);
1922
1923 free(stacks);
1924 free_chain(chain, nr_chains);
1925 }
1926
output_event(struct event_hash * event_hash)1927 static void output_event(struct event_hash *event_hash)
1928 {
1929 struct event_data *event_data = event_hash->event_data;
1930 struct tep_handle *pevent = event_data->event->tep;
1931 struct trace_seq s;
1932
1933 trace_seq_init(&s);
1934
1935 if (event_data->print_func)
1936 event_data->print_func(&s, event_hash);
1937 else if (event_data->type == EVENT_TYPE_FUNC)
1938 func_print(&s, event_hash);
1939 else
1940 trace_seq_printf(&s, "%s:0x%llx",
1941 event_data->event->name,
1942 event_hash->val);
1943 trace_seq_terminate(&s);
1944
1945 printf(" Event: %s (%lld)",
1946 s.buffer, event_hash->count);
1947
1948 trace_seq_destroy(&s);
1949
1950 if (event_hash->time_total) {
1951 event_hash->time_avg = event_hash->time_total / event_hash->count;
1952 printf(" Total: %lld Avg: %lld Max: %lld(ts:%lld.%06lld) Min:%lld(ts:%lld.%06lld)",
1953 event_hash->time_total, event_hash->time_avg,
1954 event_hash->time_max,
1955 nsecs_per_sec(event_hash->ts_max),
1956 mod_to_usec(event_hash->ts_max),
1957 event_hash->time_min,
1958 nsecs_per_sec(event_hash->ts_min),
1959 mod_to_usec(event_hash->ts_min));
1960 }
1961 printf("\n");
1962
1963 output_stacks(pevent, &event_hash->stacks);
1964 }
1965
compare_events(const void * a,const void * b)1966 static int compare_events(const void *a, const void *b)
1967 {
1968 struct event_hash * const *A = a;
1969 struct event_hash * const *B = b;
1970 const struct event_data *event_data_a = (*A)->event_data;
1971 const struct event_data *event_data_b = (*B)->event_data;
1972
1973 /* Schedule switch goes first */
1974 if (event_data_a->type == EVENT_TYPE_SCHED_SWITCH) {
1975 if (event_data_b->type != EVENT_TYPE_SCHED_SWITCH)
1976 return -1;
1977 /* lower the state the better */
1978 if ((*A)->val > (*B)->val)
1979 return 1;
1980 if ((*A)->val < (*B)->val)
1981 return -1;
1982 return 0;
1983 } else if (event_data_b->type == EVENT_TYPE_SCHED_SWITCH)
1984 return 1;
1985
1986 /* Wakeups are next */
1987 if (event_data_a->type == EVENT_TYPE_WAKEUP) {
1988 if (event_data_b->type != EVENT_TYPE_WAKEUP)
1989 return -1;
1990 return 0;
1991 } else if (event_data_b->type == EVENT_TYPE_WAKEUP)
1992 return 1;
1993
1994 if (event_data_a->id > event_data_b->id)
1995 return 1;
1996 if (event_data_a->id < event_data_b->id)
1997 return -1;
1998 if ((*A)->time_total > (*B)->time_total)
1999 return -1;
2000 if ((*A)->time_total < (*B)->time_total)
2001 return 1;
2002 return 0;
2003 }
2004
output_task(struct handle_data * h,struct task_data * task)2005 static void output_task(struct handle_data *h, struct task_data *task)
2006 {
2007 struct trace_hash_item **bucket;
2008 struct trace_hash_item *item;
2009 struct event_hash **events;
2010 const char *comm;
2011 int nr_events = 0;
2012 int i;
2013
2014 if (task->group)
2015 return;
2016
2017 if (task->comm)
2018 comm = task->comm;
2019 else
2020 comm = tep_data_comm_from_pid(h->pevent, task->pid);
2021
2022 if (task->pid < 0)
2023 printf("%s\n", task->comm);
2024 else
2025 printf("\ntask: %s-%d\n", comm, task->pid);
2026
2027 trace_hash_for_each_bucket(bucket, &task->event_hash) {
2028 trace_hash_for_each_item(item, bucket) {
2029 nr_events++;
2030 }
2031 }
2032
2033 events = malloc(sizeof(*events) * nr_events);
2034 if (!events) {
2035 warning("Could not allocate events");
2036 return;
2037 }
2038
2039 i = 0;
2040 trace_hash_for_each_bucket(bucket, &task->event_hash) {
2041 trace_hash_for_each_item(item, bucket) {
2042 events[i++] = event_from_item(item);
2043 }
2044 }
2045
2046 qsort(events, nr_events, sizeof(*events), compare_events);
2047
2048 for (i = 0; i < nr_events; i++)
2049 output_event(events[i]);
2050
2051 free(events);
2052 }
2053
output_group(struct handle_data * h,struct group_data * group)2054 static void output_group(struct handle_data *h, struct group_data *group)
2055 {
2056 struct trace_hash_item **bucket;
2057 struct trace_hash_item *item;
2058 struct event_hash **events;
2059 int nr_events = 0;
2060 int i;
2061
2062 printf("\ngroup: %s\n", group->comm);
2063
2064 trace_hash_for_each_bucket(bucket, &group->event_hash) {
2065 trace_hash_for_each_item(item, bucket) {
2066 nr_events++;
2067 }
2068 }
2069
2070 events = malloc(sizeof(*events) * nr_events);
2071 if (!events) {
2072 warning("Could not allocate events");
2073 return;
2074 }
2075
2076 i = 0;
2077 trace_hash_for_each_bucket(bucket, &group->event_hash) {
2078 trace_hash_for_each_item(item, bucket) {
2079 events[i++] = event_from_item(item);
2080 }
2081 }
2082
2083 qsort(events, nr_events, sizeof(*events), compare_events);
2084
2085 for (i = 0; i < nr_events; i++)
2086 output_event(events[i]);
2087
2088 free(events);
2089 }
2090
compare_tasks(const void * a,const void * b)2091 static int compare_tasks(const void *a, const void *b)
2092 {
2093 struct task_data * const *A = a;
2094 struct task_data * const *B = b;
2095
2096 if ((*A)->pid > (*B)->pid)
2097 return 1;
2098 else if ((*A)->pid < (*B)->pid)
2099 return -1;
2100 return 0;
2101 }
2102
compare_groups(const void * a,const void * b)2103 static int compare_groups(const void *a, const void *b)
2104 {
2105 const char *A = a;
2106 const char *B = b;
2107
2108 return strcmp(A, B);
2109 }
2110
free_event_hash(struct event_hash * event_hash)2111 static void free_event_hash(struct event_hash *event_hash)
2112 {
2113 struct trace_hash_item **bucket;
2114 struct trace_hash_item *item;
2115 struct stack_data *stack;
2116
2117 trace_hash_for_each_bucket(bucket, &event_hash->stacks) {
2118 trace_hash_while_item(item, bucket) {
2119 stack = stack_from_item(item);
2120 trace_hash_del(&stack->hash);
2121 free(stack);
2122 }
2123 }
2124 trace_hash_free(&event_hash->stacks);
2125 free(event_hash);
2126 }
2127
__free_task(struct task_data * task)2128 static void __free_task(struct task_data *task)
2129 {
2130 struct trace_hash_item **bucket;
2131 struct trace_hash_item *item;
2132 struct start_data *start;
2133 struct event_hash *event_hash;
2134
2135 free(task->comm);
2136
2137 trace_hash_for_each_bucket(bucket, &task->start_hash) {
2138 trace_hash_while_item(item, bucket) {
2139 start = start_from_item(item);
2140 if (start->stack.record)
2141 tracecmd_free_record(start->stack.record);
2142 list_del(&start->list);
2143 trace_hash_del(item);
2144 free(start);
2145 }
2146 }
2147 trace_hash_free(&task->start_hash);
2148
2149 trace_hash_for_each_bucket(bucket, &task->event_hash) {
2150 trace_hash_while_item(item, bucket) {
2151 event_hash = event_from_item(item);
2152 trace_hash_del(item);
2153 free_event_hash(event_hash);
2154 }
2155 }
2156 trace_hash_free(&task->event_hash);
2157
2158 if (task->last_stack)
2159 tracecmd_free_record(task->last_stack);
2160 }
2161
free_task(struct task_data * task)2162 static void free_task(struct task_data *task)
2163 {
2164 __free_task(task);
2165 free(task);
2166 }
2167
free_group(struct group_data * group)2168 static void free_group(struct group_data *group)
2169 {
2170 struct trace_hash_item **bucket;
2171 struct trace_hash_item *item;
2172 struct event_hash *event_hash;
2173
2174 free(group->comm);
2175
2176 trace_hash_for_each_bucket(bucket, &group->event_hash) {
2177 trace_hash_while_item(item, bucket) {
2178 event_hash = event_from_item(item);
2179 trace_hash_del(item);
2180 free_event_hash(event_hash);
2181 }
2182 }
2183 trace_hash_free(&group->event_hash);
2184 free(group);
2185 }
2186
show_global_task(struct handle_data * h,struct task_data * task)2187 static void show_global_task(struct handle_data *h,
2188 struct task_data *task)
2189 {
2190 if (trace_hash_empty(&task->event_hash))
2191 return;
2192
2193 output_task(h, task);
2194 }
2195
output_tasks(struct handle_data * h)2196 static void output_tasks(struct handle_data *h)
2197 {
2198 struct trace_hash_item **bucket;
2199 struct trace_hash_item *item;
2200 struct task_data **tasks;
2201 int nr_tasks = 0;
2202 int i;
2203
2204 trace_hash_for_each_bucket(bucket, &h->task_hash) {
2205 trace_hash_for_each_item(item, bucket) {
2206 nr_tasks++;
2207 }
2208 }
2209
2210 tasks = malloc(sizeof(*tasks) * nr_tasks);
2211 if (!tasks) {
2212 warning("Could not allocate tasks");
2213 return;
2214 }
2215
2216 nr_tasks = 0;
2217
2218 trace_hash_for_each_bucket(bucket, &h->task_hash) {
2219 trace_hash_while_item(item, bucket) {
2220 tasks[nr_tasks++] = task_from_item(item);
2221 trace_hash_del(item);
2222 }
2223 }
2224
2225 qsort(tasks, nr_tasks, sizeof(*tasks), compare_tasks);
2226
2227 for (i = 0; i < nr_tasks; i++) {
2228 output_task(h, tasks[i]);
2229 free_task(tasks[i]);
2230 }
2231
2232 free(tasks);
2233 }
2234
output_groups(struct handle_data * h)2235 static void output_groups(struct handle_data *h)
2236 {
2237 struct trace_hash_item **bucket;
2238 struct trace_hash_item *item;
2239 struct group_data **groups;
2240 int nr_groups = 0;
2241 int i;
2242
2243 trace_hash_for_each_bucket(bucket, &h->group_hash) {
2244 trace_hash_for_each_item(item, bucket) {
2245 nr_groups++;
2246 }
2247 }
2248
2249 if (nr_groups == 0)
2250 return;
2251
2252 groups = malloc(sizeof(*groups) * nr_groups);
2253 if (!groups) {
2254 warning("Could not allocate groups");
2255 return;
2256 }
2257
2258 nr_groups = 0;
2259
2260 trace_hash_for_each_bucket(bucket, &h->group_hash) {
2261 trace_hash_while_item(item, bucket) {
2262 groups[nr_groups++] = group_from_item(item);
2263 trace_hash_del(item);
2264 }
2265 }
2266
2267 qsort(groups, nr_groups, sizeof(*groups), compare_groups);
2268
2269 for (i = 0; i < nr_groups; i++) {
2270 output_group(h, groups[i]);
2271 free_group(groups[i]);
2272 }
2273
2274 free(groups);
2275 }
2276
output_handle(struct handle_data * h)2277 static void output_handle(struct handle_data *h)
2278 {
2279 int i;
2280
2281 show_global_task(h, h->global_task);
2282 for (i = 0; i < h->cpus; i++)
2283 show_global_task(h, &h->global_percpu_tasks[i]);
2284
2285 output_groups(h);
2286 output_tasks(h);
2287 }
2288
merge_event_stack(struct event_hash * event,struct stack_data * stack)2289 static void merge_event_stack(struct event_hash *event,
2290 struct stack_data *stack)
2291 {
2292 struct stack_data *exist;
2293 struct trace_hash_item *item;
2294 struct stack_match match;
2295
2296 match.caller = stack->caller;
2297 match.size = stack->size;
2298 item = trace_hash_find(&event->stacks, stack->hash.key, match_stack,
2299 &match);
2300 if (!item) {
2301 trace_hash_add(&event->stacks, &stack->hash);
2302 return;
2303 }
2304 exist = stack_from_item(item);
2305 exist->count += stack->count;
2306 exist->time += stack->time;
2307
2308 if (exist->time_max < stack->time_max) {
2309 exist->time_max = stack->time_max;
2310 exist->ts_max = stack->ts_max;
2311 }
2312 if (exist->time_min > stack->time_min) {
2313 exist->time_min = stack->time_min;
2314 exist->ts_min = stack->ts_min;
2315 }
2316 free(stack);
2317 }
2318
merge_stacks(struct event_hash * exist,struct event_hash * event)2319 static void merge_stacks(struct event_hash *exist, struct event_hash *event)
2320 {
2321 struct stack_data *stack;
2322 struct trace_hash_item *item;
2323 struct trace_hash_item **bucket;
2324
2325 trace_hash_for_each_bucket(bucket, &event->stacks) {
2326 trace_hash_while_item(item, bucket) {
2327 stack = stack_from_item(item);
2328 trace_hash_del(&stack->hash);
2329 merge_event_stack(exist, stack);
2330 }
2331 }
2332 }
2333
merge_event_into_group(struct group_data * group,struct event_hash * event)2334 static void merge_event_into_group(struct group_data *group,
2335 struct event_hash *event)
2336 {
2337 struct event_hash *exist;
2338 struct trace_hash_item *item;
2339 struct event_data_match edata;
2340 unsigned long long key;
2341
2342 if (event->event_data->type == EVENT_TYPE_WAKEUP) {
2343 edata.event_data = event->event_data;
2344 event->search_val = 0;
2345 event->val = 0;
2346 key = trace_hash((unsigned long)event->event_data);
2347 } else if (event->event_data->type == EVENT_TYPE_SCHED_SWITCH) {
2348 edata.event_data = event->event_data;
2349 event->search_val = event->val;
2350 key = (unsigned long)event->event_data +
2351 ((unsigned long)event->val * 2);
2352 key = trace_hash(key);
2353 } else {
2354 key = event->hash.key;
2355 }
2356
2357 edata.event_data = event->event_data;
2358 edata.search_val = event->search_val;
2359 edata.val = event->val;
2360
2361 item = trace_hash_find(&group->event_hash, key, match_event, &edata);
2362 if (!item) {
2363 event->hash.key = key;
2364 trace_hash_add(&group->event_hash, &event->hash);
2365 return;
2366 }
2367
2368 exist = event_from_item(item);
2369 exist->count += event->count;
2370 exist->time_total += event->time_total;
2371
2372 if (exist->time_max < event->time_max) {
2373 exist->time_max = event->time_max;
2374 exist->ts_max = event->ts_max;
2375 }
2376 if (exist->time_min > event->time_min) {
2377 exist->time_min = event->time_min;
2378 exist->ts_min = event->ts_min;
2379 }
2380
2381 merge_stacks(exist, event);
2382 free_event_hash(event);
2383 }
2384
add_group(struct handle_data * h,struct task_data * task)2385 static void add_group(struct handle_data *h, struct task_data *task)
2386 {
2387 unsigned long long key;
2388 struct trace_hash_item *item;
2389 struct group_data *grp;
2390 struct trace_hash_item **bucket;
2391 void *data = task->comm;
2392
2393 if (!task->comm)
2394 return;
2395
2396 key = trace_hash_str(task->comm);
2397
2398 item = trace_hash_find(&h->group_hash, key, match_group, data);
2399 if (item) {
2400 grp = group_from_item(item);
2401 } else {
2402 grp = malloc(sizeof(*grp));
2403 if (!grp) {
2404 warning("Could not allocate group");
2405 return;
2406 }
2407 memset(grp, 0, sizeof(*grp));
2408
2409 grp->comm = strdup(task->comm);
2410 if (!grp->comm)
2411 die("strdup");
2412 grp->hash.key = key;
2413 trace_hash_add(&h->group_hash, &grp->hash);
2414 trace_hash_init(&grp->event_hash, 32);
2415 }
2416 task->group = grp;
2417
2418 trace_hash_for_each_bucket(bucket, &task->event_hash) {
2419 trace_hash_while_item(item, bucket) {
2420 struct event_hash *event_hash;
2421
2422 event_hash = event_from_item(item);
2423 trace_hash_del(&event_hash->hash);
2424 merge_event_into_group(grp, event_hash);
2425 }
2426 }
2427 }
2428
merge_tasks(struct handle_data * h)2429 static void merge_tasks(struct handle_data *h)
2430 {
2431 struct trace_hash_item **bucket;
2432 struct trace_hash_item *item;
2433
2434 if (!merge_like_comms)
2435 return;
2436
2437 trace_hash_for_each_bucket(bucket, &h->task_hash) {
2438 trace_hash_for_each_item(item, bucket)
2439 add_group(h, task_from_item(item));
2440 }
2441 }
2442
do_trace_profile(void)2443 int do_trace_profile(void)
2444 {
2445 struct handle_data *h;
2446
2447 for (h = handles; h; h = h->next) {
2448 if (merge_like_comms)
2449 merge_tasks(h);
2450 output_handle(h);
2451 trace_hash_free(&h->task_hash);
2452 }
2453
2454 return 0;
2455 }
2456