Skip to content

Commit 49de049

Browse files
KAGA-KOKOIngo Molnar
authored andcommitted
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 <[email protected]> [ Added event->cpu < 0 test to not explode] Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Kan Liang <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Vince Weaver <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 4b6e257 commit 49de049

File tree

1 file changed

+53
-69
lines changed

1 file changed

+53
-69
lines changed

arch/x86/events/intel/cstate.c

Lines changed: 53 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ static ssize_t cstate_get_attr_cpumask(struct device *dev,
385385
static int cstate_pmu_event_init(struct perf_event *event)
386386
{
387387
u64 cfg = event->attr.config;
388-
int ret = 0;
388+
int cpu;
389389

390390
if (event->attr.type != event->pmu->type)
391391
return -ENOENT;
@@ -400,26 +400,36 @@ static int cstate_pmu_event_init(struct perf_event *event)
400400
event->attr.sample_period) /* no sampling */
401401
return -EINVAL;
402402

403+
if (event->cpu < 0)
404+
return -EINVAL;
405+
403406
if (event->pmu == &cstate_core_pmu) {
404407
if (cfg >= PERF_CSTATE_CORE_EVENT_MAX)
405408
return -EINVAL;
406409
if (!core_msr[cfg].attr)
407410
return -EINVAL;
408411
event->hw.event_base = core_msr[cfg].msr;
412+
cpu = cpumask_any_and(&cstate_core_cpu_mask,
413+
topology_sibling_cpumask(event->cpu));
409414
} else if (event->pmu == &cstate_pkg_pmu) {
410415
if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
411416
return -EINVAL;
412417
if (!pkg_msr[cfg].attr)
413418
return -EINVAL;
414419
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 {
416423
return -ENOENT;
424+
}
417425

418-
/* must be done before validate_group */
426+
if (cpu >= nr_cpu_ids)
427+
return -ENODEV;
428+
429+
event->cpu = cpu;
419430
event->hw.config = cfg;
420431
event->hw.idx = -1;
421-
422-
return ret;
432+
return 0;
423433
}
424434

425435
static 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)
469479
return 0;
470480
}
471481

482+
/*
483+
* Check if exiting cpu is the designated reader. If so migrate the
484+
* events when there is a valid target available
485+
*/
472486
static void cstate_cpu_exit(int cpu)
473487
{
474-
int i, id, target;
488+
unsigned int target;
475489

476-
/* cpu exit for cstate core */
477-
if (has_cstate_core) {
478-
id = topology_core_id(cpu);
479-
target = -1;
480-
481-
for_each_online_cpu(i) {
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+
if (has_cstate_core &&
491+
cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask)) {
492+
493+
target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
494+
/* Migrate events if there is a valid target */
495+
if (target < nr_cpu_ids) {
490496
cpumask_set_cpu(target, &cstate_core_cpu_mask);
491-
WARN_ON(cpumask_empty(&cstate_core_cpu_mask));
492-
if (target >= 0)
493497
perf_pmu_migrate_context(&cstate_core_pmu, cpu, target);
498+
}
494499
}
495500

496-
/* cpu exit for cstate pkg */
497-
if (has_cstate_pkg) {
498-
id = topology_physical_package_id(cpu);
499-
target = -1;
500-
501-
for_each_online_cpu(i) {
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)
501+
if (has_cstate_pkg &&
502+
cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask)) {
503+
504+
target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
505+
/* Migrate events if there is a valid target */
506+
if (target < nr_cpu_ids) {
510507
cpumask_set_cpu(target, &cstate_pkg_cpu_mask);
511-
WARN_ON(cpumask_empty(&cstate_pkg_cpu_mask));
512-
if (target >= 0)
513508
perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target);
509+
}
514510
}
515511
}
516512

517513
static void cstate_cpu_init(int cpu)
518514
{
519-
int i, id;
515+
unsigned int target;
520516

521-
/* cpu init for cstate core */
522-
if (has_cstate_core) {
523-
id = topology_core_id(cpu);
524-
for_each_cpu(i, &cstate_core_cpu_mask) {
525-
if (id == topology_core_id(i))
526-
break;
527-
}
528-
if (i >= nr_cpu_ids)
529-
cpumask_set_cpu(cpu, &cstate_core_cpu_mask);
530-
}
517+
/*
518+
* If this is the first online thread of that core, set it in
519+
* the core cpu mask as the designated reader.
520+
*/
521+
target = cpumask_any_and(&cstate_core_cpu_mask,
522+
topology_sibling_cpumask(cpu));
531523

532-
/* cpu init for cstate pkg */
533-
if (has_cstate_pkg) {
534-
id = topology_physical_package_id(cpu);
535-
for_each_cpu(i, &cstate_pkg_cpu_mask) {
536-
if (id == topology_physical_package_id(i))
537-
break;
538-
}
539-
if (i >= nr_cpu_ids)
540-
cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
541-
}
524+
if (has_cstate_core && target >= nr_cpu_ids)
525+
cpumask_set_cpu(cpu, &cstate_core_cpu_mask);
526+
527+
/*
528+
* If this is the first online thread of that package, set it
529+
* in the package cpu mask as the designated reader.
530+
*/
531+
target = cpumask_any_and(&cstate_pkg_cpu_mask,
532+
topology_core_cpumask(cpu));
533+
if (has_cstate_pkg && target >= nr_cpu_ids)
534+
cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
542535
}
543536

544537
static int cstate_cpu_notifier(struct notifier_block *self,
545-
unsigned long action, void *hcpu)
538+
unsigned long action, void *hcpu)
546539
{
547540
unsigned int cpu = (long)hcpu;
548541

549542
switch (action & ~CPU_TASKS_FROZEN) {
550-
case CPU_UP_PREPARE:
551-
break;
552543
case CPU_STARTING:
553544
cstate_cpu_init(cpu);
554545
break;
555-
case CPU_UP_CANCELED:
556-
case CPU_DYING:
557-
break;
558-
case CPU_ONLINE:
559-
case CPU_DEAD:
560-
break;
561546
case CPU_DOWN_PREPARE:
562547
cstate_cpu_exit(cpu);
563548
break;
564549
default:
565550
break;
566551
}
567-
568552
return NOTIFY_OK;
569553
}
570554

0 commit comments

Comments
 (0)