diff options
Diffstat (limited to 'rt-plot-task.c')
-rw-r--r-- | rt-plot-task.c | 438 |
1 files changed, 273 insertions, 165 deletions
diff --git a/rt-plot-task.c b/rt-plot-task.c index f28b7b1..9e8ffe7 100644 --- a/rt-plot-task.c +++ b/rt-plot-task.c | |||
@@ -2,8 +2,9 @@ | |||
2 | #include "trace-filter.h" | 2 | #include "trace-filter.h" |
3 | 3 | ||
4 | #define LLABEL 30 | 4 | #define LLABEL 30 |
5 | #define SEARCH_PERIODS 3 | ||
5 | 6 | ||
6 | #define DEBUG_LEVEL 4 | 7 | #define DEBUG_LEVEL 3 |
7 | #if DEBUG_LEVEL > 0 | 8 | #if DEBUG_LEVEL > 0 |
8 | #define dprintf(l, x...) \ | 9 | #define dprintf(l, x...) \ |
9 | do { \ | 10 | do { \ |
@@ -14,35 +15,87 @@ | |||
14 | #define dprintf(l, x...) do { if (0) printf(x); } while (0) | 15 | #define dprintf(l, x...) do { if (0) printf(x); } while (0) |
15 | #endif | 16 | #endif |
16 | 17 | ||
18 | /* | ||
19 | * Return 1 if @record is relevant to @match_pid. | ||
20 | */ | ||
17 | static gboolean record_matches_pid(struct graph_info *ginfo, | 21 | static gboolean record_matches_pid(struct graph_info *ginfo, |
18 | struct record *record, | 22 | struct record *record, |
19 | int match_pid) | 23 | int match_pid) |
20 | { | 24 | { |
21 | gint dint, pid = 0, match; | 25 | gint dint, pid = 0, match; |
22 | unsigned long long dull; | 26 | unsigned long long dull; |
23 | struct rt_graph_info *rtg_info = &ginfo->rtinfo; | 27 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; |
24 | 28 | ||
25 | /* Must use check_* in case record has not been found yet, | 29 | /* Must use check_* in case record has not been found yet, |
26 | * this macro was the best of many terrible options | 30 | * this macro was the best of many terrible options. |
27 | */ | 31 | */ |
28 | #define MARGS rtg_info, ginfo->pevent, record, &pid | 32 | #define ARG rtg_info, ginfo->pevent, record, &pid |
29 | match = rt_graph_check_switch_to(MARGS, &dint, &dull) || | 33 | match = rt_graph_check_switch_to(ARG, &dint, &dull) || |
30 | rt_graph_check_switch_away(MARGS, &dint, &dull) || | 34 | rt_graph_check_switch_away(ARG, &dint, &dull) || |
31 | rt_graph_check_task_release(MARGS, &dint, &dull, &dull) || | 35 | rt_graph_check_task_release(ARG, &dint, &dull, &dull) || |
32 | rt_graph_check_task_completion(MARGS, &dint, &dull) || | 36 | rt_graph_check_task_completion(ARG, &dint, &dull) || |
33 | rt_graph_check_task_block(MARGS, &dull) || | 37 | rt_graph_check_task_block(ARG, &dull) || |
34 | rt_graph_check_task_resume(MARGS, &dull) || | 38 | rt_graph_check_task_resume(ARG, &dull) || |
35 | rt_graph_check_any(MARGS, &dint, &dull); | 39 | rt_graph_check_any(ARG, &dint, &dull); |
36 | #undef MARGS | 40 | #undef ARG |
37 | return pid == match_pid; | 41 | return pid == match_pid; |
38 | } | 42 | } |
39 | 43 | ||
44 | /* | ||
45 | * Return the first record after @time (within a range) which draws a box. | ||
46 | */ | ||
47 | static struct record* | ||
48 | next_box_record(struct graph_info *ginfo, struct rt_task_info *rtt_info, | ||
49 | unsigned long long time, int *out_eid) | ||
50 | { | ||
51 | struct record *record = NULL, *ret = NULL; | ||
52 | struct pevent *pevent; | ||
53 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; | ||
54 | unsigned long long dull, max_ts; | ||
55 | int match, pid, eid, dint, cpu; | ||
56 | |||
57 | *out_eid = 0; | ||
58 | pevent = ginfo->pevent; | ||
59 | max_ts = ginfo->view_end_time + | ||
60 | SEARCH_PERIODS * rtg_info->max_period; | ||
61 | set_cpus_to_rts(ginfo, time); | ||
62 | do { | ||
63 | free_record(record); | ||
64 | record = tracecmd_read_next_data(ginfo->handle, &cpu); | ||
65 | if (!record || get_rts(ginfo, record) > max_ts) { | ||
66 | free_record(record); | ||
67 | goto out; | ||
68 | } | ||
69 | |||
70 | /* Sorry mother */ | ||
71 | #define ARG rtg_info, pevent, record, &pid | ||
72 | match = rt_graph_check_switch_to(ARG, &dint, &dull) || | ||
73 | rt_graph_check_switch_away(ARG, &dint, &dull) || | ||
74 | rt_graph_check_task_block(ARG, &dull) || | ||
75 | rt_graph_check_task_resume(ARG, &dull); | ||
76 | #undef ARG | ||
77 | eid = (match) ? pevent_data_type(pevent, record) : 0; | ||
78 | |||
79 | if (eid && pid == rtt_info->pid) { | ||
80 | ret = record; | ||
81 | *out_eid = eid; | ||
82 | goto out; | ||
83 | } | ||
84 | } while (get_rts(ginfo, record) < max_ts); | ||
85 | out: | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Return first relevant record after @time. | ||
91 | * @display: If set, only considers records which are plotted in some way | ||
92 | */ | ||
40 | static struct record* | 93 | static struct record* |
41 | __find_record(struct graph_info *ginfo, gint pid, guint64 time, int display) | 94 | __find_record(struct graph_info *ginfo, gint pid, guint64 time, int display) |
42 | { | 95 | { |
43 | int next_cpu, match, eid, is_sa = 0; | 96 | int next_cpu, match, eid, is_sa = 0; |
44 | struct record *record = NULL; | 97 | struct record *record = NULL; |
45 | struct rt_graph_info *rtg_info = &ginfo->rtinfo; | 98 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; |
46 | 99 | ||
47 | set_cpus_to_rts(ginfo, time); | 100 | set_cpus_to_rts(ginfo, time); |
48 | do { | 101 | do { |
@@ -73,10 +126,11 @@ find_display_record(struct graph_info *ginfo, gint pid, guint64 time) | |||
73 | } | 126 | } |
74 | 127 | ||
75 | /* | 128 | /* |
76 | * Update current job in @rtt_info, ensuring monotonic increase | 129 | * Update current job in @rtt_info, ensuring monotonic increase. |
77 | */ | 130 | */ |
78 | static int update_job(struct rt_task_info *rtt_info, int job) | 131 | static int update_job(struct rt_task_info *rtt_info, int job) |
79 | { | 132 | { |
133 | rtt_info->fresh = FALSE; | ||
80 | if (job < rtt_info->last_job) { | 134 | if (job < rtt_info->last_job) { |
81 | printf("Inconsistent job state for %d:%d -> %d\n", | 135 | printf("Inconsistent job state for %d:%d -> %d\n", |
82 | rtt_info->pid, rtt_info->last_job, job); | 136 | rtt_info->pid, rtt_info->last_job, job); |
@@ -89,6 +143,115 @@ static int update_job(struct rt_task_info *rtt_info, int job) | |||
89 | return 1; | 143 | return 1; |
90 | } | 144 | } |
91 | 145 | ||
146 | |||
147 | |||
148 | /* | ||
149 | * Find the information for the last release of @rtt_info on @cpu before @time. | ||
150 | * @min_ts: the minimum time stamp to parse | ||
151 | * | ||
152 | * Returns release record and @out_job, @out_release, and @out_deadline if a | ||
153 | * release was found after @mints matching @time. | ||
154 | */ | ||
155 | static struct record* | ||
156 | get_previous_release(struct graph_info *ginfo, struct rt_task_info *rtt_info, | ||
157 | int cpu, | ||
158 | unsigned long long min_ts, unsigned long long time, | ||
159 | int *out_job, | ||
160 | unsigned long long *out_release, | ||
161 | unsigned long long *out_deadline) | ||
162 | { | ||
163 | int pid, job, match; | ||
164 | unsigned long long release, deadline; | ||
165 | struct record *last_record, *record, *ret = NULL; | ||
166 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; | ||
167 | |||
168 | last_record = tracecmd_peek_data(ginfo->handle, cpu); | ||
169 | *out_job = *out_release = *out_deadline = 0; | ||
170 | if (!last_record) | ||
171 | return NULL; | ||
172 | last_record->ref_count++; | ||
173 | |||
174 | while ((record = tracecmd_read_prev(ginfo->handle, last_record))) { | ||
175 | if (record->ts < min_ts) { | ||
176 | free_record(record); | ||
177 | goto out; | ||
178 | } | ||
179 | match = rt_graph_check_task_release(rtg_info, ginfo->pevent, | ||
180 | record, &pid, &job, | ||
181 | &release, &deadline); | ||
182 | free_record(last_record); | ||
183 | last_record = record; | ||
184 | if (match && (pid == rtt_info->pid) && release <= time) { | ||
185 | ret = record; | ||
186 | last_record = NULL; | ||
187 | *out_job = job; | ||
188 | *out_release = release; | ||
189 | *out_deadline = deadline; | ||
190 | break; | ||
191 | } | ||
192 | }; | ||
193 | out: | ||
194 | free_record(last_record); | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Return information for @time, returns @job, @release, @deadline, and @record. | ||
200 | * @job: Job number at this time | ||
201 | * @release: Job's release time | ||
202 | * @deadline: Job's deadline | ||
203 | * @record: Matching record | ||
204 | */ | ||
205 | static int get_time_info(struct graph_info *ginfo, | ||
206 | struct rt_task_info *rtt_info, | ||
207 | unsigned long long time, | ||
208 | int *out_job, | ||
209 | unsigned long long *out_release, | ||
210 | unsigned long long *out_deadline, | ||
211 | struct record **out_record) | ||
212 | |||
213 | { | ||
214 | int cpu, job; | ||
215 | unsigned long long release, deadline, min_ts; | ||
216 | struct record *record; | ||
217 | struct offset_cache *offsets; | ||
218 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; | ||
219 | |||
220 | /* Seek CPUs to first record after this time */ | ||
221 | *out_job = *out_release = *out_deadline = 0; | ||
222 | *out_record = find_record(ginfo, rtt_info->pid, time); | ||
223 | if (!*out_record) | ||
224 | return 0; | ||
225 | |||
226 | /* This is not necessarily correct for sporadic, but will do for now */ | ||
227 | if (time < rtt_info->first_rels[2]) { | ||
228 | job = (time >= rtt_info->first_rels[1]) ? 2 : 1; | ||
229 | *out_job = job; | ||
230 | *out_release = rtt_info->first_rels[job - 1]; | ||
231 | *out_deadline = rtt_info->first_rels[job]; | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | min_ts = time - SEARCH_PERIODS * rtg_info->max_period; | ||
236 | *out_job = *out_release = *out_deadline = 0; | ||
237 | |||
238 | offsets = save_offsets(ginfo); | ||
239 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | ||
240 | record = get_previous_release(ginfo, rtt_info, cpu, min_ts, | ||
241 | time, &job, &release, &deadline); | ||
242 | if (record && record->ts > min_ts) { | ||
243 | *out_job = job; | ||
244 | *out_release = release; | ||
245 | *out_deadline = deadline; | ||
246 | min_ts = record->ts; | ||
247 | } | ||
248 | free_record(record); | ||
249 | } | ||
250 | restore_offsets(ginfo, offsets); | ||
251 | out: | ||
252 | return 1; | ||
253 | } | ||
254 | |||
92 | static int try_param(struct graph_info *ginfo, struct rt_task_info *rtt_info, | 255 | static int try_param(struct graph_info *ginfo, struct rt_task_info *rtt_info, |
93 | struct record *record, struct plot_info *info) | 256 | struct record *record, struct plot_info *info) |
94 | { | 257 | { |
@@ -99,7 +262,7 @@ static int try_param(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
99 | if (rtt_info->params_found) | 262 | if (rtt_info->params_found) |
100 | goto out; | 263 | goto out; |
101 | 264 | ||
102 | match = rt_graph_check_task_param(&ginfo->rtinfo, ginfo->pevent, | 265 | match = rt_graph_check_task_param(&ginfo->rtg_info, ginfo->pevent, |
103 | record, &pid, &wcet, &period); | 266 | record, &pid, &wcet, &period); |
104 | if (match && pid == rtt_info->pid) { | 267 | if (match && pid == rtt_info->pid) { |
105 | update_job(rtt_info, 0); | 268 | update_job(rtt_info, 0); |
@@ -108,6 +271,8 @@ static int try_param(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
108 | rtt_info->params_found = TRUE; | 271 | rtt_info->params_found = TRUE; |
109 | ret = 1; | 272 | ret = 1; |
110 | rtt_info->first_rels[0] = get_rts(ginfo, record); | 273 | rtt_info->first_rels[0] = get_rts(ginfo, record); |
274 | dprintf(3, "Params for %d (%llu, %llu)\n on %d", | ||
275 | pid, wcet, period, record->cpu); | ||
111 | } | 276 | } |
112 | out: | 277 | out: |
113 | return ret; | 278 | return ret; |
@@ -120,7 +285,7 @@ static int try_release(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
120 | int pid, job, match, ret = 0; | 285 | int pid, job, match, ret = 0; |
121 | unsigned long long release, deadline; | 286 | unsigned long long release, deadline; |
122 | 287 | ||
123 | match = rt_graph_check_task_release(&ginfo->rtinfo, ginfo->pevent, | 288 | match = rt_graph_check_task_release(&ginfo->rtg_info, ginfo->pevent, |
124 | record, &pid, &job, | 289 | record, &pid, &job, |
125 | &release, &deadline); | 290 | &release, &deadline); |
126 | if (match && pid == rtt_info->pid) { | 291 | if (match && pid == rtt_info->pid) { |
@@ -136,6 +301,9 @@ static int try_release(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
136 | if (job <= 3) | 301 | if (job <= 3) |
137 | rtt_info->first_rels[job - 1] = release; | 302 | rtt_info->first_rels[job - 1] = release; |
138 | 303 | ||
304 | dprintf(3, "Release for %d:%d on %d, rel: %llu, dead: %llu\n", | ||
305 | pid, job, record->cpu, release, deadline); | ||
306 | |||
139 | ret = 1; | 307 | ret = 1; |
140 | } | 308 | } |
141 | return ret; | 309 | return ret; |
@@ -148,13 +316,15 @@ static int try_completion(struct graph_info *ginfo, | |||
148 | int pid, job, match, ret = 0; | 316 | int pid, job, match, ret = 0; |
149 | unsigned long long ts; | 317 | unsigned long long ts; |
150 | 318 | ||
151 | match = rt_graph_check_task_completion(&ginfo->rtinfo, ginfo->pevent, | 319 | match = rt_graph_check_task_completion(&ginfo->rtg_info, ginfo->pevent, |
152 | record, &pid, &job, &ts); | 320 | record, &pid, &job, &ts); |
153 | if (match && pid == rtt_info->pid) { | 321 | if (match && pid == rtt_info->pid) { |
154 | update_job(rtt_info, job); | 322 | update_job(rtt_info, job); |
155 | info->completion = TRUE; | 323 | info->completion = TRUE; |
156 | info->ctime = ts; | 324 | info->ctime = ts; |
157 | info->clabel = rtt_info->label; | 325 | info->clabel = rtt_info->label; |
326 | dprintf(3, "Completion for %d:%d on %d at %llu\n", | ||
327 | pid, job, record->cpu, ts); | ||
158 | ret = 1; | 328 | ret = 1; |
159 | } | 329 | } |
160 | return ret; | 330 | return ret; |
@@ -166,10 +336,14 @@ static int try_block(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
166 | int pid, match, ret = 0; | 336 | int pid, match, ret = 0; |
167 | unsigned long long ts; | 337 | unsigned long long ts; |
168 | 338 | ||
169 | match = rt_graph_check_task_block(&ginfo->rtinfo, ginfo->pevent, | 339 | match = rt_graph_check_task_block(&ginfo->rtg_info, ginfo->pevent, |
170 | record, &pid, &ts); | 340 | record, &pid, &ts); |
171 | if (match && pid == rtt_info->pid) { | 341 | if (match && pid == rtt_info->pid) { |
342 | rtt_info->fresh = FALSE; | ||
172 | rtt_info->block_time = ts; | 343 | rtt_info->block_time = ts; |
344 | rtt_info->block_cpu = NO_CPU; | ||
345 | dprintf(3, "Resume for %d on %d at %llu\n", | ||
346 | pid, record->cpu, ts); | ||
173 | ret = 1; | 347 | ret = 1; |
174 | } | 348 | } |
175 | return ret; | 349 | return ret; |
@@ -181,7 +355,7 @@ static int try_resume(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
181 | int pid, match, ret = 0; | 355 | int pid, match, ret = 0; |
182 | unsigned long long ts; | 356 | unsigned long long ts; |
183 | 357 | ||
184 | match = rt_graph_check_task_resume(&ginfo->rtinfo, ginfo->pevent, | 358 | match = rt_graph_check_task_resume(&ginfo->rtg_info, ginfo->pevent, |
185 | record, &pid, &ts); | 359 | record, &pid, &ts); |
186 | if (match && pid == rtt_info->pid) { | 360 | if (match && pid == rtt_info->pid) { |
187 | /* info->box = TRUE; */ | 361 | /* info->box = TRUE; */ |
@@ -190,22 +364,26 @@ static int try_resume(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
190 | /* info->bthin = TRUE; */ | 364 | /* info->bthin = TRUE; */ |
191 | /* info->bstart = rtt_info->block_time; */ | 365 | /* info->bstart = rtt_info->block_time; */ |
192 | /* info->bend = ts; */ | 366 | /* info->bend = ts; */ |
367 | rtt_info->fresh = FALSE; | ||
193 | 368 | ||
194 | rtt_info->block_time = 0ULL; | 369 | rtt_info->block_time = 0ULL; |
370 | rtt_info->block_cpu = NO_CPU; | ||
371 | dprintf(3, "Resume for %d on %d at %llu\n", | ||
372 | pid, record->cpu, ts); | ||
195 | 373 | ||
196 | ret = 1; | 374 | ret = 1; |
197 | } | 375 | } |
198 | return ret; | 376 | return ret; |
199 | } | 377 | } |
200 | 378 | ||
201 | static unsigned long long | 379 | static int |
202 | try_switch_away(struct graph_info *ginfo, struct rt_task_info *rtt_info, | 380 | try_switch_away(struct graph_info *ginfo, struct rt_task_info *rtt_info, |
203 | struct record *record, struct plot_info *info) | 381 | struct record *record, struct plot_info *info) |
204 | { | 382 | { |
205 | int job, pid, match, ret = 0; | 383 | int job, pid, match, ret = 0; |
206 | unsigned long long ts; | 384 | unsigned long long ts; |
207 | 385 | ||
208 | match = rt_graph_check_switch_away(&ginfo->rtinfo, ginfo->pevent, | 386 | match = rt_graph_check_switch_away(&ginfo->rtg_info, ginfo->pevent, |
209 | record, &pid, &job, &ts); | 387 | record, &pid, &job, &ts); |
210 | if (match && pid == rtt_info->pid) { | 388 | if (match && pid == rtt_info->pid) { |
211 | update_job(rtt_info, job); | 389 | update_job(rtt_info, job); |
@@ -213,18 +391,19 @@ try_switch_away(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
213 | if (rtt_info->run_time && rtt_info->run_time < ts) { | 391 | if (rtt_info->run_time && rtt_info->run_time < ts) { |
214 | dprintf(3, "Box for %d:%d, %llu to %llu on CPU %d\n", | 392 | dprintf(3, "Box for %d:%d, %llu to %llu on CPU %d\n", |
215 | rtt_info->pid, rtt_info->last_job, | 393 | rtt_info->pid, rtt_info->last_job, |
216 | rtt_info->run_time, ts, rtt_info->last_cpu); | 394 | rtt_info->run_time, ts, record->cpu); |
217 | info->box = TRUE; | 395 | info->box = TRUE; |
218 | info->bcolor = hash_cpu(rtt_info->last_cpu); | 396 | info->bcolor = hash_cpu(record->cpu); |
219 | info->bfill = TRUE; | 397 | info->bfill = TRUE; |
220 | info->bstart = rtt_info->run_time; | 398 | info->bstart = rtt_info->run_time; |
221 | info->bend = ts; | 399 | info->bend = ts; |
222 | info->blabel = rtt_info->label; | 400 | info->blabel = rtt_info->label; |
223 | } | 401 | } |
224 | 402 | ||
225 | dprintf(3, "Switch away at %llu\n", ts); | 403 | dprintf(3, "Switch away for %d:%d on %d at %llu\n", |
404 | pid, job, record->cpu, ts); | ||
226 | rtt_info->run_time = 0ULL; | 405 | rtt_info->run_time = 0ULL; |
227 | rtt_info->last_cpu = -1; | 406 | rtt_info->run_cpu = NO_CPU; |
228 | 407 | ||
229 | ret = 1; | 408 | ret = 1; |
230 | } | 409 | } |
@@ -237,18 +416,14 @@ static int try_switch_to(struct graph_info *ginfo, struct rt_task_info *rtt_info | |||
237 | int job, pid, match, ret = 0; | 416 | int job, pid, match, ret = 0; |
238 | unsigned long long ts; | 417 | unsigned long long ts; |
239 | 418 | ||
240 | match = rt_graph_check_switch_to(&ginfo->rtinfo, ginfo->pevent, | 419 | match = rt_graph_check_switch_to(&ginfo->rtg_info, ginfo->pevent, |
241 | record, &pid, &job, &ts); | 420 | record, &pid, &job, &ts); |
242 | if (match && pid == rtt_info->pid) { | 421 | if (match && pid == rtt_info->pid) { |
243 | update_job(rtt_info, job); | 422 | update_job(rtt_info, job); |
244 | |||
245 | rtt_info->run_time = ts; | 423 | rtt_info->run_time = ts; |
246 | rtt_info->last_cpu = record->cpu; | 424 | rtt_info->run_cpu = record->cpu; |
247 | 425 | dprintf(3, "Switch to for %d:%d on %d at %llu\n", | |
248 | dprintf(3, "Switching to %d:%d at %llu on CPU %d\n", | 426 | pid, job, record->cpu, ts); |
249 | rtt_info->pid, rtt_info->last_job, | ||
250 | ts, rtt_info->last_cpu); | ||
251 | |||
252 | ret = 1; | 427 | ret = 1; |
253 | } | 428 | } |
254 | return ret; | 429 | return ret; |
@@ -261,12 +436,12 @@ static int try_other(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
261 | unsigned long long ts; | 436 | unsigned long long ts; |
262 | 437 | ||
263 | pid = rtt_info->pid; | 438 | pid = rtt_info->pid; |
264 | rt_graph_check_any(&ginfo->rtinfo, ginfo->pevent, record, | 439 | rt_graph_check_any(&ginfo->rtg_info, ginfo->pevent, record, |
265 | &epid, &eid, &ts); | 440 | &epid, &eid, &ts); |
266 | 441 | ||
267 | my_pid = (pid == epid); | 442 | my_pid = (pid == epid); |
268 | my_cpu = (rtt_info->run_time && record->cpu == rtt_info->last_cpu); | 443 | my_cpu = (rtt_info->run_time && record->cpu == rtt_info->run_cpu); |
269 | not_sa = (eid != ginfo->rtinfo.switch_away_id); | 444 | not_sa = (eid != ginfo->rtg_info.switch_away_id); |
270 | if (not_sa && (my_pid || my_cpu)) { | 445 | if (not_sa && (my_pid || my_cpu)) { |
271 | info->line = TRUE; | 446 | info->line = TRUE; |
272 | info->lcolor = hash_pid(record->cpu); | 447 | info->lcolor = hash_pid(record->cpu); |
@@ -277,117 +452,42 @@ static int try_other(struct graph_info *ginfo, struct rt_task_info *rtt_info, | |||
277 | return ret; | 452 | return ret; |
278 | } | 453 | } |
279 | 454 | ||
280 | /* | 455 | static void do_plot_end(struct graph_info *ginfo, struct rt_task_info *rtt_info, |
281 | * Find the information for the last release of @rtt_info on @cpu before @time. | 456 | struct plot_info *info) |
282 | * @min_ts: the minimum time stamp to parse | ||
283 | * | ||
284 | * Returns release record and @out_job, @out_release, and @out_deadline if a | ||
285 | * release was found after @mints matching @time. | ||
286 | */ | ||
287 | static struct record* | ||
288 | get_previous_release(struct graph_info *ginfo, struct rt_task_info *rtt_info, | ||
289 | int cpu, | ||
290 | unsigned long long min_ts, unsigned long long time, | ||
291 | int *out_job, | ||
292 | unsigned long long *out_release, | ||
293 | unsigned long long *out_deadline) | ||
294 | { | ||
295 | int pid, job, match; | ||
296 | unsigned long long release, deadline; | ||
297 | struct record *last_record, *record, *ret = NULL; | ||
298 | struct rt_graph_info *rtg_info = &ginfo->rtinfo; | ||
299 | |||
300 | last_record = tracecmd_peek_data(ginfo->handle, cpu); | ||
301 | *out_job = *out_release = *out_deadline = 0; | ||
302 | if (!last_record) | ||
303 | return NULL; | ||
304 | last_record->ref_count++; | ||
305 | |||
306 | while ((record = tracecmd_read_prev(ginfo->handle, last_record))) { | ||
307 | if (record->ts < min_ts) { | ||
308 | free_record(record); | ||
309 | goto out; | ||
310 | } | ||
311 | match = rt_graph_check_task_release(rtg_info, ginfo->pevent, | ||
312 | record, &pid, &job, | ||
313 | &release, &deadline); | ||
314 | free_record(last_record); | ||
315 | last_record = record; | ||
316 | if (match && (pid == rtt_info->pid) && release <= time) { | ||
317 | ret = record; | ||
318 | last_record = NULL; | ||
319 | *out_job = job; | ||
320 | *out_release = release; | ||
321 | *out_deadline = deadline; | ||
322 | break; | ||
323 | } | ||
324 | }; | ||
325 | out: | ||
326 | free_record(last_record); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * Return information for @time, returns @job, @release, @deadline, and @record. | ||
332 | * @job: Job number at this time | ||
333 | * @release: Job's release time | ||
334 | * @deadline: Job's deadline | ||
335 | * @record: Matching record | ||
336 | */ | ||
337 | static int get_time_info(struct graph_info *ginfo, | ||
338 | struct rt_task_info *rtt_info, | ||
339 | unsigned long long time, | ||
340 | int *out_job, | ||
341 | unsigned long long *out_release, | ||
342 | unsigned long long *out_deadline, | ||
343 | struct record **out_record) | ||
344 | |||
345 | { | 457 | { |
346 | int cpu, job; | ||
347 | unsigned long long release, deadline, min_ts; | ||
348 | struct record *record; | 458 | struct record *record; |
349 | struct offset_cache *offsets; | 459 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; |
350 | 460 | int eid; | |
351 | /* Seek CPUs to first record after this time */ | ||
352 | *out_job = *out_release = *out_deadline = 0; | ||
353 | *out_record = find_record(ginfo, rtt_info->pid, time); | ||
354 | if (!*out_record) | ||
355 | return 0; | ||
356 | |||
357 | /* This is not necessarily correct for sporadic, but will do for now */ | ||
358 | if (time < rtt_info->first_rels[2]) { | ||
359 | job = (time >= rtt_info->first_rels[1]) ? 2 : 1; | ||
360 | *out_job = job; | ||
361 | *out_release = rtt_info->first_rels[job - 1]; | ||
362 | *out_deadline = rtt_info->first_rels[job]; | ||
363 | goto out; | ||
364 | } | ||
365 | |||
366 | min_ts = time - 2*rtt_info->wcet; | ||
367 | *out_job = *out_release = *out_deadline = 0; | ||
368 | 461 | ||
369 | offsets = save_offsets(ginfo); | 462 | if (rtt_info->run_time && rtt_info->run_cpu != NO_CPU) { |
370 | for (cpu = 0; cpu < ginfo->cpus; cpu++) { | 463 | /* A box was started, finish it */ |
371 | record = get_previous_release(ginfo, rtt_info, cpu, min_ts, | 464 | info->box = TRUE; |
372 | time, &job, &release, &deadline); | 465 | info->bcolor = hash_cpu(rtt_info->run_cpu); |
373 | if (record && record->ts > min_ts) { | 466 | info->bfill = TRUE; |
374 | *out_job = job; | 467 | info->bstart = rtt_info->run_time; |
375 | *out_release = release; | 468 | info->bend = ginfo->view_end_time; |
376 | *out_deadline = deadline; | 469 | info->blabel = rtt_info->label; |
377 | min_ts = record->ts; | 470 | } else if (rtt_info->block_time && rtt_info->block_cpu != NO_CPU) { |
471 | /* Blocking happened */ | ||
472 | } else if (rtt_info->fresh) { | ||
473 | /* Nothing happened!*/ | ||
474 | record = next_box_record(ginfo, rtt_info, | ||
475 | ginfo->view_end_time, &eid); | ||
476 | |||
477 | if (record) { | ||
478 | if (eid == rtg_info->switch_away_id) { | ||
479 | /* In a run */ | ||
480 | info->box = TRUE; | ||
481 | info->bcolor = hash_cpu(record->cpu); | ||
482 | info->bfill = TRUE; | ||
483 | info->bstart = ginfo->view_start_time; | ||
484 | info->bend = ginfo->view_end_time; | ||
485 | } else if (eid == rtg_info->task_resume_id) { | ||
486 | /* In a block */ | ||
487 | } | ||
488 | free_record(record); | ||
378 | } | 489 | } |
379 | free_record(record); | ||
380 | } | 490 | } |
381 | restore_offsets(ginfo, offsets); | ||
382 | out: | ||
383 | return 1; | ||
384 | } | ||
385 | |||
386 | static inline int in_res(struct graph_info *ginfo, unsigned long long time, | ||
387 | unsigned long target) | ||
388 | { | ||
389 | return time > target - 2/ginfo->resolution && | ||
390 | time < target + 2/ginfo->resolution; | ||
391 | } | 491 | } |
392 | 492 | ||
393 | static int rt_task_plot_event(struct graph_info *ginfo, struct graph_plot *plot, | 493 | static int rt_task_plot_event(struct graph_info *ginfo, struct graph_plot *plot, |
@@ -396,15 +496,11 @@ static int rt_task_plot_event(struct graph_info *ginfo, struct graph_plot *plot, | |||
396 | struct rt_task_info *rtt_info = plot->private; | 496 | struct rt_task_info *rtt_info = plot->private; |
397 | int match; | 497 | int match; |
398 | 498 | ||
499 | dprintf(4,"%s\n", __FUNCTION__); | ||
500 | |||
399 | /* No more records, finish what we started */ | 501 | /* No more records, finish what we started */ |
400 | if (!record) { | 502 | if (!record) { |
401 | if (rtt_info->last_cpu >= 0 && | 503 | do_plot_end(ginfo, rtt_info, info); |
402 | rtt_info->run_time) { | ||
403 | info->box = TRUE; | ||
404 | info->bstart = rtt_info->last_time; | ||
405 | info->bend = ginfo->view_end_time; | ||
406 | info->bcolor = hash_cpu(rtt_info->last_cpu); | ||
407 | } | ||
408 | return 0; | 504 | return 0; |
409 | } | 505 | } |
410 | 506 | ||
@@ -417,11 +513,6 @@ static int rt_task_plot_event(struct graph_info *ginfo, struct graph_plot *plot, | |||
417 | try_resume(ginfo, rtt_info, record, info) || | 513 | try_resume(ginfo, rtt_info, record, info) || |
418 | try_other(ginfo, rtt_info, record, info); | 514 | try_other(ginfo, rtt_info, record, info); |
419 | 515 | ||
420 | if (match) { | ||
421 | rtt_info->last_time = get_rts(ginfo, record); | ||
422 | rtt_info->last_cpu = record->cpu; | ||
423 | } | ||
424 | |||
425 | return match; | 516 | return match; |
426 | } | 517 | } |
427 | 518 | ||
@@ -431,22 +522,26 @@ static void rt_task_plot_start(struct graph_info *ginfo, struct graph_plot *plot | |||
431 | int i; | 522 | int i; |
432 | struct rt_task_info *rtt_info = plot->private; | 523 | struct rt_task_info *rtt_info = plot->private; |
433 | 524 | ||
525 | dprintf(4,"%s\n", __FUNCTION__); | ||
526 | |||
434 | rtt_info->wcet = 0ULL; | 527 | rtt_info->wcet = 0ULL; |
435 | rtt_info->period = 0ULL; | 528 | rtt_info->period = 0ULL; |
436 | rtt_info->run_time = 0ULL; | 529 | |
437 | rtt_info->block_time = 0ULL; | 530 | rtt_info->run_time = time; |
438 | rtt_info->last_cpu = -1; | 531 | rtt_info->block_time = time; |
439 | rtt_info->last_job = -1; | 532 | rtt_info->run_cpu = NO_CPU; |
533 | rtt_info->block_cpu = NO_CPU; | ||
440 | rtt_info->params_found = FALSE; | 534 | rtt_info->params_found = FALSE; |
535 | rtt_info->fresh = TRUE; | ||
441 | for (i = 0; i < 3; i++) | 536 | for (i = 0; i < 3; i++) |
442 | rtt_info->first_rels[i] = 0ULL; | 537 | rtt_info->first_rels[i] = 0ULL; |
443 | update_job(rtt_info, 0); | 538 | rtt_info->last_job = 0; |
444 | } | 539 | } |
445 | 540 | ||
446 | static void rt_task_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) | 541 | static void rt_task_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) |
447 | { | 542 | { |
448 | struct rt_task_info *rtt_info = plot->private; | 543 | struct rt_task_info *rtt_info = plot->private; |
449 | printf("Destroying plot %d\n", rtt_info->pid); | 544 | dprintf(4,"%s\n", __FUNCTION__); |
450 | free(rtt_info->label); | 545 | free(rtt_info->label); |
451 | task_plot_destroy(ginfo, plot); | 546 | task_plot_destroy(ginfo, plot); |
452 | } | 547 | } |
@@ -462,6 +557,8 @@ static int rt_task_plot_display_last_event(struct graph_info *ginfo, | |||
462 | struct offset_cache *offsets; | 557 | struct offset_cache *offsets; |
463 | struct rt_task_info *rtt_info = plot->private; | 558 | struct rt_task_info *rtt_info = plot->private; |
464 | 559 | ||
560 | dprintf(4,"%s\n", __FUNCTION__); | ||
561 | |||
465 | offsets = save_offsets(ginfo); | 562 | offsets = save_offsets(ginfo); |
466 | record = find_display_record(ginfo, rtt_info->pid, time); | 563 | record = find_display_record(ginfo, rtt_info->pid, time); |
467 | restore_offsets(ginfo, offsets); | 564 | restore_offsets(ginfo, offsets); |
@@ -481,10 +578,17 @@ static int rt_task_plot_display_last_event(struct graph_info *ginfo, | |||
481 | return 1; | 578 | return 1; |
482 | } | 579 | } |
483 | 580 | ||
581 | static inline int in_res(struct graph_info *ginfo, unsigned long long time, | ||
582 | unsigned long target) | ||
583 | { | ||
584 | return time > target - 2/ginfo->resolution && | ||
585 | time < target + 2/ginfo->resolution; | ||
586 | } | ||
587 | |||
484 | static int rt_task_plot_display_info(struct graph_info *ginfo, | 588 | static int rt_task_plot_display_info(struct graph_info *ginfo, |
485 | struct graph_plot *plot, | 589 | struct graph_plot *plot, |
486 | struct trace_seq *s, | 590 | struct trace_seq *s, |
487 | unsigned long long time) | 591 | unsigned long long time) |
488 | { | 592 | { |
489 | const char *comm; | 593 | const char *comm; |
490 | int pid, job, eid; | 594 | int pid, job, eid; |
@@ -495,6 +599,8 @@ static int rt_task_plot_display_info(struct graph_info *ginfo, | |||
495 | struct rt_task_info *rtt_info = plot->private; | 599 | struct rt_task_info *rtt_info = plot->private; |
496 | struct offset_cache *offsets; | 600 | struct offset_cache *offsets; |
497 | 601 | ||
602 | dprintf(4,"%s\n", __FUNCTION__); | ||
603 | |||
498 | offsets = save_offsets(ginfo); | 604 | offsets = save_offsets(ginfo); |
499 | get_time_info(ginfo, rtt_info, time, | 605 | get_time_info(ginfo, rtt_info, time, |
500 | &job, &release, &deadline, &record); | 606 | &job, &release, &deadline, &record); |
@@ -535,6 +641,8 @@ static int rt_task_plot_match_time(struct graph_info *ginfo, | |||
535 | struct rt_task_info *rtt_info = plot->private; | 641 | struct rt_task_info *rtt_info = plot->private; |
536 | int next_cpu, match, ret; | 642 | int next_cpu, match, ret; |
537 | 643 | ||
644 | dprintf(4,"%s\n", __FUNCTION__); | ||
645 | |||
538 | set_cpus_to_rts(ginfo, time); | 646 | set_cpus_to_rts(ginfo, time); |
539 | 647 | ||
540 | do { | 648 | do { |
@@ -600,14 +708,14 @@ void rt_plot_task_plotted(struct graph_info *ginfo, gint **plotted) | |||
600 | 708 | ||
601 | void rt_plot_task(struct graph_info *ginfo, int pid, int pos) | 709 | void rt_plot_task(struct graph_info *ginfo, int pid, int pos) |
602 | { | 710 | { |
603 | struct rt_graph_info *rtinfo = &ginfo->rtinfo; | 711 | struct rt_graph_info *rtg_info = &ginfo->rtg_info; |
604 | struct rt_task_info *rtt_info; | 712 | struct rt_task_info *rtt_info; |
605 | struct graph_plot *plot; | 713 | struct graph_plot *plot; |
606 | const char *comm; | 714 | const char *comm; |
607 | char *plot_label; | 715 | char *plot_label; |
608 | int len; | 716 | int len; |
609 | 717 | ||
610 | if (!find_task_list(rtinfo->tasks, pid)) | 718 | if (!find_task_list(rtg_info->tasks, pid)) |
611 | die("Cannot create RT plot of non-RT task %d!\n", pid); | 719 | die("Cannot create RT plot of non-RT task %d!\n", pid); |
612 | 720 | ||
613 | rtt_info = malloc_or_die(sizeof(*rtt_info)); | 721 | rtt_info = malloc_or_die(sizeof(*rtt_info)); |