diff options
Diffstat (limited to 'rt-plot.c')
-rw-r--r-- | rt-plot.c | 178 |
1 files changed, 73 insertions, 105 deletions
@@ -28,15 +28,15 @@ void insert_record(struct graph_info *ginfo, struct record_list *list, | |||
28 | 28 | ||
29 | while (pos->next) { | 29 | while (pos->next) { |
30 | unsigned long long next_rts = get_rts(ginfo, pos->next->record); | 30 | unsigned long long next_rts = get_rts(ginfo, pos->next->record); |
31 | if (( reverse && !next_rts > get_rts(ginfo, record)) || | 31 | if (( reverse && next_rts < get_rts(ginfo, record)) || |
32 | (!reverse && next_rts < get_rts(ginfo, record))){ | 32 | (!reverse && next_rts > get_rts(ginfo, record))){ |
33 | break; | 33 | break; |
34 | } | 34 | } |
35 | pos = pos->next; | 35 | pos = pos->next; |
36 | } | 36 | } |
37 | 37 | ||
38 | node->next = pos->next; | 38 | node->next = pos->next; |
39 | pos->next = node; | 39 | pos->next = node; |
40 | } | 40 | } |
41 | 41 | ||
42 | 42 | ||
@@ -53,7 +53,7 @@ int pop_record(struct graph_info *ginfo, struct record_list *list, | |||
53 | list->next = list->next->next; | 53 | list->next = list->next->next; |
54 | (*node)->next = 0; | 54 | (*node)->next = 0; |
55 | 55 | ||
56 | return 1; | 56 | return 1; |
57 | } | 57 | } |
58 | 58 | ||
59 | 59 | ||
@@ -91,7 +91,7 @@ prev_release_iterator(struct graph_info *ginfo, struct record *rec, void *data) | |||
91 | *(args->out_job) = job; | 91 | *(args->out_job) = job; |
92 | *(args->out_release) = release; | 92 | *(args->out_release) = release; |
93 | *(args->out_deadline) = deadline; | 93 | *(args->out_deadline) = deadline; |
94 | 94 | ||
95 | /* Cache to minimize work later */ | 95 | /* Cache to minimize work later */ |
96 | args->common->last_job.no = job; | 96 | args->common->last_job.no = job; |
97 | args->common->last_job.release = release; | 97 | args->common->last_job.release = release; |
@@ -122,14 +122,14 @@ prev_display_iterator(struct graph_info *ginfo, struct record *record, void *dat | |||
122 | if (get_rts(ginfo, record) < args->min_ts) { | 122 | if (get_rts(ginfo, record) < args->min_ts) { |
123 | return 0; | 123 | return 0; |
124 | } | 124 | } |
125 | 125 | ||
126 | eid = pevent_data_type(ginfo->pevent, record); | 126 | eid = pevent_data_type(ginfo->pevent, record); |
127 | ignored = (eid == ginfo->event_sched_switch_id); | 127 | ignored = (eid == ginfo->event_sched_switch_id); |
128 | 128 | ||
129 | if (!ignored) { | 129 | if (!ignored) { |
130 | ignored = args->common->is_drawn(ginfo, eid); | 130 | ignored = args->common->is_drawn(ginfo, eid); |
131 | } | 131 | } |
132 | 132 | ||
133 | if (!ignored && args->common->record_matches(args->common, ginfo, record)) { | 133 | if (!ignored && args->common->record_matches(args->common, ginfo, record)) { |
134 | args->result = record; | 134 | args->result = record; |
135 | ++record->ref_count; | 135 | ++record->ref_count; |
@@ -147,8 +147,6 @@ static struct record* | |||
147 | find_prev_display_record(struct graph_info *ginfo, struct rt_plot_common *rt_info, | 147 | find_prev_display_record(struct graph_info *ginfo, struct rt_plot_common *rt_info, |
148 | unsigned long long time, unsigned long long range) | 148 | unsigned long long time, unsigned long long range) |
149 | { | 149 | { |
150 | int eid, ignored, match, cpu; | ||
151 | struct record *prev, *next, *res = NULL; | ||
152 | struct prev_display_args args = {rt_info, NULL, 0}; | 150 | struct prev_display_args args = {rt_info, NULL, 0}; |
153 | 151 | ||
154 | if (range) { | 152 | if (range) { |
@@ -342,98 +340,64 @@ rt_plot_match_time(struct graph_info *ginfo, struct graph_plot *plot, | |||
342 | return ret; | 340 | return ret; |
343 | } | 341 | } |
344 | 342 | ||
345 | |||
346 | |||
347 | /** | 343 | /** |
348 | * next_rts - find a real-time timestamp AROUND an FTRACE time | 344 | * set_cpu_to_rts - seek CPU to a time closely preceding a real-time timestamp. |
349 | * @ginfo: Current state of the graph | ||
350 | * @cpu: CPU to search | ||
351 | * @ft_target: FTRACE time to seek towards | ||
352 | * | ||
353 | * Returns the RT time of a record CLOSELY BEFORE @ft_time. | ||
354 | */ | ||
355 | unsigned long long | ||
356 | next_rts(struct graph_info *ginfo, int cpu, unsigned long long ft_target) | ||
357 | { | ||
358 | struct record *record; | ||
359 | unsigned long long ts = 0ULL; | ||
360 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, ft_target); | ||
361 | record = tracecmd_read_data(ginfo->handle, cpu); | ||
362 | if (record) { | ||
363 | ts = get_rts(ginfo, record); | ||
364 | free_record(record); | ||
365 | return ts; | ||
366 | } else | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | /** | ||
371 | * set_cpu_to_rts - seek CPU to a time closely preceding a real-time timestamp | ||
372 | * @ginfo: Current state o the graph | ||
373 | * @cpu: The CPU to seek | 345 | * @cpu: The CPU to seek |
374 | * @rt_target: RT time to seek towards | 346 | * @rt_target: RT time to seek towards |
375 | * | 347 | * |
376 | * This seeks to a real-time timestamp, not the default ftrace timestamps. | 348 | * This seeks to a real-time timestamp, not the default ftrace timestamps. |
377 | * The @cpu seek location will be placed before the given time, but will | 349 | * The @cpu seek location will be placed on the last record whose timestamp |
378 | * not necessarily be placed _right_ before the time. | 350 | * is less than @rt_target. |
379 | */ | 351 | */ |
380 | unsigned long long | 352 | long long correction = 0; |
381 | set_cpu_to_rts(struct graph_info *ginfo, unsigned long long rt_target, int cpu) | 353 | unsigned long long set_cpu_to_rts(struct graph_info *ginfo, |
354 | unsigned long long rt_target, int cpu) | ||
382 | { | 355 | { |
383 | struct record *record; | 356 | struct record *record, *last_record; |
384 | unsigned long long last_rts, rts, seek_time, last_seek; | 357 | unsigned long long rts, seek_time; |
385 | long long diff; | 358 | long long next_diff; |
386 | 359 | ||
387 | rts = next_rts(ginfo, cpu, rt_target); | 360 | seek_time = rt_target + correction; |
388 | diff = rt_target - rts; | 361 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, seek_time); |
389 | 362 | ||
390 | /* "Guess" a new target based on difference */ | 363 | last_record = tracecmd_read_data(ginfo->handle, cpu); |
391 | seek_time = rt_target + diff; | 364 | rts = get_rts(ginfo, last_record); |
392 | rts = next_rts(ginfo, cpu, seek_time); | 365 | if (rts < rt_target) { |
393 | diff = rt_target - rts; | 366 | while ((record = tracecmd_read_data(ginfo->handle, cpu))) { |
394 | 367 | if (get_rts(ginfo, record) >= rt_target) { | |
395 | /* Zero in in 1.5x the difference increments */ | 368 | free_record(record); |
396 | if (rts && diff > 0) { | 369 | break; |
397 | /* rts rt_target | real-time time | 370 | } |
398 | * seek ? | trace-cmd time | 371 | free_record(last_record); |
399 | * ---|---->>----|-------- | 372 | last_record = record; |
400 | */ | 373 | } |
401 | do { | 374 | } else if (rts > rt_target) { |
402 | last_seek = seek_time; | 375 | while ((record = tracecmd_read_prev(ginfo->handle, last_record))) { |
403 | last_rts = rts; | 376 | if (get_rts(ginfo, record) <= rt_target) { |
404 | seek_time = seek_time + 1.5 * (rt_target - rts); | 377 | free_record(last_record); |
405 | rts = next_rts(ginfo, cpu, seek_time); | 378 | last_record = record; |
406 | } while (rts < rt_target && last_rts != rts); | 379 | break; |
407 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, last_seek); | 380 | } |
408 | seek_time = last_seek; | 381 | free_record(last_record); |
409 | } else if (rts && diff < 0) { | 382 | last_record = record; |
410 | /* rt_target rts | real-time time | 383 | } |
411 | * ? seek | trace-cmd time | ||
412 | * ---|----<<----|-------- | ||
413 | */ | ||
414 | do { | ||
415 | seek_time = seek_time - 1.5 * (rts - rt_target); | ||
416 | last_rts = rts; | ||
417 | rts = next_rts(ginfo, cpu, seek_time); | ||
418 | } while (rts > rt_target && rts != last_rts); | ||
419 | } | 384 | } |
420 | 385 | ||
421 | /* Get to first record at or after time */ | 386 | if (last_record) { |
422 | while ((record = tracecmd_read_data(ginfo->handle, cpu))) { | 387 | next_diff = (last_record->ts - rt_target); |
423 | if (get_rts(ginfo, record) >= rt_target) | 388 | if (correction) |
424 | break; | 389 | correction = correction *3/ 4 + (next_diff) / 4; |
425 | free_record(record); | 390 | else |
391 | correction = next_diff; | ||
392 | tracecmd_set_cursor(ginfo->handle, cpu, last_record->offset); | ||
393 | free_record(last_record); | ||
426 | } | 394 | } |
427 | if (record) { | 395 | |
428 | tracecmd_set_cursor(ginfo->handle, cpu, record->offset); | ||
429 | free_record(record); | ||
430 | } else | ||
431 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, seek_time); | ||
432 | return rts; | 396 | return rts; |
433 | } | 397 | } |
434 | 398 | ||
435 | /** | 399 | /** |
436 | * set_cpus_to_time - seek all cpus to real-time @rt_target | 400 | * set_cpus_to_time - seek all cpus to real-time @rt_target. |
437 | */ | 401 | */ |
438 | unsigned long long set_cpus_to_rts(struct graph_info *ginfo, unsigned long long rt_target) | 402 | unsigned long long set_cpus_to_rts(struct graph_info *ginfo, unsigned long long rt_target) |
439 | { | 403 | { |
@@ -491,6 +455,9 @@ int is_task_running(struct graph_info *ginfo, | |||
491 | return running; | 455 | return running; |
492 | } | 456 | } |
493 | 457 | ||
458 | /** | ||
459 | * iterate - pass records in real-time timestamp order to @cb. | ||
460 | */ | ||
494 | void iterate(struct graph_info *ginfo, int reverse, iterate_cb cb, void *data) | 461 | void iterate(struct graph_info *ginfo, int reverse, iterate_cb cb, void *data) |
495 | { | 462 | { |
496 | int proceed, cpu; | 463 | int proceed, cpu; |
@@ -502,47 +469,48 @@ void iterate(struct graph_info *ginfo, int reverse, iterate_cb cb, void *data) | |||
502 | memset(nodes, 0, sizeof(*nodes) * ginfo->cpus); | 469 | memset(nodes, 0, sizeof(*nodes) * ginfo->cpus); |
503 | memset(&list, 0, sizeof(list)); | 470 | memset(&list, 0, sizeof(list)); |
504 | 471 | ||
505 | /* Maintains a list of the next record on each cpu, sorted by | 472 | /* Start with the first record on each CPU */ |
506 | * timestamp. Start with the first record on each cpu. | ||
507 | */ | ||
508 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | 473 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { |
509 | next = tracecmd_peek_data(ginfo->handle, cpu); | 474 | next = tracecmd_peek_data(ginfo->handle, cpu); |
510 | if (next) { | 475 | if (next) { |
511 | if (reverse) { | 476 | if (reverse) { |
477 | /* Reading backwards is clumsy...*/ | ||
512 | prev = next; | 478 | prev = next; |
513 | next = tracecmd_read_prev(ginfo->handle, prev); | 479 | next = tracecmd_read_prev(ginfo->handle, prev); |
514 | if (prev != next && prev->data) { | 480 | if (prev != next && prev->data) |
515 | free_record(prev); | 481 | free_record(prev); |
516 | } | 482 | } else { |
483 | next = tracecmd_read_data(ginfo->handle, cpu); | ||
517 | } | 484 | } |
518 | insert_record(ginfo, &list, next, &nodes[cpu], reverse); | 485 | insert_record(ginfo, &list, next, &nodes[cpu], reverse); |
519 | } | 486 | } |
520 | } | 487 | } |
521 | 488 | ||
522 | /* Read sequentially from all cpus */ | 489 | /* Read record with the next timestamp until the callback is finished |
490 | * consuming data | ||
491 | */ | ||
523 | while (pop_record(ginfo, &list, &node)) { | 492 | while (pop_record(ginfo, &list, &node)) { |
524 | next = node->record; | 493 | next = node->record; |
525 | 494 | ||
495 | /* Pass records into callback */ | ||
526 | proceed = cb(ginfo, next, data); | 496 | proceed = cb(ginfo, next, data); |
527 | |||
528 | if (!proceed) { | 497 | if (!proceed) { |
529 | free_record(next); | 498 | free_record(next); |
530 | break; | 499 | break; |
531 | } | 500 | } |
532 | 501 | ||
502 | /* Replace this record with the next record from the same CPU */ | ||
533 | prev = next; | 503 | prev = next; |
534 | 504 | if (!reverse) | |
535 | if (!reverse) { | ||
536 | next = tracecmd_read_data(ginfo->handle, next->cpu); | 505 | next = tracecmd_read_data(ginfo->handle, next->cpu); |
537 | } else { | 506 | else |
538 | next = tracecmd_read_prev(ginfo->handle, next); | 507 | next = tracecmd_read_prev(ginfo->handle, next); |
539 | } | ||
540 | |||
541 | free_record(prev); | 508 | free_record(prev); |
542 | 509 | if (prev != next) | |
543 | insert_record(ginfo, &list, next, node, reverse); | 510 | insert_record(ginfo, &list, next, node, reverse); |
544 | } | 511 | } |
545 | 512 | ||
513 | /* Free unused records */ | ||
546 | while (pop_record(ginfo, &list, &node)) { | 514 | while (pop_record(ginfo, &list, &node)) { |
547 | free_record(node->record); | 515 | free_record(node->record); |
548 | } | 516 | } |
@@ -550,7 +518,7 @@ void iterate(struct graph_info *ginfo, int reverse, iterate_cb cb, void *data) | |||
550 | 518 | ||
551 | 519 | ||
552 | /** | 520 | /** |
553 | * Find the information for the last release of @match_tid on @cpu before @time. | 521 | * get_previous_release - return stats for the latest release of @match_tid |
554 | * | 522 | * |
555 | * This method will NOT re-seek the CPUs near time. The caller must have placed | 523 | * This method will NOT re-seek the CPUs near time. The caller must have placed |
556 | * the CPUs near the the CPUs themselves. | 524 | * the CPUs near the the CPUs themselves. |