aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2016-03-20 14:59:02 -0400
committerIngo Molnar <mingo@kernel.org>2016-03-31 04:30:36 -0400
commit49de0493e5f67a8023fa6fa5c89097c1f77de74e (patch)
tree28d03554fd4a8629da2156e52790c2d6b05158a6
parent4b6e2571bf00019e016255ad62b56feb9f498db7 (diff)
x86/perf/intel/cstate: Make cstate hotplug handling actually work
The current implementation aside of being an incomprehensible mess is broken. # cat /sys/bus/event_source/devices/cstate_core/cpumask 0-17 That's on a quad socket machine with 72 physical cores! Qualitee stuff. So it's not a surprise that event migration in case of CPU hotplug does not work either. # perf stat -e cstate_core/c6-residency/ -C 1 sleep 60 & # echo 0 >/sys/devices/system/cpu/cpu1/online Tracing cstate_pmu_event_update gives me: [001] cstate_pmu_event_update <-event_sched_out After the fix it properly moves the event: [001] cstate_pmu_event_update <-event_sched_out [073] cstate_pmu_event_update <-__perf_event_read [073] cstate_pmu_event_update <-event_sched_out The migration of pkg events does not work either. Not that I'm surprised. I really could not be bothered to decode that loop mess and simply replaced it by querying the proper cpumasks which give us the answer in a comprehensible way. This also requires to direct the event to the current active reader CPU in cstate_pmu_event_init() otherwise the hotplug logic can't work. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> [ Added event->cpu < 0 test to not explode] Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Borislav Petkov <bp@suse.de> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Kan Liang <kan.liang@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Vince Weaver <vincent.weaver@maine.edu> Link: http://lkml.kernel.org/r/20160320185623.422519970@linutronix.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/events/intel/cstate.c122
1 files changed, 53 insertions, 69 deletions
diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c
index 7946c4231169..5c2f55fe142a 100644
--- a/arch/x86/events/intel/cstate.c
+++ b/arch/x86/events/intel/cstate.c
@@ -385,7 +385,7 @@ static ssize_t cstate_get_attr_cpumask(struct device *dev,
385static int cstate_pmu_event_init(struct perf_event *event) 385static int cstate_pmu_event_init(struct perf_event *event)
386{ 386{
387 u64 cfg = event->attr.config; 387 u64 cfg = event->attr.config;
388 int ret = 0; 388 int cpu;
389 389
390 if (event->attr.type != event->pmu->type) 390 if (event->attr.type != event->pmu->type)
391 return -ENOENT; 391 return -ENOENT;
@@ -400,26 +400,36 @@ static int cstate_pmu_event_init(struct perf_event *event)
400 event->attr.sample_period) /* no sampling */ 400 event->attr.sample_period) /* no sampling */
401 return -EINVAL; 401 return -EINVAL;
402 402
403 if (event->cpu < 0)
404 return -EINVAL;
405
403 if (event->pmu == &cstate_core_pmu) { 406 if (event->pmu == &cstate_core_pmu) {
404 if (cfg >= PERF_CSTATE_CORE_EVENT_MAX) 407 if (cfg >= PERF_CSTATE_CORE_EVENT_MAX)
405 return -EINVAL; 408 return -EINVAL;
406 if (!core_msr[cfg].attr) 409 if (!core_msr[cfg].attr)
407 return -EINVAL; 410 return -EINVAL;
408 event->hw.event_base = core_msr[cfg].msr; 411 event->hw.event_base = core_msr[cfg].msr;
412 cpu = cpumask_any_and(&cstate_core_cpu_mask,
413 topology_sibling_cpumask(event->cpu));
409 } else if (event->pmu == &cstate_pkg_pmu) { 414 } else if (event->pmu == &cstate_pkg_pmu) {
410 if (cfg >= PERF_CSTATE_PKG_EVENT_MAX) 415 if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
411 return -EINVAL; 416 return -EINVAL;
412 if (!pkg_msr[cfg].attr) 417 if (!pkg_msr[cfg].attr)
413 return -EINVAL; 418 return -EINVAL;
414 event->hw.event_base = pkg_msr[cfg].msr; 419 event->hw.event_base = pkg_msr[cfg].msr;
415 } else 420 cpu = cpumask_any_and(&cstate_pkg_cpu_mask,
421 topology_core_cpumask(event->cpu));
422 } else {
416 return -ENOENT; 423 return -ENOENT;
424 }
417 425
418 /* must be done before validate_group */ 426 if (cpu >= nr_cpu_ids)
427 return -ENODEV;
428
429 event->cpu = cpu;
419 event->hw.config = cfg; 430 event->hw.config = cfg;
420 event->hw.idx = -1; 431 event->hw.idx = -1;
421 432 return 0;
422 return ret;
423} 433}
424 434
425static inline u64 cstate_pmu_read_counter(struct perf_event *event) 435static inline u64 cstate_pmu_read_counter(struct perf_event *event)
@@ -469,102 +479,76 @@ static int cstate_pmu_event_add(struct perf_event *event, int mode)
469 return 0; 479 return 0;
470} 480}
471 481
482/*
483 * Check if exiting cpu is the designated reader. If so migrate the
484 * events when there is a valid target available
485 */
472static void cstate_cpu_exit(int cpu) 486static void cstate_cpu_exit(int cpu)
473{ 487{
474 int i, id, target; 488 unsigned int target;
475 489
476 /* cpu exit for cstate core */ 490 if (has_cstate_core &&
477 if (has_cstate_core) { 491 cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask)) {
478 id = topology_core_id(cpu); 492
479 target = -1; 493 target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
480 494 /* Migrate events if there is a valid target */
481 for_each_online_cpu(i) { 495 if (target < nr_cpu_ids) {
482 if (i == cpu)
483 continue;
484 if (id == topology_core_id(i)) {
485 target = i;
486 break;
487 }
488 }
489 if (cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask) && target >= 0)
490 cpumask_set_cpu(target, &cstate_core_cpu_mask); 496 cpumask_set_cpu(target, &cstate_core_cpu_mask);
491 WARN_ON(cpumask_empty(&cstate_core_cpu_mask));
492 if (target >= 0)
493 perf_pmu_migrate_context(&cstate_core_pmu, cpu, target); 497 perf_pmu_migrate_context(&cstate_core_pmu, cpu, target);
498 }
494 } 499 }
495 500
496 /* cpu exit for cstate pkg */ 501 if (has_cstate_pkg &&
497 if (has_cstate_pkg) { 502 cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask)) {
498 id = topology_physical_package_id(cpu); 503
499 target = -1; 504 target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
500 505 /* Migrate events if there is a valid target */
501 for_each_online_cpu(i) { 506 if (target < nr_cpu_ids) {
502 if (i == cpu)
503 continue;
504 if (id == topology_physical_package_id(i)) {
505 target = i;
506 break;
507 }
508 }
509 if (cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask) && target >= 0)
510 cpumask_set_cpu(target, &cstate_pkg_cpu_mask); 507 cpumask_set_cpu(target, &cstate_pkg_cpu_mask);
511 WARN_ON(cpumask_empty(&cstate_pkg_cpu_mask));
512 if (target >= 0)
513 perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target); 508 perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target);
509 }
514 } 510 }
515} 511}
516 512
517static void cstate_cpu_init(int cpu) 513static void cstate_cpu_init(int cpu)
518{ 514{
519 int i, id; 515 unsigned int target;
520 516
521 /* cpu init for cstate core */ 517 /*
522 if (has_cstate_core) { 518 * If this is the first online thread of that core, set it in
523 id = topology_core_id(cpu); 519 * the core cpu mask as the designated reader.
524 for_each_cpu(i, &cstate_core_cpu_mask) { 520 */
525 if (id == topology_core_id(i)) 521 target = cpumask_any_and(&cstate_core_cpu_mask,
526 break; 522 topology_sibling_cpumask(cpu));
527 }
528 if (i >= nr_cpu_ids)
529 cpumask_set_cpu(cpu, &cstate_core_cpu_mask);
530 }
531 523
532 /* cpu init for cstate pkg */ 524 if (has_cstate_core && target >= nr_cpu_ids)
533 if (has_cstate_pkg) { 525 cpumask_set_cpu(cpu, &cstate_core_cpu_mask);
534 id = topology_physical_package_id(cpu); 526
535 for_each_cpu(i, &cstate_pkg_cpu_mask) { 527 /*
536 if (id == topology_physical_package_id(i)) 528 * If this is the first online thread of that package, set it
537 break; 529 * in the package cpu mask as the designated reader.
538 } 530 */
539 if (i >= nr_cpu_ids) 531 target = cpumask_any_and(&cstate_pkg_cpu_mask,
540 cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask); 532 topology_core_cpumask(cpu));
541 } 533 if (has_cstate_pkg && target >= nr_cpu_ids)
534 cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
542} 535}
543 536
544static int cstate_cpu_notifier(struct notifier_block *self, 537static int cstate_cpu_notifier(struct notifier_block *self,
545 unsigned long action, void *hcpu) 538 unsigned long action, void *hcpu)
546{ 539{
547 unsigned int cpu = (long)hcpu; 540 unsigned int cpu = (long)hcpu;
548 541
549 switch (action & ~CPU_TASKS_FROZEN) { 542 switch (action & ~CPU_TASKS_FROZEN) {
550 case CPU_UP_PREPARE:
551 break;
552 case CPU_STARTING: 543 case CPU_STARTING:
553 cstate_cpu_init(cpu); 544 cstate_cpu_init(cpu);
554 break; 545 break;
555 case CPU_UP_CANCELED:
556 case CPU_DYING:
557 break;
558 case CPU_ONLINE:
559 case CPU_DEAD:
560 break;
561 case CPU_DOWN_PREPARE: 546 case CPU_DOWN_PREPARE:
562 cstate_cpu_exit(cpu); 547 cstate_cpu_exit(cpu);
563 break; 548 break;
564 default: 549 default:
565 break; 550 break;
566 } 551 }
567
568 return NOTIFY_OK; 552 return NOTIFY_OK;
569} 553}
570 554