diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-08-30 16:28:06 -0400 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-08-30 16:28:06 -0400 |
| commit | 129f97bd91c3f971ee4c3d09264efca1384bd9b6 (patch) | |
| tree | 6b060a9c33337f3013015b43db0333d75abb5eda | |
| parent | 15bbd1e788af29d06b3fb64cefd0e2e3cdd64a8b (diff) | |
Fixed performance / memory leak of mouse hovering
| -rw-r--r-- | kernel-shark.c | 6 | ||||
| -rw-r--r-- | rt-plot-container.c | 2 | ||||
| -rw-r--r-- | rt-plot-task.c | 17 | ||||
| -rw-r--r-- | rt-plot.c | 379 | ||||
| -rw-r--r-- | rt-plot.h | 23 | ||||
| -rw-r--r-- | trace-graph.c | 11 | ||||
| -rw-r--r-- | trace-input.c | 5 |
7 files changed, 325 insertions, 118 deletions
diff --git a/kernel-shark.c b/kernel-shark.c index d921040..5961e30 100644 --- a/kernel-shark.c +++ b/kernel-shark.c | |||
| @@ -303,7 +303,9 @@ int kernelshark_load_file(struct shark_info *info, const char *file) | |||
| 303 | display_warnings = 0; | 303 | display_warnings = 0; |
| 304 | pr_stat("\nLoading file %s", file); | 304 | pr_stat("\nLoading file %s", file); |
| 305 | trace_dialog_register_alt_warning(alt_warn); | 305 | trace_dialog_register_alt_warning(alt_warn); |
| 306 | printf("load\n"); | ||
| 306 | handle = tracecmd_open(file); | 307 | handle = tracecmd_open(file); |
| 308 | printf("loaded %d\n", handle); | ||
| 307 | trace_dialog_register_alt_warning(NULL); | 309 | trace_dialog_register_alt_warning(NULL); |
| 308 | if (display_warnings) { | 310 | if (display_warnings) { |
| 309 | errno = 0; | 311 | errno = 0; |
| @@ -313,6 +315,7 @@ int kernelshark_load_file(struct shark_info *info, const char *file) | |||
| 313 | if (!handle) | 315 | if (!handle) |
| 314 | return -1; | 316 | return -1; |
| 315 | 317 | ||
| 318 | printf("loaded good\n"); | ||
| 316 | tracecmd_close(info->handle); | 319 | tracecmd_close(info->handle); |
| 317 | info->handle = handle; | 320 | info->handle = handle; |
| 318 | trace_graph_load_handle(info->ginfo, handle); | 321 | trace_graph_load_handle(info->ginfo, handle); |
| @@ -1850,12 +1853,15 @@ void kernel_shark(int argc, char **argv) | |||
| 1850 | break; | 1853 | break; |
| 1851 | case 'c': | 1854 | case 'c': |
| 1852 | clean = 1; | 1855 | clean = 1; |
| 1856 | break; | ||
| 1853 | default: | 1857 | default: |
| 1854 | /* assume the other options are for gtk */ | 1858 | /* assume the other options are for gtk */ |
| 1855 | break; | 1859 | break; |
| 1856 | } | 1860 | } |
| 1857 | } | 1861 | } |
| 1858 | 1862 | ||
| 1863 | |||
| 1864 | |||
| 1859 | if ((argc - optind) >= 1) { | 1865 | if ((argc - optind) >= 1) { |
| 1860 | if (input_file) | 1866 | if (input_file) |
| 1861 | usage(basename(argv[0])); | 1867 | usage(basename(argv[0])); |
diff --git a/rt-plot-container.c b/rt-plot-container.c index cb814fa..94f78ee 100644 --- a/rt-plot-container.c +++ b/rt-plot-container.c | |||
| @@ -40,7 +40,7 @@ int get_server_info(struct graph_info *ginfo, struct rt_plot_common *rt, | |||
| 40 | *out_release = *out_deadline = *out_job = *out_tid = 0; | 40 | *out_release = *out_deadline = *out_job = *out_tid = 0; |
| 41 | 41 | ||
| 42 | /* Get current job info for server task */ | 42 | /* Get current job info for server task */ |
| 43 | get_previous_release(ginfo, sid, time, | 43 | get_previous_release(ginfo, rt, sid, time, |
| 44 | out_job, out_release, out_deadline); | 44 | out_job, out_release, out_deadline); |
| 45 | 45 | ||
| 46 | /* Need to reset back to current location */ | 46 | /* Need to reset back to current location */ |
diff --git a/rt-plot-task.c b/rt-plot-task.c index 77a517b..6e0013d 100644 --- a/rt-plot-task.c +++ b/rt-plot-task.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #include <stdio.h> | 1 | #include <stdio.h> |
| 2 | #include <string.h> | 2 | #include <string.h> |
| 3 | #include <stdlib.h> | ||
| 3 | #include "trace-graph.h" | 4 | #include "trace-graph.h" |
| 4 | #include "trace-filter.h" | 5 | #include "trace-filter.h" |
| 5 | 6 | ||
| @@ -133,7 +134,7 @@ static int get_time_info(struct graph_info *ginfo, | |||
| 133 | goto out; | 134 | goto out; |
| 134 | } | 135 | } |
| 135 | 136 | ||
| 136 | get_previous_release(ginfo, rtt_info->pid, time, | 137 | get_previous_release(ginfo, &rtt_info->common, rtt_info->pid, time, |
| 137 | out_job, out_release, out_deadline); | 138 | out_job, out_release, out_deadline); |
| 138 | out: | 139 | out: |
| 139 | return 1; | 140 | return 1; |
| @@ -492,7 +493,7 @@ rt_task_plot_write_header(struct rt_plot_common *rt, | |||
| 492 | const char *comm; | 493 | const char *comm; |
| 493 | int pid, job = -1, found; | 494 | int pid, job = -1, found; |
| 494 | struct record *record; | 495 | struct record *record; |
| 495 | unsigned long long release, deadline; | 496 | unsigned long long release = 0, deadline = 0; |
| 496 | struct rt_task_info *rtt_info = (struct rt_task_info*)rt; | 497 | struct rt_task_info *rtt_info = (struct rt_task_info*)rt; |
| 497 | 498 | ||
| 498 | found = get_time_info(ginfo, rtt_info, time, | 499 | found = get_time_info(ginfo, rtt_info, time, |
| @@ -502,7 +503,11 @@ rt_task_plot_write_header(struct rt_plot_common *rt, | |||
| 502 | 503 | ||
| 503 | pid = rtt_info->pid; | 504 | pid = rtt_info->pid; |
| 504 | comm = pevent_data_comm_from_pid(ginfo->pevent, pid); | 505 | comm = pevent_data_comm_from_pid(ginfo->pevent, pid); |
| 505 | trace_seq_printf(s, "%s-%d:%d\n", comm, pid, job); | 506 | trace_seq_printf(s, "%s-%d", comm, pid); |
| 507 | if (job != -1) { | ||
| 508 | trace_seq_printf(s, ":%d", job); | ||
| 509 | } | ||
| 510 | trace_seq_putc(s, '\n'); | ||
| 506 | 511 | ||
| 507 | if (in_res(ginfo, deadline, time)) { | 512 | if (in_res(ginfo, deadline, time)) { |
| 508 | trace_seq_printf(s, "\nlitmus_deadline\n" | 513 | trace_seq_printf(s, "\nlitmus_deadline\n" |
| @@ -514,6 +519,11 @@ rt_task_plot_write_header(struct rt_plot_common *rt, | |||
| 514 | "release(job(%d,%d)): %llu\n", | 519 | "release(job(%d,%d)): %llu\n", |
| 515 | pid, job, release); | 520 | pid, job, release); |
| 516 | } | 521 | } |
| 522 | |||
| 523 | if (deadline != 0 && deadline < time) { | ||
| 524 | trace_seq_printf(s, "\nTARDY\n"); | ||
| 525 | } | ||
| 526 | |||
| 517 | out: | 527 | out: |
| 518 | return record; | 528 | return record; |
| 519 | } | 529 | } |
| @@ -634,6 +644,7 @@ void rt_plot_task(struct graph_info *ginfo, int pid, int pos) | |||
| 634 | if (!params) | 644 | if (!params) |
| 635 | die ("RT task %d added without RT params!\n", pid); | 645 | die ("RT task %d added without RT params!\n", pid); |
| 636 | rtt_info = malloc_or_die(sizeof(*rtt_info)); | 646 | rtt_info = malloc_or_die(sizeof(*rtt_info)); |
| 647 | memset(rtt_info, 0, sizeof(*rtt_info)); | ||
| 637 | rtt_info->pid = pid; | 648 | rtt_info->pid = pid; |
| 638 | rtt_info->label = malloc_or_die(LLABEL); | 649 | rtt_info->label = malloc_or_die(LLABEL); |
| 639 | rtt_info->block_label = malloc_or_die(LLABEL); | 650 | rtt_info->block_label = malloc_or_die(LLABEL); |
| @@ -1,5 +1,170 @@ | |||
| 1 | #include <gtk/gtk.h> | 1 | #include <gtk/gtk.h> |
| 2 | #include <string.h> | ||
| 2 | #include "trace-graph.h" | 3 | #include "trace-graph.h" |
| 4 | #include "list.h" | ||
| 5 | |||
| 6 | |||
| 7 | struct record_list { | ||
| 8 | struct record_list *next; | ||
| 9 | struct record *record; | ||
| 10 | }; | ||
| 11 | |||
| 12 | /* | ||
| 13 | * Insert @record into @list, storing the record in @node. | ||
| 14 | */ | ||
| 15 | void insert_record(struct graph_info *ginfo, struct record_list *list, | ||
| 16 | struct record *record, struct record_list *node, | ||
| 17 | int reverse) | ||
| 18 | { | ||
| 19 | if (node->next) | ||
| 20 | die("Node is in use!"); | ||
| 21 | if (!record) { | ||
| 22 | printf("No record\n"); | ||
| 23 | return; | ||
| 24 | } | ||
| 25 | |||
| 26 | node->record = record; | ||
| 27 | |||
| 28 | struct record_list *pos = list; | ||
| 29 | |||
| 30 | while (pos->next) { | ||
| 31 | unsigned long long next_rts = get_rts(ginfo, pos->next->record); | ||
| 32 | if (( reverse && !next_rts > get_rts(ginfo, record)) || | ||
| 33 | (!reverse && next_rts < get_rts(ginfo, record))){ | ||
| 34 | break; | ||
| 35 | } | ||
| 36 | pos = pos->next; | ||
| 37 | } | ||
| 38 | |||
| 39 | node->next = pos->next; | ||
| 40 | pos->next = node; | ||
| 41 | } | ||
| 42 | |||
| 43 | |||
| 44 | /* | ||
| 45 | * Remove the first record in @list and put into @node. | ||
| 46 | */ | ||
| 47 | int pop_record(struct graph_info *ginfo, struct record_list *list, | ||
| 48 | struct record_list **node) | ||
| 49 | { | ||
| 50 | if (!list->next) | ||
| 51 | return 0; | ||
| 52 | |||
| 53 | *node = list->next; | ||
| 54 | list->next = list->next->next; | ||
| 55 | (*node)->next = 0; | ||
| 56 | |||
| 57 | return 1; | ||
| 58 | } | ||
| 59 | |||
| 60 | |||
| 61 | /* For communication between get_previous_release and its iterator */ | ||
| 62 | struct prev_release_args { | ||
| 63 | unsigned long long min_ts; | ||
| 64 | struct rt_plot_common *common; | ||
| 65 | unsigned long long time; | ||
| 66 | int match_tid; | ||
| 67 | unsigned int *out_job; | ||
| 68 | unsigned long long *out_release; | ||
| 69 | unsigned long long *out_deadline; | ||
| 70 | }; | ||
| 71 | |||
| 72 | |||
| 73 | static int | ||
| 74 | prev_release_iterator(struct graph_info *ginfo, struct record *rec, void *data) | ||
| 75 | { | ||
| 76 | int tid, is_release, job; | ||
| 77 | unsigned long long release, deadline; | ||
| 78 | struct prev_release_args *args = data; | ||
| 79 | |||
| 80 | if (get_rts(ginfo, rec) < args->min_ts) { | ||
| 81 | args->common->last_job.release = get_rts(ginfo, rec); | ||
| 82 | args->common->last_job.deadline = args->time; | ||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | #define ARG ginfo, rec, &tid, &job, &release, &deadline | ||
| 87 | is_release = rt_graph_check_task_release(ARG) || | ||
| 88 | rt_graph_check_server_release(ARG); | ||
| 89 | #undef ARG | ||
| 90 | |||
| 91 | if (is_release && args->match_tid == tid && release <= args->time) { | ||
| 92 | *(args->out_job) = job; | ||
| 93 | *(args->out_release) = release; | ||
| 94 | *(args->out_deadline) = deadline; | ||
| 95 | |||
| 96 | /* Cache to minimize work later */ | ||
| 97 | args->common->last_job.no = job; | ||
| 98 | args->common->last_job.release = release; | ||
| 99 | args->common->last_job.deadline = deadline; | ||
| 100 | args->common->last_job.start = get_rts(ginfo, rec); | ||
| 101 | args->common->last_job.end = args->time; | ||
| 102 | return 0; | ||
| 103 | } else { | ||
| 104 | return 1; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | |||
| 109 | /* For communication between find_prev_display_record and its iterator */ | ||
| 110 | struct prev_display_args { | ||
| 111 | struct rt_plot_common *common; | ||
| 112 | struct record *result; | ||
| 113 | unsigned long long min_ts; | ||
| 114 | }; | ||
| 115 | |||
| 116 | |||
| 117 | static int | ||
| 118 | prev_display_iterator(struct graph_info *ginfo, struct record *record, void *data) | ||
| 119 | { | ||
| 120 | int eid, ignored; | ||
| 121 | struct prev_display_args *args = data; | ||
| 122 | |||
| 123 | if (get_rts(ginfo, record) < args->min_ts) { | ||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | eid = pevent_data_type(ginfo->pevent, record); | ||
| 128 | ignored = (eid == ginfo->event_sched_switch_id); | ||
| 129 | |||
| 130 | if (!ignored) { | ||
| 131 | ignored = args->common->is_drawn(ginfo, eid); | ||
| 132 | } | ||
| 133 | |||
| 134 | if (!ignored && args->common->record_matches(args->common, ginfo, record)) { | ||
| 135 | args->result = record; | ||
| 136 | ++record->ref_count; | ||
| 137 | printf("success!\n"); | ||
| 138 | return 0; | ||
| 139 | } else { | ||
| 140 | return 1; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | |||
| 145 | /* | ||
| 146 | * Return first displayed record before @time, abandoning search after @range. | ||
| 147 | */ | ||
| 148 | static struct record* | ||
| 149 | find_prev_display_record(struct graph_info *ginfo, struct rt_plot_common *rt_info, | ||
| 150 | unsigned long long time, unsigned long long range) | ||
| 151 | { | ||
| 152 | int eid, ignored, match, cpu; | ||
| 153 | struct record *prev, *next, *res = NULL; | ||
| 154 | struct prev_display_args args = {rt_info, NULL, 0}; | ||
| 155 | |||
| 156 | if (range) { | ||
| 157 | args.min_ts = time - range; | ||
| 158 | } else { | ||
| 159 | args.min_ts = time - max_rt_search(ginfo); | ||
| 160 | } | ||
| 161 | |||
| 162 | set_cpus_to_rts(ginfo, time); | ||
| 163 | iterate(ginfo, 1, prev_display_iterator, &args); | ||
| 164 | |||
| 165 | return args.result; | ||
| 166 | } | ||
| 167 | |||
| 3 | 168 | ||
| 4 | /** | 169 | /** |
| 5 | * Return first relevant record after @time. | 170 | * Return first relevant record after @time. |
| @@ -10,7 +175,7 @@ __find_rt_record(struct graph_info *ginfo, struct rt_plot_common *rt_info, | |||
| 10 | guint64 time, int display, unsigned long long range) | 175 | guint64 time, int display, unsigned long long range) |
| 11 | { | 176 | { |
| 12 | int next_cpu, match, eid, ignored; | 177 | int next_cpu, match, eid, ignored; |
| 13 | struct record *record; | 178 | struct record *record = NULL; |
| 14 | 179 | ||
| 15 | set_cpus_to_rts(ginfo, time); | 180 | set_cpus_to_rts(ginfo, time); |
| 16 | while ((record = tracecmd_read_next_data(ginfo->handle, &next_cpu))) { | 181 | while ((record = tracecmd_read_next_data(ginfo->handle, &next_cpu))) { |
| @@ -71,49 +236,6 @@ rt_plot_display_last_event(struct graph_info *ginfo, struct graph_plot *plot, | |||
| 71 | return 1; | 236 | return 1; |
| 72 | } | 237 | } |
| 73 | 238 | ||
| 74 | /* | ||
| 75 | * Return first displayed record before @time, abandoning search after @range. | ||
| 76 | */ | ||
| 77 | static struct record* | ||
| 78 | find_prev_display_record(struct graph_info *ginfo, struct rt_plot_common *rt_info, | ||
| 79 | unsigned long long time, unsigned long long range) | ||
| 80 | { | ||
| 81 | int eid, ignored, match, cpu; | ||
| 82 | struct record *prev, *res = NULL; | ||
| 83 | unsigned long long min_ts; | ||
| 84 | |||
| 85 | if (range) | ||
| 86 | min_ts = time - range; | ||
| 87 | else | ||
| 88 | min_ts = time - max_rt_search(ginfo); | ||
| 89 | |||
| 90 | set_cpus_to_rts(ginfo, time); | ||
| 91 | |||
| 92 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
| 93 | prev = tracecmd_peek_data(ginfo->handle, cpu); | ||
| 94 | while ((prev = tracecmd_read_prev(ginfo->handle, prev)) && | ||
| 95 | get_rts(ginfo, prev) > min_ts) { | ||
| 96 | eid = pevent_data_type(ginfo->pevent, prev); | ||
| 97 | ignored = (eid == ginfo->event_sched_switch_id); | ||
| 98 | if (!ignored) { | ||
| 99 | ignored = rt_info->is_drawn(ginfo, eid); | ||
| 100 | } | ||
| 101 | match = !ignored && | ||
| 102 | rt_info->record_matches(rt_info, ginfo, prev); | ||
| 103 | if (match) { | ||
| 104 | if (!res || | ||
| 105 | get_rts(ginfo, prev) > get_rts(ginfo, res)) { | ||
| 106 | free_record(res); | ||
| 107 | res = prev; | ||
| 108 | } | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | free_record(prev); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | return res; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | 239 | /** |
| 118 | * rt_plot_display_info - write information about @time into @s | 240 | * rt_plot_display_info - write information about @time into @s |
| 119 | */ | 241 | */ |
| @@ -128,14 +250,22 @@ rt_plot_display_info(struct graph_info *ginfo, struct graph_plot *plot, | |||
| 128 | long long pdiff, rdiff; | 250 | long long pdiff, rdiff; |
| 129 | int eid; | 251 | int eid; |
| 130 | 252 | ||
| 253 | /* printf("\nBegin display\n"); */ | ||
| 254 | |||
| 131 | /* Write plot-specific data */ | 255 | /* Write plot-specific data */ |
| 132 | data_record = rt_info->write_header(rt_info, ginfo, s, time); | 256 | data_record = rt_info->write_header(rt_info, ginfo, s, time); |
| 257 | /* printf("Data record: "); print_record(data_record); */ | ||
| 133 | 258 | ||
| 134 | /* Select closest relevant record */ | 259 | /* Select closest relevant record */ |
| 135 | range = 2 / ginfo->resolution; | 260 | range = 2 / ginfo->resolution; |
| 136 | 261 | ||
| 262 | |||
| 137 | record = __find_rt_record(ginfo, rt_info, time, 1, range); | 263 | record = __find_rt_record(ginfo, rt_info, time, 1, range); |
| 138 | prev_record = find_prev_display_record(ginfo, rt_info, time, range); | 264 | prev_record = find_prev_display_record(ginfo, rt_info, time, range); |
| 265 | //prev_record = NULL; | ||
| 266 | |||
| 267 | /* printf("Next: "); print_record(record); */ | ||
| 268 | /* printf("Prev: "); print_record(prev_record); */ | ||
| 139 | 269 | ||
| 140 | if (!record) { | 270 | if (!record) { |
| 141 | record = prev_record; | 271 | record = prev_record; |
| @@ -144,34 +274,42 @@ rt_plot_display_info(struct graph_info *ginfo, struct graph_plot *plot, | |||
| 144 | rtime = get_rts(ginfo, record); | 274 | rtime = get_rts(ginfo, record); |
| 145 | pdiff = (ptime < time) ? time - ptime : ptime - time; | 275 | pdiff = (ptime < time) ? time - ptime : ptime - time; |
| 146 | rdiff = (rtime < time) ? time - rtime : rtime - time; | 276 | rdiff = (rtime < time) ? time - rtime : rtime - time; |
| 147 | record = (pdiff < rdiff) ? prev_record : record; | 277 | if (pdiff < rdiff) { |
| 278 | free_record(record); | ||
| 279 | record = prev_record; | ||
| 280 | } else { | ||
| 281 | free_record(prev_record); | ||
| 282 | } | ||
| 148 | } | 283 | } |
| 149 | 284 | ||
| 150 | /* Write event info */ | 285 | /* Write event info */ |
| 151 | if (record) { | 286 | if (record) { |
| 152 | rts = get_rts(ginfo, record); | 287 | /* rts = get_rts(ginfo, record); */ |
| 153 | eid = pevent_data_type(ginfo->pevent, record); | 288 | /* eid = pevent_data_type(ginfo->pevent, record); */ |
| 154 | 289 | ||
| 155 | if (in_res(ginfo, rts, time)) { | 290 | /* if (in_res(ginfo, rts, time)) { */ |
| 156 | event = pevent_data_event_from_type(ginfo->pevent, eid); | 291 | /* event = pevent_data_event_from_type(ginfo->pevent, eid); */ |
| 157 | if (event) { | 292 | /* if (event) { */ |
| 158 | trace_seq_putc(s, '\n'); | 293 | /* trace_seq_putc(s, '\n'); */ |
| 159 | trace_seq_puts(s, event->name); | 294 | /* trace_seq_puts(s, event->name); */ |
| 160 | trace_seq_putc(s, '\n'); | 295 | /* trace_seq_putc(s, '\n'); */ |
| 161 | pevent_event_info(s, event, record); | 296 | /* pevent_event_info(s, event, record); */ |
| 162 | } else | 297 | /* } else */ |
| 163 | trace_seq_printf(s, "\nUNKNOWN EVENT %d\n", eid); | 298 | /* trace_seq_printf(s, "\nUNKNOWN EVENT %d\n", eid); */ |
| 164 | } | 299 | /* } */ |
| 165 | free_record(record); | 300 | free_record(record); |
| 301 | /* printf("Freed record: "); print_record(record); */ | ||
| 166 | } | 302 | } |
| 167 | 303 | ||
| 168 | /* Metadata */ | 304 | /* Metadata */ |
| 169 | trace_seq_putc(s, '\n'); | 305 | trace_seq_putc(s, '\n'); |
| 170 | nano_to_milli(time, &msec, &nsec); | 306 | nano_to_milli(time, &msec, &nsec); |
| 171 | trace_seq_printf(s, "%llu.%06llu ms", msec, nsec); | 307 | trace_seq_printf(s, "%llu.%06llu ms", msec, nsec); |
| 308 | |||
| 172 | if (data_record) { | 309 | if (data_record) { |
| 173 | trace_seq_printf(s, " CPU: %03d", data_record->cpu); | 310 | trace_seq_printf(s, " CPU: %03d", data_record->cpu); |
| 174 | free_record(data_record); | 311 | free_record(data_record); |
| 312 | /* printf("Freed data: "); print_record(data_record); */ | ||
| 175 | } | 313 | } |
| 176 | 314 | ||
| 177 | return 1; | 315 | return 1; |
| @@ -360,6 +498,64 @@ int is_task_running(struct graph_info *ginfo, | |||
| 360 | return running; | 498 | return running; |
| 361 | } | 499 | } |
| 362 | 500 | ||
| 501 | void iterate(struct graph_info *ginfo, int reverse, iterate_cb cb, void *data) | ||
| 502 | { | ||
| 503 | int proceed, cpu; | ||
| 504 | struct record *next, *prev; | ||
| 505 | struct record_list list; | ||
| 506 | struct record_list *nodes, *node; | ||
| 507 | |||
| 508 | nodes = malloc_or_die(sizeof(*nodes) * ginfo->cpus); | ||
| 509 | memset(nodes, 0, sizeof(*nodes) * ginfo->cpus); | ||
| 510 | memset(&list, 0, sizeof(list)); | ||
| 511 | |||
| 512 | /* Maintains a list of the next record on each cpu, sorted by | ||
| 513 | * timestamp. Start with the first record on each cpu. | ||
| 514 | */ | ||
| 515 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
| 516 | next = tracecmd_peek_data(ginfo->handle, cpu); | ||
| 517 | if (next) { | ||
| 518 | if (reverse) { | ||
| 519 | prev = next; | ||
| 520 | next = tracecmd_read_prev(ginfo->handle, prev); | ||
| 521 | if (prev != next && prev->data) { | ||
| 522 | free_record(prev); | ||
| 523 | } | ||
| 524 | } | ||
| 525 | insert_record(ginfo, &list, next, &nodes[cpu], reverse); | ||
| 526 | } | ||
| 527 | } | ||
| 528 | |||
| 529 | /* Read sequentially from all cpus */ | ||
| 530 | while (pop_record(ginfo, &list, &node)) { | ||
| 531 | next = node->record; | ||
| 532 | |||
| 533 | proceed = cb(ginfo, next, data); | ||
| 534 | |||
| 535 | if (!proceed) { | ||
| 536 | free_record(next); | ||
| 537 | break; | ||
| 538 | } | ||
| 539 | |||
| 540 | prev = next; | ||
| 541 | |||
| 542 | if (!reverse) { | ||
| 543 | next = tracecmd_read_data(ginfo->handle, next->cpu); | ||
| 544 | } else { | ||
| 545 | next = tracecmd_read_prev(ginfo->handle, next); | ||
| 546 | } | ||
| 547 | |||
| 548 | free_record(prev); | ||
| 549 | |||
| 550 | insert_record(ginfo, &list, next, node, reverse); | ||
| 551 | } | ||
| 552 | |||
| 553 | while (pop_record(ginfo, &list, &node)) { | ||
| 554 | free_record(node->record); | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | |||
| 363 | /** | 559 | /** |
| 364 | * Find the information for the last release of @match_tid on @cpu before @time. | 560 | * Find the information for the last release of @match_tid on @cpu before @time. |
| 365 | * | 561 | * |
| @@ -369,63 +565,26 @@ int is_task_running(struct graph_info *ginfo, | |||
| 369 | * Returns release record and @out_job, @out_release, and @out_deadline if a | 565 | * Returns release record and @out_job, @out_release, and @out_deadline if a |
| 370 | * release was found for @tid before @time. | 566 | * release was found for @tid before @time. |
| 371 | */ | 567 | */ |
| 372 | void get_previous_release(struct graph_info *ginfo, int match_tid, | 568 | void get_previous_release(struct graph_info *ginfo, struct rt_plot_common *common, |
| 569 | int match_tid, | ||
| 373 | unsigned long long time, | 570 | unsigned long long time, |
| 374 | int *out_job, | 571 | int *out_job, |
| 375 | unsigned long long *out_release, | 572 | unsigned long long *out_release, |
| 376 | unsigned long long *out_deadline) | 573 | unsigned long long *out_deadline) |
| 377 | { | 574 | { |
| 378 | int tid, cpu, match, job; | 575 | struct prev_release_args args = { |
| 379 | unsigned long long release, deadline, min_ts; | 576 | (time - max_rt_search(ginfo)), common, time, match_tid, |
| 380 | struct record *last_rec = NULL, *rec, *ret = NULL; | 577 | out_job, out_release, out_deadline}; |
| 381 | 578 | ||
| 382 | *out_job = -2; | 579 | /* Use cached job info, if possible */ |
| 383 | 580 | if (time >= common->last_job.start && | |
| 384 | min_ts = time - max_rt_search(ginfo); | 581 | time <= common->last_job.end) { |
| 385 | 582 | *out_job = common->last_job.no; | |
| 386 | /* The release record could have occurred on any CPU. Search all */ | 583 | *out_release = common->last_job.release; |
| 387 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | 584 | *out_deadline = common->last_job.deadline; |
| 388 | set_cpu_to_rts(ginfo, time, cpu); | 585 | return; |
| 389 | last_rec = tracecmd_peek_data(ginfo->handle, cpu); | ||
| 390 | |||
| 391 | /* Require a record to start with */ | ||
| 392 | if (!last_rec) { | ||
| 393 | goto loop_end; | ||
| 394 | } | ||
| 395 | last_rec->ref_count++; | ||
| 396 | |||
| 397 | while ((rec = tracecmd_read_prev(ginfo->handle, last_rec))) { | ||
| 398 | if (get_rts(ginfo, rec) < min_ts) { | ||
| 399 | free_record(rec); | ||
| 400 | |||
| 401 | goto loop_end; | ||
| 402 | } | ||
| 403 | |||
| 404 | #define ARG ginfo, rec, &tid, &job, &release, &deadline | ||
| 405 | match = rt_graph_check_task_release(ARG) || | ||
| 406 | rt_graph_check_server_release(ARG); | ||
| 407 | #undef ARG | ||
| 408 | |||
| 409 | free_record(last_rec); | ||
| 410 | last_rec = rec; | ||
| 411 | |||
| 412 | /* Only consider releases before the current time */ | ||
| 413 | if (match && tid == match_tid && release <= time) { | ||
| 414 | /* Return the lastest release */ | ||
| 415 | if (!ret || *out_job < job) { | ||
| 416 | free_record(ret); | ||
| 417 | ret = rec; | ||
| 418 | *out_job = job; | ||
| 419 | *out_release = release; | ||
| 420 | *out_deadline = deadline; | ||
| 421 | } | ||
| 422 | last_rec = NULL; | ||
| 423 | goto loop_end; | ||
| 424 | } | ||
| 425 | } | ||
| 426 | loop_end: | ||
| 427 | free_record(last_rec); | ||
| 428 | } | 586 | } |
| 429 | 587 | ||
| 430 | free_record(ret); | 588 | set_cpus_to_rts(ginfo, time); |
| 589 | iterate(ginfo, 1, prev_release_iterator, &args); | ||
| 431 | } | 590 | } |
| @@ -16,12 +16,29 @@ typedef struct record* (*write_header_cb)(struct rt_plot_common *rt, | |||
| 16 | struct graph_info *ginfo, | 16 | struct graph_info *ginfo, |
| 17 | struct trace_seq *s, | 17 | struct trace_seq *s, |
| 18 | unsigned long long time); | 18 | unsigned long long time); |
| 19 | typedef int (*iterate_cb)(struct graph_info *ginfo, struct record *record, void *data); | ||
| 20 | |||
| 21 | struct job_info { | ||
| 22 | unsigned long long release; | ||
| 23 | unsigned long long deadline; | ||
| 24 | unsigned long long start; | ||
| 25 | unsigned long long end; | ||
| 26 | unsigned long long no; | ||
| 27 | }; | ||
| 28 | |||
| 29 | |||
| 19 | struct rt_plot_common { | 30 | struct rt_plot_common { |
| 20 | record_matches_cb record_matches; | 31 | record_matches_cb record_matches; |
| 21 | is_drawn_cb is_drawn; | 32 | is_drawn_cb is_drawn; |
| 22 | write_header_cb write_header; | 33 | write_header_cb write_header; |
| 34 | |||
| 35 | /* Cache the current job info. Used in mouseovers to avoid recalulating | ||
| 36 | * job information when the mouse does not cross job boundaries. | ||
| 37 | */ | ||
| 38 | struct job_info last_job; | ||
| 23 | }; | 39 | }; |
| 24 | 40 | ||
| 41 | |||
| 25 | int | 42 | int |
| 26 | rt_plot_display_last_event(struct graph_info *ginfo, struct graph_plot *plot, | 43 | rt_plot_display_last_event(struct graph_info *ginfo, struct graph_plot *plot, |
| 27 | struct trace_seq *s, unsigned long long time); | 44 | struct trace_seq *s, unsigned long long time); |
| @@ -60,9 +77,13 @@ void set_cpus_to_rts(struct graph_info *ginfo, | |||
| 60 | int is_task_running(struct graph_info *ginfo, | 77 | int is_task_running(struct graph_info *ginfo, |
| 61 | unsigned long long time, | 78 | unsigned long long time, |
| 62 | int pid); | 79 | int pid); |
| 63 | void get_previous_release(struct graph_info *ginfo, int tid, | 80 | void get_previous_release(struct graph_info *ginfo, struct rt_plot_common *common, |
| 81 | int tid, | ||
| 64 | unsigned long long time, int *job, | 82 | unsigned long long time, int *job, |
| 65 | unsigned long long *release, | 83 | unsigned long long *release, |
| 66 | unsigned long long *deadline); | 84 | unsigned long long *deadline); |
| 67 | 85 | ||
| 86 | void iterate(struct graph_info *ginfo, int reverse, iterate_cb cb, void *data); | ||
| 87 | |||
| 88 | |||
| 68 | #endif | 89 | #endif |
diff --git a/trace-graph.c b/trace-graph.c index f9bd4af..f843e26 100644 --- a/trace-graph.c +++ b/trace-graph.c | |||
| @@ -1863,7 +1863,6 @@ static void draw_plot(struct graph_info *ginfo, struct graph_plot *plot, | |||
| 1863 | static void draw_hashed_plots(struct graph_info *ginfo) | 1863 | static void draw_hashed_plots(struct graph_info *ginfo) |
| 1864 | { | 1864 | { |
| 1865 | gint cpu, pid; | 1865 | gint cpu, pid; |
| 1866 | gboolean started; | ||
| 1867 | struct record *record; | 1866 | struct record *record; |
| 1868 | struct plot_hash *hash; | 1867 | struct plot_hash *hash; |
| 1869 | struct plot_list *list; | 1868 | struct plot_list *list; |
| @@ -1882,7 +1881,7 @@ static void draw_hashed_plots(struct graph_info *ginfo) | |||
| 1882 | 1881 | ||
| 1883 | // TODO: hack to clean up until first release, make unhacky | 1882 | // TODO: hack to clean up until first release, make unhacky |
| 1884 | if (ginfo->rtg_info.clean_records && | 1883 | if (ginfo->rtg_info.clean_records && |
| 1885 | ginfo->rtg_info.start_time == 0) { | 1884 | (ginfo->rtg_info.start_time == 0 || ginfo->view_start_time < ginfo->rtg_info.start_time)) { |
| 1886 | unsigned long long dull, rel = 0; | 1885 | unsigned long long dull, rel = 0; |
| 1887 | char *dchar; | 1886 | char *dchar; |
| 1888 | int dint; | 1887 | int dint; |
| @@ -1964,6 +1963,8 @@ static void draw_plots(struct graph_info *ginfo, gint new_width) | |||
| 1964 | set_color(ginfo->draw, plot->gc, plot->last_color); | 1963 | set_color(ginfo->draw, plot->gc, plot->last_color); |
| 1965 | } | 1964 | } |
| 1966 | 1965 | ||
| 1966 | printf("we here1\n"); | ||
| 1967 | |||
| 1967 | trace_set_cursor(GDK_WATCH); | 1968 | trace_set_cursor(GDK_WATCH); |
| 1968 | /* Shortcut if we don't have any task plots */ | 1969 | /* Shortcut if we don't have any task plots */ |
| 1969 | if (!ginfo->nr_task_hash && !ginfo->all_recs) { | 1970 | if (!ginfo->nr_task_hash && !ginfo->all_recs) { |
| @@ -1991,6 +1992,8 @@ static void draw_plots(struct graph_info *ginfo, gint new_width) | |||
| 1991 | goto out; | 1992 | goto out; |
| 1992 | } | 1993 | } |
| 1993 | 1994 | ||
| 1995 | printf("we here\n"); | ||
| 1996 | |||
| 1994 | draw_hashed_plots(ginfo); | 1997 | draw_hashed_plots(ginfo); |
| 1995 | 1998 | ||
| 1996 | out: | 1999 | out: |
| @@ -2097,8 +2100,10 @@ static void draw_timeline(struct graph_info *ginfo, gint width) | |||
| 2097 | static void draw_info(struct graph_info *ginfo, | 2100 | static void draw_info(struct graph_info *ginfo, |
| 2098 | gint new_width) | 2101 | gint new_width) |
| 2099 | { | 2102 | { |
| 2103 | printf("we going?\n"); | ||
| 2100 | if (!ginfo->handle) | 2104 | if (!ginfo->handle) |
| 2101 | return; | 2105 | return; |
| 2106 | printf("we gone\n"); | ||
| 2102 | 2107 | ||
| 2103 | ginfo->resolution = (gdouble)new_width / (gdouble)(ginfo->view_end_time - | 2108 | ginfo->resolution = (gdouble)new_width / (gdouble)(ginfo->view_end_time - |
| 2104 | ginfo->view_start_time); | 2109 | ginfo->view_start_time); |
| @@ -2107,6 +2112,7 @@ static void draw_info(struct graph_info *ginfo, | |||
| 2107 | 2112 | ||
| 2108 | draw_timeline(ginfo, new_width); | 2113 | draw_timeline(ginfo, new_width); |
| 2109 | 2114 | ||
| 2115 | printf("drawing plots\n"); | ||
| 2110 | draw_plots(ginfo, new_width); | 2116 | draw_plots(ginfo, new_width); |
| 2111 | 2117 | ||
| 2112 | ginfo->read_comms = FALSE; | 2118 | ginfo->read_comms = FALSE; |
| @@ -2324,6 +2330,7 @@ static void redraw_pixmap_backend(struct graph_info *ginfo) | |||
| 2324 | if (old_pix) | 2330 | if (old_pix) |
| 2325 | g_object_unref(old_pix); | 2331 | g_object_unref(old_pix); |
| 2326 | 2332 | ||
| 2333 | |||
| 2327 | if (ginfo->hadj_value) { | 2334 | if (ginfo->hadj_value) { |
| 2328 | // gtk_adjustment_set_lower(ginfo->hadj, -100.0); | 2335 | // gtk_adjustment_set_lower(ginfo->hadj, -100.0); |
| 2329 | gtk_adjustment_set_value(ginfo->hadj, ginfo->hadj_value); | 2336 | gtk_adjustment_set_value(ginfo->hadj, ginfo->hadj_value); |
diff --git a/trace-input.c b/trace-input.c index 5b01386..48dafe9 100644 --- a/trace-input.c +++ b/trace-input.c | |||
| @@ -719,8 +719,11 @@ void free_record(struct record *record) | |||
| 719 | if (!record) | 719 | if (!record) |
| 720 | return; | 720 | return; |
| 721 | 721 | ||
| 722 | if (!record->ref_count) | 722 | if (!record->ref_count) { |
| 723 | struct record *rec = NULL; | ||
| 724 | rec->ref_count = 2; | ||
| 723 | die("record ref count is zero!"); | 725 | die("record ref count is zero!"); |
| 726 | } | ||
| 724 | 727 | ||
| 725 | record->ref_count--; | 728 | record->ref_count--; |
| 726 | 729 | ||
