diff options
-rw-r--r-- | trace-plot-cpu.c | 32 | ||||
-rw-r--r-- | trace-plot-task.c | 126 |
2 files changed, 143 insertions, 15 deletions
diff --git a/trace-plot-cpu.c b/trace-plot-cpu.c index 09b1690..d6800ef 100644 --- a/trace-plot-cpu.c +++ b/trace-plot-cpu.c | |||
@@ -27,6 +27,7 @@ struct cpu_plot_info { | |||
27 | int cpu; | 27 | int cpu; |
28 | unsigned long long last_time; | 28 | unsigned long long last_time; |
29 | int last_pid; | 29 | int last_pid; |
30 | struct record *last_record; | ||
30 | }; | 31 | }; |
31 | 32 | ||
32 | static gint hash_pid(gint val) | 33 | static gint hash_pid(gint val) |
@@ -192,6 +193,7 @@ static void cpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot, | |||
192 | cpu = cpu_info->cpu; | 193 | cpu = cpu_info->cpu; |
193 | cpu_info->last_time = 0ULL; | 194 | cpu_info->last_time = 0ULL; |
194 | cpu_info->last_pid = -1; | 195 | cpu_info->last_pid = -1; |
196 | cpu_info->last_record = NULL; | ||
195 | } | 197 | } |
196 | 198 | ||
197 | static int cpu_plot_event(struct graph_info *ginfo, | 199 | static int cpu_plot_event(struct graph_info *ginfo, |
@@ -200,6 +202,7 @@ static int cpu_plot_event(struct graph_info *ginfo, | |||
200 | struct plot_info *info) | 202 | struct plot_info *info) |
201 | { | 203 | { |
202 | struct cpu_plot_info *cpu_info = plot->private; | 204 | struct cpu_plot_info *cpu_info = plot->private; |
205 | struct tracecmd_input *handle = ginfo->handle; | ||
203 | int sched_pid; | 206 | int sched_pid; |
204 | int orig_pid; | 207 | int orig_pid; |
205 | int is_sched_switch; | 208 | int is_sched_switch; |
@@ -212,6 +215,11 @@ static int cpu_plot_event(struct graph_info *ginfo, | |||
212 | cpu = cpu_info->cpu; | 215 | cpu = cpu_info->cpu; |
213 | 216 | ||
214 | if (!record) { | 217 | if (!record) { |
218 | if (cpu_info->last_record) { | ||
219 | free_record(cpu_info->last_record); | ||
220 | cpu_info->last_record = NULL; | ||
221 | } | ||
222 | |||
215 | /* Finish a box if the last record was not idle */ | 223 | /* Finish a box if the last record was not idle */ |
216 | if (cpu_info->last_pid > 0) { | 224 | if (cpu_info->last_pid > 0) { |
217 | info->box = TRUE; | 225 | info->box = TRUE; |
@@ -222,6 +230,30 @@ static int cpu_plot_event(struct graph_info *ginfo, | |||
222 | return 0; | 230 | return 0; |
223 | } | 231 | } |
224 | 232 | ||
233 | /* | ||
234 | * If last record is NULL, then it may exist off the | ||
235 | * viewable range. Search to see if one exists. | ||
236 | */ | ||
237 | if (!cpu_info->last_record) { | ||
238 | struct record *trecord; | ||
239 | |||
240 | trecord = tracecmd_read_prev(handle, record); | ||
241 | if (trecord) { | ||
242 | filter = filter_record(ginfo, trecord, | ||
243 | &orig_pid, &sched_pid, | ||
244 | &is_sched_switch); | ||
245 | cpu_info->last_pid = is_sched_switch ? sched_pid : orig_pid; | ||
246 | } | ||
247 | cpu_info->last_record = trecord; | ||
248 | /* We moved the cursor, put it back */ | ||
249 | trecord = tracecmd_read_data(handle, record->cpu); | ||
250 | free_record(trecord); | ||
251 | } | ||
252 | |||
253 | free_record(cpu_info->last_record); | ||
254 | cpu_info->last_record = record; | ||
255 | tracecmd_record_ref(record); | ||
256 | |||
225 | cpu = cpu_info->cpu; | 257 | cpu = cpu_info->cpu; |
226 | 258 | ||
227 | filter = filter_record(ginfo, record, &orig_pid, &sched_pid, &is_sched_switch); | 259 | filter = filter_record(ginfo, record, &orig_pid, &sched_pid, &is_sched_switch); |
diff --git a/trace-plot-task.c b/trace-plot-task.c index c8d0905..aac771e 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; |
@@ -104,26 +105,31 @@ static gboolean record_matches_pid(struct graph_info *ginfo, | |||
104 | return FALSE; | 105 | return FALSE; |
105 | } | 106 | } |
106 | 107 | ||
107 | static void set_cpus_to_time(struct graph_info *ginfo, unsigned long long time) | 108 | static void set_cpu_to_time(int cpu, struct graph_info *ginfo, unsigned long long time) |
108 | { | 109 | { |
109 | struct record *record; | 110 | struct record *record; |
110 | int cpu; | ||
111 | 111 | ||
112 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | 112 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time); |
113 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time); | ||
114 | 113 | ||
115 | while ((record = tracecmd_read_data(ginfo->handle, cpu))) { | 114 | while ((record = tracecmd_read_data(ginfo->handle, cpu))) { |
116 | if (record->ts >= time) | 115 | if (record->ts >= time) |
117 | break; | 116 | break; |
118 | 117 | ||
119 | free_record(record); | 118 | 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 | } | 119 | } |
120 | if (record) { | ||
121 | tracecmd_set_cursor(ginfo->handle, cpu, record->offset); | ||
122 | free_record(record); | ||
123 | } else | ||
124 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, time); | ||
125 | } | ||
126 | |||
127 | static void set_cpus_to_time(struct graph_info *ginfo, unsigned long long time) | ||
128 | { | ||
129 | int cpu; | ||
130 | |||
131 | for (cpu = 0; cpu < ginfo->cpus; cpu++) | ||
132 | set_cpu_to_time(cpu, ginfo, time); | ||
127 | } | 133 | } |
128 | 134 | ||
129 | static int task_plot_match_time(struct graph_info *ginfo, struct graph_plot *plot, | 135 | static int task_plot_match_time(struct graph_info *ginfo, struct graph_plot *plot, |
@@ -315,6 +321,8 @@ static void task_plot_start(struct graph_info *ginfo, struct graph_plot *plot, | |||
315 | { | 321 | { |
316 | struct task_plot_info *task_info = plot->private; | 322 | struct task_plot_info *task_info = plot->private; |
317 | 323 | ||
324 | memset(task_info->last_records, 0, sizeof(struct record *) * ginfo->cpus); | ||
325 | |||
318 | task_info->last_time = 0ULL; | 326 | task_info->last_time = 0ULL; |
319 | task_info->last_cpu = -1; | 327 | task_info->last_cpu = -1; |
320 | task_info->wake_time = 0ULL; | 328 | task_info->wake_time = 0ULL; |
@@ -327,16 +335,22 @@ static int task_plot_event(struct graph_info *ginfo, | |||
327 | struct plot_info *info) | 335 | struct plot_info *info) |
328 | { | 336 | { |
329 | struct task_plot_info *task_info = plot->private; | 337 | struct task_plot_info *task_info = plot->private; |
338 | struct tracecmd_input *handle = ginfo->handle; | ||
330 | gboolean match; | 339 | gboolean match; |
331 | int sched_pid; | 340 | int sched_pid; |
332 | int rec_pid; | 341 | int rec_pid; |
333 | int is_wakeup; | 342 | int is_wakeup; |
334 | int is_sched; | 343 | int is_sched; |
335 | int pid; | 344 | int pid; |
345 | int cpu; | ||
336 | 346 | ||
337 | pid = task_info->pid; | 347 | pid = task_info->pid; |
338 | 348 | ||
339 | if (!record) { | 349 | if (!record) { |
350 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
351 | free_record(task_info->last_records[cpu]); | ||
352 | task_info->last_records[cpu] = NULL; | ||
353 | } | ||
340 | /* no more records, finish a box if one was started */ | 354 | /* no more records, finish a box if one was started */ |
341 | if (task_info->last_cpu >= 0) { | 355 | if (task_info->last_cpu >= 0) { |
342 | info->box = TRUE; | 356 | info->box = TRUE; |
@@ -350,14 +364,85 @@ static int task_plot_event(struct graph_info *ginfo, | |||
350 | match = record_matches_pid(ginfo, record, pid, &rec_pid, | 364 | match = record_matches_pid(ginfo, record, pid, &rec_pid, |
351 | &sched_pid, &is_sched, &is_wakeup); | 365 | &sched_pid, &is_sched, &is_wakeup); |
352 | 366 | ||
353 | if (!match && record->cpu != task_info->last_cpu) | 367 | |
368 | if (!match && record->cpu != task_info->last_cpu) { | ||
369 | if (!task_info->last_records[record->cpu]) { | ||
370 | task_info->last_records[record->cpu] = record; | ||
371 | tracecmd_record_ref(record); | ||
372 | } | ||
354 | return 0; | 373 | return 0; |
374 | } | ||
355 | 375 | ||
356 | if (match) { | 376 | if (match) { |
357 | info->line = TRUE; | 377 | info->line = TRUE; |
358 | info->lcolor = hash_pid(rec_pid); | 378 | info->lcolor = hash_pid(rec_pid); |
359 | info->ltime = record->ts; | 379 | info->ltime = record->ts; |
360 | 380 | ||
381 | /* | ||
382 | * Is this our first match? | ||
383 | * | ||
384 | * If last record is NULL, then it may exist off the | ||
385 | * viewable range. Search to see if one exists, and if | ||
386 | * it is the record we want to match. | ||
387 | */ | ||
388 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
389 | struct record *trecord, *t2record; | ||
390 | struct record *saved; | ||
391 | int this_cpu = record->cpu; | ||
392 | int tsched_pid; | ||
393 | int tpid; | ||
394 | int tis_wakeup; | ||
395 | int tis_sched; | ||
396 | |||
397 | if (task_info->last_records[cpu]) | ||
398 | continue; | ||
399 | |||
400 | if (cpu == this_cpu) { | ||
401 | static int once; | ||
402 | |||
403 | trecord = tracecmd_read_prev(handle, record); | ||
404 | /* Set cpu cursor back to what it was */ | ||
405 | saved = tracecmd_read_data(handle, cpu); | ||
406 | if (!once && saved->offset != record->offset) { | ||
407 | once++; | ||
408 | warning("failed to reset cursor!"); | ||
409 | } | ||
410 | free_record(saved); | ||
411 | } else { | ||
412 | static int once; | ||
413 | |||
414 | saved = tracecmd_peek_data(handle, cpu); | ||
415 | set_cpu_to_time(cpu, ginfo, record->ts); | ||
416 | t2record = tracecmd_read_data(handle, cpu); | ||
417 | trecord = tracecmd_read_prev(handle, t2record); | ||
418 | free_record(t2record); | ||
419 | /* reset cursor back to what it was */ | ||
420 | if (saved) | ||
421 | tracecmd_set_cursor(handle, cpu, saved->offset); | ||
422 | else { | ||
423 | saved = tracecmd_read_data(handle, cpu); | ||
424 | if (!once && saved) { | ||
425 | once++; | ||
426 | warning("failed to reset cursor to end!"); | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | if (!trecord) | ||
431 | continue; | ||
432 | |||
433 | if (record_matches_pid(ginfo, trecord, pid, &tpid, | ||
434 | &tsched_pid, &tis_sched, &tis_wakeup) && | ||
435 | !tis_wakeup && | ||
436 | (!is_sched || (is_sched && sched_pid == pid))) { | ||
437 | task_info->last_records[cpu] = trecord; | ||
438 | task_info->last_cpu = trecord->cpu; | ||
439 | task_info->last_time = trecord->ts; | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | free_record(trecord); | ||
444 | } | ||
445 | |||
361 | if (is_wakeup) { | 446 | if (is_wakeup) { |
362 | /* Wake up but not task */ | 447 | /* Wake up but not task */ |
363 | info->ltime = hash_pid(rec_pid); | 448 | info->ltime = hash_pid(rec_pid); |
@@ -424,6 +509,12 @@ static int task_plot_event(struct graph_info *ginfo, | |||
424 | return 1; | 509 | return 1; |
425 | } | 510 | } |
426 | 511 | ||
512 | cpu = record->cpu; | ||
513 | |||
514 | if (!task_info->last_records[cpu]) { | ||
515 | free_record(task_info->last_records[cpu]); | ||
516 | task_info->last_records[cpu] = record; | ||
517 | } | ||
427 | /* not a match, and on the last CPU, scheduled out? */ | 518 | /* not a match, and on the last CPU, scheduled out? */ |
428 | if (task_info->last_cpu >= 0) { | 519 | if (task_info->last_cpu >= 0) { |
429 | info->box = TRUE; | 520 | info->box = TRUE; |
@@ -622,6 +713,7 @@ void task_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) | |||
622 | 713 | ||
623 | trace_graph_plot_remove_all_recs(ginfo, plot); | 714 | trace_graph_plot_remove_all_recs(ginfo, plot); |
624 | 715 | ||
716 | free(task_info->last_records); | ||
625 | free(task_info); | 717 | free(task_info); |
626 | } | 718 | } |
627 | 719 | ||
@@ -740,6 +832,8 @@ void graph_plot_init_tasks(struct graph_info *ginfo) | |||
740 | } | 832 | } |
741 | 833 | ||
742 | task_info = malloc_or_die(sizeof(*task_info)); | 834 | task_info = malloc_or_die(sizeof(*task_info)); |
835 | task_info->last_records = | ||
836 | malloc_or_die(sizeof(struct record *) * ginfo->cpus); | ||
743 | task_info->pid = pid; | 837 | task_info->pid = pid; |
744 | 838 | ||
745 | snprintf(label, 100, "TASK %d", pid); | 839 | snprintf(label, 100, "TASK %d", pid); |
@@ -756,6 +850,8 @@ void graph_plot_task(struct graph_info *ginfo, int pid, int pos) | |||
756 | int len; | 850 | int len; |
757 | 851 | ||
758 | task_info = malloc_or_die(sizeof(*task_info)); | 852 | task_info = malloc_or_die(sizeof(*task_info)); |
853 | task_info->last_records = | ||
854 | malloc_or_die(sizeof(struct record *) * ginfo->cpus); | ||
759 | task_info->pid = pid; | 855 | task_info->pid = pid; |
760 | comm = pevent_data_comm_from_pid(ginfo->pevent, pid); | 856 | comm = pevent_data_comm_from_pid(ginfo->pevent, pid); |
761 | 857 | ||