aboutsummaryrefslogtreecommitdiffstats
path: root/rt-plot-cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'rt-plot-cpu.c')
-rw-r--r--rt-plot-cpu.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/rt-plot-cpu.c b/rt-plot-cpu.c
new file mode 100644
index 0000000..6884286
--- /dev/null
+++ b/rt-plot-cpu.c
@@ -0,0 +1,461 @@
1#include "trace-graph.h"
2#include "cpu.h"
3
4#define DEBUG_LEVEL 0
5#if DEBUG_LEVEL > 0
6#define dprintf(l, x...) \
7 do { \
8 if (l <= DEBUG_LEVEL) \
9 printf(x); \
10 } while (0)
11#else
12#define dprintf(l, x...) do { if (0) printf(x); } while (0)
13#endif
14
15static struct record*
16next_sa_record(struct graph_info *ginfo, struct rt_cpu_info *rtc_info,
17 unsigned long long time, int *out_pid)
18{
19 struct pevent *pevent;
20 struct record *ret = NULL, *record;
21 struct rt_graph_info *rtg_info = &ginfo->rtg_info;
22 unsigned long long max_ts, dull;
23 int pid, dint, match;
24
25 max_ts = time + SEARCH_PERIODS * rtg_info->max_period;
26 pevent = ginfo->pevent;
27
28 set_cpu_to_rts(ginfo, time, rtc_info->cpu);
29
30 while ((record = tracecmd_read_data(ginfo->handle, rtc_info->cpu))) {
31 if (get_rts(ginfo, record) > max_ts) {
32 free_record(record);
33 break;
34 }
35 match = rt_graph_check_switch_away(rtg_info, pevent, record,
36 &pid, &dint, &dull);
37 if (match) {
38 ret = record;
39 *out_pid = pid;
40 break;
41 }
42 free_record(record);
43 }
44 return ret;
45}
46
47static struct record*
48find_record(struct graph_info *ginfo, int cpu, unsigned long long time)
49{
50 struct record *record = NULL;
51 set_cpu_to_rts(ginfo, time, cpu);
52
53 while ((record = tracecmd_read_data(ginfo->handle, cpu))) {
54 if (get_rts(ginfo, record) >= time)
55 break;
56 free_record(record);
57 }
58 return record;
59}
60
61
62static void update_pid(struct rt_cpu_info *rtc_info, int pid)
63{
64 rtc_info->fresh = FALSE;
65 if (pid != rtc_info->run_pid) {
66 rtc_info->run_pid = pid;
67 snprintf(rtc_info->label, LLABEL, "%d", rtc_info->run_pid);
68 }
69}
70
71static int
72try_switch_away(struct graph_info *ginfo, struct rt_cpu_info *rtc_info,
73 struct record *record, struct plot_info *info)
74{
75 int job, pid, match;
76 unsigned long long ts;
77
78 match = rt_graph_check_switch_away(&ginfo->rtg_info, ginfo->pevent,
79 record, &pid, &job, &ts);
80 if (match) {
81 update_pid(rtc_info, pid);
82 if (rtc_info->run_time && rtc_info->run_time < ts) {
83 info->box = TRUE;
84 info->bcolor = hash_pid(rtc_info->run_pid);
85 info->bfill = TRUE;
86 info->bstart = rtc_info->run_time;
87 info->bend = ts;
88 info->blabel = rtc_info->label;
89 }
90 rtc_info->run_pid = 0;
91 rtc_info->run_time = 0Ull;
92 }
93 return match;
94}
95
96static int
97try_switch_to(struct graph_info *ginfo, struct rt_cpu_info *rtc_info,
98 struct record *record, struct plot_info *info)
99{
100 int job, pid, match;
101 unsigned long long ts;
102
103 match = rt_graph_check_switch_to(&ginfo->rtg_info, ginfo->pevent,
104 record, &pid, &job, &ts);
105 if (match) {
106 update_pid(rtc_info, pid);
107 rtc_info->run_time = ts;
108 }
109 return match;
110}
111
112static int
113try_completion(struct graph_info *ginfo, struct rt_cpu_info *rtc_info,
114 struct record *record, struct plot_info *info)
115{
116 int pid, job, match;
117 unsigned long long ts;
118
119 match = rt_graph_check_task_completion(&ginfo->rtg_info, ginfo->pevent,
120 record, &pid, &job, &ts);
121 if (match) {
122 info->completion = TRUE;
123 info->ctime = ts;
124 }
125 return match;
126}
127
128static void do_plot_end(struct graph_info *ginfo, struct rt_cpu_info *rtc_info,
129 struct plot_info *info)
130{
131 int pid;
132 struct record *record;
133
134 if (rtc_info->run_time && rtc_info->run_pid) {
135 info->box = TRUE;
136 info->bcolor = hash_pid(rtc_info->run_pid);
137 info->bfill = TRUE;
138 info->bstart = rtc_info->run_time;
139 info->bend = ginfo->view_end_time;
140 info->blabel = rtc_info->label;
141 rtc_info->fresh = FALSE;
142 } else if (rtc_info->fresh) {
143 record = next_sa_record(ginfo, rtc_info,
144 ginfo->view_end_time,
145 &pid);
146 if (record) {
147 update_pid(rtc_info, pid);
148 info->box = TRUE;
149 info->bcolor = hash_pid(pid);
150 info->bfill = TRUE;
151 info->blabel = rtc_info->label;
152 info->bstart = ginfo->view_start_time;
153 info->bend = ginfo->view_end_time;
154 rtc_info->fresh = FALSE;
155 }
156 free_record(record);
157 }
158}
159
160static int rt_cpu_plot_match_time(struct graph_info *ginfo,
161 struct graph_plot *plot,
162 unsigned long long time)
163{
164 int ret = 0;
165 struct rt_cpu_info *rtc_info = plot->private;
166 struct record = find_record(ginfo, rtc_info->cpu, time);
167
168 if (record && get_rts(ginfo, record) == time)
169 ret = 1;
170 free_record(record);
171
172 return ret;
173}
174
175static void rt_cpu_plot_start(struct graph_info *ginfo, struct graph_plot *plot,
176 unsigned long long time)
177{
178 struct rt_cpu_info *rtc_info = plot->private;
179
180 rtc_info->run_time = time;
181 rtc_info->run_pid = 0;
182 rtc_info->fresh = TRUE;
183}
184
185static int rt_cpu_plot_event(struct graph_info *ginfo, struct graph_plot *plot,
186 struct record *record, struct plot_info *info)
187{
188 int pid, eid, match;
189 unsigned long long ts;
190 struct rt_cpu_info *rtc_info = plot->private;
191 struct rt_graph_info *rtg_info = &ginfo->rtg_info;
192 const char *comm;
193
194 if (!record) {
195 do_plot_end(ginfo, rtc_info, info);
196 return 0;
197 }
198
199 if (record->cpu != rtc_info->cpu)
200 return 0;
201
202 match = try_switch_away(ginfo, rtc_info, record, info) ||
203 try_switch_to(ginfo, rtc_info, record, info) ||
204 try_completion(ginfo, rtc_info, record, info) ||
205 trace_graph_check_sched_switch(ginfo, record,
206 &pid, &comm);
207 if (!match) {
208 rt_graph_check_any(rtg_info, ginfo->pevent, record,
209 &pid, &eid, &ts);
210 info->line = TRUE;
211 info->lcolor = hash_pid(pid);
212 info->ltime = ts;
213 }
214 return 1;
215}
216
217static int
218rt_cpu_plot_display_last_event(struct graph_info *ginfo, struct graph_plot *plot,
219 struct trace_seq *s, unsigned long long time)
220{
221 struct rt_cpu_info *rtc_info = plot->private;
222 struct event_format *event;
223 struct record *record;
224 unsigned long long offset;
225 int eid, cpu;
226
227 cpu = rtc_info->cpu;
228 record = tracecmd_peek_data(ginfo->handle, cpu);
229 if (record)
230 offset = record->offset;
231
232 record = find_record(ginfo, cpu, time);
233
234 if (offset)
235 tracecmd_set_cursor(ginfo->handle, cpu, offset);
236 if (!record)
237 return 0;
238
239 eid = pevent_data_type(ginfo->pevent, record);
240 event = pevent_data_event_from_type(ginfo->pevent, eid);
241 if (event) {
242 trace_seq_puts(s, event->name);
243 trace_seq_printf(s, "\n"); /* Doesn't work otherwise */
244 } else
245 trace_seq_printf(s, "UNKNOWN EVENT %d\n", eid);
246 free_record(record);
247
248 return 1;
249}
250
251
252struct record*
253rt_cpu_plot_find_record(struct graph_info *ginfo, struct graph_plot *plot,
254 unsigned long long time)
255{
256 struct rt_cpu_info *rtc_info = plot->private;
257 return find_record(ginfo, rtc_info->cpu, time);
258}
259
260static int get_time_info(struct graph_info *ginfo,
261 struct rt_cpu_info *rtc_info,
262 unsigned long long time,
263 int *out_pid, int *out_job,
264 struct record **out_record)
265{
266 struct record *record;
267 struct rt_graph_info *rtg_info = &ginfo->rtg_info;
268 unsigned long long dull, max_ts;
269 int cpu, is_running, pid, job;
270
271 cpu = rtc_info->cpu;
272 *out_pid = *out_job = is_running = 0;
273
274 record = find_record(ginfo, cpu, time);
275 *out_record = record;
276 if (!record)
277 goto out;
278
279 max_ts = time + SEARCH_PERIODS * rtg_info->max_period;
280 do {
281 if (get_rts(ginfo, record) > max_ts)
282 break;
283
284#define ARG rtg_info, ginfo->pevent, record, &pid, &job, &dull
285 if (rt_graph_check_switch_to(ARG)) {
286 /* Nothing is running */
287 goto out;
288 } else if (rt_graph_check_switch_away(ARG)) {
289 is_running = 1;
290 *out_pid = pid;
291 *out_job = job;
292 goto out;
293 }
294 if (*out_record != record)
295 free_record(record);
296#undef ARG
297 } while ((record = tracecmd_read_data(ginfo->handle, cpu)));
298 out:
299 if (*out_record != record)
300 free_record(record);
301 return is_running;
302}
303
304static int
305rt_cpu_plot_display_info(struct graph_info *ginfo, struct graph_plot *plot,
306 struct trace_seq *s, unsigned long long time)
307{
308 struct rt_cpu_info *rtc_info = plot->private;
309 unsigned long long msec, nsec, rts;
310 int pid, eid, job, is_running;
311 struct record *record;
312 struct event_format *event;
313 const char *comm;
314
315 is_running = get_time_info(ginfo, rtc_info, time,
316 &pid, &job, &record);
317
318 if (is_running) {
319 comm = pevent_data_comm_from_pid(ginfo->pevent, pid);
320 trace_seq_printf(s, "%s-%d:%d\n", comm, pid, job);
321 }
322
323 if (record) {
324 rts = get_rts(ginfo, record);
325 if (in_res(ginfo, rts, time)) {
326 eid = pevent_data_type(ginfo->pevent, record);
327 event = pevent_data_event_from_type(ginfo->pevent, eid);
328 if (event) {
329 trace_seq_putc(s, '\n');
330 trace_seq_puts(s, event->name);
331 trace_seq_putc(s, '\n');
332 pevent_event_info(s, event, record);
333 } else
334 trace_seq_printf(s, "\nUNKNOWN EVENT %d\n", eid);
335 }
336 free_record(record);
337 }
338 trace_seq_putc(s, '\n');
339 nano_to_milli(time, &msec, &nsec);
340 trace_seq_printf(s, "%llu.%06llu ms CPU: %03d",
341 msec, nsec, rtc_info->cpu);
342
343 return 1;
344}
345
346static void rt_cpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot)
347{
348 struct rt_cpu_info *rtc_info = plot->private;
349
350 trace_graph_plot_remove_all_recs(ginfo, plot);
351 free(rtc_info->label);
352 free(rtc_info);
353}
354
355
356static const struct plot_callbacks rt_cpu_cb = {
357 .start = rt_cpu_plot_start,
358 .destroy = rt_cpu_plot_destroy,
359 .plot_event = rt_cpu_plot_event,
360 .display_last_event = rt_cpu_plot_display_last_event,
361 .display_info = rt_cpu_plot_display_info,
362 .match_time = rt_cpu_plot_match_time,
363 .find_record = rt_cpu_plot_find_record,
364};
365
366void rt_plot_cpus_update_callback(gboolean accept,
367 gboolean all_cpus,
368 guint64 *selected_cpu_mask,
369 gpointer data)
370{
371 struct graph_info *ginfo = data;
372 struct rt_cpu_info *rtc_info;
373 struct graph_plot *plot;
374 gboolean old_all_cpus;
375 guint64 *old_cpu_mask;
376 int i;
377
378 if (!accept)
379 return;
380
381 /* Get the current status */
382 rt_plot_cpus_plotted(ginfo, &old_all_cpus, &old_cpu_mask);
383
384 if (old_all_cpus == all_cpus ||
385 (selected_cpu_mask &&
386 cpus_equal(old_cpu_mask, selected_cpu_mask, ginfo->cpus))) {
387 /* Nothing to do */
388 g_free(old_cpu_mask);
389 return;
390 }
391
392 if (!all_cpus) {
393 /*
394 * Remove any plots not selected.
395 * Go backwards, since removing a plot shifts the
396 * array from current position back.
397 */
398 for (i = ginfo->plots - 1; i >= 0; i--) {
399 plot = ginfo->plot_array[i];
400 if (plot->type != PLOT_TYPE_CPU)
401 continue;
402 rtc_info = plot->private;
403 if (!cpu_isset(selected_cpu_mask, rtc_info->cpu))
404 trace_graph_plot_remove(ginfo, plot);
405 }
406 }
407
408 /* Now add any plots not set */
409 for (i = 0; i < ginfo->cpus; i++) {
410 if (!all_cpus && !cpu_isset(selected_cpu_mask, i))
411 continue;
412 if (cpu_isset(old_cpu_mask, i))
413 continue;
414 rt_plot_cpu(ginfo, i);
415 }
416
417 g_free(old_cpu_mask);
418
419 trace_graph_refresh(ginfo);
420}
421
422void rt_plot_cpus_plotted(struct graph_info *ginfo,
423 gboolean *all_cpus, guint64 **cpu_mask)
424{
425 struct rt_cpu_info *rtc_info;
426 struct graph_plot *plot;
427 int i;
428
429 *cpu_mask = g_new0(guint64, (ginfo->cpus >> 6) + 1);
430 g_assert(*cpu_mask);
431
432 for (i = 0; i < ginfo->plots; i++) {
433 plot = ginfo->plot_array[i];
434 if (plot->type != PLOT_TYPE_RT_CPU)
435 continue;
436 rtc_info = plot->private;
437 cpu_set(*cpu_mask, rtc_info->cpu);
438 }
439
440 *all_cpus = cpu_weight(*cpu_mask, ginfo->cpus) == ginfo->cpus ?
441 TRUE : FALSE;
442}
443
444
445void rt_plot_cpu(struct graph_info *ginfo, int cpu)
446{
447 struct rt_cpu_info *rtc_info;
448 struct graph_plot *plot;
449 char label[100];
450
451 rtc_info = malloc_or_die(sizeof(*rtc_info));
452 memset(rtc_info, 0, sizeof(*rtc_info));
453 rtc_info->cpu = cpu;
454 rtc_info->label = malloc_or_die(LLABEL);
455
456 snprintf(label, 100, "*CPU %d", cpu);
457
458 plot = trace_graph_plot_append(ginfo, label, PLOT_TYPE_RT_CPU,
459 TIME_TYPE_RT, &rt_cpu_cb, rtc_info);
460 trace_graph_plot_add_all_recs(ginfo, plot);
461}