diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ft2csv.c | 195 | ||||
-rw-r--r-- | src/timestamp.c | 6 |
2 files changed, 176 insertions, 25 deletions
diff --git a/src/ft2csv.c b/src/ft2csv.c index a6b1bf2..b75b284 100644 --- a/src/ft2csv.c +++ b/src/ft2csv.c | |||
@@ -41,8 +41,14 @@ static unsigned int skipped = 0; | |||
41 | static unsigned int non_rt = 0; | 41 | static unsigned int non_rt = 0; |
42 | static unsigned int interleaved = 0; | 42 | static unsigned int interleaved = 0; |
43 | static unsigned int avoided = 0; | 43 | static unsigned int avoided = 0; |
44 | static unsigned int lvl_a_sched = 0; | ||
45 | static unsigned int lvl_b_sched = 0; | ||
46 | static unsigned int lvl_c_sched = 0; | ||
47 | static unsigned int other_sched = 0; | ||
48 | static unsigned int filtered = 0; | ||
44 | 49 | ||
45 | #define CYCLES_PER_US 2128 | 50 | #define CYCLES_PER_US 2128 |
51 | static unsigned long long threshold = CYCLES_PER_US * 10000; /* 10 ms == 10 full ticks */ | ||
46 | 52 | ||
47 | static struct timestamp* next(struct timestamp* start, struct timestamp* end, | 53 | static struct timestamp* next(struct timestamp* start, struct timestamp* end, |
48 | int cpu) | 54 | int cpu) |
@@ -94,48 +100,180 @@ static struct timestamp* find_second_ts(struct timestamp* start, | |||
94 | start->event); | 100 | start->event); |
95 | } | 101 | } |
96 | 102 | ||
97 | typedef void (*pair_fmt_t)(struct timestamp* first, struct timestamp* second); | 103 | static struct timestamp* next_pid(struct timestamp* start, struct timestamp* end, |
104 | unsigned int pid, unsigned long id1, unsigned long id2) | ||
105 | { | ||
106 | struct timestamp* pos; | ||
107 | unsigned int last_seqno = 0; | ||
108 | |||
109 | for (pos = start; pos != end; pos++) { | ||
110 | /* check for for holes in the sequence number */ | ||
111 | if (last_seqno && last_seqno + 1 != pos->seq_no) { | ||
112 | /* stumbled across a hole */ | ||
113 | return NULL; | ||
114 | } | ||
115 | last_seqno = pos->seq_no; | ||
116 | |||
117 | /* only care about this PID */ | ||
118 | if (ts_pid_fragment(pos) == pid) { | ||
119 | /* is it the right one? */ | ||
120 | if (pos->event == id1 || pos->event == id2) | ||
121 | return pos; | ||
122 | else | ||
123 | /* Don't allow unexptected IDs interleaved. | ||
124 | * Tasks are sequential, there shouldn't be | ||
125 | * anything else. */ | ||
126 | return NULL; | ||
127 | } | ||
128 | } | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | static struct timestamp* accumulate_exec_time( | ||
133 | struct timestamp* start, struct timestamp* end, | ||
134 | unsigned int pid, unsigned long stop_id, uint64_t *sum) | ||
135 | { | ||
136 | struct timestamp* pos = start; | ||
137 | uint64_t exec_start; | ||
138 | |||
139 | *sum = 0; | ||
140 | |||
141 | while (1) { | ||
142 | exec_start = pos->timestamp; | ||
143 | |||
144 | /* find a suspension */ | ||
145 | pos = next_pid(pos + 1, end, pid, TS_LOCK_SUSPEND, stop_id); | ||
146 | if (!pos) | ||
147 | /* broken stream */ | ||
148 | return NULL; | ||
149 | |||
150 | /* account for exec until pos */ | ||
151 | *sum += pos->timestamp - exec_start; | ||
152 | |||
153 | if (pos->event == stop_id) | ||
154 | /* no suspension */ | ||
155 | return pos; | ||
156 | |||
157 | /* find matching resume */ | ||
158 | pos = next_pid(pos + 1, end, pid, TS_LOCK_RESUME, 0); | ||
159 | if (!pos) | ||
160 | /* broken stream */ | ||
161 | return NULL; | ||
162 | |||
163 | /* must be a resume => start over */ | ||
164 | } | ||
165 | } | ||
166 | |||
167 | typedef void (*pair_fmt_t)(struct timestamp* first, struct timestamp* second, uint64_t exec_time); | ||
98 | 168 | ||
99 | static void print_pair_csv(struct timestamp* first, struct timestamp* second) | 169 | static void print_pair_csv(struct timestamp* first, struct timestamp* second, uint64_t exec_time) |
100 | { | 170 | { |
101 | printf("%llu, %llu, %llu\n", | 171 | printf("%llu, %llu, %llu\n", |
102 | (unsigned long long) first->timestamp, | 172 | (unsigned long long) first->timestamp, |
103 | (unsigned long long) second->timestamp, | 173 | (unsigned long long) second->timestamp, |
104 | (unsigned long long) | 174 | (unsigned long long) exec_time); |
105 | (second->timestamp - first->timestamp)); | ||
106 | } | 175 | } |
107 | 176 | ||
108 | static void print_pair_bin(struct timestamp* first, struct timestamp* second) | 177 | static void print_pair_bin(struct timestamp* first, struct timestamp* second, uint64_t exec_time) |
109 | { | 178 | { |
110 | float delta = second->timestamp - first->timestamp; | 179 | float delta = exec_time; |
111 | fwrite(&delta, sizeof(delta), 1, stdout); | 180 | fwrite(&delta, sizeof(delta), 1, stdout); |
112 | } | 181 | } |
113 | 182 | ||
114 | pair_fmt_t format_pair = print_pair_csv; | 183 | pair_fmt_t format_pair = print_pair_csv; |
115 | 184 | ||
116 | static void show_csv(struct timestamp* first, struct timestamp *end) | 185 | static void find_event_by_pid(struct timestamp* first, struct timestamp* end) |
117 | { | 186 | { |
118 | struct timestamp *second; | 187 | struct timestamp *second; |
119 | 188 | uint64_t exec_time = 0; | |
120 | if (first->cpu == avoid_cpu || | 189 | |
121 | (only_cpu != -1 && first->cpu != only_cpu)) { | 190 | /* special case: take suspensions into account */ |
122 | avoided++; | 191 | if (first->event == TS_LOCK_START) { |
123 | return; | 192 | second = accumulate_exec_time(first, end, |
193 | ts_pid_fragment(first), | ||
194 | first->event + 3, &exec_time); | ||
195 | } else { | ||
196 | second = next_pid(first + 1, end, ts_pid_fragment(first), | ||
197 | first->event + 1, 0); | ||
198 | if (second) | ||
199 | exec_time = second->timestamp - first->timestamp; | ||
124 | } | 200 | } |
201 | if (second) { | ||
202 | if (exec_time > threshold) | ||
203 | filtered++; | ||
204 | else | ||
205 | format_pair(first, second, exec_time); | ||
206 | complete++; | ||
207 | } else | ||
208 | incomplete++; | ||
209 | } | ||
210 | |||
211 | static void find_event_by_eid(struct timestamp *first, struct timestamp* end) | ||
212 | { | ||
213 | struct timestamp *second; | ||
214 | uint64_t exec_time; | ||
125 | 215 | ||
126 | second = find_second_ts(first, end); | 216 | second = find_second_ts(first, end); |
127 | if (second) { | 217 | if (second) { |
128 | if (first->task_type != TSK_RT && | 218 | exec_time = second->timestamp - first->timestamp; |
219 | if (exec_time > threshold) | ||
220 | filtered++; | ||
221 | else if (first->task_type != TSK_RT && | ||
129 | second->task_type != TSK_RT && !want_best_effort) | 222 | second->task_type != TSK_RT && !want_best_effort) |
130 | non_rt++; | 223 | { |
131 | else { | 224 | if (TS_LVLA_SCHED_END == second->event && |
132 | format_pair(first, second); | 225 | second->task_type == TSK_LVLA) |
226 | { | ||
227 | format_pair(first, second, exec_time); | ||
228 | complete++; | ||
229 | lvl_a_sched++; | ||
230 | } else if (TS_LVLB_SCHED_END == second->event && | ||
231 | second->task_type == TSK_LVLB) | ||
232 | { | ||
233 | format_pair(first, second, exec_time); | ||
234 | complete++; | ||
235 | lvl_b_sched++; | ||
236 | } else if (TS_LVLC_SCHED_END == second->event && | ||
237 | second->task_type == TSK_LVLC) | ||
238 | { | ||
239 | format_pair(first, second, exec_time); | ||
240 | complete++; | ||
241 | lvl_c_sched++; | ||
242 | |||
243 | } else { | ||
244 | non_rt++; | ||
245 | } | ||
246 | } else if ((TS_LVLA_SCHED_END == second->event || | ||
247 | TS_LVLB_SCHED_END == second->event || | ||
248 | TS_LVLC_SCHED_END == second->event) && | ||
249 | TSK_RT == second->task_type) | ||
250 | { | ||
251 | other_sched++; | ||
252 | } else | ||
253 | { | ||
254 | format_pair(first, second, exec_time); | ||
133 | complete++; | 255 | complete++; |
134 | } | 256 | } |
135 | } else | 257 | } else |
136 | incomplete++; | 258 | incomplete++; |
137 | } | 259 | } |
138 | 260 | ||
261 | static void show_csv(struct timestamp* first, struct timestamp *end) | ||
262 | { | ||
263 | |||
264 | |||
265 | if (first->cpu == avoid_cpu || | ||
266 | (only_cpu != -1 && first->cpu != only_cpu)) { | ||
267 | avoided++; | ||
268 | return; | ||
269 | } | ||
270 | |||
271 | if (first->event <= PID_RECORDS_RANGE) | ||
272 | find_event_by_pid(first, end); | ||
273 | else | ||
274 | find_event_by_eid(first, end); | ||
275 | } | ||
276 | |||
139 | typedef void (*single_fmt_t)(struct timestamp* ts); | 277 | typedef void (*single_fmt_t)(struct timestamp* ts); |
140 | 278 | ||
141 | static void print_single_csv(struct timestamp* ts) | 279 | static void print_single_csv(struct timestamp* ts) |
@@ -271,17 +409,24 @@ int main(int argc, char** argv) | |||
271 | show_id(ts, end, id); | 409 | show_id(ts, end, id); |
272 | 410 | ||
273 | fprintf(stderr, | 411 | fprintf(stderr, |
274 | "Total : %10d\n" | 412 | "Total : %10d\n" |
275 | "Skipped : %10d\n" | 413 | "Skipped : %10d\n" |
276 | "Avoided : %10d\n" | 414 | "Avoided : %10d\n" |
277 | "Complete : %10d\n" | 415 | "Complete : %10d\n" |
278 | "Incomplete : %10d\n" | 416 | "Incomplete : %10d\n" |
279 | "Non RT : %10d\n" | 417 | "Filtered : %10d\n" |
280 | "Interleaved : %10d\n", | 418 | "Non RT : %10d\n" |
419 | "Interleaved : %10d\n" | ||
420 | "Lvl-A Sched : %10d\n" | ||
421 | "Lvl-B Sched : %10d\n" | ||
422 | "Lvl-C Sched : %10d\n" | ||
423 | "Other Sched (non-A) : %10d\n", | ||
281 | (int) count, | 424 | (int) count, |
282 | skipped, avoided, complete, | 425 | skipped, avoided, complete, |
283 | incomplete, non_rt, | 426 | incomplete, filtered, non_rt, |
284 | interleaved); | 427 | interleaved, lvl_a_sched, lvl_b_sched, lvl_c_sched, |
428 | other_sched); | ||
429 | |||
285 | 430 | ||
286 | return 0; | 431 | return 0; |
287 | } | 432 | } |
diff --git a/src/timestamp.c b/src/timestamp.c index 442c445..cad3fb5 100644 --- a/src/timestamp.c +++ b/src/timestamp.c | |||
@@ -22,6 +22,12 @@ static struct event_name event_table[] = | |||
22 | EVENT(PLUGIN_TICK), | 22 | EVENT(PLUGIN_TICK), |
23 | EVENT(CXS), | 23 | EVENT(CXS), |
24 | EVENT(SEND_RESCHED), | 24 | EVENT(SEND_RESCHED), |
25 | EVENT(LVLA_RELEASE), | ||
26 | EVENT(LVLA_SCHED), | ||
27 | EVENT(LVLB_RELEASE), | ||
28 | EVENT(LVLB_SCHED), | ||
29 | EVENT(LVLC_RELEASE), | ||
30 | EVENT(LVLC_SCHED), | ||
25 | {"RELEASE_LATENCY", TS_RELEASE_LATENCY}, | 31 | {"RELEASE_LATENCY", TS_RELEASE_LATENCY}, |
26 | 32 | ||
27 | EVENT(SYSCALL_IN), | 33 | EVENT(SYSCALL_IN), |