aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2010-05-10 02:20:19 -0400
committerIngo Molnar <mingo@elte.hu>2010-05-10 02:20:19 -0400
commit1f0ac7183f4d270bd9ce511254ba5d931d4f29c9 (patch)
tree124b2682a249b0393f29e929537aa76ab299bb5f /tools/perf/util
parent232a5c948da5e23dff27e48180abf4a4238f7602 (diff)
parent76ba7e846fcc89d9d4b25b89e303c9058de96d60 (diff)
Merge branch 'perf/test' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing into perf/core
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/event.h3
-rw-r--r--tools/perf/util/session.c125
-rw-r--r--tools/perf/util/session.h36
3 files changed, 110 insertions, 54 deletions
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index b364da5b0cbf..6cc1b1dced55 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -84,11 +84,12 @@ struct build_id_event {
84 char filename[]; 84 char filename[];
85}; 85};
86 86
87enum perf_header_event_type { /* above any possible kernel type */ 87enum perf_user_event_type { /* above any possible kernel type */
88 PERF_RECORD_HEADER_ATTR = 64, 88 PERF_RECORD_HEADER_ATTR = 64,
89 PERF_RECORD_HEADER_EVENT_TYPE = 65, 89 PERF_RECORD_HEADER_EVENT_TYPE = 65,
90 PERF_RECORD_HEADER_TRACING_DATA = 66, 90 PERF_RECORD_HEADER_TRACING_DATA = 66,
91 PERF_RECORD_HEADER_BUILD_ID = 67, 91 PERF_RECORD_HEADER_BUILD_ID = 67,
92 PERF_RECORD_FINISHED_ROUND = 68,
92 PERF_RECORD_HEADER_MAX 93 PERF_RECORD_HEADER_MAX
93}; 94};
94 95
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 71bc608e0ec6..c088d8f9b51c 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -98,7 +98,6 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
98 self->unknown_events = 0; 98 self->unknown_events = 0;
99 self->machines = RB_ROOT; 99 self->machines = RB_ROOT;
100 self->repipe = repipe; 100 self->repipe = repipe;
101 self->ordered_samples.flush_limit = ULLONG_MAX;
102 INIT_LIST_HEAD(&self->ordered_samples.samples_head); 101 INIT_LIST_HEAD(&self->ordered_samples.samples_head);
103 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 102 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
104 103
@@ -195,6 +194,18 @@ static int process_event_stub(event_t *event __used,
195 return 0; 194 return 0;
196} 195}
197 196
197static int process_finished_round_stub(event_t *event __used,
198 struct perf_session *session __used,
199 struct perf_event_ops *ops __used)
200{
201 dump_printf(": unhandled!\n");
202 return 0;
203}
204
205static int process_finished_round(event_t *event,
206 struct perf_session *session,
207 struct perf_event_ops *ops);
208
198static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 209static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
199{ 210{
200 if (handler->sample == NULL) 211 if (handler->sample == NULL)
@@ -223,6 +234,12 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
223 handler->tracing_data = process_event_stub; 234 handler->tracing_data = process_event_stub;
224 if (handler->build_id == NULL) 235 if (handler->build_id == NULL)
225 handler->build_id = process_event_stub; 236 handler->build_id = process_event_stub;
237 if (handler->finished_round == NULL) {
238 if (handler->ordered_samples)
239 handler->finished_round = process_finished_round;
240 else
241 handler->finished_round = process_finished_round_stub;
242 }
226} 243}
227 244
228static const char *event__name[] = { 245static const char *event__name[] = {
@@ -360,16 +377,14 @@ struct sample_queue {
360 struct list_head list; 377 struct list_head list;
361}; 378};
362 379
363#define FLUSH_PERIOD (2 * NSEC_PER_SEC)
364
365static void flush_sample_queue(struct perf_session *s, 380static void flush_sample_queue(struct perf_session *s,
366 struct perf_event_ops *ops) 381 struct perf_event_ops *ops)
367{ 382{
368 struct list_head *head = &s->ordered_samples.samples_head; 383 struct list_head *head = &s->ordered_samples.samples_head;
369 u64 limit = s->ordered_samples.flush_limit; 384 u64 limit = s->ordered_samples.next_flush;
370 struct sample_queue *tmp, *iter; 385 struct sample_queue *tmp, *iter;
371 386
372 if (!ops->ordered_samples) 387 if (!ops->ordered_samples || !limit)
373 return; 388 return;
374 389
375 list_for_each_entry_safe(iter, tmp, head, list) { 390 list_for_each_entry_safe(iter, tmp, head, list) {
@@ -388,6 +403,55 @@ static void flush_sample_queue(struct perf_session *s,
388 } 403 }
389} 404}
390 405
406/*
407 * When perf record finishes a pass on every buffers, it records this pseudo
408 * event.
409 * We record the max timestamp t found in the pass n.
410 * Assuming these timestamps are monotonic across cpus, we know that if
411 * a buffer still has events with timestamps below t, they will be all
412 * available and then read in the pass n + 1.
413 * Hence when we start to read the pass n + 2, we can safely flush every
414 * events with timestamps below t.
415 *
416 * ============ PASS n =================
417 * CPU 0 | CPU 1
418 * |
419 * cnt1 timestamps | cnt2 timestamps
420 * 1 | 2
421 * 2 | 3
422 * - | 4 <--- max recorded
423 *
424 * ============ PASS n + 1 ==============
425 * CPU 0 | CPU 1
426 * |
427 * cnt1 timestamps | cnt2 timestamps
428 * 3 | 5
429 * 4 | 6
430 * 5 | 7 <---- max recorded
431 *
432 * Flush every events below timestamp 4
433 *
434 * ============ PASS n + 2 ==============
435 * CPU 0 | CPU 1
436 * |
437 * cnt1 timestamps | cnt2 timestamps
438 * 6 | 8
439 * 7 | 9
440 * - | 10
441 *
442 * Flush every events below timestamp 7
443 * etc...
444 */
445static int process_finished_round(event_t *event __used,
446 struct perf_session *session,
447 struct perf_event_ops *ops)
448{
449 flush_sample_queue(session, ops);
450 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
451
452 return 0;
453}
454
391static void __queue_sample_end(struct sample_queue *new, struct list_head *head) 455static void __queue_sample_end(struct sample_queue *new, struct list_head *head)
392{ 456{
393 struct sample_queue *iter; 457 struct sample_queue *iter;
@@ -456,17 +520,12 @@ static void __queue_sample_event(struct sample_queue *new,
456} 520}
457 521
458static int queue_sample_event(event_t *event, struct sample_data *data, 522static int queue_sample_event(event_t *event, struct sample_data *data,
459 struct perf_session *s, 523 struct perf_session *s)
460 struct perf_event_ops *ops)
461{ 524{
462 u64 timestamp = data->time; 525 u64 timestamp = data->time;
463 struct sample_queue *new; 526 struct sample_queue *new;
464 u64 flush_limit;
465 527
466 528
467 if (s->ordered_samples.flush_limit == ULLONG_MAX)
468 s->ordered_samples.flush_limit = timestamp + FLUSH_PERIOD;
469
470 if (timestamp < s->ordered_samples.last_flush) { 529 if (timestamp < s->ordered_samples.last_flush) {
471 printf("Warning: Timestamp below last timeslice flush\n"); 530 printf("Warning: Timestamp below last timeslice flush\n");
472 return -EINVAL; 531 return -EINVAL;
@@ -489,23 +548,8 @@ static int queue_sample_event(event_t *event, struct sample_data *data,
489 __queue_sample_event(new, s); 548 __queue_sample_event(new, s);
490 s->ordered_samples.last_inserted = new; 549 s->ordered_samples.last_inserted = new;
491 550
492 /* 551 if (new->timestamp > s->ordered_samples.max_timestamp)
493 * We want to have a slice of events covering 2 * FLUSH_PERIOD 552 s->ordered_samples.max_timestamp = new->timestamp;
494 * If FLUSH_PERIOD is big enough, it ensures every events that occured
495 * in the first half of the timeslice have all been buffered and there
496 * are none remaining (we need that because of the weakly ordered
497 * event recording we have). Then once we reach the 2 * FLUSH_PERIOD
498 * timeslice, we flush the first half to be gentle with the memory
499 * (the second half can still get new events in the middle, so wait
500 * another period to flush it)
501 */
502 flush_limit = s->ordered_samples.flush_limit;
503
504 if (new->timestamp > flush_limit &&
505 new->timestamp - flush_limit > FLUSH_PERIOD) {
506 s->ordered_samples.flush_limit += FLUSH_PERIOD;
507 flush_sample_queue(s, ops);
508 }
509 553
510 return 0; 554 return 0;
511} 555}
@@ -521,7 +565,7 @@ static int perf_session__process_sample(event_t *event, struct perf_session *s,
521 bzero(&data, sizeof(struct sample_data)); 565 bzero(&data, sizeof(struct sample_data));
522 event__parse_sample(event, s->sample_type, &data); 566 event__parse_sample(event, s->sample_type, &data);
523 567
524 queue_sample_event(event, &data, s, ops); 568 queue_sample_event(event, &data, s);
525 569
526 return 0; 570 return 0;
527} 571}
@@ -573,6 +617,8 @@ static int perf_session__process_event(struct perf_session *self,
573 return ops->tracing_data(event, self); 617 return ops->tracing_data(event, self);
574 case PERF_RECORD_HEADER_BUILD_ID: 618 case PERF_RECORD_HEADER_BUILD_ID:
575 return ops->build_id(event, self); 619 return ops->build_id(event, self);
620 case PERF_RECORD_FINISHED_ROUND:
621 return ops->finished_round(event, self, ops);
576 default: 622 default:
577 self->unknown_events++; 623 self->unknown_events++;
578 return -1; 624 return -1;
@@ -651,15 +697,18 @@ more:
651 p = &event; 697 p = &event;
652 p += sizeof(struct perf_event_header); 698 p += sizeof(struct perf_event_header);
653 699
654 err = do_read(self->fd, p, size - sizeof(struct perf_event_header)); 700 if (size - sizeof(struct perf_event_header)) {
655 if (err <= 0) { 701 err = do_read(self->fd, p,
656 if (err == 0) { 702 size - sizeof(struct perf_event_header));
657 pr_err("unexpected end of event stream\n"); 703 if (err <= 0) {
658 goto done; 704 if (err == 0) {
659 } 705 pr_err("unexpected end of event stream\n");
706 goto done;
707 }
660 708
661 pr_err("failed to read event data\n"); 709 pr_err("failed to read event data\n");
662 goto out_err; 710 goto out_err;
711 }
663 } 712 }
664 713
665 if (size == 0 || 714 if (size == 0 ||
@@ -787,7 +836,7 @@ more:
787done: 836done:
788 err = 0; 837 err = 0;
789 /* do the final flush for ordered samples */ 838 /* do the final flush for ordered samples */
790 self->ordered_samples.flush_limit = ULLONG_MAX; 839 self->ordered_samples.next_flush = ULLONG_MAX;
791 flush_sample_queue(self, ops); 840 flush_sample_queue(self, ops);
792out_err: 841out_err:
793 ui_progress__delete(progress); 842 ui_progress__delete(progress);
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index eb9f179376a5..242d528bfae2 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -14,7 +14,8 @@ struct thread;
14 14
15struct ordered_samples { 15struct ordered_samples {
16 u64 last_flush; 16 u64 last_flush;
17 u64 flush_limit; 17 u64 next_flush;
18 u64 max_timestamp;
18 struct list_head samples_head; 19 struct list_head samples_head;
19 struct sample_queue *last_inserted; 20 struct sample_queue *last_inserted;
20}; 21};
@@ -42,23 +43,28 @@ struct perf_session {
42 char filename[0]; 43 char filename[0];
43}; 44};
44 45
46struct perf_event_ops;
47
45typedef int (*event_op)(event_t *self, struct perf_session *session); 48typedef int (*event_op)(event_t *self, struct perf_session *session);
49typedef int (*event_op2)(event_t *self, struct perf_session *session,
50 struct perf_event_ops *ops);
46 51
47struct perf_event_ops { 52struct perf_event_ops {
48 event_op sample, 53 event_op sample,
49 mmap, 54 mmap,
50 comm, 55 comm,
51 fork, 56 fork,
52 exit, 57 exit,
53 lost, 58 lost,
54 read, 59 read,
55 throttle, 60 throttle,
56 unthrottle, 61 unthrottle,
57 attr, 62 attr,
58 event_type, 63 event_type,
59 tracing_data, 64 tracing_data,
60 build_id; 65 build_id;
61 bool ordered_samples; 66 event_op2 finished_round;
67 bool ordered_samples;
62}; 68};
63 69
64struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe); 70struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe);