aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2012-08-19 14:05:00 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2012-10-19 16:54:29 -0400
commit4531e293279cdc817f7ac37bff9472e74cb085ee (patch)
tree1f3d0ce8a4e49d1b33ad6891acc0bfc0b6ae0a2d
parent44da17bf24f2e67ab71ecb552ebf7b460e64999e (diff)
Add filtering of IRQ-disturbed samples (on by default)
Interrupts can cause massive outliers. Instead of trying to filter them afterwards, let's not even include such samples in the first place.
-rw-r--r--src/ft2csv.c195
1 files changed, 143 insertions, 52 deletions
diff --git a/src/ft2csv.c b/src/ft2csv.c
index ff3db23..d8e8e95 100644
--- a/src/ft2csv.c
+++ b/src/ft2csv.c
@@ -31,6 +31,7 @@
31 31
32static int want_interleaved = 1; 32static int want_interleaved = 1;
33static int want_best_effort = 0; 33static int want_best_effort = 0;
34static int want_interrupted = 0;
34static int find_by_pid = AUTO_SELECT; 35static int find_by_pid = AUTO_SELECT;
35 36
36/* discard samples from a specific CPU */ 37/* discard samples from a specific CPU */
@@ -40,22 +41,24 @@ static int only_cpu = -1;
40 41
41static unsigned int complete = 0; 42static unsigned int complete = 0;
42static unsigned int incomplete = 0; 43static unsigned int incomplete = 0;
44static unsigned int interrupted = 0;
43static unsigned int skipped = 0; 45static unsigned int skipped = 0;
44static unsigned int non_rt = 0; 46static unsigned int non_rt = 0;
45static unsigned int interleaved = 0; 47static unsigned int interleaved = 0;
46static unsigned int avoided = 0; 48static unsigned int avoided = 0;
47 49
48#define CYCLES_PER_US 2128 50static struct timestamp* next(struct timestamp* first, struct timestamp* end,
49
50static struct timestamp* next(struct timestamp* start, struct timestamp* end,
51 int cpu) 51 int cpu)
52{ 52{
53 struct timestamp* pos; 53 struct timestamp* pos;
54 unsigned int last_seqno = 0; 54 uint32_t last_seqno = 0, next_seqno = 0;
55
55 56
56 for (pos = start; pos != end; pos++) { 57 last_seqno = first->seq_no;
58 for (pos = first + 1; pos < end; pos++) {
57 /* check for for holes in the sequence number */ 59 /* check for for holes in the sequence number */
58 if (last_seqno && last_seqno + 1 != pos->seq_no) { 60 next_seqno = last_seqno + 1;
61 if (next_seqno != pos->seq_no) {
59 /* stumbled across a hole */ 62 /* stumbled across a hole */
60 return NULL; 63 return NULL;
61 } 64 }
@@ -69,7 +72,8 @@ static struct timestamp* next(struct timestamp* start, struct timestamp* end,
69 72
70static struct timestamp* next_id(struct timestamp* start, struct timestamp* end, 73static struct timestamp* next_id(struct timestamp* start, struct timestamp* end,
71 int cpu, unsigned long id, 74 int cpu, unsigned long id,
72 unsigned long stop_id) 75 unsigned long stop_id,
76 int *interrupt_flag)
73{ 77{
74 struct timestamp* pos = start; 78 struct timestamp* pos = start;
75 int restarts = 0; 79 int restarts = 0;
@@ -79,45 +83,74 @@ static struct timestamp* next_id(struct timestamp* start, struct timestamp* end,
79 break; 83 break;
80 else if (pos->event == stop_id) 84 else if (pos->event == stop_id)
81 return NULL; 85 return NULL;
82 pos++; 86
83 restarts++; 87 restarts++;
84 if (!want_interleaved) 88 if (!want_interleaved)
85 return NULL; 89 return NULL;
90 if (pos->irq_flag && !want_interrupted) {
91 *interrupt_flag = 1;
92 return NULL;
93 }
86 } 94 }
87 if (pos) 95 if (pos)
88 interleaved += restarts; 96 interleaved += restarts;
97
98 if (pos && pos->irq_flag) {
99 interrupted++;
100 if (!want_interrupted) {
101 *interrupt_flag = 1;
102 return NULL;
103 }
104 }
105
89 return pos; 106 return pos;
90} 107}
91 108
92static struct timestamp* find_second_ts(struct timestamp* start, 109static struct timestamp* find_second_ts(struct timestamp* start,
93 struct timestamp* end) 110 struct timestamp* end,
111 int *interrupt_flag)
94{ 112{
95 /* convention: the end->event is start->event + 1 */ 113 /* convention: the end->event is start->event + 1 */
96 return next_id(start + 1, end, start->cpu, start->event + 1, 114 return next_id(start, end, start->cpu, start->event + 1,
97 start->event); 115 start->event, interrupt_flag);
98} 116}
99 117
100static struct timestamp* next_pid(struct timestamp* start, struct timestamp* end, 118static struct timestamp* next_pid(struct timestamp* first, struct timestamp* end,
101 unsigned int pid, unsigned long id1, unsigned long id2) 119 unsigned long id1, unsigned long id2,
120 int interrupts_significant, int *interrupted_flag)
102{ 121{
103 struct timestamp* pos; 122 struct timestamp* pos;
104 unsigned int last_seqno = 0; 123 uint32_t last_seqno = 0, next_seqno = 0;
105 124
106 for (pos = start; pos != end; pos++) { 125
126 last_seqno = first->seq_no;
127 for (pos = first + 1; pos < end; pos++) {
107 /* check for for holes in the sequence number */ 128 /* check for for holes in the sequence number */
108 if (last_seqno && last_seqno + 1 != pos->seq_no) { 129 next_seqno = last_seqno + 1;
130 if (next_seqno != pos->seq_no) {
109 /* stumbled across a hole */ 131 /* stumbled across a hole */
110 return NULL; 132 return NULL;
111 } 133 }
112 last_seqno = pos->seq_no; 134 last_seqno = pos->seq_no;
113 135
136 if (interrupts_significant
137 && pos->cpu == first->cpu
138 && pos->irq_flag) {
139 /* did an interrupt get in the way? */
140 interrupted++;
141 if (!want_interrupted) {
142 *interrupted_flag = 1;
143 return NULL;
144 }
145 }
146
114 /* only care about this PID */ 147 /* only care about this PID */
115 if (pos->pid == pid) { 148 if (pos->pid == first->pid) {
116 /* is it the right one? */ 149 /* is it the right one? */
117 if (pos->event == id1 || pos->event == id2) 150 if (pos->event == id1 || pos->event == id2)
118 return pos; 151 return pos;
119 else 152 else
120 /* Don't allow unexptected IDs interleaved. 153 /* Don't allow unexpected IDs interleaved.
121 * Tasks are sequential, there shouldn't be 154 * Tasks are sequential, there shouldn't be
122 * anything else. */ 155 * anything else. */
123 return NULL; 156 return NULL;
@@ -126,21 +159,55 @@ static struct timestamp* next_pid(struct timestamp* start, struct timestamp* end
126 return NULL; 159 return NULL;
127} 160}
128 161
162static struct timestamp* skip_over_suspension(struct timestamp *pos,
163 struct timestamp *end,
164 uint64_t *last_time)
165{
166 /* Find matching resume. */
167 pos = next_pid(pos, end,
168 TS_LOCK_RESUME, TS_SCHED_START,
169 0, NULL);
170
171 if (!pos || pos->timestamp < *last_time)
172 /* broken stream */
173 return NULL;
174
175 *last_time = pos->timestamp;
176
177 if (pos->event == TS_SCHED_START) {
178 /* Was scheduled out, find TS_SCHED_END. */
179 pos = next_pid(pos, end, TS_SCHED_END, 0, 0, NULL);
180 if (!pos || pos->timestamp < *last_time)
181 return NULL;
182
183 /* next find TS_LOCK_RESUME */
184 pos = next_pid(pos, end, TS_LOCK_RESUME, 0, 0, NULL);
185 }
186
187
188 return pos;
189}
190
129static struct timestamp* accumulate_exec_time( 191static struct timestamp* accumulate_exec_time(
130 struct timestamp* start, struct timestamp* end, 192 struct timestamp* start, struct timestamp* end,
131 unsigned int pid, unsigned long stop_id, uint64_t *sum) 193 unsigned long stop_id, uint64_t *sum,
194 int *interrupted_flag)
132{ 195{
133 struct timestamp* pos = start; 196 struct timestamp *pos = start;
134 uint64_t exec_start; 197 uint64_t exec_start;
198 uint64_t last_time = start->timestamp;
135 199
136 *sum = 0; 200 *sum = 0;
137 201
138 while (1) { 202 while (1) {
139 exec_start = pos->timestamp; 203 exec_start = pos->timestamp;
140 204
141 /* find a suspension */ 205 /* Find a suspension or the proper end. */
142 pos = next_pid(pos + 1, end, pid, TS_LOCK_SUSPEND, stop_id); 206 pos = next_pid(pos, end,
143 if (!pos) 207 TS_LOCK_SUSPEND, stop_id,
208 1, interrupted_flag);
209
210 if (!pos || pos->timestamp < last_time)
144 /* broken stream */ 211 /* broken stream */
145 return NULL; 212 return NULL;
146 213
@@ -148,16 +215,25 @@ static struct timestamp* accumulate_exec_time(
148 *sum += pos->timestamp - exec_start; 215 *sum += pos->timestamp - exec_start;
149 216
150 if (pos->event == stop_id) 217 if (pos->event == stop_id)
151 /* no suspension */ 218 /* no suspension or preemption */
152 return pos; 219 return pos;
220 else {
221 last_time = pos->timestamp;
153 222
154 /* find matching resume */ 223 /* handle self-suspension */
155 pos = next_pid(pos + 1, end, pid, TS_LOCK_RESUME, 0); 224 pos = skip_over_suspension(pos, end, &last_time);
156 if (!pos) 225
157 /* broken stream */ 226 /* Must be a resume => start over. If a resume sample is
158 return NULL; 227 * affected by interrupts we don't care since it does not
228 * contribute to the reported execution cost.
229 */
159 230
160 /* must be a resume => start over */ 231 if (!pos || pos->timestamp < last_time)
232 /* broken stream */
233 return NULL;
234
235 last_time = pos->timestamp;
236 }
161 } 237 }
162} 238}
163 239
@@ -183,22 +259,26 @@ static void find_event_by_pid(struct timestamp* first, struct timestamp* end)
183{ 259{
184 struct timestamp *second; 260 struct timestamp *second;
185 uint64_t exec_time = 0; 261 uint64_t exec_time = 0;
262 int interrupted = 0;
186 263
187 /* special case: take suspensions into account */ 264 /* special case: take suspensions into account */
188 if (first->event >= SUSPENSION_RANGE) { 265 if (first->event >= SUSPENSION_RANGE) {
189 second = accumulate_exec_time(first, end, 266 second = accumulate_exec_time(first, end,
190 first->pid, 267 first->event + 1, &exec_time,
191 first->event + 1, &exec_time); 268 &interrupted);
192 } else { 269 } else {
193 second = next_pid(first + 1, end, first->pid, 270 second = next_pid(first, end,
194 first->event + 1, 0); 271 first->event + 1, 0,
195 if (second) 272 1, &interrupted);
273 if (second && second->timestamp > first->timestamp)
196 exec_time = second->timestamp - first->timestamp; 274 exec_time = second->timestamp - first->timestamp;
275 else
276 second = NULL;
197 } 277 }
198 if (second) { 278 if (second) {
199 format_pair(first, second, exec_time); 279 format_pair(first, second, exec_time);
200 complete++; 280 complete++;
201 } else 281 } else if (!interrupted)
202 incomplete++; 282 incomplete++;
203} 283}
204 284
@@ -206,8 +286,9 @@ static void find_event_by_eid(struct timestamp *first, struct timestamp* end)
206{ 286{
207 struct timestamp *second; 287 struct timestamp *second;
208 uint64_t exec_time; 288 uint64_t exec_time;
289 int interrupted = 0;
209 290
210 second = find_second_ts(first, end); 291 second = find_second_ts(first, end, &interrupted);
211 if (second) { 292 if (second) {
212 exec_time = second->timestamp - first->timestamp; 293 exec_time = second->timestamp - first->timestamp;
213 if (first->task_type != TSK_RT && 294 if (first->task_type != TSK_RT &&
@@ -217,7 +298,7 @@ static void find_event_by_eid(struct timestamp *first, struct timestamp* end)
217 format_pair(first, second, exec_time); 298 format_pair(first, second, exec_time);
218 complete++; 299 complete++;
219 } 300 }
220 } else 301 } else if (!interrupted)
221 incomplete++; 302 incomplete++;
222} 303}
223 304
@@ -295,6 +376,7 @@ static void show_single_records(struct timestamp* start, struct timestamp* end,
295 " -r: raw binary format -- don't produce .csv output \n" \ 376 " -r: raw binary format -- don't produce .csv output \n" \
296 " -a: avoid CPU -- skip samples from a specific CPU\n" \ 377 " -a: avoid CPU -- skip samples from a specific CPU\n" \
297 " -o: only CPU -- skip all samples from other CPUs\n" \ 378 " -o: only CPU -- skip all samples from other CPUs\n" \
379 " -x: allow interrupts -- don't skip samples with IRQ-happned flag \n" \
298 "" 380 ""
299 381
300static void die(char* msg) 382static void die(char* msg)
@@ -306,7 +388,7 @@ static void die(char* msg)
306 exit(1); 388 exit(1);
307} 389}
308 390
309#define OPTS "ibra:o:pe" 391#define OPTS "ibra:o:pex"
310 392
311int main(int argc, char** argv) 393int main(int argc, char** argv)
312{ 394{
@@ -323,13 +405,17 @@ int main(int argc, char** argv)
323 want_interleaved = 0; 405 want_interleaved = 0;
324 fprintf(stderr, "Discarging interleaved samples.\n"); 406 fprintf(stderr, "Discarging interleaved samples.\n");
325 break; 407 break;
408 case 'x':
409 want_interrupted = 1;
410 fprintf(stderr, "Not filtering disturbed-by-interrupt samples.\n");
411 break;
326 case 'b': 412 case 'b':
327 fprintf(stderr,"Not filtering samples from best-effort" 413 fprintf(stderr,"Not filtering samples from best-effort"
328 " tasks.\n"); 414 " tasks.\n");
329 want_best_effort = 1; 415 want_best_effort = 1;
330 break; 416 break;
331 case 'r': 417 case 'r':
332 fprintf(stderr, "Generating binary (raw) output.\n"); 418 fprintf(stderr, "Generating binary, NumPy-compatible output.\n");
333 single_fmt = print_single_bin; 419 single_fmt = print_single_bin;
334 format_pair = print_pair_bin; 420 format_pair = print_pair_bin;
335 break; 421 break;
@@ -382,18 +468,23 @@ int main(int argc, char** argv)
382 else 468 else
383 show_id(ts, end, id); 469 show_id(ts, end, id);
384 470
385 fprintf(stderr, 471 if (count == skipped)
386 "Total : %10d\n" 472 fprintf(stderr, "Event %s not present.\n",
387 "Skipped : %10d\n" 473 argv[optind]);
388 "Avoided : %10d\n" 474 else
389 "Complete : %10d\n" 475 fprintf(stderr,
390 "Incomplete : %10d\n" 476 "Total : %10d\n"
391 "Non RT : %10d\n" 477 "Skipped : %10d\n"
392 "Interleaved : %10d\n", 478 "Avoided : %10d\n"
393 (int) count, 479 "Complete : %10d\n"
394 skipped, avoided, complete, 480 "Incomplete : %10d\n"
395 incomplete, non_rt, 481 "Non RT : %10d\n"
396 interleaved); 482 "Interleaved : %10d\n"
483 "Interrupted : %10d\n",
484 (int) count,
485 skipped, avoided, complete,
486 incomplete, non_rt,
487 interleaved, interrupted);
397 488
398 return 0; 489 return 0;
399} 490}