aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/dumpstack_64.c2
-rw-r--r--include/linux/perf_event.h1
-rw-r--r--kernel/events/core.c104
-rw-r--r--tools/perf/builtin-top.c13
4 files changed, 78 insertions, 42 deletions
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 6d728d9284bd..af7785ff5aa0 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -129,7 +129,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
129 if (!stack) { 129 if (!stack) {
130 if (regs) 130 if (regs)
131 stack = (unsigned long *)regs->sp; 131 stack = (unsigned long *)regs->sp;
132 else if (task && task != current) 132 else if (task != current)
133 stack = (unsigned long *)task->thread.sp; 133 stack = (unsigned long *)task->thread.sp;
134 else 134 else
135 stack = &dummy; 135 stack = &dummy;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 0b91db2522cc..412b790f5da6 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -589,6 +589,7 @@ struct hw_perf_event {
589 u64 sample_period; 589 u64 sample_period;
590 u64 last_period; 590 u64 last_period;
591 local64_t period_left; 591 local64_t period_left;
592 u64 interrupts_seq;
592 u64 interrupts; 593 u64 interrupts;
593 594
594 u64 freq_time_stamp; 595 u64 freq_time_stamp;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index de859fb4038f..7c3b9de55f6b 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2300,6 +2300,9 @@ do { \
2300 return div64_u64(dividend, divisor); 2300 return div64_u64(dividend, divisor);
2301} 2301}
2302 2302
2303static DEFINE_PER_CPU(int, perf_throttled_count);
2304static DEFINE_PER_CPU(u64, perf_throttled_seq);
2305
2303static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count) 2306static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count)
2304{ 2307{
2305 struct hw_perf_event *hwc = &event->hw; 2308 struct hw_perf_event *hwc = &event->hw;
@@ -2325,16 +2328,29 @@ static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count)
2325 } 2328 }
2326} 2329}
2327 2330
2328static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) 2331/*
2332 * combine freq adjustment with unthrottling to avoid two passes over the
2333 * events. At the same time, make sure, having freq events does not change
2334 * the rate of unthrottling as that would introduce bias.
2335 */
2336static void perf_adjust_freq_unthr_context(struct perf_event_context *ctx,
2337 int needs_unthr)
2329{ 2338{
2330 struct perf_event *event; 2339 struct perf_event *event;
2331 struct hw_perf_event *hwc; 2340 struct hw_perf_event *hwc;
2332 u64 interrupts, now; 2341 u64 now, period = TICK_NSEC;
2333 s64 delta; 2342 s64 delta;
2334 2343
2335 if (!ctx->nr_freq) 2344 /*
2345 * only need to iterate over all events iff:
2346 * - context have events in frequency mode (needs freq adjust)
2347 * - there are events to unthrottle on this cpu
2348 */
2349 if (!(ctx->nr_freq || needs_unthr))
2336 return; 2350 return;
2337 2351
2352 raw_spin_lock(&ctx->lock);
2353
2338 list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { 2354 list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
2339 if (event->state != PERF_EVENT_STATE_ACTIVE) 2355 if (event->state != PERF_EVENT_STATE_ACTIVE)
2340 continue; 2356 continue;
@@ -2344,13 +2360,8 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period)
2344 2360
2345 hwc = &event->hw; 2361 hwc = &event->hw;
2346 2362
2347 interrupts = hwc->interrupts; 2363 if (needs_unthr && hwc->interrupts == MAX_INTERRUPTS) {
2348 hwc->interrupts = 0; 2364 hwc->interrupts = 0;
2349
2350 /*
2351 * unthrottle events on the tick
2352 */
2353 if (interrupts == MAX_INTERRUPTS) {
2354 perf_log_throttle(event, 1); 2365 perf_log_throttle(event, 1);
2355 event->pmu->start(event, 0); 2366 event->pmu->start(event, 0);
2356 } 2367 }
@@ -2358,14 +2369,26 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period)
2358 if (!event->attr.freq || !event->attr.sample_freq) 2369 if (!event->attr.freq || !event->attr.sample_freq)
2359 continue; 2370 continue;
2360 2371
2361 event->pmu->read(event); 2372 /*
2373 * stop the event and update event->count
2374 */
2375 event->pmu->stop(event, PERF_EF_UPDATE);
2376
2362 now = local64_read(&event->count); 2377 now = local64_read(&event->count);
2363 delta = now - hwc->freq_count_stamp; 2378 delta = now - hwc->freq_count_stamp;
2364 hwc->freq_count_stamp = now; 2379 hwc->freq_count_stamp = now;
2365 2380
2381 /*
2382 * restart the event
2383 * reload only if value has changed
2384 */
2366 if (delta > 0) 2385 if (delta > 0)
2367 perf_adjust_period(event, period, delta); 2386 perf_adjust_period(event, period, delta);
2387
2388 event->pmu->start(event, delta > 0 ? PERF_EF_RELOAD : 0);
2368 } 2389 }
2390
2391 raw_spin_unlock(&ctx->lock);
2369} 2392}
2370 2393
2371/* 2394/*
@@ -2388,16 +2411,13 @@ static void rotate_ctx(struct perf_event_context *ctx)
2388 */ 2411 */
2389static void perf_rotate_context(struct perf_cpu_context *cpuctx) 2412static void perf_rotate_context(struct perf_cpu_context *cpuctx)
2390{ 2413{
2391 u64 interval = (u64)cpuctx->jiffies_interval * TICK_NSEC;
2392 struct perf_event_context *ctx = NULL; 2414 struct perf_event_context *ctx = NULL;
2393 int rotate = 0, remove = 1, freq = 0; 2415 int rotate = 0, remove = 1;
2394 2416
2395 if (cpuctx->ctx.nr_events) { 2417 if (cpuctx->ctx.nr_events) {
2396 remove = 0; 2418 remove = 0;
2397 if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active) 2419 if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active)
2398 rotate = 1; 2420 rotate = 1;
2399 if (cpuctx->ctx.nr_freq)
2400 freq = 1;
2401 } 2421 }
2402 2422
2403 ctx = cpuctx->task_ctx; 2423 ctx = cpuctx->task_ctx;
@@ -2405,37 +2425,26 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx)
2405 remove = 0; 2425 remove = 0;
2406 if (ctx->nr_events != ctx->nr_active) 2426 if (ctx->nr_events != ctx->nr_active)
2407 rotate = 1; 2427 rotate = 1;
2408 if (ctx->nr_freq)
2409 freq = 1;
2410 } 2428 }
2411 2429
2412 if (!rotate && !freq) 2430 if (!rotate)
2413 goto done; 2431 goto done;
2414 2432
2415 perf_ctx_lock(cpuctx, cpuctx->task_ctx); 2433 perf_ctx_lock(cpuctx, cpuctx->task_ctx);
2416 perf_pmu_disable(cpuctx->ctx.pmu); 2434 perf_pmu_disable(cpuctx->ctx.pmu);
2417 2435
2418 if (freq) { 2436 cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
2419 perf_ctx_adjust_freq(&cpuctx->ctx, interval); 2437 if (ctx)
2420 if (ctx) 2438 ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE);
2421 perf_ctx_adjust_freq(ctx, interval);
2422 }
2423
2424 if (rotate) {
2425 cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
2426 if (ctx)
2427 ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE);
2428 2439
2429 rotate_ctx(&cpuctx->ctx); 2440 rotate_ctx(&cpuctx->ctx);
2430 if (ctx) 2441 if (ctx)
2431 rotate_ctx(ctx); 2442 rotate_ctx(ctx);
2432 2443
2433 perf_event_sched_in(cpuctx, ctx, current); 2444 perf_event_sched_in(cpuctx, ctx, current);
2434 }
2435 2445
2436 perf_pmu_enable(cpuctx->ctx.pmu); 2446 perf_pmu_enable(cpuctx->ctx.pmu);
2437 perf_ctx_unlock(cpuctx, cpuctx->task_ctx); 2447 perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
2438
2439done: 2448done:
2440 if (remove) 2449 if (remove)
2441 list_del_init(&cpuctx->rotation_list); 2450 list_del_init(&cpuctx->rotation_list);
@@ -2445,10 +2454,22 @@ void perf_event_task_tick(void)
2445{ 2454{
2446 struct list_head *head = &__get_cpu_var(rotation_list); 2455 struct list_head *head = &__get_cpu_var(rotation_list);
2447 struct perf_cpu_context *cpuctx, *tmp; 2456 struct perf_cpu_context *cpuctx, *tmp;
2457 struct perf_event_context *ctx;
2458 int throttled;
2448 2459
2449 WARN_ON(!irqs_disabled()); 2460 WARN_ON(!irqs_disabled());
2450 2461
2462 __this_cpu_inc(perf_throttled_seq);
2463 throttled = __this_cpu_xchg(perf_throttled_count, 0);
2464
2451 list_for_each_entry_safe(cpuctx, tmp, head, rotation_list) { 2465 list_for_each_entry_safe(cpuctx, tmp, head, rotation_list) {
2466 ctx = &cpuctx->ctx;
2467 perf_adjust_freq_unthr_context(ctx, throttled);
2468
2469 ctx = cpuctx->task_ctx;
2470 if (ctx)
2471 perf_adjust_freq_unthr_context(ctx, throttled);
2472
2452 if (cpuctx->jiffies_interval == 1 || 2473 if (cpuctx->jiffies_interval == 1 ||
2453 !(jiffies % cpuctx->jiffies_interval)) 2474 !(jiffies % cpuctx->jiffies_interval))
2454 perf_rotate_context(cpuctx); 2475 perf_rotate_context(cpuctx);
@@ -4514,6 +4535,7 @@ static int __perf_event_overflow(struct perf_event *event,
4514{ 4535{
4515 int events = atomic_read(&event->event_limit); 4536 int events = atomic_read(&event->event_limit);
4516 struct hw_perf_event *hwc = &event->hw; 4537 struct hw_perf_event *hwc = &event->hw;
4538 u64 seq;
4517 int ret = 0; 4539 int ret = 0;
4518 4540
4519 /* 4541 /*
@@ -4523,14 +4545,20 @@ static int __perf_event_overflow(struct perf_event *event,
4523 if (unlikely(!is_sampling_event(event))) 4545 if (unlikely(!is_sampling_event(event)))
4524 return 0; 4546 return 0;
4525 4547
4526 if (unlikely(hwc->interrupts >= max_samples_per_tick)) { 4548 seq = __this_cpu_read(perf_throttled_seq);
4527 if (throttle) { 4549 if (seq != hwc->interrupts_seq) {
4550 hwc->interrupts_seq = seq;
4551 hwc->interrupts = 1;
4552 } else {
4553 hwc->interrupts++;
4554 if (unlikely(throttle
4555 && hwc->interrupts >= max_samples_per_tick)) {
4556 __this_cpu_inc(perf_throttled_count);
4528 hwc->interrupts = MAX_INTERRUPTS; 4557 hwc->interrupts = MAX_INTERRUPTS;
4529 perf_log_throttle(event, 0); 4558 perf_log_throttle(event, 0);
4530 ret = 1; 4559 ret = 1;
4531 } 4560 }
4532 } else 4561 }
4533 hwc->interrupts++;
4534 4562
4535 if (event->attr.freq) { 4563 if (event->attr.freq) {
4536 u64 now = perf_clock(); 4564 u64 now = perf_clock();
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e8b033c074f9..d869b214ada2 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -88,8 +88,6 @@ void get_term_dimensions(struct winsize *ws)
88 88
89static void perf_top__update_print_entries(struct perf_top *top) 89static void perf_top__update_print_entries(struct perf_top *top)
90{ 90{
91 top->print_entries = top->winsize.ws_row;
92
93 if (top->print_entries > 9) 91 if (top->print_entries > 9)
94 top->print_entries -= 9; 92 top->print_entries -= 9;
95} 93}
@@ -99,6 +97,13 @@ static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *ar
99 struct perf_top *top = arg; 97 struct perf_top *top = arg;
100 98
101 get_term_dimensions(&top->winsize); 99 get_term_dimensions(&top->winsize);
100 if (!top->print_entries
101 || (top->print_entries+4) > top->winsize.ws_row) {
102 top->print_entries = top->winsize.ws_row;
103 } else {
104 top->print_entries += 4;
105 top->winsize.ws_row = top->print_entries;
106 }
102 perf_top__update_print_entries(top); 107 perf_top__update_print_entries(top);
103} 108}
104 109
@@ -452,8 +457,10 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
452 }; 457 };
453 perf_top__sig_winch(SIGWINCH, NULL, top); 458 perf_top__sig_winch(SIGWINCH, NULL, top);
454 sigaction(SIGWINCH, &act, NULL); 459 sigaction(SIGWINCH, &act, NULL);
455 } else 460 } else {
461 perf_top__sig_winch(SIGWINCH, NULL, top);
456 signal(SIGWINCH, SIG_DFL); 462 signal(SIGWINCH, SIG_DFL);
463 }
457 break; 464 break;
458 case 'E': 465 case 'E':
459 if (top->evlist->nr_entries > 1) { 466 if (top->evlist->nr_entries > 1) {