aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r--tools/perf/util/session.c125
1 files changed, 87 insertions, 38 deletions
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);