diff options
Diffstat (limited to 'rt-graph.c')
-rw-r--r-- | rt-graph.c | 143 |
1 files changed, 130 insertions, 13 deletions
@@ -1,7 +1,7 @@ | |||
1 | #include "rt-graph.h" | 1 | #include "trace-graph.h" |
2 | #include "trace-hash.h" | 2 | #include "trace-hash.h" |
3 | 3 | ||
4 | #define DEBUG_LEVEL 0 | 4 | #define DEBUG_LEVEL 4 |
5 | #if DEBUG_LEVEL > 0 | 5 | #if DEBUG_LEVEL > 0 |
6 | #define dprintf(l, x...) \ | 6 | #define dprintf(l, x...) \ |
7 | do { \ | 7 | do { \ |
@@ -17,6 +17,9 @@ static guint get_event_hash_key(gint eid) | |||
17 | return trace_hash(eid) % TS_HASH_SIZE; | 17 | return trace_hash(eid) % TS_HASH_SIZE; |
18 | } | 18 | } |
19 | 19 | ||
20 | /* | ||
21 | * Returns cached field for @eid at @key. | ||
22 | */ | ||
20 | struct format_field* find_ts_hash(struct ts_list **events, | 23 | struct format_field* find_ts_hash(struct ts_list **events, |
21 | gint key, gint eid) | 24 | gint key, gint eid) |
22 | { | 25 | { |
@@ -29,10 +32,11 @@ struct format_field* find_ts_hash(struct ts_list **events, | |||
29 | } | 32 | } |
30 | 33 | ||
31 | /* | 34 | /* |
32 | * Return format field for @eid, caching its location if this is the first try | 35 | * Return field for @eid at @key, caching if necessary. |
33 | */ | 36 | */ |
34 | static struct format_field* add_ts_hash(struct ts_list **events, gint eid, gint key, | 37 | static struct format_field* |
35 | struct pevent *pevent, struct record *record) | 38 | add_ts_hash(struct ts_list **events, gint eid, gint key, |
39 | struct pevent *pevent, struct record *record) | ||
36 | { | 40 | { |
37 | struct ts_list *list; | 41 | struct ts_list *list; |
38 | struct format_field *field; | 42 | struct format_field *field; |
@@ -59,16 +63,12 @@ static struct format_field* add_ts_hash(struct ts_list **events, gint eid, gint | |||
59 | */ | 63 | */ |
60 | int rt_graph_check_any(struct rt_graph_info *rtinfo, | 64 | int rt_graph_check_any(struct rt_graph_info *rtinfo, |
61 | struct pevent *pevent, struct record *record, | 65 | struct pevent *pevent, struct record *record, |
62 | gint *epid, unsigned long long *ts) | 66 | gint *epid, gint *out_eid, unsigned long long *ts) |
63 | { | 67 | { |
64 | guint key, eid; | 68 | guint key, eid; |
65 | struct format_field *field; | 69 | struct format_field *field; |
66 | 70 | ||
67 | eid = pevent_data_type(pevent, record); | 71 | eid = pevent_data_type(pevent, record); |
68 | |||
69 | if (eid == rtinfo->switch_away_id) | ||
70 | return 0; | ||
71 | |||
72 | key = get_event_hash_key(eid); | 72 | key = get_event_hash_key(eid); |
73 | field = find_ts_hash(rtinfo->events, key, eid); | 73 | field = find_ts_hash(rtinfo->events, key, eid); |
74 | 74 | ||
@@ -80,6 +80,7 @@ int rt_graph_check_any(struct rt_graph_info *rtinfo, | |||
80 | 80 | ||
81 | dprintf(3, "Read (%d) record for task %d at %llu\n", | 81 | dprintf(3, "Read (%d) record for task %d at %llu\n", |
82 | eid, *epid, *ts); | 82 | eid, *epid, *ts); |
83 | *out_eid = eid; | ||
83 | return 1; | 84 | return 1; |
84 | } | 85 | } |
85 | 86 | ||
@@ -222,7 +223,7 @@ int rt_graph_check_switch_away(struct rt_graph_info *rtinfo, | |||
222 | 223 | ||
223 | /** | 224 | /** |
224 | * rt_graph_check_task_release - check for litmus_task_release record | 225 | * rt_graph_check_task_release - check for litmus_task_release record |
225 | * Return 1 and @pid, @job, and @deadline if the record matches | 226 | * Return 1 and @pid, @job, @release, and @deadline if the record matches |
226 | */ | 227 | */ |
227 | int rt_graph_check_task_release(struct rt_graph_info *rtinfo, | 228 | int rt_graph_check_task_release(struct rt_graph_info *rtinfo, |
228 | struct pevent *pevent, struct record *record, | 229 | struct pevent *pevent, struct record *record, |
@@ -271,7 +272,7 @@ int rt_graph_check_task_release(struct rt_graph_info *rtinfo, | |||
271 | 272 | ||
272 | /** | 273 | /** |
273 | * rt_graph_check_task_completion - check for litmus_task_completion record | 274 | * rt_graph_check_task_completion - check for litmus_task_completion record |
274 | * Return 1 and @pid, @job if the record matches | 275 | * Return 1 and @pid, @job, and @ts if the record matches |
275 | */ | 276 | */ |
276 | int rt_graph_check_task_completion(struct rt_graph_info *rtinfo, | 277 | int rt_graph_check_task_completion(struct rt_graph_info *rtinfo, |
277 | struct pevent *pevent, struct record *record, | 278 | struct pevent *pevent, struct record *record, |
@@ -314,7 +315,7 @@ int rt_graph_check_task_completion(struct rt_graph_info *rtinfo, | |||
314 | 315 | ||
315 | /** | 316 | /** |
316 | * rt_graph_check_task_block - check for litmus_task_block record | 317 | * rt_graph_check_task_block - check for litmus_task_block record |
317 | * Return 1 and @pid if the record matches | 318 | * Return 1, @pid, and @ts if the record matches |
318 | */ | 319 | */ |
319 | int rt_graph_check_task_block(struct rt_graph_info *rtinfo, | 320 | int rt_graph_check_task_block(struct rt_graph_info *rtinfo, |
320 | struct pevent *pevent, struct record *record, | 321 | struct pevent *pevent, struct record *record, |
@@ -431,3 +432,119 @@ void init_rt_event_cache(struct rt_graph_info *rtinfo) | |||
431 | rtinfo->resume_pid_field = NULL; | 432 | rtinfo->resume_pid_field = NULL; |
432 | rtinfo->resume_ts_field = NULL; | 433 | rtinfo->resume_ts_field = NULL; |
433 | } | 434 | } |
435 | |||
436 | /** | ||
437 | * get_rts - extract real-time timestamp from a record | ||
438 | * | ||
439 | * This will only have to extract the timestamp once; after the time | ||
440 | * is extracted it will be cached in the record itself. | ||
441 | */ | ||
442 | unsigned long long | ||
443 | get_rts(struct graph_info *ginfo, struct record *record) | ||
444 | { | ||
445 | gint epid, eid; | ||
446 | unsigned long long ts; | ||
447 | if (!record->cached_rts) { | ||
448 | rt_graph_check_any(&ginfo->rtinfo, ginfo->pevent, record, | ||
449 | &epid, &eid, &ts); | ||
450 | record->cached_rts = ts; | ||
451 | } else | ||
452 | ts = record->cached_rts; | ||
453 | return ts; | ||
454 | } | ||
455 | |||
456 | /** | ||
457 | * next_rts - find a real-time timestamp AROUND an FTRACE time | ||
458 | * @ginfo: Current state of the graph | ||
459 | * @cpu: CPU to search | ||
460 | * @ft_target: FTRACE time to seek towards | ||
461 | * | ||
462 | * Returns the RT time of a record CLOSELY BEFORE @ft_time. | ||
463 | */ | ||
464 | unsigned long long | ||
465 | next_rts(struct graph_info *ginfo, int cpu, unsigned long long ft_target) | ||
466 | { | ||
467 | struct record *record; | ||
468 | unsigned long long ts = 0ULL; | ||
469 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, ft_target); | ||
470 | record = tracecmd_read_data(ginfo->handle, cpu); | ||
471 | if (record) { | ||
472 | ts = get_rts(ginfo, record); | ||
473 | free_record(record); | ||
474 | return ts; | ||
475 | } else | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * set_cpu_to_rts - seek CPU to a time closely preceding a real-time timestamp | ||
481 | * @ginfo: Current state o the graph | ||
482 | * @cpu: The CPU to seek | ||
483 | * @rt_target: RT time to seek towards | ||
484 | * | ||
485 | * This seeks to a real-time timestamp, not the default ftrace timestamps. | ||
486 | * The @cpu seek location will be placed before the given time, but will | ||
487 | * not necessarily be placed _right_ before the time. | ||
488 | */ | ||
489 | void | ||
490 | set_cpu_to_rts(struct graph_info *ginfo, unsigned long long rt_target, int cpu) | ||
491 | { | ||
492 | struct record *record; | ||
493 | unsigned long long last_rts, rts, seek_time, last_seek; | ||
494 | long long diff; | ||
495 | |||
496 | rts = next_rts(ginfo, cpu, rt_target); | ||
497 | diff = rt_target - rts; | ||
498 | |||
499 | /* "Guess" a new target based on difference */ | ||
500 | seek_time = rt_target + diff; | ||
501 | rts = next_rts(ginfo, cpu, seek_time); | ||
502 | diff = rt_target - rts; | ||
503 | |||
504 | /* Zero in in 1.5x the difference increments */ | ||
505 | if (rts && diff > 0) { | ||
506 | /* rts rt_target | ||
507 | * seek ? | ||
508 | * ---|---->>----|--- | ||
509 | */ | ||
510 | do { | ||
511 | last_seek = seek_time; | ||
512 | last_rts = rts; | ||
513 | seek_time = seek_time + 1.5 * (rt_target - rts); | ||
514 | rts = next_rts(ginfo, cpu, seek_time); | ||
515 | } while (rts < rt_target && last_rts != rts); | ||
516 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, last_seek); | ||
517 | seek_time = last_seek; | ||
518 | } else if (rts && diff < 0) { | ||
519 | /* rt_target rts | ||
520 | * ? seek | ||
521 | * ---|----<<----|--- | ||
522 | */ | ||
523 | do { | ||
524 | seek_time = seek_time - 1.5 * (rts - rt_target); | ||
525 | rts = next_rts(ginfo, cpu, seek_time); | ||
526 | } while (rts > rt_target); | ||
527 | } | ||
528 | |||
529 | /* Get to first record at or after time */ | ||
530 | while ((record = tracecmd_read_data(ginfo->handle, cpu))) { | ||
531 | if (get_rts(ginfo, record) >= rt_target) | ||
532 | break; | ||
533 | free_record(record); | ||
534 | } | ||
535 | if (record) { | ||
536 | tracecmd_set_cursor(ginfo->handle, cpu, record->offset); | ||
537 | free_record(record); | ||
538 | } else | ||
539 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, seek_time); | ||
540 | } | ||
541 | |||
542 | /** | ||
543 | * set_cpus_to_time - seek all cpus to real-time @rt_target | ||
544 | */ | ||
545 | void set_cpus_to_rts(struct graph_info *ginfo, unsigned long long rt_target) | ||
546 | { | ||
547 | int cpu; | ||
548 | for (cpu = 0; cpu < ginfo->cpus; cpu++) | ||
549 | set_cpu_to_rts(ginfo, rt_target, cpu); | ||
550 | } | ||