aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2012-03-28 20:00:09 -0400
committerJonathan Herman <hermanjl@cs.unc.edu>2012-03-28 20:00:09 -0400
commit384a901c64991dc0b87838ef6f31cf539e5eeb3d (patch)
treea46576279e447fab4eaae94b1cf96c6f64fbfffa
parent7ebeccc383b15c3aea44a00fe2e920c395378613 (diff)
containers: both virtual tasks and cpus now drawn
-rw-r--r--Makefile2
-rw-r--r--rt-graph.c2
-rw-r--r--rt-plot-container.c46
-rw-r--r--rt-plot-container.h1
-rw-r--r--rt-plot-vcpu.c279
-rw-r--r--rt-plot-vcpu.h30
-rw-r--r--rt-plot-vtask.c208
-rw-r--r--rt-plot-vtask.h4
-rw-r--r--rt-plot.c352
9 files changed, 751 insertions, 173 deletions
diff --git a/Makefile b/Makefile
index f1254c3..1a8c0a2 100644
--- a/Makefile
+++ b/Makefile
@@ -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
301TRACE_VIEW_OBJS = trace-view.o trace-view-store.o 301TRACE_VIEW_OBJS = trace-view.o trace-view-store.o
302RT_GRAPH_OBJS = rt-graph.o rt-plot-task.o rt-plot-cpu.o rt-plot-container.o rt-plot.o \ 302RT_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
304TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o \ 304TRACE_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
diff --git a/rt-graph.c b/rt-graph.c
index fbf61bd..239018e 100644
--- a/rt-graph.c
+++ b/rt-graph.c
@@ -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
7struct vtask_info {
8 struct rt_task_info task_info;
9 struct cont_list *cont;
10};
11
12static 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
41int rt_plot_get_containers(struct graph_info *ginfo, gint **conts, 7int 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
6typedef void (*cont_dialog_cb_func)(gboolean, gint*, gint*, gpointer); 7typedef 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
26static 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
49static 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
69static 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
87static 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
114static int 25static int
115try_server_switch_away(struct graph_info *ginfo, struct vcpu_info *vcpu_info, 26try_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
271static void rt_vcpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot, 182
183const 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
193void 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 */
221void 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
291static void rt_vcpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) 242/**
243 *
244 */
245void 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 */
302static int rt_vcpu_plot_record_matches(struct rt_plot_common *rt, 256int 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 */
325static int 279int
326rt_vcpu_plot_is_drawn(struct graph_info *ginfo, int eid) 280rt_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
337static struct record* 291/**
292 *
293 */
294struct record*
338rt_vcpu_plot_write_header(struct rt_plot_common *rt, 295rt_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 */
321int 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
362const 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
372void 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 */
347int 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); 370int 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 */
391int 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
25void insert_vcpu(struct graph_info *ginfo, struct cont_list *cont, 27void 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 */
32int vcpu_try_release(struct graph_info *ginfo, struct vcpu_info *vcpu_info,
33 struct record *record, struct plot_info *info);
34int vcpu_try_completion(struct graph_info *ginfo,
35 struct vcpu_info *vcpu_info,
36 struct record *record, struct plot_info *info);
37int vcpu_try_block(struct graph_info *ginfo, struct vcpu_info *vcpu_info,
38 struct record *record, struct plot_info *info);
39int 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 */
43void rt_vcpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot,
44 unsigned long long time);
45void rt_vcpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot);
46
47/* rt-plot-common methods */
48int rt_vcpu_plot_record_matches(struct rt_plot_common *rt,
49 struct graph_info *ginfo,
50 struct record *record);
51int rt_vcpu_plot_is_drawn(struct graph_info *ginfo, int eid);
52struct record*
53rt_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
16static 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
31static int
32try_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
65static 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
85static 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
100static 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
115static 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
148static 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
170const 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
180void 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
3void 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 */
8struct 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 */
37int
38rt_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 */
71int
72rt_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*
111rt_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 */
120int
121rt_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 */
156unsigned long long
157next_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 */
181void
182set_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 */
237void 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 */
248int 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 */
298struct 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}