aboutsummaryrefslogtreecommitdiffstats
path: root/rt-plot.c
diff options
context:
space:
mode:
Diffstat (limited to 'rt-plot.c')
-rw-r--r--rt-plot.c352
1 files changed, 352 insertions, 0 deletions
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}