diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-03-28 16:34:20 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-03-28 16:34:20 -0400 |
commit | 57672aa4f46311a82d4a9437d512adb099a7f8bf (patch) | |
tree | dcd072ee724f62327599df2b3c3edaaabacbe45b | |
parent | b53dd6d749e0a164010f2cf1fedab2b10b8bb305 (diff) |
containers: virtual cpus display in the normal case
-rw-r--r-- | rt-graph.h | 2 | ||||
-rw-r--r-- | rt-plot-container.c | 374 | ||||
-rw-r--r-- | rt-plot-container.h | 21 | ||||
-rw-r--r-- | rt-plot-task.c | 2 | ||||
-rw-r--r-- | rt-plot-vcpu-task.h | 9 | ||||
-rw-r--r-- | rt-plot-vcpu.c | 372 | ||||
-rw-r--r-- | rt-plot-vcpu.h | 22 | ||||
-rw-r--r-- | rt-plot.h | 65 | ||||
-rw-r--r-- | trace-graph.c | 2 |
9 files changed, 866 insertions, 3 deletions
@@ -10,7 +10,7 @@ | |||
10 | #include "rt-plot-container.h" | 10 | #include "rt-plot-container.h" |
11 | 11 | ||
12 | #define LLABEL 30 | 12 | #define LLABEL 30 |
13 | #define SEARCH_PERIODS 3 | 13 | #define SEARCH_PERIODS 1 |
14 | #define NO_CPU -1 | 14 | #define NO_CPU -1 |
15 | #define RT_TS_FIELD "__rt_ts" | 15 | #define RT_TS_FIELD "__rt_ts" |
16 | 16 | ||
diff --git a/rt-plot-container.c b/rt-plot-container.c new file mode 100644 index 0000000..f36e2f8 --- /dev/null +++ b/rt-plot-container.c | |||
@@ -0,0 +1,374 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include "trace-graph.h" | ||
4 | #include "trace-hash.h" | ||
5 | #include "trace-filter.h" | ||
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, | ||
42 | gboolean plotted_only) | ||
43 | { | ||
44 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; | ||
45 | struct cont_list *cont; | ||
46 | int i, count = 0; | ||
47 | |||
48 | *conts = NULL; | ||
49 | for (i = 0; i < CONT_HASH_SIZE; i++) { | ||
50 | for (cont = rtg_info->containers[i]; cont; cont = cont->next) { | ||
51 | if (!plotted_only || cont->plotted) { | ||
52 | trace_array_add(conts, &count, cont->cid); | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | return count; | ||
57 | } | ||
58 | |||
59 | int get_server_info(struct graph_info *ginfo, struct rt_plot_common *rt, | ||
60 | int match_sid, unsigned long long time, | ||
61 | unsigned long long *out_release, | ||
62 | unsigned long long *out_deadline, | ||
63 | int *out_job, int *out_tid, | ||
64 | struct record **out_record) | ||
65 | { | ||
66 | struct record *record; | ||
67 | int sid, job, tid, match, next_cpu, is_running = 0; | ||
68 | unsigned long long when, max_ts; | ||
69 | |||
70 | *out_record = find_rt_record(ginfo, rt, time); | ||
71 | if (!(*out_record)) | ||
72 | return 0; | ||
73 | |||
74 | *out_release = *out_deadline = *out_job = *out_tid = 0; | ||
75 | |||
76 | /* Get current job info for server task */ | ||
77 | get_previous_release(ginfo, sid, time, | ||
78 | out_job, out_release, out_deadline); | ||
79 | |||
80 | /* Need to reset back to current location */ | ||
81 | record = find_rt_record(ginfo, rt, time); | ||
82 | if (!record) | ||
83 | goto out; | ||
84 | |||
85 | /* TODO: read backwards too */ | ||
86 | max_ts = time + max_rt_search(ginfo); | ||
87 | do { | ||
88 | if (get_rts(ginfo, record) > max_ts) | ||
89 | break; | ||
90 | |||
91 | match = rt_graph_check_server_switch_away(ginfo, record, | ||
92 | &sid, &job, &tid, | ||
93 | &when); | ||
94 | if (match && sid == match_sid) { | ||
95 | *out_tid = tid; | ||
96 | is_running = 1; | ||
97 | break; | ||
98 | } | ||
99 | free_record(record); | ||
100 | } while ((record = tracecmd_read_next_data(ginfo->handle, &next_cpu))); | ||
101 | |||
102 | if (record && record != *out_record) | ||
103 | free_record(record); | ||
104 | out: | ||
105 | return is_running; | ||
106 | } | ||
107 | |||
108 | void rt_plot_container(struct graph_info *ginfo, int cid) | ||
109 | { | ||
110 | struct cont_list *cont; | ||
111 | struct vcpu_list *vlist; | ||
112 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; | ||
113 | int key; | ||
114 | |||
115 | key = get_container_key(cid); | ||
116 | cont = find_container(rtg_info->containers, cid, key); | ||
117 | if (!cont) | ||
118 | die("Cannot create plot of non-existent container %d!\n", cid); | ||
119 | if (!cont->vcpus) | ||
120 | die("Cannot plot container %d with no vcpus!\n", cid); | ||
121 | |||
122 | cont->plotted = TRUE; | ||
123 | |||
124 | for (vlist = cont->vcpus; vlist; vlist = vlist->next) { | ||
125 | /* insert_vtask(ginfo, cont, vlist); */ | ||
126 | insert_vcpu(ginfo, cont, vlist); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | void rt_plot_add_all_containers(struct graph_info *ginfo) | ||
131 | { | ||
132 | struct cont_list *cont, **conts; | ||
133 | int i; | ||
134 | |||
135 | conts = ginfo->rtg_info.containers; | ||
136 | for (i = 0; i < CONT_HASH_SIZE; i++) { | ||
137 | for (cont = *conts; cont; cont = cont->next) { | ||
138 | rt_plot_container(ginfo, cont->cid); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | |||
143 | struct cont_filter_helper { | ||
144 | gboolean all_conts; | ||
145 | GtkWidget **buttons; | ||
146 | int *conts; | ||
147 | gboolean *selected; | ||
148 | int num_conts; | ||
149 | }; | ||
150 | |||
151 | #define ALL_CONTS_STR "All Containers" | ||
152 | #define DIALOG_WIDTH 400 | ||
153 | #define DIALOG_HEIGHT 600 | ||
154 | |||
155 | static void cont_toggle(gpointer data, GtkWidget *widget) | ||
156 | { | ||
157 | struct cont_filter_helper *helper = data; | ||
158 | const gchar *label; | ||
159 | gboolean active; | ||
160 | int cont; | ||
161 | |||
162 | label = gtk_button_get_label(GTK_BUTTON(widget)); | ||
163 | active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); | ||
164 | |||
165 | if (strcmp(label, ALL_CONTS_STR) == 0) { | ||
166 | helper->all_conts = active; | ||
167 | if (active) { | ||
168 | for (cont = 0; cont < helper->num_conts; cont++) { | ||
169 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(helper->buttons[cont]), | ||
170 | TRUE); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | for (cont = 0; cont < helper->num_conts; cont++) { | ||
176 | if (helper->buttons[cont] == widget) { | ||
177 | helper->selected[cont] = active; | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | |||
183 | |||
184 | static void do_container_filter(struct graph_info *ginfo, | ||
185 | struct cont_filter_helper *helper, gpointer data) | ||
186 | { | ||
187 | struct graph_plot *plot; | ||
188 | struct vtask_info *vtask; | ||
189 | struct vcpu_info *vcpu; | ||
190 | struct cont_list *cont; | ||
191 | int i, c, *append; | ||
192 | |||
193 | append = malloc_or_die(helper->num_conts * sizeof(gint)); | ||
194 | for (i = 0; i < helper->num_conts; i++) | ||
195 | append[i] = helper->selected[i]; | ||
196 | |||
197 | for (i = ginfo->plots - 1; i >= 0; i--) { | ||
198 | plot = ginfo->plot_array[i]; | ||
199 | |||
200 | if (plot->type != PLOT_TYPE_SERVER_TASK && | ||
201 | plot->type != PLOT_TYPE_SERVER_CPU) | ||
202 | continue; | ||
203 | |||
204 | if (plot->type == PLOT_TYPE_SERVER_TASK) { | ||
205 | vtask = plot->private; | ||
206 | cont = vtask->cont; | ||
207 | } else { | ||
208 | vcpu = plot->private; | ||
209 | cont = vcpu->cont; | ||
210 | } | ||
211 | |||
212 | for (c = 0; c < helper->num_conts; c++) { | ||
213 | if (helper->conts[c] == cont->cid) | ||
214 | break; | ||
215 | } | ||
216 | if (c > helper->num_conts) | ||
217 | continue; | ||
218 | |||
219 | if (helper->selected[c]) { | ||
220 | append[c] = FALSE; | ||
221 | } else { | ||
222 | cont->plotted = FALSE; | ||
223 | trace_graph_plot_remove(ginfo, plot); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* Add new plots */ | ||
228 | for (c = 0; c < helper->num_conts; c++) { | ||
229 | if (append[c]) | ||
230 | rt_plot_container(ginfo, helper->conts[c]); | ||
231 | } | ||
232 | trace_graph_refresh(ginfo); | ||
233 | } | ||
234 | |||
235 | void trace_container_dialog(struct graph_info *ginfo, | ||
236 | gpointer data) | ||
237 | { | ||
238 | GtkWidget *dialog, *scrollwin, *viewport, *hbox, *vbox, *check, *twidget; | ||
239 | GtkRequisition req; | ||
240 | struct tracecmd_input *handle; | ||
241 | struct pevent *pevent; | ||
242 | struct cont_filter_helper *cont_helper; | ||
243 | struct cont_list *cont; | ||
244 | gchar label[100]; | ||
245 | gint *selected, *conts; | ||
246 | gboolean tbool; | ||
247 | int i, result, cont_num, height, width, cont_count, select_count; | ||
248 | int start, min_cont, tint; | ||
249 | |||
250 | handle = ginfo->handle; | ||
251 | if (!handle) | ||
252 | return; | ||
253 | pevent = tracecmd_get_pevent(handle); | ||
254 | if (!pevent) | ||
255 | return; | ||
256 | |||
257 | select_count = rt_plot_get_containers(ginfo, &selected, TRUE); | ||
258 | free(selected); | ||
259 | cont_count = rt_plot_get_containers(ginfo, &conts, FALSE); | ||
260 | |||
261 | /* Create helper */ | ||
262 | cont_helper = g_new0(typeof(*cont_helper), 1); | ||
263 | cont_helper->num_conts = cont_count; | ||
264 | cont_helper->buttons = g_new0(GtkWidget*, cont_count + 1); | ||
265 | cont_helper->conts = conts; | ||
266 | cont_helper->selected = g_new0(gint, cont_count); | ||
267 | |||
268 | /* Create dialog window */ | ||
269 | dialog = gtk_dialog_new_with_buttons("Select Containers", NULL, | ||
270 | GTK_DIALOG_MODAL, "Apply", | ||
271 | GTK_RESPONSE_ACCEPT, | ||
272 | GTK_STOCK_CANCEL, | ||
273 | GTK_RESPONSE_REJECT, NULL); | ||
274 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | ||
275 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | ||
276 | GTK_POLICY_AUTOMATIC, | ||
277 | GTK_POLICY_AUTOMATIC); | ||
278 | viewport = gtk_viewport_new(NULL, NULL); | ||
279 | gtk_widget_show(viewport); | ||
280 | |||
281 | /* Create scroll area */ | ||
282 | gtk_container_add(GTK_CONTAINER(scrollwin), viewport); | ||
283 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); | ||
284 | hbox = gtk_hbox_new(FALSE, 0); | ||
285 | gtk_container_add(GTK_CONTAINER(viewport), hbox); | ||
286 | gtk_widget_show(hbox); | ||
287 | |||
288 | vbox = gtk_vbox_new(TRUE, 0); | ||
289 | gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, FALSE, 0); | ||
290 | gtk_widget_show(vbox); | ||
291 | |||
292 | /* Create all container button */ | ||
293 | check = gtk_check_button_new_with_label(ALL_CONTS_STR); | ||
294 | gtk_box_pack_start(GTK_BOX(vbox), check, TRUE, TRUE, 0); | ||
295 | cont_helper->buttons[cont_count] = check; | ||
296 | if (select_count == cont_count) | ||
297 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE); | ||
298 | gtk_widget_show(check); | ||
299 | g_signal_connect_swapped (check, "toggled", | ||
300 | G_CALLBACK (cont_toggle), | ||
301 | (gpointer) cont_helper); | ||
302 | |||
303 | /* Create per-container buttons */ | ||
304 | cont_num = 0; | ||
305 | for (i = 0; i < CONT_HASH_SIZE; i++) { | ||
306 | for (cont = ginfo->rtg_info.containers[i]; cont; cont = cont->next) { | ||
307 | g_snprintf(label, 200, "%s-%d", cont->name, cont->cid); | ||
308 | check = gtk_check_button_new_with_label(label); | ||
309 | cont_helper->buttons[cont_num] = check; | ||
310 | cont_helper->conts[cont_num] = cont->cid; | ||
311 | cont_helper->selected[cont_num] = cont->plotted; | ||
312 | |||
313 | cont_num++; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | for (start = 0; start < cont_count - 1; start++) { | ||
318 | min_cont = start; | ||
319 | for (i = start + 1; i < cont_count; i++) { | ||
320 | if (cont_helper->conts[i] < cont_helper->conts[min_cont]) | ||
321 | min_cont = i; | ||
322 | } | ||
323 | if (min_cont != start) { | ||
324 | twidget = cont_helper->buttons[min_cont]; | ||
325 | tint = cont_helper->conts[min_cont]; | ||
326 | tbool = cont_helper->selected[min_cont]; | ||
327 | |||
328 | cont_helper->buttons[min_cont] = cont_helper->buttons[start]; | ||
329 | cont_helper->conts[min_cont] = cont_helper->conts[start]; | ||
330 | cont_helper->selected[min_cont] = cont_helper->selected[start]; | ||
331 | cont_helper->buttons[start] = twidget; | ||
332 | cont_helper->conts[start] = tint; | ||
333 | cont_helper->selected[start] = tbool; | ||
334 | } | ||
335 | } | ||
336 | for (i = 0; i < cont_count; i++) { | ||
337 | check = cont_helper->buttons[i]; | ||
338 | gtk_box_pack_start(GTK_BOX(vbox), check, TRUE, FALSE, 0); | ||
339 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), cont_helper->selected[i]); | ||
340 | gtk_widget_show(check); | ||
341 | g_signal_connect_swapped (check, "toggled", | ||
342 | G_CALLBACK (cont_toggle), | ||
343 | (gpointer) cont_helper); | ||
344 | |||
345 | } | ||
346 | |||
347 | |||
348 | /* Size */ | ||
349 | gtk_widget_size_request(hbox, &req); | ||
350 | height = req.height; | ||
351 | gtk_widget_size_request(scrollwin, &req); | ||
352 | height += req.height; | ||
353 | gtk_widget_size_request(dialog, &req); | ||
354 | width = req.width; | ||
355 | height += req.height; | ||
356 | if (width > DIALOG_WIDTH) | ||
357 | width = DIALOG_WIDTH; | ||
358 | if (height > DIALOG_HEIGHT) | ||
359 | height = DIALOG_HEIGHT; | ||
360 | gtk_widget_set_size_request(GTK_WIDGET(dialog), | ||
361 | width, height); | ||
362 | gtk_widget_show_all(dialog); | ||
363 | |||
364 | /* Run dialog */ | ||
365 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
366 | if (result == GTK_RESPONSE_ACCEPT) | ||
367 | do_container_filter(ginfo, cont_helper, data); | ||
368 | |||
369 | gtk_widget_destroy(dialog); | ||
370 | g_free(cont_helper->conts); | ||
371 | g_free(cont_helper->buttons); | ||
372 | g_free(cont_helper->selected); | ||
373 | g_free(cont_helper); | ||
374 | } | ||
diff --git a/rt-plot-container.h b/rt-plot-container.h new file mode 100644 index 0000000..e6c57b0 --- /dev/null +++ b/rt-plot-container.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef __RT_PLOT_CONTAINER_H | ||
2 | #define __RT_PLOT_CONTAINER_H | ||
3 | |||
4 | #include "rt-plot-vcpu.h" | ||
5 | |||
6 | typedef void (*cont_dialog_cb_func)(gboolean, gint*, gint*, gpointer); | ||
7 | |||
8 | void trace_container_dialog(struct graph_info *ginfo, | ||
9 | gpointer data); | ||
10 | void rt_plot_container(struct graph_info *ginfo, int cid); | ||
11 | int rt_plot_get_containers(struct graph_info *ginfo, gint **plotted, | ||
12 | gboolean plotted_only); | ||
13 | void rt_plot_add_all_containers(struct graph_info *ginfo); | ||
14 | |||
15 | int get_server_info(struct graph_info *ginfo, | ||
16 | struct rt_plot_common *rt, | ||
17 | int match_sid, unsigned long long time, | ||
18 | unsigned long long *release, unsigned long long *deadline, | ||
19 | int *job, int *tid, struct record **record); | ||
20 | |||
21 | #endif | ||
diff --git a/rt-plot-task.c b/rt-plot-task.c index 3175f23..c72013f 100644 --- a/rt-plot-task.c +++ b/rt-plot-task.c | |||
@@ -3,7 +3,7 @@ | |||
3 | #include "trace-graph.h" | 3 | #include "trace-graph.h" |
4 | #include "trace-filter.h" | 4 | #include "trace-filter.h" |
5 | 5 | ||
6 | #define DEBUG_LEVEL 4 | 6 | #define DEBUG_LEVEL 0 |
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-vcpu-task.h b/rt-plot-vcpu-task.h new file mode 100644 index 0000000..7edd4aa --- /dev/null +++ b/rt-plot-vcpu-task.h | |||
@@ -0,0 +1,9 @@ | |||
1 | struct vcpu_info { | ||
2 | int sid; | ||
3 | int run_tid; | ||
4 | unsigned long long run_time; | ||
5 | gboolean fresh; | ||
6 | char *label; | ||
7 | |||
8 | struct cont_list *cont; | ||
9 | }; | ||
diff --git a/rt-plot-vcpu.c b/rt-plot-vcpu.c new file mode 100644 index 0000000..fb1cf8d --- /dev/null +++ b/rt-plot-vcpu.c | |||
@@ -0,0 +1,372 @@ | |||
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_tid(struct vcpu_info *info, int tid) | ||
17 | { | ||
18 | info->fresh = FALSE; | ||
19 | if (tid != info->run_tid) { | ||
20 | info->run_tid = tid; | ||
21 | snprintf(info->label, LLABEL, "%d", tid); | ||
22 | } | ||
23 | } | ||
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 | ||
115 | try_server_switch_away(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
116 | struct record *record, struct plot_info *info) | ||
117 | { | ||
118 | int job, sid, tid, match, ret = 0; | ||
119 | unsigned long long ts; | ||
120 | |||
121 | match = rt_graph_check_server_switch_away(ginfo, record, | ||
122 | &sid, &job, | ||
123 | &tid, &ts); | ||
124 | if (match && sid == vcpu_info->sid) { | ||
125 | update_tid(vcpu_info, tid); | ||
126 | |||
127 | if (vcpu_info->run_time && vcpu_info->run_time < ts && | ||
128 | job != 1) { | ||
129 | info->box = TRUE; | ||
130 | info->bcolor = hash_pid(tid); | ||
131 | info->bfill = vcpu_info->running; | ||
132 | info->bstart = vcpu_info->run_time; | ||
133 | info->bend = ts; | ||
134 | info->blabel = vcpu_info->label; | ||
135 | } | ||
136 | |||
137 | dprintf(3, "VCPU switch away from %d on %d:%d at %llu\n", | ||
138 | tid, sid, job, ts); | ||
139 | vcpu_info->run_time = 0ULL; | ||
140 | vcpu_info->run_cpu = NO_CPU; | ||
141 | vcpu_info->run_tid = 0; | ||
142 | vcpu_info->running = FALSE; | ||
143 | |||
144 | ret = 1; | ||
145 | } | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static int try_server_switch_to(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
151 | struct record *record, struct plot_info *info) | ||
152 | { | ||
153 | int job, sid, tid, match, ret = 0; | ||
154 | unsigned long long ts; | ||
155 | |||
156 | match = rt_graph_check_server_switch_to(ginfo, record, | ||
157 | &sid, &job, &tid, &ts); | ||
158 | if (match && sid == vcpu_info->sid) { | ||
159 | update_tid(vcpu_info, tid); | ||
160 | vcpu_info->run_time = ts; | ||
161 | vcpu_info->run_cpu = record->cpu; | ||
162 | vcpu_info->run_tid = tid; | ||
163 | dprintf(3, "Switch to %d for %d:%d at %llu\n", | ||
164 | tid, sid, job, ts); | ||
165 | ret = 1; | ||
166 | } | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static int try_switch_to(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
171 | struct record *record, struct plot_info *info) | ||
172 | { | ||
173 | int job, pid, match, ret = 0; | ||
174 | unsigned long long ts; | ||
175 | |||
176 | match = rt_graph_check_switch_to(ginfo, record, &pid, &job, &ts); | ||
177 | if (match && pid && pid == vcpu_info->run_tid && vcpu_info->run_time) { | ||
178 | vcpu_info->running = TRUE; | ||
179 | |||
180 | /* Draw empty box for time spent not running a task */ | ||
181 | info->box = TRUE; | ||
182 | info->bcolor = hash_pid(pid); | ||
183 | info->bfill = FALSE; | ||
184 | info->bstart = vcpu_info->run_time; | ||
185 | info->bend = ts; | ||
186 | info->blabel = vcpu_info->label; | ||
187 | |||
188 | vcpu_info->run_time = ts; | ||
189 | ret = 1; | ||
190 | } | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | static int try_switch_away(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
195 | struct record *record, struct plot_info *info) | ||
196 | { | ||
197 | int job, pid, match, ret = 0; | ||
198 | unsigned long long ts; | ||
199 | |||
200 | match = rt_graph_check_switch_away(ginfo, record, &pid, &job, &ts); | ||
201 | if (match && pid && pid == vcpu_info->run_tid && vcpu_info->running) { | ||
202 | vcpu_info->running = FALSE; | ||
203 | |||
204 | info->box = TRUE; | ||
205 | info->bcolor = hash_pid(pid); | ||
206 | info->bfill = TRUE; | ||
207 | info->bstart = vcpu_info->run_time; | ||
208 | info->bend = ts; | ||
209 | info->blabel = vcpu_info->label; | ||
210 | |||
211 | vcpu_info->run_time = ts; | ||
212 | ret = 1; | ||
213 | } | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | |||
218 | static void do_plot_end(struct graph_info *ginfo, struct vcpu_info *vcpu_info, | ||
219 | struct plot_info *info) | ||
220 | { | ||
221 | /* TODO: me */ | ||
222 | } | ||
223 | |||
224 | |||
225 | static int rt_vcpu_plot_event(struct graph_info *ginfo, struct graph_plot *plot, | ||
226 | struct record *record, struct plot_info *info) | ||
227 | { | ||
228 | int match; | ||
229 | struct vcpu_info *vcpu_info = plot->private; | ||
230 | |||
231 | if (!record) { | ||
232 | do_plot_end(ginfo, vcpu_info, info); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | match = try_server_switch_away(ginfo, vcpu_info, record, info) || | ||
237 | try_server_switch_to(ginfo, vcpu_info, record, info) || | ||
238 | try_block(ginfo, vcpu_info, record, info) || | ||
239 | try_resume(ginfo, vcpu_info, record, info) || | ||
240 | try_release(ginfo, vcpu_info, record, info) || | ||
241 | try_completion(ginfo, vcpu_info, record, info) || | ||
242 | try_switch_to(ginfo, vcpu_info, record, info) || | ||
243 | try_switch_away(ginfo, vcpu_info, record, info); | ||
244 | return match; | ||
245 | } | ||
246 | |||
247 | static void rt_vcpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot, | ||
248 | unsigned long long time) | ||
249 | { | ||
250 | struct vcpu_info *vcpu_info = plot->private; | ||
251 | |||
252 | dprintf(4,"%s\n", __FUNCTION__); | ||
253 | |||
254 | vcpu_info->run_time = time; | ||
255 | vcpu_info->block_time = time; | ||
256 | vcpu_info->run_cpu = NO_CPU; | ||
257 | vcpu_info->run_tid = 0; | ||
258 | vcpu_info->block_cpu = NO_CPU; | ||
259 | vcpu_info->fresh = FALSE; | ||
260 | |||
261 | vcpu_info->fresh = TRUE; | ||
262 | vcpu_info->running = FALSE; | ||
263 | |||
264 | vcpu_info->run_tid = -1; | ||
265 | update_tid(vcpu_info, 0); | ||
266 | } | ||
267 | |||
268 | static void rt_vcpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) | ||
269 | { | ||
270 | struct vcpu_info *vcpu_info = plot->private; | ||
271 | trace_graph_plot_remove_all_recs(ginfo, plot); | ||
272 | free(vcpu_info->label); | ||
273 | free(vcpu_info); | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * Return 1 if @record is relevant to @match_sid. | ||
278 | */ | ||
279 | static int rt_vcpu_plot_record_matches(struct rt_plot_common *rt, | ||
280 | struct graph_info *ginfo, | ||
281 | struct record *record) | ||
282 | { | ||
283 | struct vcpu_info *vcpu_info = (struct vcpu_info*)rt; | ||
284 | int dint, sid, match; | ||
285 | unsigned long long dull; | ||
286 | |||
287 | #define ARG ginfo, record, &sid | ||
288 | match = rt_graph_check_server_switch_to(ARG, &dint, &dint, &dull) || | ||
289 | rt_graph_check_server_switch_away(ARG, &dint, &dint, &dull) || | ||
290 | rt_graph_check_server_completion(ARG, &dint, &dull) || | ||
291 | rt_graph_check_server_release(ARG, &dint, &dull, &dull) || | ||
292 | rt_graph_check_server_block(ARG, &dull) || | ||
293 | rt_graph_check_server_resume(ARG, &dull); | ||
294 | #undef ARG | ||
295 | return (sid == vcpu_info->sid); | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * Return true if the given record type is drawn on screen. This does not | ||
300 | * include event line markes. | ||
301 | */ | ||
302 | static int | ||
303 | rt_vcpu_plot_is_drawn(struct graph_info *ginfo, int eid) | ||
304 | { | ||
305 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; | ||
306 | return (eid == rtg_info->server_switch_to_id || | ||
307 | eid == rtg_info->server_switch_away_id || | ||
308 | eid == rtg_info->server_release_id || | ||
309 | eid == rtg_info->server_completion_id || | ||
310 | eid == rtg_info->server_block_id || | ||
311 | eid == rtg_info->server_resume_id); | ||
312 | } | ||
313 | |||
314 | static struct record* | ||
315 | rt_vcpu_plot_write_header(struct rt_plot_common *rt, | ||
316 | struct graph_info *ginfo, | ||
317 | struct trace_seq *s, | ||
318 | unsigned long long time) | ||
319 | { | ||
320 | int is_running, job, tid; | ||
321 | unsigned long long release, deadline; | ||
322 | struct vcpu_info *vcpu_info = (struct vcpu_info*)rt; | ||
323 | struct record *record; | ||
324 | |||
325 | is_running = get_server_info(ginfo, rt, vcpu_info->sid, time, | ||
326 | &release, &deadline, | ||
327 | &job, &tid, &record); | ||
328 | |||
329 | trace_seq_printf(s, "%s-%d:%d", vcpu_info->cont->name, | ||
330 | vcpu_info->sid, job); | ||
331 | if (is_running) { | ||
332 | trace_seq_printf(s, " - %d", tid); | ||
333 | } | ||
334 | trace_seq_putc(s, '\n'); | ||
335 | return record; | ||
336 | } | ||
337 | |||
338 | |||
339 | const struct plot_callbacks rt_vcpu_cb = { | ||
340 | .start = rt_vcpu_plot_start, | ||
341 | .destroy = rt_vcpu_plot_destroy, | ||
342 | .plot_event = rt_vcpu_plot_event, | ||
343 | .display_last_event = rt_plot_display_last_event, | ||
344 | .display_info = rt_plot_display_info, | ||
345 | .match_time = rt_plot_match_time, | ||
346 | .find_record = rt_plot_find_record, | ||
347 | }; | ||
348 | |||
349 | void insert_vcpu(struct graph_info *ginfo, struct cont_list *cont, | ||
350 | struct vcpu_list *vcpu_info) | ||
351 | { | ||
352 | struct graph_plot *plot; | ||
353 | struct vcpu_info *vcpu; | ||
354 | char *label; | ||
355 | |||
356 | vcpu = malloc_or_die(sizeof(*vcpu)); | ||
357 | vcpu->sid = vcpu_info->sid; | ||
358 | vcpu->cont = cont; | ||
359 | vcpu->label = malloc_or_die(LLABEL); | ||
360 | |||
361 | vcpu->common.record_matches = rt_vcpu_plot_record_matches; | ||
362 | vcpu->common.is_drawn = rt_vcpu_plot_is_drawn; | ||
363 | vcpu->common.write_header = rt_vcpu_plot_write_header; | ||
364 | |||
365 | g_assert(cont); | ||
366 | |||
367 | label = malloc_or_die(1); | ||
368 | snprintf(label, 2, " "); | ||
369 | plot = trace_graph_plot_append(ginfo, label, PLOT_TYPE_SERVER_CPU, | ||
370 | TIME_TYPE_RT, &rt_vcpu_cb, vcpu); | ||
371 | trace_graph_plot_add_all_recs(ginfo, plot); | ||
372 | } | ||
diff --git a/rt-plot-vcpu.h b/rt-plot-vcpu.h new file mode 100644 index 0000000..14add34 --- /dev/null +++ b/rt-plot-vcpu.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #include "trace-graph.h" | ||
2 | |||
3 | struct vcpu_list; | ||
4 | |||
5 | struct vcpu_info { | ||
6 | struct rt_plot_common common; | ||
7 | |||
8 | int sid; | ||
9 | int run_tid; | ||
10 | int run_cpu; | ||
11 | unsigned long long run_time; | ||
12 | int block_cpu; | ||
13 | unsigned long long block_time; | ||
14 | gboolean fresh; | ||
15 | gboolean running; | ||
16 | char *label; | ||
17 | |||
18 | struct cont_list *cont; | ||
19 | }; | ||
20 | |||
21 | void insert_vcpu(struct graph_info *ginfo, struct cont_list *cont, | ||
22 | struct vcpu_list *vcpu_info); | ||
diff --git a/rt-plot.h b/rt-plot.h new file mode 100644 index 0000000..0abc5c4 --- /dev/null +++ b/rt-plot.h | |||
@@ -0,0 +1,65 @@ | |||
1 | #ifndef __RT_PLOT_H | ||
2 | #define __RT_PLOT_H | ||
3 | |||
4 | #include <gtk/gtk.h> | ||
5 | #include "trace-cmd.h" | ||
6 | |||
7 | struct graph_plot; | ||
8 | struct graph_info; | ||
9 | struct rt_plot_common; | ||
10 | |||
11 | typedef int (*record_matches_cb)(struct rt_plot_common *rt, | ||
12 | struct graph_info *ginfo, | ||
13 | struct record *record); | ||
14 | typedef int (*is_drawn_cb)(struct graph_info *ginfo, int eid); | ||
15 | typedef struct record* (*write_header_cb)(struct rt_plot_common *rt, | ||
16 | struct graph_info *ginfo, | ||
17 | struct trace_seq *s, | ||
18 | unsigned long long time); | ||
19 | struct rt_plot_common { | ||
20 | record_matches_cb record_matches; | ||
21 | is_drawn_cb is_drawn; | ||
22 | write_header_cb write_header; | ||
23 | }; | ||
24 | |||
25 | int | ||
26 | rt_plot_display_last_event(struct graph_info *ginfo, struct graph_plot *plot, | ||
27 | struct trace_seq *s, unsigned long long time); | ||
28 | int | ||
29 | rt_plot_display_info(struct graph_info *ginfo, struct graph_plot *plot, | ||
30 | struct trace_seq *s, unsigned long long time); | ||
31 | struct record* | ||
32 | rt_plot_find_record(struct graph_info *ginfo, struct graph_plot *plot, | ||
33 | unsigned long long time); | ||
34 | int | ||
35 | rt_plot_match_time(struct graph_info *ginfo, struct graph_plot *plot, | ||
36 | unsigned long long time); | ||
37 | struct record* | ||
38 | __find_rt_record(struct graph_info *ginfo, struct rt_plot_common *rt, | ||
39 | guint64 time, int display); | ||
40 | |||
41 | static inline struct record* | ||
42 | find_rt_record(struct graph_info *ginfo, struct rt_plot_common *rt, guint64 time) | ||
43 | { | ||
44 | return __find_rt_record(ginfo, rt, time, 0); | ||
45 | } | ||
46 | |||
47 | static inline struct record* | ||
48 | find_rt_display_record(struct graph_info *ginfo, | ||
49 | struct rt_plot_common *rt, guint64 time) | ||
50 | { | ||
51 | return __find_rt_record(ginfo, rt, time, 1); | ||
52 | } | ||
53 | |||
54 | unsigned long long next_rts(struct graph_info *ginfo, int cpu, | ||
55 | unsigned long long ft_target); | ||
56 | void set_cpu_to_rts(struct graph_info *ginfo, | ||
57 | unsigned long long rt_target, int cpu); | ||
58 | void set_cpus_to_rts(struct graph_info *ginfo, | ||
59 | unsigned long long rt_target); | ||
60 | struct record* get_previous_release(struct graph_info *ginfo, int tid, | ||
61 | unsigned long long time, int *job, | ||
62 | unsigned long long *release, | ||
63 | unsigned long long *deadline); | ||
64 | |||
65 | #endif | ||
diff --git a/trace-graph.c b/trace-graph.c index d309bc8..d8367ae 100644 --- a/trace-graph.c +++ b/trace-graph.c | |||
@@ -1695,7 +1695,7 @@ static void draw_plot_box(struct graph_info *ginfo, int i, | |||
1695 | fill, | 1695 | fill, |
1696 | x1, y, | 1696 | x1, y, |
1697 | x2 - x1, size); | 1697 | x2 - x1, size); |
1698 | if (!thin && is_high_res(ginfo)) { | 1698 | if (!thin && fill && is_high_res(ginfo)) { |
1699 | gdk_draw_rectangle(ginfo->curr_pixmap, | 1699 | gdk_draw_rectangle(ginfo->curr_pixmap, |
1700 | ginfo->draw->style->black_gc, | 1700 | ginfo->draw->style->black_gc, |
1701 | FALSE, | 1701 | FALSE, |