diff options
Diffstat (limited to 'trace-plot-task.c')
-rw-r--r-- | trace-plot-task.c | 166 |
1 files changed, 142 insertions, 24 deletions
diff --git a/trace-plot-task.c b/trace-plot-task.c index c8d0905..794b889 100644 --- a/trace-plot-task.c +++ b/trace-plot-task.c | |||
@@ -29,6 +29,7 @@ | |||
29 | struct task_plot_info { | 29 | struct task_plot_info { |
30 | int pid; | 30 | int pid; |
31 | struct cpu_data *cpu_data; | 31 | struct cpu_data *cpu_data; |
32 | struct record **last_records; | ||
32 | unsigned long long last_time; | 33 | unsigned long long last_time; |
33 | unsigned long long wake_time; | 34 | unsigned long long wake_time; |
34 | unsigned long long display_wake_time; | 35 | unsigned long long display_wake_time; |
@@ -54,7 +55,9 @@ static gint hash_pid(gint val) | |||
54 | 55 | ||
55 | static int hash_cpu(int cpu) | 56 | static int hash_cpu(int cpu) |
56 | { | 57 | { |
57 | return trace_hash(cpu + 124); | 58 | cpu = (cpu << 3) + cpu * 21; |
59 | |||
60 | return trace_hash(cpu); | ||
58 | } | 61 | } |
59 | 62 | ||
60 | static gboolean is_running(struct graph_info *ginfo, struct record *record) | 63 | static gboolean is_running(struct graph_info *ginfo, struct record *record) |
@@ -104,26 +107,31 @@ static gboolean record_matches_pid(struct graph_info *ginfo, | |||
104 | return FALSE; | 107 | return FALSE; |
105 | } | 108 | } |
106 | 109 | ||
107 | static void set_cpus_to_time(struct graph_info *ginfo, unsigned long long time) | 110 | static void set_cpu_to_time(int cpu, struct graph_info *ginfo, unsigned long long time) |
108 | { | 111 | { |
109 | struct record *record; | 112 | struct record *record; |
110 | int cpu; | ||
111 | 113 | ||
112 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | 114 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time); |
113 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time); | ||
114 | 115 | ||
115 | while ((record = tracecmd_read_data(ginfo->handle, cpu))) { | 116 | while ((record = tracecmd_read_data(ginfo->handle, cpu))) { |
116 | if (record->ts >= time) | 117 | if (record->ts >= time) |
117 | break; | 118 | break; |
118 | 119 | ||
119 | free_record(record); | 120 | free_record(record); |
120 | } | ||
121 | if (record) { | ||
122 | tracecmd_set_cursor(ginfo->handle, cpu, record->offset); | ||
123 | free_record(record); | ||
124 | } else | ||
125 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time); | ||
126 | } | 121 | } |
122 | if (record) { | ||
123 | tracecmd_set_cursor(ginfo->handle, cpu, record->offset); | ||
124 | free_record(record); | ||
125 | } else | ||
126 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time); | ||
127 | } | ||
128 | |||
129 | static void set_cpus_to_time(struct graph_info *ginfo, unsigned long long time) | ||
130 | { | ||
131 | int cpu; | ||
132 | |||
133 | for (cpu = 0; cpu < ginfo->cpus; cpu++) | ||
134 | set_cpu_to_time(cpu, ginfo, time); | ||
127 | } | 135 | } |
128 | 136 | ||
129 | static int task_plot_match_time(struct graph_info *ginfo, struct graph_plot *plot, | 137 | static int task_plot_match_time(struct graph_info *ginfo, struct graph_plot *plot, |
@@ -315,12 +323,92 @@ static void task_plot_start(struct graph_info *ginfo, struct graph_plot *plot, | |||
315 | { | 323 | { |
316 | struct task_plot_info *task_info = plot->private; | 324 | struct task_plot_info *task_info = plot->private; |
317 | 325 | ||
326 | memset(task_info->last_records, 0, sizeof(struct record *) * ginfo->cpus); | ||
327 | |||
318 | task_info->last_time = 0ULL; | 328 | task_info->last_time = 0ULL; |
319 | task_info->last_cpu = -1; | 329 | task_info->last_cpu = -1; |
320 | task_info->wake_time = 0ULL; | 330 | task_info->wake_time = 0ULL; |
321 | task_info->display_wake_time = 0ULL; | 331 | task_info->display_wake_time = 0ULL; |
322 | } | 332 | } |
323 | 333 | ||
334 | static void update_last_record(struct graph_info *ginfo, | ||
335 | struct task_plot_info *task_info, | ||
336 | struct record *record) | ||
337 | { | ||
338 | struct tracecmd_input *handle = ginfo->handle; | ||
339 | struct record *trecord, *t2record; | ||
340 | struct record *saved; | ||
341 | unsigned long long ts; | ||
342 | int sched_pid; | ||
343 | int pid; | ||
344 | int rec_pid; | ||
345 | int is_wakeup; | ||
346 | int is_sched; | ||
347 | int this_cpu; | ||
348 | int cpu; | ||
349 | |||
350 | pid = task_info->pid; | ||
351 | |||
352 | if (record) { | ||
353 | ts = record->ts; | ||
354 | this_cpu = record->cpu; | ||
355 | } else { | ||
356 | ts = ginfo->view_end_time; | ||
357 | this_cpu = -1; | ||
358 | } | ||
359 | |||
360 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
361 | |||
362 | if (task_info->last_records[cpu]) | ||
363 | continue; | ||
364 | |||
365 | if (cpu == this_cpu) { | ||
366 | static int once; | ||
367 | |||
368 | trecord = tracecmd_read_prev(handle, record); | ||
369 | /* Set cpu cursor back to what it was */ | ||
370 | saved = tracecmd_read_data(handle, cpu); | ||
371 | if (!once && saved->offset != record->offset) { | ||
372 | once++; | ||
373 | warning("failed to reset cursor!"); | ||
374 | } | ||
375 | free_record(saved); | ||
376 | } else { | ||
377 | static int once; | ||
378 | |||
379 | saved = tracecmd_peek_data(handle, cpu); | ||
380 | set_cpu_to_time(cpu, ginfo, ts); | ||
381 | t2record = tracecmd_read_data(handle, cpu); | ||
382 | trecord = tracecmd_read_prev(handle, t2record); | ||
383 | free_record(t2record); | ||
384 | /* reset cursor back to what it was */ | ||
385 | if (saved) | ||
386 | tracecmd_set_cursor(handle, cpu, saved->offset); | ||
387 | else { | ||
388 | saved = tracecmd_read_data(handle, cpu); | ||
389 | if (!once && saved) { | ||
390 | once++; | ||
391 | warning("failed to reset cursor to end!"); | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | if (!trecord) | ||
396 | continue; | ||
397 | |||
398 | if (record_matches_pid(ginfo, trecord, pid, &rec_pid, | ||
399 | &sched_pid, &is_sched, &is_wakeup) && | ||
400 | !is_wakeup && | ||
401 | (!is_sched || (is_sched && sched_pid == pid))) { | ||
402 | task_info->last_records[cpu] = trecord; | ||
403 | task_info->last_cpu = trecord->cpu; | ||
404 | task_info->last_time = trecord->ts; | ||
405 | break; | ||
406 | } | ||
407 | |||
408 | free_record(trecord); | ||
409 | } | ||
410 | } | ||
411 | |||
324 | static int task_plot_event(struct graph_info *ginfo, | 412 | static int task_plot_event(struct graph_info *ginfo, |
325 | struct graph_plot *plot, | 413 | struct graph_plot *plot, |
326 | struct record *record, | 414 | struct record *record, |
@@ -333,10 +421,12 @@ static int task_plot_event(struct graph_info *ginfo, | |||
333 | int is_wakeup; | 421 | int is_wakeup; |
334 | int is_sched; | 422 | int is_sched; |
335 | int pid; | 423 | int pid; |
424 | int cpu; | ||
336 | 425 | ||
337 | pid = task_info->pid; | 426 | pid = task_info->pid; |
338 | 427 | ||
339 | if (!record) { | 428 | if (!record) { |
429 | update_last_record(ginfo, task_info, record); | ||
340 | /* no more records, finish a box if one was started */ | 430 | /* no more records, finish a box if one was started */ |
341 | if (task_info->last_cpu >= 0) { | 431 | if (task_info->last_cpu >= 0) { |
342 | info->box = TRUE; | 432 | info->box = TRUE; |
@@ -344,20 +434,39 @@ static int task_plot_event(struct graph_info *ginfo, | |||
344 | info->bend = ginfo->view_end_time; | 434 | info->bend = ginfo->view_end_time; |
345 | info->bcolor = hash_cpu(task_info->last_cpu); | 435 | info->bcolor = hash_cpu(task_info->last_cpu); |
346 | } | 436 | } |
437 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
438 | free_record(task_info->last_records[cpu]); | ||
439 | task_info->last_records[cpu] = NULL; | ||
440 | } | ||
347 | return 0; | 441 | return 0; |
348 | } | 442 | } |
349 | 443 | ||
350 | match = record_matches_pid(ginfo, record, pid, &rec_pid, | 444 | match = record_matches_pid(ginfo, record, pid, &rec_pid, |
351 | &sched_pid, &is_sched, &is_wakeup); | 445 | &sched_pid, &is_sched, &is_wakeup); |
352 | 446 | ||
353 | if (!match && record->cpu != task_info->last_cpu) | 447 | |
448 | if (!match && record->cpu != task_info->last_cpu) { | ||
449 | if (!task_info->last_records[record->cpu]) { | ||
450 | task_info->last_records[record->cpu] = record; | ||
451 | tracecmd_record_ref(record); | ||
452 | } | ||
354 | return 0; | 453 | return 0; |
454 | } | ||
355 | 455 | ||
356 | if (match) { | 456 | if (match) { |
357 | info->line = TRUE; | 457 | info->line = TRUE; |
358 | info->lcolor = hash_pid(rec_pid); | 458 | info->lcolor = hash_pid(rec_pid); |
359 | info->ltime = record->ts; | 459 | info->ltime = record->ts; |
360 | 460 | ||
461 | /* | ||
462 | * Is this our first match? | ||
463 | * | ||
464 | * If last record is NULL, then it may exist off the | ||
465 | * viewable range. Search to see if one exists, and if | ||
466 | * it is the record we want to match. | ||
467 | */ | ||
468 | update_last_record(ginfo, task_info, record); | ||
469 | |||
361 | if (is_wakeup) { | 470 | if (is_wakeup) { |
362 | /* Wake up but not task */ | 471 | /* Wake up but not task */ |
363 | info->ltime = hash_pid(rec_pid); | 472 | info->ltime = hash_pid(rec_pid); |
@@ -424,6 +533,12 @@ static int task_plot_event(struct graph_info *ginfo, | |||
424 | return 1; | 533 | return 1; |
425 | } | 534 | } |
426 | 535 | ||
536 | cpu = record->cpu; | ||
537 | |||
538 | if (!task_info->last_records[cpu]) { | ||
539 | free_record(task_info->last_records[cpu]); | ||
540 | task_info->last_records[cpu] = record; | ||
541 | } | ||
427 | /* not a match, and on the last CPU, scheduled out? */ | 542 | /* not a match, and on the last CPU, scheduled out? */ |
428 | if (task_info->last_cpu >= 0) { | 543 | if (task_info->last_cpu >= 0) { |
429 | info->box = TRUE; | 544 | info->box = TRUE; |
@@ -571,7 +686,9 @@ int task_plot_display_info(struct graph_info *ginfo, | |||
571 | struct pevent *pevent; | 686 | struct pevent *pevent; |
572 | unsigned long sec, usec; | 687 | unsigned long sec, usec; |
573 | const char *comm; | 688 | const char *comm; |
689 | int cpu; | ||
574 | int type; | 690 | int type; |
691 | int sched_pid = -1; | ||
575 | int pid; | 692 | int pid; |
576 | 693 | ||
577 | pid = task_info->pid; | 694 | pid = task_info->pid; |
@@ -582,7 +699,7 @@ int task_plot_display_info(struct graph_info *ginfo, | |||
582 | pevent = ginfo->pevent; | 699 | pevent = ginfo->pevent; |
583 | 700 | ||
584 | pid = pevent_data_pid(ginfo->pevent, record); | 701 | pid = pevent_data_pid(ginfo->pevent, record); |
585 | comm = pevent_data_comm_from_pid(ginfo->pevent, pid); | 702 | cpu = record->cpu; |
586 | 703 | ||
587 | convert_nano(record->ts, &sec, &usec); | 704 | convert_nano(record->ts, &sec, &usec); |
588 | 705 | ||
@@ -600,16 +717,12 @@ int task_plot_display_info(struct graph_info *ginfo, | |||
600 | trace_seq_putc(s, '\n'); | 717 | trace_seq_putc(s, '\n'); |
601 | } else | 718 | } else |
602 | trace_seq_printf(s, "UNKNOW EVENT %d\n", type); | 719 | trace_seq_printf(s, "UNKNOW EVENT %d\n", type); |
603 | } else { | ||
604 | if (record->ts < time) | ||
605 | trace_graph_check_sched_switch(ginfo, record, &pid, &comm); | ||
606 | } | 720 | } |
721 | trace_graph_check_sched_switch(ginfo, record, &sched_pid, &comm); | ||
607 | 722 | ||
608 | trace_seq_printf(s, "%lu.%06lu", sec, usec); | 723 | trace_seq_printf(s, "%lu.%06lu", sec, usec); |
609 | if (pid) | 724 | if (pid == task_info->pid || sched_pid == task_info->pid) |
610 | trace_seq_printf(s, " %s-%d", comm, pid); | 725 | trace_seq_printf(s, " CPU: %03d", cpu); |
611 | else | ||
612 | trace_seq_puts(s, " <idle>"); | ||
613 | 726 | ||
614 | free_record(record); | 727 | free_record(record); |
615 | 728 | ||
@@ -622,6 +735,7 @@ void task_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) | |||
622 | 735 | ||
623 | trace_graph_plot_remove_all_recs(ginfo, plot); | 736 | trace_graph_plot_remove_all_recs(ginfo, plot); |
624 | 737 | ||
738 | free(task_info->last_records); | ||
625 | free(task_info); | 739 | free(task_info); |
626 | } | 740 | } |
627 | 741 | ||
@@ -740,6 +854,8 @@ void graph_plot_init_tasks(struct graph_info *ginfo) | |||
740 | } | 854 | } |
741 | 855 | ||
742 | task_info = malloc_or_die(sizeof(*task_info)); | 856 | task_info = malloc_or_die(sizeof(*task_info)); |
857 | task_info->last_records = | ||
858 | malloc_or_die(sizeof(struct record *) * ginfo->cpus); | ||
743 | task_info->pid = pid; | 859 | task_info->pid = pid; |
744 | 860 | ||
745 | snprintf(label, 100, "TASK %d", pid); | 861 | snprintf(label, 100, "TASK %d", pid); |
@@ -756,6 +872,8 @@ void graph_plot_task(struct graph_info *ginfo, int pid, int pos) | |||
756 | int len; | 872 | int len; |
757 | 873 | ||
758 | task_info = malloc_or_die(sizeof(*task_info)); | 874 | task_info = malloc_or_die(sizeof(*task_info)); |
875 | task_info->last_records = | ||
876 | malloc_or_die(sizeof(struct record *) * ginfo->cpus); | ||
759 | task_info->pid = pid; | 877 | task_info->pid = pid; |
760 | comm = pevent_data_comm_from_pid(ginfo->pevent, pid); | 878 | comm = pevent_data_comm_from_pid(ginfo->pevent, pid); |
761 | 879 | ||