aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/perf_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/cpu/perf_event.c')
-rw-r--r--arch/x86/kernel/cpu/perf_event.c83
1 files changed, 62 insertions, 21 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 87848ebe2bb7..4f7001f28936 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -190,6 +190,7 @@ static bool check_hw_exists(void)
190 u64 val, val_fail, val_new= ~0; 190 u64 val, val_fail, val_new= ~0;
191 int i, reg, reg_fail, ret = 0; 191 int i, reg, reg_fail, ret = 0;
192 int bios_fail = 0; 192 int bios_fail = 0;
193 int reg_safe = -1;
193 194
194 /* 195 /*
195 * Check to see if the BIOS enabled any of the counters, if so 196 * Check to see if the BIOS enabled any of the counters, if so
@@ -204,6 +205,8 @@ static bool check_hw_exists(void)
204 bios_fail = 1; 205 bios_fail = 1;
205 val_fail = val; 206 val_fail = val;
206 reg_fail = reg; 207 reg_fail = reg;
208 } else {
209 reg_safe = i;
207 } 210 }
208 } 211 }
209 212
@@ -222,11 +225,22 @@ static bool check_hw_exists(void)
222 } 225 }
223 226
224 /* 227 /*
228 * If all the counters are enabled, the below test will always
229 * fail. The tools will also become useless in this scenario.
230 * Just fail and disable the hardware counters.
231 */
232
233 if (reg_safe == -1) {
234 reg = reg_safe;
235 goto msr_fail;
236 }
237
238 /*
225 * Read the current value, change it and read it back to see if it 239 * Read the current value, change it and read it back to see if it
226 * matches, this is needed to detect certain hardware emulators 240 * matches, this is needed to detect certain hardware emulators
227 * (qemu/kvm) that don't trap on the MSR access and always return 0s. 241 * (qemu/kvm) that don't trap on the MSR access and always return 0s.
228 */ 242 */
229 reg = x86_pmu_event_addr(0); 243 reg = x86_pmu_event_addr(reg_safe);
230 if (rdmsrl_safe(reg, &val)) 244 if (rdmsrl_safe(reg, &val))
231 goto msr_fail; 245 goto msr_fail;
232 val ^= 0xffffUL; 246 val ^= 0xffffUL;
@@ -611,6 +625,7 @@ struct sched_state {
611 int event; /* event index */ 625 int event; /* event index */
612 int counter; /* counter index */ 626 int counter; /* counter index */
613 int unassigned; /* number of events to be assigned left */ 627 int unassigned; /* number of events to be assigned left */
628 int nr_gp; /* number of GP counters used */
614 unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; 629 unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
615}; 630};
616 631
@@ -620,27 +635,29 @@ struct sched_state {
620struct perf_sched { 635struct perf_sched {
621 int max_weight; 636 int max_weight;
622 int max_events; 637 int max_events;
623 struct perf_event **events; 638 int max_gp;
624 struct sched_state state;
625 int saved_states; 639 int saved_states;
640 struct event_constraint **constraints;
641 struct sched_state state;
626 struct sched_state saved[SCHED_STATES_MAX]; 642 struct sched_state saved[SCHED_STATES_MAX];
627}; 643};
628 644
629/* 645/*
630 * Initialize interator that runs through all events and counters. 646 * Initialize interator that runs through all events and counters.
631 */ 647 */
632static void perf_sched_init(struct perf_sched *sched, struct perf_event **events, 648static void perf_sched_init(struct perf_sched *sched, struct event_constraint **constraints,
633 int num, int wmin, int wmax) 649 int num, int wmin, int wmax, int gpmax)
634{ 650{
635 int idx; 651 int idx;
636 652
637 memset(sched, 0, sizeof(*sched)); 653 memset(sched, 0, sizeof(*sched));
638 sched->max_events = num; 654 sched->max_events = num;
639 sched->max_weight = wmax; 655 sched->max_weight = wmax;
640 sched->events = events; 656 sched->max_gp = gpmax;
657 sched->constraints = constraints;
641 658
642 for (idx = 0; idx < num; idx++) { 659 for (idx = 0; idx < num; idx++) {
643 if (events[idx]->hw.constraint->weight == wmin) 660 if (constraints[idx]->weight == wmin)
644 break; 661 break;
645 } 662 }
646 663
@@ -687,7 +704,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
687 if (sched->state.event >= sched->max_events) 704 if (sched->state.event >= sched->max_events)
688 return false; 705 return false;
689 706
690 c = sched->events[sched->state.event]->hw.constraint; 707 c = sched->constraints[sched->state.event];
691 /* Prefer fixed purpose counters */ 708 /* Prefer fixed purpose counters */
692 if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) { 709 if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) {
693 idx = INTEL_PMC_IDX_FIXED; 710 idx = INTEL_PMC_IDX_FIXED;
@@ -696,11 +713,16 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
696 goto done; 713 goto done;
697 } 714 }
698 } 715 }
716
699 /* Grab the first unused counter starting with idx */ 717 /* Grab the first unused counter starting with idx */
700 idx = sched->state.counter; 718 idx = sched->state.counter;
701 for_each_set_bit_from(idx, c->idxmsk, INTEL_PMC_IDX_FIXED) { 719 for_each_set_bit_from(idx, c->idxmsk, INTEL_PMC_IDX_FIXED) {
702 if (!__test_and_set_bit(idx, sched->state.used)) 720 if (!__test_and_set_bit(idx, sched->state.used)) {
721 if (sched->state.nr_gp++ >= sched->max_gp)
722 return false;
723
703 goto done; 724 goto done;
725 }
704 } 726 }
705 727
706 return false; 728 return false;
@@ -745,7 +767,7 @@ static bool perf_sched_next_event(struct perf_sched *sched)
745 if (sched->state.weight > sched->max_weight) 767 if (sched->state.weight > sched->max_weight)
746 return false; 768 return false;
747 } 769 }
748 c = sched->events[sched->state.event]->hw.constraint; 770 c = sched->constraints[sched->state.event];
749 } while (c->weight != sched->state.weight); 771 } while (c->weight != sched->state.weight);
750 772
751 sched->state.counter = 0; /* start with first counter */ 773 sched->state.counter = 0; /* start with first counter */
@@ -756,12 +778,12 @@ static bool perf_sched_next_event(struct perf_sched *sched)
756/* 778/*
757 * Assign a counter for each event. 779 * Assign a counter for each event.
758 */ 780 */
759int perf_assign_events(struct perf_event **events, int n, 781int perf_assign_events(struct event_constraint **constraints, int n,
760 int wmin, int wmax, int *assign) 782 int wmin, int wmax, int gpmax, int *assign)
761{ 783{
762 struct perf_sched sched; 784 struct perf_sched sched;
763 785
764 perf_sched_init(&sched, events, n, wmin, wmax); 786 perf_sched_init(&sched, constraints, n, wmin, wmax, gpmax);
765 787
766 do { 788 do {
767 if (!perf_sched_find_counter(&sched)) 789 if (!perf_sched_find_counter(&sched))
@@ -788,9 +810,9 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
788 x86_pmu.start_scheduling(cpuc); 810 x86_pmu.start_scheduling(cpuc);
789 811
790 for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) { 812 for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) {
791 hwc = &cpuc->event_list[i]->hw; 813 cpuc->event_constraint[i] = NULL;
792 c = x86_pmu.get_event_constraints(cpuc, i, cpuc->event_list[i]); 814 c = x86_pmu.get_event_constraints(cpuc, i, cpuc->event_list[i]);
793 hwc->constraint = c; 815 cpuc->event_constraint[i] = c;
794 816
795 wmin = min(wmin, c->weight); 817 wmin = min(wmin, c->weight);
796 wmax = max(wmax, c->weight); 818 wmax = max(wmax, c->weight);
@@ -801,7 +823,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
801 */ 823 */
802 for (i = 0; i < n; i++) { 824 for (i = 0; i < n; i++) {
803 hwc = &cpuc->event_list[i]->hw; 825 hwc = &cpuc->event_list[i]->hw;
804 c = hwc->constraint; 826 c = cpuc->event_constraint[i];
805 827
806 /* never assigned */ 828 /* never assigned */
807 if (hwc->idx == -1) 829 if (hwc->idx == -1)
@@ -821,9 +843,26 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
821 } 843 }
822 844
823 /* slow path */ 845 /* slow path */
824 if (i != n) 846 if (i != n) {
825 unsched = perf_assign_events(cpuc->event_list, n, wmin, 847 int gpmax = x86_pmu.num_counters;
826 wmax, assign); 848
849 /*
850 * Do not allow scheduling of more than half the available
851 * generic counters.
852 *
853 * This helps avoid counter starvation of sibling thread by
854 * ensuring at most half the counters cannot be in exclusive
855 * mode. There is no designated counters for the limits. Any
856 * N/2 counters can be used. This helps with events with
857 * specific counter constraints.
858 */
859 if (is_ht_workaround_enabled() && !cpuc->is_fake &&
860 READ_ONCE(cpuc->excl_cntrs->exclusive_present))
861 gpmax /= 2;
862
863 unsched = perf_assign_events(cpuc->event_constraint, n, wmin,
864 wmax, gpmax, assign);
865 }
827 866
828 /* 867 /*
829 * In case of success (unsched = 0), mark events as committed, 868 * In case of success (unsched = 0), mark events as committed,
@@ -840,7 +879,7 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
840 e = cpuc->event_list[i]; 879 e = cpuc->event_list[i];
841 e->hw.flags |= PERF_X86_EVENT_COMMITTED; 880 e->hw.flags |= PERF_X86_EVENT_COMMITTED;
842 if (x86_pmu.commit_scheduling) 881 if (x86_pmu.commit_scheduling)
843 x86_pmu.commit_scheduling(cpuc, e, assign[i]); 882 x86_pmu.commit_scheduling(cpuc, i, assign[i]);
844 } 883 }
845 } 884 }
846 885
@@ -1292,8 +1331,10 @@ static void x86_pmu_del(struct perf_event *event, int flags)
1292 x86_pmu.put_event_constraints(cpuc, event); 1331 x86_pmu.put_event_constraints(cpuc, event);
1293 1332
1294 /* Delete the array entry. */ 1333 /* Delete the array entry. */
1295 while (++i < cpuc->n_events) 1334 while (++i < cpuc->n_events) {
1296 cpuc->event_list[i-1] = cpuc->event_list[i]; 1335 cpuc->event_list[i-1] = cpuc->event_list[i];
1336 cpuc->event_constraint[i-1] = cpuc->event_constraint[i];
1337 }
1297 --cpuc->n_events; 1338 --cpuc->n_events;
1298 1339
1299 perf_event_update_userpage(event); 1340 perf_event_update_userpage(event);