diff options
| author | Ingo Molnar <mingo@elte.hu> | 2010-05-10 02:20:19 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-05-10 02:20:19 -0400 |
| commit | 1f0ac7183f4d270bd9ce511254ba5d931d4f29c9 (patch) | |
| tree | 124b2682a249b0393f29e929537aa76ab299bb5f /tools/perf/util/session.c | |
| parent | 232a5c948da5e23dff27e48180abf4a4238f7602 (diff) | |
| parent | 76ba7e846fcc89d9d4b25b89e303c9058de96d60 (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/session.c')
| -rw-r--r-- | tools/perf/util/session.c | 125 |
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 | ||
| 197 | static 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 | |||
| 205 | static int process_finished_round(event_t *event, | ||
| 206 | struct perf_session *session, | ||
| 207 | struct perf_event_ops *ops); | ||
| 208 | |||
| 198 | static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) | 209 | static 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 | ||
| 228 | static const char *event__name[] = { | 245 | static 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 | |||
| 365 | static void flush_sample_queue(struct perf_session *s, | 380 | static 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 | */ | ||
| 445 | static 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 | |||
| 391 | static void __queue_sample_end(struct sample_queue *new, struct list_head *head) | 455 | static 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 | ||
| 458 | static int queue_sample_event(event_t *event, struct sample_data *data, | 522 | static 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: | |||
| 787 | done: | 836 | done: |
| 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); |
| 792 | out_err: | 841 | out_err: |
| 793 | ui_progress__delete(progress); | 842 | ui_progress__delete(progress); |
