diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-03-28 20:00:09 -0400 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-03-28 20:00:09 -0400 |
| commit | 384a901c64991dc0b87838ef6f31cf539e5eeb3d (patch) | |
| tree | a46576279e447fab4eaae94b1cf96c6f64fbfffa | |
| parent | 7ebeccc383b15c3aea44a00fe2e920c395378613 (diff) | |
containers: both virtual tasks and cpus now drawn
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | rt-graph.c | 2 | ||||
| -rw-r--r-- | rt-plot-container.c | 46 | ||||
| -rw-r--r-- | rt-plot-container.h | 1 | ||||
| -rw-r--r-- | rt-plot-vcpu.c | 279 | ||||
| -rw-r--r-- | rt-plot-vcpu.h | 30 | ||||
| -rw-r--r-- | rt-plot-vtask.c | 208 | ||||
| -rw-r--r-- | rt-plot-vtask.h | 4 | ||||
| -rw-r--r-- | rt-plot.c | 352 |
9 files changed, 751 insertions, 173 deletions
| @@ -300,7 +300,7 @@ TRACE_CMD_OBJS = trace-cmd.o trace-record.o trace-read.o trace-split.o trace-lis | |||
| 300 | trace-stack.o trace-options.o | 300 | trace-stack.o trace-options.o |
| 301 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o | 301 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o |
| 302 | RT_GRAPH_OBJS = rt-graph.o rt-plot-task.o rt-plot-cpu.o rt-plot-container.o rt-plot.o \ | 302 | RT_GRAPH_OBJS = rt-graph.o rt-plot-task.o rt-plot-cpu.o rt-plot-container.o rt-plot.o \ |
| 303 | rt-plot-vcpu.o | 303 | rt-plot-vcpu.o rt-plot-vtask.o |
| 304 | TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o \ | 304 | TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o \ |
| 305 | trace-plot-cpu.o trace-plot-task.o \ | 305 | trace-plot-cpu.o trace-plot-task.o \ |
| 306 | $(RT_GRAPH_OBJS) task-list.o | 306 | $(RT_GRAPH_OBJS) task-list.o |
| @@ -3,7 +3,7 @@ | |||
| 3 | #include "trace-graph.h" | 3 | #include "trace-graph.h" |
| 4 | #include "trace-hash.h" | 4 | #include "trace-hash.h" |
| 5 | 5 | ||
| 6 | #define DEBUG_LEVEL 0 | 6 | #define DEBUG_LEVEL 4 |
| 7 | #if DEBUG_LEVEL > 0 | 7 | #if DEBUG_LEVEL > 0 |
| 8 | #define dprintf(l, x...) \ | 8 | #define dprintf(l, x...) \ |
| 9 | do { \ | 9 | do { \ |
diff --git a/rt-plot-container.c b/rt-plot-container.c index f36e2f8..97e9fd8 100644 --- a/rt-plot-container.c +++ b/rt-plot-container.c | |||
| @@ -4,40 +4,6 @@ | |||
| 4 | #include "trace-hash.h" | 4 | #include "trace-hash.h" |
| 5 | #include "trace-filter.h" | 5 | #include "trace-filter.h" |
| 6 | 6 | ||
| 7 | struct vtask_info { | ||
| 8 | struct rt_task_info task_info; | ||
| 9 | struct cont_list *cont; | ||
| 10 | }; | ||
| 11 | |||
| 12 | static void insert_vtask(struct graph_info *ginfo, struct cont_list *cont, | ||
| 13 | struct vcpu_list *vcpu_info) | ||
| 14 | { | ||
| 15 | struct graph_plot *plot; | ||
| 16 | struct vtask_info *vtask; | ||
| 17 | char *label; | ||
| 18 | int len; | ||
| 19 | |||
| 20 | vtask = malloc_or_die(sizeof(*vtask)); | ||
| 21 | vtask->task_info.pid = vcpu_info->sid; | ||
| 22 | vtask->task_info.wcet = vcpu_info->params.wcet; | ||
| 23 | vtask->task_info.period = vcpu_info->params.period; | ||
| 24 | vtask->task_info.label = malloc_or_die(LLABEL); | ||
| 25 | vtask->cont = cont; | ||
| 26 | |||
| 27 | g_assert(cont); | ||
| 28 | |||
| 29 | len = strlen(cont->name) + 100; | ||
| 30 | label = malloc_or_die(len); | ||
| 31 | snprintf(label, len, "%s-%d\n(%1.1f, %1.1f)", | ||
| 32 | cont->name, -vtask->task_info.pid, | ||
| 33 | nano_as_milli(vtask->task_info.wcet), | ||
| 34 | nano_as_milli(vtask->task_info.period)); | ||
| 35 | |||
| 36 | plot = trace_graph_plot_append(ginfo, label, PLOT_TYPE_SERVER_TASK, | ||
| 37 | TIME_TYPE_RT, &rt_task_cb, vtask); | ||
| 38 | trace_graph_plot_add_all_recs(ginfo, plot); | ||
| 39 | } | ||
| 40 | |||
| 41 | int rt_plot_get_containers(struct graph_info *ginfo, gint **conts, | 7 | int rt_plot_get_containers(struct graph_info *ginfo, gint **conts, |
| 42 | gboolean plotted_only) | 8 | gboolean plotted_only) |
| 43 | { | 9 | { |
| @@ -122,7 +88,7 @@ void rt_plot_container(struct graph_info *ginfo, int cid) | |||
| 122 | cont->plotted = TRUE; | 88 | cont->plotted = TRUE; |
| 123 | 89 | ||
| 124 | for (vlist = cont->vcpus; vlist; vlist = vlist->next) { | 90 | for (vlist = cont->vcpus; vlist; vlist = vlist->next) { |
| 125 | /* insert_vtask(ginfo, cont, vlist); */ | 91 | insert_vtask(ginfo, cont, vlist); |
| 126 | insert_vcpu(ginfo, cont, vlist); | 92 | insert_vcpu(ginfo, cont, vlist); |
| 127 | } | 93 | } |
| 128 | } | 94 | } |
| @@ -185,7 +151,6 @@ static void do_container_filter(struct graph_info *ginfo, | |||
| 185 | struct cont_filter_helper *helper, gpointer data) | 151 | struct cont_filter_helper *helper, gpointer data) |
| 186 | { | 152 | { |
| 187 | struct graph_plot *plot; | 153 | struct graph_plot *plot; |
| 188 | struct vtask_info *vtask; | ||
| 189 | struct vcpu_info *vcpu; | 154 | struct vcpu_info *vcpu; |
| 190 | struct cont_list *cont; | 155 | struct cont_list *cont; |
| 191 | int i, c, *append; | 156 | int i, c, *append; |
| @@ -201,13 +166,8 @@ static void do_container_filter(struct graph_info *ginfo, | |||
| 201 | plot->type != PLOT_TYPE_SERVER_CPU) | 166 | plot->type != PLOT_TYPE_SERVER_CPU) |
| 202 | continue; | 167 | continue; |
| 203 | 168 | ||
| 204 | if (plot->type == PLOT_TYPE_SERVER_TASK) { | 169 | vcpu = plot->private; |
| 205 | vtask = plot->private; | 170 | cont = vcpu->cont; |
| 206 | cont = vtask->cont; | ||
| 207 | } else { | ||
| 208 | vcpu = plot->private; | ||
| 209 | cont = vcpu->cont; | ||
| 210 | } | ||
| 211 | 171 | ||
| 212 | for (c = 0; c < helper->num_conts; c++) { | 172 | for (c = 0; c < helper->num_conts; c++) { |
| 213 | if (helper->conts[c] == cont->cid) | 173 | if (helper->conts[c] == cont->cid) |
diff --git a/rt-plot-container.h b/rt-plot-container.h index e6c57b0..cde5c2f 100644 --- a/rt-plot-container.h +++ b/rt-plot-container.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define __RT_PLOT_CONTAINER_H | 2 | #define __RT_PLOT_CONTAINER_H |
| 3 | 3 | ||
| 4 | #include "rt-plot-vcpu.h" | 4 | #include "rt-plot-vcpu.h" |
| 5 | #include "rt-plot-vtask.h" | ||
| 5 | 6 | ||
| 6 | typedef void (*cont_dialog_cb_func)(gboolean, gint*, gint*, gpointer); | 7 | typedef void (*cont_dialog_cb_func)(gboolean, gint*, gint*, gpointer); |
| 7 | 8 | ||
diff --git a/rt-plot-vcpu.c b/rt-plot-vcpu.c index 7951ad4..0ec55da 100644 --- a/rt-plot-vcpu.c +++ b/rt-plot-vcpu.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | #include <string.h> | 2 | #include <string.h> |
| 3 | #include "trace-graph.h" | 3 | #include "trace-graph.h" |
| 4 | 4 | ||
| 5 | #define DEBUG_LEVEL 4 | 5 | #define DEBUG_LEVEL 0 |
| 6 | #if DEBUG_LEVEL > 0 | 6 | #if DEBUG_LEVEL > 0 |
| 7 | #define dprintf(l, x...) \ | 7 | #define dprintf(l, x...) \ |
| 8 | do { \ | 8 | do { \ |
| @@ -22,95 +22,6 @@ static void update_tid(struct vcpu_info *info, int tid) | |||
| 22 | } | 22 | } |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | |||
| 26 | static int try_release(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 27 | struct record *record, struct plot_info *info) | ||
| 28 | { | ||
| 29 | int sid, job, match, ret = 0; | ||
| 30 | unsigned long long release, deadline; | ||
| 31 | |||
| 32 | match = rt_graph_check_server_release(ginfo, record, &sid, &job, | ||
| 33 | &release, &deadline); | ||
| 34 | if (match && sid == vcpu_info->sid) { | ||
| 35 | info->release = TRUE; | ||
| 36 | info->rtime = release; | ||
| 37 | |||
| 38 | info->deadline = TRUE; | ||
| 39 | info->dtime = deadline; | ||
| 40 | |||
| 41 | dprintf(3, "VCPU release for %d:%d on %d, rel: %llu, dead: %llu\n", | ||
| 42 | sid, job, record->cpu, release, deadline); | ||
| 43 | |||
| 44 | ret = 1; | ||
| 45 | } | ||
| 46 | return ret; | ||
| 47 | } | ||
| 48 | |||
| 49 | static int try_completion(struct graph_info *ginfo, | ||
| 50 | struct vcpu_info *vcpu_info, | ||
| 51 | struct record *record, struct plot_info *info) | ||
| 52 | { | ||
| 53 | int sid, job, match, ret = 0; | ||
| 54 | unsigned long long ts; | ||
| 55 | |||
| 56 | match = rt_graph_check_server_completion(ginfo, record, &sid, &job, &ts); | ||
| 57 | if (match && sid == vcpu_info->sid) { | ||
| 58 | |||
| 59 | info->completion = TRUE; | ||
| 60 | info->ctime = ts; | ||
| 61 | |||
| 62 | dprintf(3, "VCPU completion for %d:%d on %d at %llu\n", | ||
| 63 | sid, job, record->cpu, ts); | ||
| 64 | ret = 1; | ||
| 65 | } | ||
| 66 | return ret; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int try_block(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 70 | struct record *record, struct plot_info *info) | ||
| 71 | { | ||
| 72 | int sid, match, ret = 0; | ||
| 73 | unsigned long long ts; | ||
| 74 | |||
| 75 | match = rt_graph_check_server_block(ginfo, record, &sid, &ts); | ||
| 76 | if (match && sid == vcpu_info->sid) { | ||
| 77 | vcpu_info->fresh = FALSE; | ||
| 78 | vcpu_info->block_time = ts; | ||
| 79 | vcpu_info->block_cpu = NO_CPU; | ||
| 80 | dprintf(3, "VCPU resume for %d on %d at %llu\n", | ||
| 81 | sid, record->cpu, ts); | ||
| 82 | ret = 1; | ||
| 83 | } | ||
| 84 | return ret; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int try_resume(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 88 | struct record *record, struct plot_info *info) | ||
| 89 | { | ||
| 90 | int sid, match, ret = 0; | ||
| 91 | unsigned long long ts; | ||
| 92 | |||
| 93 | match = rt_graph_check_server_resume(ginfo, record, &sid, &ts); | ||
| 94 | |||
| 95 | if (match && sid == vcpu_info->sid) { | ||
| 96 | info->box = TRUE; | ||
| 97 | info->bcolor = 0x0; | ||
| 98 | info->bfill = TRUE; | ||
| 99 | info->bthin = TRUE; | ||
| 100 | info->bstart = vcpu_info->block_time; | ||
| 101 | info->bend = ts; | ||
| 102 | vcpu_info->fresh = FALSE; | ||
| 103 | |||
| 104 | vcpu_info->block_time = 0ULL; | ||
| 105 | vcpu_info->block_cpu = NO_CPU; | ||
| 106 | dprintf(3, "VCPU resume for %d on %d at %llu\n", | ||
| 107 | sid, record->cpu, ts); | ||
| 108 | |||
| 109 | ret = 1; | ||
| 110 | } | ||
| 111 | return ret; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int | 25 | static int |
| 115 | try_server_switch_away(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | 26 | try_server_switch_away(struct graph_info *ginfo, struct vcpu_info *vcpu_info, |
| 116 | struct record *record, struct plot_info *info) | 27 | struct record *record, struct plot_info *info) |
| @@ -259,16 +170,55 @@ static int rt_vcpu_plot_event(struct graph_info *ginfo, struct graph_plot *plot, | |||
| 259 | 170 | ||
| 260 | match = try_server_switch_away(ginfo, vcpu_info, record, info) || | 171 | match = try_server_switch_away(ginfo, vcpu_info, record, info) || |
| 261 | try_server_switch_to(ginfo, vcpu_info, record, info) || | 172 | try_server_switch_to(ginfo, vcpu_info, record, info) || |
| 262 | try_block(ginfo, vcpu_info, record, info) || | 173 | vcpu_try_block(ginfo, vcpu_info, record, info) || |
| 263 | try_resume(ginfo, vcpu_info, record, info) || | 174 | vcpu_try_resume(ginfo, vcpu_info, record, info) || |
| 264 | try_release(ginfo, vcpu_info, record, info) || | 175 | vcpu_try_release(ginfo, vcpu_info, record, info) || |
| 265 | try_completion(ginfo, vcpu_info, record, info) || | 176 | vcpu_try_completion(ginfo, vcpu_info, record, info) || |
| 266 | try_switch_to(ginfo, vcpu_info, record, info) || | 177 | try_switch_to(ginfo, vcpu_info, record, info) || |
| 267 | try_switch_away(ginfo, vcpu_info, record, info); | 178 | try_switch_away(ginfo, vcpu_info, record, info); |
| 268 | return match; | 179 | return match; |
| 269 | } | 180 | } |
| 270 | 181 | ||
| 271 | static void rt_vcpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot, | 182 | |
| 183 | const struct plot_callbacks rt_vcpu_cb = { | ||
| 184 | .start = rt_vcpu_plot_start, | ||
| 185 | .destroy = rt_vcpu_plot_destroy, | ||
| 186 | .plot_event = rt_vcpu_plot_event, | ||
| 187 | .display_last_event = rt_plot_display_last_event, | ||
| 188 | .display_info = rt_plot_display_info, | ||
| 189 | .match_time = rt_plot_match_time, | ||
| 190 | .find_record = rt_plot_find_record, | ||
| 191 | }; | ||
| 192 | |||
| 193 | void insert_vcpu(struct graph_info *ginfo, struct cont_list *cont, | ||
| 194 | struct vcpu_list *vcpu_info) | ||
| 195 | { | ||
| 196 | struct graph_plot *plot; | ||
| 197 | struct vcpu_info *vcpu; | ||
| 198 | char *label; | ||
| 199 | |||
| 200 | vcpu = malloc_or_die(sizeof(*vcpu)); | ||
| 201 | vcpu->sid = vcpu_info->sid; | ||
| 202 | vcpu->cont = cont; | ||
| 203 | vcpu->label = malloc_or_die(LLABEL); | ||
| 204 | |||
| 205 | vcpu->common.record_matches = rt_vcpu_plot_record_matches; | ||
| 206 | vcpu->common.is_drawn = rt_vcpu_plot_is_drawn; | ||
| 207 | vcpu->common.write_header = rt_vcpu_plot_write_header; | ||
| 208 | |||
| 209 | g_assert(cont); | ||
| 210 | |||
| 211 | label = malloc_or_die(1); | ||
| 212 | snprintf(label, 2, " "); | ||
| 213 | plot = trace_graph_plot_append(ginfo, label, PLOT_TYPE_SERVER_CPU, | ||
| 214 | TIME_TYPE_RT, &rt_vcpu_cb, vcpu); | ||
| 215 | trace_graph_plot_add_all_recs(ginfo, plot); | ||
| 216 | } | ||
| 217 | |||
| 218 | /** | ||
| 219 | * | ||
| 220 | */ | ||
| 221 | void rt_vcpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot, | ||
| 272 | unsigned long long time) | 222 | unsigned long long time) |
| 273 | { | 223 | { |
| 274 | struct vcpu_info *vcpu_info = plot->private; | 224 | struct vcpu_info *vcpu_info = plot->private; |
| @@ -284,11 +234,15 @@ static void rt_vcpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot | |||
| 284 | 234 | ||
| 285 | vcpu_info->fresh = TRUE; | 235 | vcpu_info->fresh = TRUE; |
| 286 | vcpu_info->running = FALSE; | 236 | vcpu_info->running = FALSE; |
| 237 | vcpu_info->last_job = -1; | ||
| 287 | 238 | ||
| 288 | vcpu_info->run_tid = 0; | 239 | vcpu_info->run_tid = 0; |
| 289 | } | 240 | } |
| 290 | 241 | ||
| 291 | static void rt_vcpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) | 242 | /** |
| 243 | * | ||
| 244 | */ | ||
| 245 | void rt_vcpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) | ||
| 292 | { | 246 | { |
| 293 | struct vcpu_info *vcpu_info = plot->private; | 247 | struct vcpu_info *vcpu_info = plot->private; |
| 294 | trace_graph_plot_remove_all_recs(ginfo, plot); | 248 | trace_graph_plot_remove_all_recs(ginfo, plot); |
| @@ -296,10 +250,10 @@ static void rt_vcpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *pl | |||
| 296 | free(vcpu_info); | 250 | free(vcpu_info); |
| 297 | } | 251 | } |
| 298 | 252 | ||
| 299 | /* | 253 | /** |
| 300 | * Return 1 if @record is relevant to @match_sid. | 254 | * Return 1 if @record is relevant to @match_sid. |
| 301 | */ | 255 | */ |
| 302 | static int rt_vcpu_plot_record_matches(struct rt_plot_common *rt, | 256 | int rt_vcpu_plot_record_matches(struct rt_plot_common *rt, |
| 303 | struct graph_info *ginfo, | 257 | struct graph_info *ginfo, |
| 304 | struct record *record) | 258 | struct record *record) |
| 305 | { | 259 | { |
| @@ -318,11 +272,11 @@ static int rt_vcpu_plot_record_matches(struct rt_plot_common *rt, | |||
| 318 | return (sid == vcpu_info->sid); | 272 | return (sid == vcpu_info->sid); |
| 319 | } | 273 | } |
| 320 | 274 | ||
| 321 | /* | 275 | /** |
| 322 | * Return true if the given record type is drawn on screen. This does not | 276 | * Return true if the given record type is drawn on screen. This does not |
| 323 | * include event line markes. | 277 | * include event line markes. |
| 324 | */ | 278 | */ |
| 325 | static int | 279 | int |
| 326 | rt_vcpu_plot_is_drawn(struct graph_info *ginfo, int eid) | 280 | rt_vcpu_plot_is_drawn(struct graph_info *ginfo, int eid) |
| 327 | { | 281 | { |
| 328 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; | 282 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; |
| @@ -334,7 +288,10 @@ rt_vcpu_plot_is_drawn(struct graph_info *ginfo, int eid) | |||
| 334 | eid == rtg_info->server_resume_id); | 288 | eid == rtg_info->server_resume_id); |
| 335 | } | 289 | } |
| 336 | 290 | ||
| 337 | static struct record* | 291 | /** |
| 292 | * | ||
| 293 | */ | ||
| 294 | struct record* | ||
| 338 | rt_vcpu_plot_write_header(struct rt_plot_common *rt, | 295 | rt_vcpu_plot_write_header(struct rt_plot_common *rt, |
| 339 | struct graph_info *ginfo, | 296 | struct graph_info *ginfo, |
| 340 | struct trace_seq *s, | 297 | struct trace_seq *s, |
| @@ -358,38 +315,104 @@ rt_vcpu_plot_write_header(struct rt_plot_common *rt, | |||
| 358 | return record; | 315 | return record; |
| 359 | } | 316 | } |
| 360 | 317 | ||
| 318 | /** | ||
| 319 | * vcpu_try_release - draw release and deadline arrows if record matches | ||
| 320 | */ | ||
| 321 | int vcpu_try_release(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 322 | struct record *record, struct plot_info *info) | ||
| 323 | { | ||
| 324 | int sid, job, match, ret = 0; | ||
| 325 | unsigned long long release, deadline; | ||
| 361 | 326 | ||
| 362 | const struct plot_callbacks rt_vcpu_cb = { | 327 | match = rt_graph_check_server_release(ginfo, record, &sid, &job, |
| 363 | .start = rt_vcpu_plot_start, | 328 | &release, &deadline); |
| 364 | .destroy = rt_vcpu_plot_destroy, | 329 | if (match && sid == vcpu_info->sid) { |
| 365 | .plot_event = rt_vcpu_plot_event, | 330 | info->release = TRUE; |
| 366 | .display_last_event = rt_plot_display_last_event, | 331 | info->rtime = release; |
| 367 | .display_info = rt_plot_display_info, | ||
| 368 | .match_time = rt_plot_match_time, | ||
| 369 | .find_record = rt_plot_find_record, | ||
| 370 | }; | ||
| 371 | 332 | ||
| 372 | void insert_vcpu(struct graph_info *ginfo, struct cont_list *cont, | 333 | info->deadline = TRUE; |
| 373 | struct vcpu_list *vcpu_info) | 334 | info->dtime = deadline; |
| 335 | |||
| 336 | dprintf(3, "VCPU release for %d:%d on %d, rel: %llu, dead: %llu\n", | ||
| 337 | sid, job, record->cpu, release, deadline); | ||
| 338 | |||
| 339 | ret = 1; | ||
| 340 | } | ||
| 341 | return ret; | ||
| 342 | } | ||
| 343 | |||
| 344 | /** | ||
| 345 | * vcpu_try_completion - draw completion if record matches | ||
| 346 | */ | ||
| 347 | int vcpu_try_completion(struct graph_info *ginfo, | ||
| 348 | struct vcpu_info *vcpu_info, | ||
| 349 | struct record *record, struct plot_info *info) | ||
| 374 | { | 350 | { |
| 375 | struct graph_plot *plot; | 351 | int sid, job, match, ret = 0; |
| 376 | struct vcpu_info *vcpu; | 352 | unsigned long long ts; |
| 377 | char *label; | ||
| 378 | 353 | ||
| 379 | vcpu = malloc_or_die(sizeof(*vcpu)); | 354 | match = rt_graph_check_server_completion(ginfo, record, &sid, &job, &ts); |
| 380 | vcpu->sid = vcpu_info->sid; | 355 | if (match && sid == vcpu_info->sid) { |
| 381 | vcpu->cont = cont; | ||
| 382 | vcpu->label = malloc_or_die(LLABEL); | ||
| 383 | 356 | ||
| 384 | vcpu->common.record_matches = rt_vcpu_plot_record_matches; | 357 | info->completion = TRUE; |
| 385 | vcpu->common.is_drawn = rt_vcpu_plot_is_drawn; | 358 | info->ctime = ts; |
| 386 | vcpu->common.write_header = rt_vcpu_plot_write_header; | ||
| 387 | 359 | ||
| 388 | g_assert(cont); | 360 | dprintf(3, "VCPU completion for %d:%d on %d at %llu\n", |
| 361 | sid, job, record->cpu, ts); | ||
| 362 | ret = 1; | ||
| 363 | } | ||
| 364 | return ret; | ||
| 365 | } | ||
| 389 | 366 | ||
| 390 | label = malloc_or_die(1); | 367 | /** |
| 391 | snprintf(label, 2, " "); | 368 | * vcpu_try_block - start block box if record matches |
| 392 | plot = trace_graph_plot_append(ginfo, label, PLOT_TYPE_SERVER_CPU, | 369 | */ |
| 393 | TIME_TYPE_RT, &rt_vcpu_cb, vcpu); | 370 | int vcpu_try_block(struct graph_info *ginfo, struct vcpu_info *vcpu_info, |
| 394 | trace_graph_plot_add_all_recs(ginfo, plot); | 371 | struct record *record, struct plot_info *info) |
| 372 | { | ||
| 373 | int sid, match, ret = 0; | ||
| 374 | unsigned long long ts; | ||
| 375 | |||
| 376 | match = rt_graph_check_server_block(ginfo, record, &sid, &ts); | ||
| 377 | if (match && sid == vcpu_info->sid) { | ||
| 378 | vcpu_info->fresh = FALSE; | ||
| 379 | vcpu_info->block_time = ts; | ||
| 380 | vcpu_info->block_cpu = NO_CPU; | ||
| 381 | dprintf(3, "VCPU resume for %d on %d at %llu\n", | ||
| 382 | sid, record->cpu, ts); | ||
| 383 | ret = 1; | ||
| 384 | } | ||
| 385 | return ret; | ||
| 395 | } | 386 | } |
| 387 | |||
| 388 | /** | ||
| 389 | * vcpu_try_resume - end block box if record matches | ||
| 390 | */ | ||
| 391 | int vcpu_try_resume(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 392 | struct record *record, struct plot_info *info) | ||
| 393 | { | ||
| 394 | int sid, match, ret = 0; | ||
| 395 | unsigned long long ts; | ||
| 396 | |||
| 397 | match = rt_graph_check_server_resume(ginfo, record, &sid, &ts); | ||
| 398 | |||
| 399 | if (match && sid == vcpu_info->sid) { | ||
| 400 | info->box = TRUE; | ||
| 401 | info->bcolor = 0x0; | ||
| 402 | info->bfill = TRUE; | ||
| 403 | info->bthin = TRUE; | ||
| 404 | info->bstart = vcpu_info->block_time; | ||
| 405 | info->bend = ts; | ||
| 406 | vcpu_info->fresh = FALSE; | ||
| 407 | |||
| 408 | vcpu_info->block_time = 0ULL; | ||
| 409 | vcpu_info->block_cpu = NO_CPU; | ||
| 410 | dprintf(3, "VCPU resume for %d on %d at %llu\n", | ||
| 411 | sid, record->cpu, ts); | ||
| 412 | |||
| 413 | ret = 1; | ||
| 414 | } | ||
| 415 | return ret; | ||
| 416 | } | ||
| 417 | |||
| 418 | |||
diff --git a/rt-plot-vcpu.h b/rt-plot-vcpu.h index 9c50a63..f88e6ab 100644 --- a/rt-plot-vcpu.h +++ b/rt-plot-vcpu.h | |||
| @@ -11,6 +11,8 @@ struct vcpu_info { | |||
| 11 | int run_cpu; | 11 | int run_cpu; |
| 12 | unsigned long long run_time; | 12 | unsigned long long run_time; |
| 13 | 13 | ||
| 14 | int last_job; | ||
| 15 | |||
| 14 | int block_cpu; | 16 | int block_cpu; |
| 15 | unsigned long long block_time; | 17 | unsigned long long block_time; |
| 16 | 18 | ||
| @@ -24,3 +26,31 @@ struct vcpu_info { | |||
| 24 | 26 | ||
| 25 | void insert_vcpu(struct graph_info *ginfo, struct cont_list *cont, | 27 | void insert_vcpu(struct graph_info *ginfo, struct cont_list *cont, |
| 26 | struct vcpu_list *vcpu_info); | 28 | struct vcpu_list *vcpu_info); |
| 29 | |||
| 30 | |||
| 31 | /* drawing methods */ | ||
| 32 | int vcpu_try_release(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 33 | struct record *record, struct plot_info *info); | ||
| 34 | int vcpu_try_completion(struct graph_info *ginfo, | ||
| 35 | struct vcpu_info *vcpu_info, | ||
| 36 | struct record *record, struct plot_info *info); | ||
| 37 | int vcpu_try_block(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 38 | struct record *record, struct plot_info *info); | ||
| 39 | int vcpu_try_resume(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 40 | struct record *record, struct plot_info *info); | ||
| 41 | |||
| 42 | /* trace-plot methods */ | ||
| 43 | void rt_vcpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot, | ||
| 44 | unsigned long long time); | ||
| 45 | void rt_vcpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot); | ||
| 46 | |||
| 47 | /* rt-plot-common methods */ | ||
| 48 | int rt_vcpu_plot_record_matches(struct rt_plot_common *rt, | ||
| 49 | struct graph_info *ginfo, | ||
| 50 | struct record *record); | ||
| 51 | int rt_vcpu_plot_is_drawn(struct graph_info *ginfo, int eid); | ||
| 52 | struct record* | ||
| 53 | rt_vcpu_plot_write_header(struct rt_plot_common *rt, | ||
| 54 | struct graph_info *ginfo, | ||
| 55 | struct trace_seq *s, | ||
| 56 | unsigned long long time); | ||
diff --git a/rt-plot-vtask.c b/rt-plot-vtask.c new file mode 100644 index 0000000..5b54343 --- /dev/null +++ b/rt-plot-vtask.c | |||
| @@ -0,0 +1,208 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include "trace-graph.h" | ||
| 4 | |||
| 5 | #define DEBUG_LEVEL 0 | ||
| 6 | #if DEBUG_LEVEL > 0 | ||
| 7 | #define dprintf(l, x...) \ | ||
| 8 | do { \ | ||
| 9 | if (l <= DEBUG_LEVEL) \ | ||
| 10 | printf(x); \ | ||
| 11 | } while (0) | ||
| 12 | #else | ||
| 13 | #define dprintf(l, x...) do { if (0) printf(x); } while (0) | ||
| 14 | #endif | ||
| 15 | |||
| 16 | static void update_job(struct vcpu_info *info, int job) | ||
| 17 | { | ||
| 18 | info->fresh = FALSE; | ||
| 19 | if (job < info->last_job) { | ||
| 20 | dprintf(1, "Inconsistent job state for server %d:%d -> %d\n", | ||
| 21 | info->sid, info->last_job, job); | ||
| 22 | } | ||
| 23 | |||
| 24 | if (job > info->last_job) { | ||
| 25 | info->last_job = job; | ||
| 26 | snprintf(info->label, LLABEL, "%d:%d", | ||
| 27 | info->sid, info->last_job); | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | static int | ||
| 32 | try_server_switch_away(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 33 | struct record *record, struct plot_info *info) | ||
| 34 | { | ||
| 35 | int job, sid, tid, match, ret = 0; | ||
| 36 | unsigned long long ts; | ||
| 37 | |||
| 38 | match = rt_graph_check_server_switch_away(ginfo, record, | ||
| 39 | &sid, &job, | ||
| 40 | &tid, &ts); | ||
| 41 | if (match && sid == vcpu_info->sid) { | ||
| 42 | /* update_job(vcpu_info, job); */ | ||
| 43 | |||
| 44 | if (vcpu_info->run_time < ts) { | ||
| 45 | info->box = TRUE; | ||
| 46 | info->bcolor = hash_pid(sid); | ||
| 47 | info->bfill = TRUE; | ||
| 48 | info->bstart = vcpu_info->run_time; | ||
| 49 | info->bend = ts; | ||
| 50 | info->blabel = vcpu_info->label; | ||
| 51 | } | ||
| 52 | |||
| 53 | dprintf(3, "VCPU switch away from %d on %d:%d at %llu\n", | ||
| 54 | tid, sid, job, ts); | ||
| 55 | vcpu_info->run_time = 0ULL; | ||
| 56 | vcpu_info->run_cpu = NO_CPU; | ||
| 57 | vcpu_info->run_tid = 0; | ||
| 58 | |||
| 59 | ret = 1; | ||
| 60 | } | ||
| 61 | |||
| 62 | return ret; | ||
| 63 | } | ||
| 64 | |||
| 65 | static int try_server_switch_to(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 66 | struct record *record, struct plot_info *info) | ||
| 67 | { | ||
| 68 | int job, sid, tid, match, ret = 0; | ||
| 69 | unsigned long long ts; | ||
| 70 | |||
| 71 | match = rt_graph_check_server_switch_to(ginfo, record, | ||
| 72 | &sid, &job, &tid, &ts); | ||
| 73 | if (match && sid == vcpu_info->sid) { | ||
| 74 | update_job(vcpu_info, job); | ||
| 75 | vcpu_info->run_time = ts; | ||
| 76 | vcpu_info->run_cpu = record->cpu; | ||
| 77 | vcpu_info->run_tid = tid; | ||
| 78 | dprintf(3, "Switch to %d for %d:%d at %llu\n", | ||
| 79 | tid, sid, job, ts); | ||
| 80 | ret = 1; | ||
| 81 | } | ||
| 82 | return ret; | ||
| 83 | } | ||
| 84 | |||
| 85 | static int try_switch_to(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 86 | struct record *record, struct plot_info *info) | ||
| 87 | { | ||
| 88 | int job, pid, match, ret = 0; | ||
| 89 | unsigned long long ts; | ||
| 90 | |||
| 91 | match = rt_graph_check_switch_to(ginfo, record, &pid, &job, &ts); | ||
| 92 | if (match && pid && pid == vcpu_info->run_tid && vcpu_info->run_time) { | ||
| 93 | info->line = TRUE; | ||
| 94 | info->lcolor = hash_pid(pid); | ||
| 95 | ret = 1; | ||
| 96 | } | ||
| 97 | return ret; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int try_switch_away(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 101 | struct record *record, struct plot_info *info) | ||
| 102 | { | ||
| 103 | int job, pid, match, ret = 0; | ||
| 104 | unsigned long long ts; | ||
| 105 | |||
| 106 | match = rt_graph_check_switch_away(ginfo, record, &pid, &job, &ts); | ||
| 107 | if (match && pid && pid == vcpu_info->run_tid) { | ||
| 108 | info->line = TRUE; | ||
| 109 | info->lcolor = hash_pid(pid); | ||
| 110 | ret = 1; | ||
| 111 | } | ||
| 112 | return ret; | ||
| 113 | } | ||
| 114 | |||
| 115 | static void do_plot_end(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
| 116 | struct plot_info *info) | ||
| 117 | { | ||
| 118 | int tid, job, is_running; | ||
| 119 | unsigned long long deadline, release; | ||
| 120 | struct record *record; | ||
| 121 | |||
| 122 | if (vcpu_info->run_time && vcpu_info->run_cpu != NO_CPU) { | ||
| 123 | info->box = TRUE; | ||
| 124 | info->bcolor = hash_pid(vcpu_info->sid); | ||
| 125 | info->bfill = TRUE; | ||
| 126 | info->bstart = vcpu_info->run_time; | ||
| 127 | info->bend = ginfo->view_end_time; | ||
| 128 | info->blabel = vcpu_info->label; | ||
| 129 | } else if (vcpu_info->fresh) { | ||
| 130 | is_running = get_server_info(ginfo, | ||
| 131 | (struct rt_plot_common*)vcpu_info, | ||
| 132 | vcpu_info->sid, | ||
| 133 | ginfo->view_end_time, | ||
| 134 | &release, &deadline, | ||
| 135 | &job, &tid, &record); | ||
| 136 | if (is_running) { | ||
| 137 | update_job(vcpu_info, job); | ||
| 138 | info->box = TRUE; | ||
| 139 | info->bcolor = hash_pid(vcpu_info->sid); | ||
| 140 | info->bfill = TRUE; | ||
| 141 | info->bstart = vcpu_info->run_time; | ||
| 142 | info->bend = ginfo->view_end_time; | ||
| 143 | info->blabel = vcpu_info->label; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | static int rt_vtask_plot_event(struct graph_info *ginfo, struct graph_plot *plot, | ||
| 149 | struct record *record, struct plot_info *info) | ||
| 150 | { | ||
| 151 | int match; | ||
| 152 | struct vcpu_info *vcpu_info = plot->private; | ||
| 153 | |||
| 154 | if (!record) { | ||
| 155 | do_plot_end(ginfo, vcpu_info, info); | ||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | match = try_server_switch_away(ginfo, vcpu_info, record, info) || | ||
| 160 | try_server_switch_to(ginfo, vcpu_info, record, info) || | ||
| 161 | vcpu_try_block(ginfo, vcpu_info, record, info) || | ||
| 162 | vcpu_try_resume(ginfo, vcpu_info, record, info) || | ||
| 163 | vcpu_try_release(ginfo, vcpu_info, record, info) || | ||
| 164 | vcpu_try_completion(ginfo, vcpu_info, record, info) || | ||
| 165 | try_switch_to(ginfo, vcpu_info, record, info) || | ||
| 166 | try_switch_away(ginfo, vcpu_info, record, info); | ||
| 167 | return match; | ||
| 168 | } | ||
| 169 | |||
| 170 | const struct plot_callbacks rt_vtask_cb = { | ||
| 171 | .start = rt_vcpu_plot_start, | ||
| 172 | .destroy = rt_vcpu_plot_destroy, | ||
| 173 | .plot_event = rt_vtask_plot_event, | ||
| 174 | .display_last_event = rt_plot_display_last_event, | ||
| 175 | .display_info = rt_plot_display_info, | ||
| 176 | .match_time = rt_plot_match_time, | ||
| 177 | .find_record = rt_plot_find_record, | ||
| 178 | }; | ||
| 179 | |||
| 180 | void insert_vtask(struct graph_info *ginfo, struct cont_list *cont, | ||
| 181 | struct vcpu_list *vcpu_info) | ||
| 182 | { | ||
| 183 | struct graph_plot *plot; | ||
| 184 | struct vcpu_info *vtask; | ||
| 185 | char *label; | ||
| 186 | int len; | ||
| 187 | |||
| 188 | vtask = malloc_or_die(sizeof(*vtask)); | ||
| 189 | vtask->sid = vcpu_info->sid; | ||
| 190 | vtask->label = malloc_or_die(LLABEL); | ||
| 191 | vtask->cont = cont; | ||
| 192 | |||
| 193 | vtask->common.record_matches = rt_vcpu_plot_record_matches; | ||
| 194 | vtask->common.is_drawn = rt_vcpu_plot_is_drawn; | ||
| 195 | vtask->common.write_header = rt_vcpu_plot_write_header; | ||
| 196 | |||
| 197 | |||
| 198 | len = strlen(cont->name) + 100; | ||
| 199 | label = malloc_or_die(len); | ||
| 200 | snprintf(label, len, "%s - %d\n(%1.1f, %1.1f)", | ||
| 201 | cont->name, -vtask->sid, | ||
| 202 | nano_as_milli(vcpu_info->params.wcet), | ||
| 203 | nano_as_milli(vcpu_info->params.period)); | ||
| 204 | |||
| 205 | plot = trace_graph_plot_append(ginfo, label, PLOT_TYPE_SERVER_TASK, | ||
| 206 | TIME_TYPE_RT, &rt_vtask_cb, vtask); | ||
| 207 | trace_graph_plot_add_all_recs(ginfo, plot); | ||
| 208 | } | ||
diff --git a/rt-plot-vtask.h b/rt-plot-vtask.h new file mode 100644 index 0000000..05a026c --- /dev/null +++ b/rt-plot-vtask.h | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | #include "trace-graph.h" | ||
| 2 | |||
| 3 | void insert_vtask(struct graph_info *ginfo, struct cont_list *cont, | ||
| 4 | struct vcpu_list *vcpu_info); | ||
diff --git a/rt-plot.c b/rt-plot.c new file mode 100644 index 0000000..b04caf1 --- /dev/null +++ b/rt-plot.c | |||
| @@ -0,0 +1,352 @@ | |||
| 1 | #include <gtk/gtk.h> | ||
| 2 | #include "trace-graph.h" | ||
| 3 | |||
| 4 | /** | ||
| 5 | * Return first relevant record after @time. | ||
| 6 | * @display: If set, only considers records which aren't plotted | ||
| 7 | */ | ||
| 8 | struct record* | ||
| 9 | __find_rt_record(struct graph_info *ginfo, struct rt_plot_common *rt_info, | ||
| 10 | guint64 time, int display) | ||
| 11 | { | ||
| 12 | int next_cpu, match, eid, ignored; | ||
| 13 | struct record *record; | ||
| 14 | |||
| 15 | set_cpus_to_rts(ginfo, time); | ||
| 16 | while ((record = tracecmd_read_next_data(ginfo->handle, &next_cpu))) { | ||
| 17 | eid = pevent_data_type(ginfo->pevent, record); | ||
| 18 | ignored = (eid == ginfo->event_sched_switch_id); | ||
| 19 | if (!ignored && display) { | ||
| 20 | ignored = rt_info->is_drawn(ginfo, eid); | ||
| 21 | } | ||
| 22 | match = !ignored && | ||
| 23 | rt_info->record_matches(rt_info, ginfo, record); | ||
| 24 | |||
| 25 | if (get_rts(ginfo, record) >= time && match) | ||
| 26 | break; | ||
| 27 | free_record(record); | ||
| 28 | }; | ||
| 29 | |||
| 30 | return record; | ||
| 31 | } | ||
| 32 | |||
| 33 | |||
| 34 | /** | ||
| 35 | * rt_plot_display_last_event - write event name at @time onto plot. | ||
| 36 | */ | ||
| 37 | int | ||
| 38 | rt_plot_display_last_event(struct graph_info *ginfo, struct graph_plot *plot, | ||
| 39 | struct trace_seq *s, unsigned long long time) | ||
| 40 | { | ||
| 41 | int eid; | ||
| 42 | struct event_format *event; | ||
| 43 | struct record *record; | ||
| 44 | struct offset_cache *offsets; | ||
| 45 | struct rt_plot_common *rt_info = plot->private; | ||
| 46 | |||
| 47 | offsets = save_offsets(ginfo); | ||
| 48 | |||
| 49 | record = find_rt_display_record(ginfo, rt_info, time); | ||
| 50 | |||
| 51 | restore_offsets(ginfo, offsets); | ||
| 52 | if (!record) | ||
| 53 | return 0; | ||
| 54 | |||
| 55 | eid = pevent_data_type(ginfo->pevent, record); | ||
| 56 | event = pevent_data_event_from_type(ginfo->pevent, eid); | ||
| 57 | if (event) | ||
| 58 | trace_seq_puts(s, event->name); | ||
| 59 | else | ||
| 60 | trace_seq_printf(s, "UNKNOWN EVENT %d\n", eid); | ||
| 61 | trace_seq_putc(s, '\n'); | ||
| 62 | trace_seq_printf(s, "CPU %d\n", record->cpu); | ||
| 63 | free_record(record); | ||
| 64 | |||
| 65 | return 1; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * rt_plot_display_info - write information about @time into @s | ||
| 70 | */ | ||
| 71 | int | ||
| 72 | rt_plot_display_info(struct graph_info *ginfo, struct graph_plot *plot, | ||
| 73 | struct trace_seq *s, unsigned long long time) | ||
| 74 | { | ||
| 75 | struct rt_plot_common *rt_info = plot->private; | ||
| 76 | struct event_format *event; | ||
| 77 | struct record *record; | ||
| 78 | unsigned long long msec, nsec, rts; | ||
| 79 | int eid; | ||
| 80 | |||
| 81 | record = rt_info->write_header(rt_info, ginfo, s, time); | ||
| 82 | |||
| 83 | if (record) { | ||
| 84 | rts = get_rts(ginfo, record); | ||
| 85 | eid = pevent_data_type(ginfo->pevent, record); | ||
| 86 | |||
| 87 | if (in_res(ginfo, rts, time)) { | ||
| 88 | event = pevent_data_event_from_type(ginfo->pevent, eid); | ||
| 89 | if (event) { | ||
| 90 | trace_seq_putc(s, '\n'); | ||
| 91 | trace_seq_puts(s, event->name); | ||
| 92 | trace_seq_putc(s, '\n'); | ||
| 93 | pevent_event_info(s, event, record); | ||
| 94 | } else | ||
| 95 | trace_seq_printf(s, "\nUNKNOWN EVENT %d\n", eid); | ||
| 96 | } | ||
| 97 | trace_seq_putc(s, '\n'); | ||
| 98 | nano_to_milli(time, &msec, &nsec); | ||
| 99 | trace_seq_printf(s, "%llu.%06llu ms CPU: %03d", | ||
| 100 | msec, nsec, record->cpu); | ||
| 101 | free_record(record); | ||
| 102 | } | ||
| 103 | |||
| 104 | return 1; | ||
| 105 | } | ||
| 106 | |||
| 107 | /** | ||
| 108 | * rt_plot_find_rt_record - return matching record around @time. | ||
| 109 | */ | ||
| 110 | struct record* | ||
| 111 | rt_plot_find_record(struct graph_info *ginfo, struct graph_plot *plot, | ||
| 112 | unsigned long long time) | ||
| 113 | { | ||
| 114 | return find_rt_record(ginfo, plot->private, time); | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * rt_plot_match_time - return 1 if there is an exact match at @time. | ||
| 119 | */ | ||
| 120 | int | ||
| 121 | rt_plot_match_time(struct graph_info *ginfo, struct graph_plot *plot, | ||
| 122 | unsigned long long time) | ||
| 123 | { | ||
| 124 | struct record *record = NULL; | ||
| 125 | struct rt_plot_common *rt_info = plot->private; | ||
| 126 | int next_cpu, match, ret; | ||
| 127 | |||
| 128 | set_cpus_to_rts(ginfo, time); | ||
| 129 | |||
| 130 | do { | ||
| 131 | free_record(record); | ||
| 132 | record = tracecmd_read_next_data(ginfo->handle, &next_cpu); | ||
| 133 | if (!record) | ||
| 134 | return 0; | ||
| 135 | match = rt_info->record_matches(rt_info, ginfo, record); | ||
| 136 | } while ((!match && get_rts(ginfo, record) < time + 1) || | ||
| 137 | (match && get_rts(ginfo, record) < time)); | ||
| 138 | |||
| 139 | if (record && get_rts(ginfo, record) == time) | ||
| 140 | ret = 1; | ||
| 141 | free_record(record); | ||
| 142 | |||
| 143 | return ret; | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | |||
| 148 | /** | ||
| 149 | * next_rts - find a real-time timestamp AROUND an FTRACE time | ||
| 150 | * @ginfo: Current state of the graph | ||
| 151 | * @cpu: CPU to search | ||
| 152 | * @ft_target: FTRACE time to seek towards | ||
| 153 | * | ||
| 154 | * Returns the RT time of a record CLOSELY BEFORE @ft_time. | ||
| 155 | */ | ||
| 156 | unsigned long long | ||
| 157 | next_rts(struct graph_info *ginfo, int cpu, unsigned long long ft_target) | ||
| 158 | { | ||
| 159 | struct record *record; | ||
| 160 | unsigned long long ts = 0ULL; | ||
| 161 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, ft_target); | ||
| 162 | record = tracecmd_read_data(ginfo->handle, cpu); | ||
| 163 | if (record) { | ||
| 164 | ts = get_rts(ginfo, record); | ||
| 165 | free_record(record); | ||
| 166 | return ts; | ||
| 167 | } else | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | /** | ||
| 172 | * set_cpu_to_rts - seek CPU to a time closely preceding a real-time timestamp | ||
| 173 | * @ginfo: Current state o the graph | ||
| 174 | * @cpu: The CPU to seek | ||
| 175 | * @rt_target: RT time to seek towards | ||
| 176 | * | ||
| 177 | * This seeks to a real-time timestamp, not the default ftrace timestamps. | ||
| 178 | * The @cpu seek location will be placed before the given time, but will | ||
| 179 | * not necessarily be placed _right_ before the time. | ||
| 180 | */ | ||
| 181 | void | ||
| 182 | set_cpu_to_rts(struct graph_info *ginfo, unsigned long long rt_target, int cpu) | ||
| 183 | { | ||
| 184 | struct record *record; | ||
| 185 | unsigned long long last_rts, rts, seek_time, last_seek; | ||
| 186 | long long diff; | ||
| 187 | |||
| 188 | rts = next_rts(ginfo, cpu, rt_target); | ||
| 189 | diff = rt_target - rts; | ||
| 190 | |||
| 191 | /* "Guess" a new target based on difference */ | ||
| 192 | seek_time = rt_target + diff; | ||
| 193 | rts = next_rts(ginfo, cpu, seek_time); | ||
| 194 | diff = rt_target - rts; | ||
| 195 | |||
| 196 | /* Zero in in 1.5x the difference increments */ | ||
| 197 | if (rts && diff > 0) { | ||
| 198 | /* rts rt_target | real-time time | ||
| 199 | * seek ? | trace-cmd time | ||
| 200 | * ---|---->>----|-------- | ||
| 201 | */ | ||
| 202 | do { | ||
| 203 | last_seek = seek_time; | ||
| 204 | last_rts = rts; | ||
| 205 | seek_time = seek_time + 1.5 * (rt_target - rts); | ||
| 206 | rts = next_rts(ginfo, cpu, seek_time); | ||
| 207 | } while (rts < rt_target && last_rts != rts); | ||
| 208 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, last_seek); | ||
| 209 | seek_time = last_seek; | ||
| 210 | } else if (rts && diff < 0) { | ||
| 211 | /* rt_target rts | real-time time | ||
| 212 | * ? seek | trace-cmd time | ||
| 213 | * ---|----<<----|-------- | ||
| 214 | */ | ||
| 215 | do { | ||
| 216 | seek_time = seek_time - 1.5 * (rts - rt_target); | ||
| 217 | rts = next_rts(ginfo, cpu, seek_time); | ||
| 218 | } while (rts > rt_target); | ||
| 219 | } | ||
| 220 | |||
| 221 | /* Get to first record at or after time */ | ||
| 222 | while ((record = tracecmd_read_data(ginfo->handle, cpu))) { | ||
| 223 | if (get_rts(ginfo, record) >= rt_target) | ||
| 224 | break; | ||
| 225 | free_record(record); | ||
| 226 | } | ||
| 227 | if (record) { | ||
| 228 | tracecmd_set_cursor(ginfo->handle, cpu, record->offset); | ||
| 229 | free_record(record); | ||
| 230 | } else | ||
| 231 | tracecmd_set_cpu_to_timestamp(ginfo->handle, cpu, seek_time); | ||
| 232 | } | ||
| 233 | |||
| 234 | /** | ||
| 235 | * set_cpus_to_time - seek all cpus to real-time @rt_target | ||
| 236 | */ | ||
| 237 | void set_cpus_to_rts(struct graph_info *ginfo, unsigned long long rt_target) | ||
| 238 | { | ||
| 239 | int cpu; | ||
| 240 | for (cpu = 0; cpu < ginfo->cpus; cpu++) | ||
| 241 | set_cpu_to_rts(ginfo, rt_target, cpu); | ||
| 242 | } | ||
| 243 | |||
| 244 | |||
| 245 | /** | ||
| 246 | * is_task_running - return 1 if @match_pid is running at @time. | ||
| 247 | */ | ||
| 248 | int is_task_running(struct graph_info *ginfo, | ||
| 249 | unsigned long long time, | ||
| 250 | int match_pid) | ||
| 251 | { | ||
| 252 | int pid, job, cpu, running = 0; | ||
| 253 | unsigned long long ts, min_ts; | ||
| 254 | struct record *rec; | ||
| 255 | |||
| 256 | set_cpus_to_rts(ginfo, time); | ||
| 257 | |||
| 258 | min_ts = time - max_rt_search(ginfo); | ||
| 259 | |||
| 260 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
| 261 | rec = tracecmd_peek_data(ginfo->handle, cpu); | ||
| 262 | if (!rec) | ||
| 263 | continue; | ||
| 264 | |||
| 265 | while ((rec = tracecmd_read_prev(ginfo->handle, rec))) { | ||
| 266 | if (get_rts(ginfo, rec) < min_ts) | ||
| 267 | goto out; | ||
| 268 | |||
| 269 | #define ARG ginfo, rec, &pid, &job, &ts | ||
| 270 | if (rt_graph_check_switch_away(ARG)) { | ||
| 271 | if (pid == match_pid) | ||
| 272 | goto out; | ||
| 273 | } else if (rt_graph_check_switch_to(ARG)) { | ||
| 274 | if (pid == match_pid) { | ||
| 275 | running = 1; | ||
| 276 | goto out; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | #undef ARG | ||
| 280 | } | ||
| 281 | free_record(rec); | ||
| 282 | |||
| 283 | } | ||
| 284 | out: | ||
| 285 | free_record(rec); | ||
| 286 | return running; | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * Find the information for the last release of @match_tid on @cpu before @time. | ||
| 291 | * | ||
| 292 | * This method will NOT re-seek the CPUs near time. The caller must have placed | ||
| 293 | * the CPUs near the the CPUs themselves. | ||
| 294 | * | ||
| 295 | * Returns release record and @out_job, @out_release, and @out_deadline if a | ||
| 296 | * release was found for @tid before @time. | ||
| 297 | */ | ||
| 298 | struct record* get_previous_release(struct graph_info *ginfo, int match_tid, | ||
| 299 | unsigned long long time, | ||
| 300 | int *out_job, | ||
| 301 | unsigned long long *out_release, | ||
| 302 | unsigned long long *out_deadline) | ||
| 303 | { | ||
| 304 | int tid, cpu, match, job; | ||
| 305 | unsigned long long release, deadline, min_ts; | ||
| 306 | struct record *last_rec = NULL, *rec, *ret = NULL; | ||
| 307 | |||
| 308 | min_ts = time - max_rt_search(ginfo); | ||
| 309 | |||
| 310 | /* The release record could have occurred on any CPU. Search all */ | ||
| 311 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
| 312 | last_rec = tracecmd_peek_data(ginfo->handle, cpu); | ||
| 313 | |||
| 314 | /* Require a record to start with */ | ||
| 315 | if (!last_rec) | ||
| 316 | goto loop_end; | ||
| 317 | last_rec->ref_count++; | ||
| 318 | |||
| 319 | while ((rec = tracecmd_read_prev(ginfo->handle, last_rec))) { | ||
| 320 | if (rec->ts < min_ts) { | ||
| 321 | free_record(rec); | ||
| 322 | goto loop_end; | ||
| 323 | } | ||
| 324 | |||
| 325 | #define ARG ginfo, rec, &tid, &job, &release, &deadline | ||
| 326 | match = rt_graph_check_task_release(ARG) || | ||
| 327 | rt_graph_check_server_release(ARG); | ||
| 328 | #undef ARG | ||
| 329 | |||
| 330 | free_record(last_rec); | ||
| 331 | last_rec = rec; | ||
| 332 | |||
| 333 | /* Only consider releases before the current time */ | ||
| 334 | if (match && tid == match_tid && release <= time) { | ||
| 335 | /* Return the lastest release */ | ||
| 336 | if (!ret || *out_job < job) { | ||
| 337 | free_record(ret); | ||
| 338 | ret = rec; | ||
| 339 | *out_job = job; | ||
| 340 | *out_release = release; | ||
| 341 | *out_deadline = deadline; | ||
| 342 | } | ||
| 343 | |||
| 344 | last_rec = NULL; | ||
| 345 | goto loop_end; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | loop_end: | ||
| 349 | free_record(last_rec); | ||
| 350 | } | ||
| 351 | return ret; | ||
| 352 | } | ||
