diff options
Diffstat (limited to 'kernel/perf_event.c')
| -rw-r--r-- | kernel/perf_event.c | 42 |
1 files changed, 34 insertions, 8 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 517d827f4982..cb6c0d2af68f 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -674,6 +674,8 @@ event_sched_in(struct perf_event *event, | |||
| 674 | 674 | ||
| 675 | event->tstamp_running += ctx->time - event->tstamp_stopped; | 675 | event->tstamp_running += ctx->time - event->tstamp_stopped; |
| 676 | 676 | ||
| 677 | event->shadow_ctx_time = ctx->time - ctx->timestamp; | ||
| 678 | |||
| 677 | if (!is_software_event(event)) | 679 | if (!is_software_event(event)) |
| 678 | cpuctx->active_oncpu++; | 680 | cpuctx->active_oncpu++; |
| 679 | ctx->nr_active++; | 681 | ctx->nr_active++; |
| @@ -3396,7 +3398,8 @@ static u32 perf_event_tid(struct perf_event *event, struct task_struct *p) | |||
| 3396 | } | 3398 | } |
| 3397 | 3399 | ||
| 3398 | static void perf_output_read_one(struct perf_output_handle *handle, | 3400 | static void perf_output_read_one(struct perf_output_handle *handle, |
| 3399 | struct perf_event *event) | 3401 | struct perf_event *event, |
| 3402 | u64 enabled, u64 running) | ||
| 3400 | { | 3403 | { |
| 3401 | u64 read_format = event->attr.read_format; | 3404 | u64 read_format = event->attr.read_format; |
| 3402 | u64 values[4]; | 3405 | u64 values[4]; |
| @@ -3404,11 +3407,11 @@ static void perf_output_read_one(struct perf_output_handle *handle, | |||
| 3404 | 3407 | ||
| 3405 | values[n++] = perf_event_count(event); | 3408 | values[n++] = perf_event_count(event); |
| 3406 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { | 3409 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { |
| 3407 | values[n++] = event->total_time_enabled + | 3410 | values[n++] = enabled + |
| 3408 | atomic64_read(&event->child_total_time_enabled); | 3411 | atomic64_read(&event->child_total_time_enabled); |
| 3409 | } | 3412 | } |
| 3410 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { | 3413 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { |
| 3411 | values[n++] = event->total_time_running + | 3414 | values[n++] = running + |
| 3412 | atomic64_read(&event->child_total_time_running); | 3415 | atomic64_read(&event->child_total_time_running); |
| 3413 | } | 3416 | } |
| 3414 | if (read_format & PERF_FORMAT_ID) | 3417 | if (read_format & PERF_FORMAT_ID) |
| @@ -3421,7 +3424,8 @@ static void perf_output_read_one(struct perf_output_handle *handle, | |||
| 3421 | * XXX PERF_FORMAT_GROUP vs inherited events seems difficult. | 3424 | * XXX PERF_FORMAT_GROUP vs inherited events seems difficult. |
| 3422 | */ | 3425 | */ |
| 3423 | static void perf_output_read_group(struct perf_output_handle *handle, | 3426 | static void perf_output_read_group(struct perf_output_handle *handle, |
| 3424 | struct perf_event *event) | 3427 | struct perf_event *event, |
| 3428 | u64 enabled, u64 running) | ||
| 3425 | { | 3429 | { |
| 3426 | struct perf_event *leader = event->group_leader, *sub; | 3430 | struct perf_event *leader = event->group_leader, *sub; |
| 3427 | u64 read_format = event->attr.read_format; | 3431 | u64 read_format = event->attr.read_format; |
| @@ -3431,10 +3435,10 @@ static void perf_output_read_group(struct perf_output_handle *handle, | |||
| 3431 | values[n++] = 1 + leader->nr_siblings; | 3435 | values[n++] = 1 + leader->nr_siblings; |
| 3432 | 3436 | ||
| 3433 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) | 3437 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) |
| 3434 | values[n++] = leader->total_time_enabled; | 3438 | values[n++] = enabled; |
| 3435 | 3439 | ||
| 3436 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) | 3440 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) |
| 3437 | values[n++] = leader->total_time_running; | 3441 | values[n++] = running; |
| 3438 | 3442 | ||
| 3439 | if (leader != event) | 3443 | if (leader != event) |
| 3440 | leader->pmu->read(leader); | 3444 | leader->pmu->read(leader); |
| @@ -3459,13 +3463,35 @@ static void perf_output_read_group(struct perf_output_handle *handle, | |||
| 3459 | } | 3463 | } |
| 3460 | } | 3464 | } |
| 3461 | 3465 | ||
| 3466 | #define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\ | ||
| 3467 | PERF_FORMAT_TOTAL_TIME_RUNNING) | ||
| 3468 | |||
| 3462 | static void perf_output_read(struct perf_output_handle *handle, | 3469 | static void perf_output_read(struct perf_output_handle *handle, |
| 3463 | struct perf_event *event) | 3470 | struct perf_event *event) |
| 3464 | { | 3471 | { |
| 3472 | u64 enabled = 0, running = 0, now, ctx_time; | ||
| 3473 | u64 read_format = event->attr.read_format; | ||
| 3474 | |||
| 3475 | /* | ||
| 3476 | * compute total_time_enabled, total_time_running | ||
| 3477 | * based on snapshot values taken when the event | ||
| 3478 | * was last scheduled in. | ||
| 3479 | * | ||
| 3480 | * we cannot simply called update_context_time() | ||
| 3481 | * because of locking issue as we are called in | ||
| 3482 | * NMI context | ||
| 3483 | */ | ||
| 3484 | if (read_format & PERF_FORMAT_TOTAL_TIMES) { | ||
| 3485 | now = perf_clock(); | ||
| 3486 | ctx_time = event->shadow_ctx_time + now; | ||
| 3487 | enabled = ctx_time - event->tstamp_enabled; | ||
| 3488 | running = ctx_time - event->tstamp_running; | ||
| 3489 | } | ||
| 3490 | |||
| 3465 | if (event->attr.read_format & PERF_FORMAT_GROUP) | 3491 | if (event->attr.read_format & PERF_FORMAT_GROUP) |
| 3466 | perf_output_read_group(handle, event); | 3492 | perf_output_read_group(handle, event, enabled, running); |
| 3467 | else | 3493 | else |
| 3468 | perf_output_read_one(handle, event); | 3494 | perf_output_read_one(handle, event, enabled, running); |
| 3469 | } | 3495 | } |
| 3470 | 3496 | ||
| 3471 | void perf_output_sample(struct perf_output_handle *handle, | 3497 | void perf_output_sample(struct perf_output_handle *handle, |
