aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/perf_counter.c
diff options
context:
space:
mode:
authorJaswinder Singh Rajput <jaswinderrajput@gmail.com>2009-02-27 09:45:14 -0500
committerIngo Molnar <mingo@elte.hu>2009-02-28 04:38:32 -0500
commitf87ad35d37fa543925210550f7db20a54c83ed70 (patch)
tree97ceff0080ac183f9416176b558d46271a044bdc /arch/x86/kernel/cpu/perf_counter.c
parentb56a3802dc6df29aa27d2c12edf420258091ad66 (diff)
x86: AMD Support for perf_counter
Supported basic performance counter for AMD K7 and later: $ perfstat -e 0,1,2,3,4,5,-1,-2,-3,-4,-5 ls > /dev/null Performance counter stats for 'ls': 12.298610 task clock ticks (msecs) 3298477 CPU cycles (events) 1406354 instructions (events) 749035 cache references (events) 16939 cache misses (events) 100589 branches (events) 11159 branch misses (events) 7.627540 cpu clock ticks (msecs) 12.298610 task clock ticks (msecs) 500 pagefaults (events) 6 context switches (events) 3 CPU migrations (events) Wall-clock time elapsed: 8.672290 msecs Signed-off-by: Jaswinder Singh Rajput <jaswinderrajput@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/cpu/perf_counter.c')
-rw-r--r--arch/x86/kernel/cpu/perf_counter.c83
1 files changed, 81 insertions, 2 deletions
diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index a3c88529bb72..266618aa1a03 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -74,6 +74,24 @@ static int pmc_intel_event_map(int event)
74} 74}
75 75
76/* 76/*
77 * AMD Performance Monitor K7 and later.
78 */
79static const int amd_perfmon_event_map[] =
80{
81 [PERF_COUNT_CPU_CYCLES] = 0x0076,
82 [PERF_COUNT_INSTRUCTIONS] = 0x00c0,
83 [PERF_COUNT_CACHE_REFERENCES] = 0x0080,
84 [PERF_COUNT_CACHE_MISSES] = 0x0081,
85 [PERF_COUNT_BRANCH_INSTRUCTIONS] = 0x00c4,
86 [PERF_COUNT_BRANCH_MISSES] = 0x00c5,
87};
88
89static int pmc_amd_event_map(int event)
90{
91 return amd_perfmon_event_map[event];
92}
93
94/*
77 * Propagate counter elapsed time into the generic counter. 95 * Propagate counter elapsed time into the generic counter.
78 * Can only be executed on the CPU where the counter is active. 96 * Can only be executed on the CPU where the counter is active.
79 * Returns the delta events processed. 97 * Returns the delta events processed.
@@ -151,8 +169,9 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
151 * so we install an artificial 1<<31 period regardless of 169 * so we install an artificial 1<<31 period regardless of
152 * the generic counter period: 170 * the generic counter period:
153 */ 171 */
154 if ((s64)hwc->irq_period <= 0 || hwc->irq_period > 0x7FFFFFFF) 172 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
155 hwc->irq_period = 0x7FFFFFFF; 173 if ((s64)hwc->irq_period <= 0 || hwc->irq_period > 0x7FFFFFFF)
174 hwc->irq_period = 0x7FFFFFFF;
156 175
157 atomic64_set(&hwc->period_left, hwc->irq_period); 176 atomic64_set(&hwc->period_left, hwc->irq_period);
158 177
@@ -184,6 +203,22 @@ static u64 pmc_intel_save_disable_all(void)
184 return ctrl; 203 return ctrl;
185} 204}
186 205
206static u64 pmc_amd_save_disable_all(void)
207{
208 int idx;
209 u64 val, ctrl = 0;
210
211 for (idx = 0; idx < nr_counters_generic; idx++) {
212 rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
213 if (val & ARCH_PERFMON_EVENTSEL0_ENABLE)
214 ctrl |= (1 << idx);
215 val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
216 wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
217 }
218
219 return ctrl;
220}
221
187u64 hw_perf_save_disable(void) 222u64 hw_perf_save_disable(void)
188{ 223{
189 if (unlikely(!perf_counters_initialized)) 224 if (unlikely(!perf_counters_initialized))
@@ -198,6 +233,20 @@ static void pmc_intel_restore_all(u64 ctrl)
198 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl); 233 wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
199} 234}
200 235
236static void pmc_amd_restore_all(u64 ctrl)
237{
238 u64 val;
239 int idx;
240
241 for (idx = 0; idx < nr_counters_generic; idx++) {
242 if (ctrl & (1 << idx)) {
243 rdmsrl(MSR_K7_EVNTSEL0 + idx, val);
244 val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
245 wrmsrl(MSR_K7_EVNTSEL0 + idx, val);
246 }
247 }
248}
249
201void hw_perf_restore(u64 ctrl) 250void hw_perf_restore(u64 ctrl)
202{ 251{
203 if (unlikely(!perf_counters_initialized)) 252 if (unlikely(!perf_counters_initialized))
@@ -314,6 +363,9 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
314{ 363{
315 unsigned int event; 364 unsigned int event;
316 365
366 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
367 return -1;
368
317 if (unlikely(hwc->nmi)) 369 if (unlikely(hwc->nmi))
318 return -1; 370 return -1;
319 371
@@ -401,6 +453,7 @@ void perf_counter_print_debug(void)
401 cpu = smp_processor_id(); 453 cpu = smp_processor_id();
402 cpuc = &per_cpu(cpu_hw_counters, cpu); 454 cpuc = &per_cpu(cpu_hw_counters, cpu);
403 455
456 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
404 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl); 457 rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, ctrl);
405 rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status); 458 rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, status);
406 rdmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, overflow); 459 rdmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, overflow);
@@ -411,6 +464,7 @@ void perf_counter_print_debug(void)
411 printk(KERN_INFO "CPU#%d: status: %016llx\n", cpu, status); 464 printk(KERN_INFO "CPU#%d: status: %016llx\n", cpu, status);
412 printk(KERN_INFO "CPU#%d: overflow: %016llx\n", cpu, overflow); 465 printk(KERN_INFO "CPU#%d: overflow: %016llx\n", cpu, overflow);
413 printk(KERN_INFO "CPU#%d: fixed: %016llx\n", cpu, fixed); 466 printk(KERN_INFO "CPU#%d: fixed: %016llx\n", cpu, fixed);
467 }
414 printk(KERN_INFO "CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used); 468 printk(KERN_INFO "CPU#%d: used: %016llx\n", cpu, *(u64 *)cpuc->used);
415 469
416 for (idx = 0; idx < nr_counters_generic; idx++) { 470 for (idx = 0; idx < nr_counters_generic; idx++) {
@@ -588,6 +642,9 @@ void perf_counter_unthrottle(void)
588 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) 642 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
589 return; 643 return;
590 644
645 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
646 return;
647
591 if (unlikely(!perf_counters_initialized)) 648 if (unlikely(!perf_counters_initialized))
592 return; 649 return;
593 650
@@ -692,6 +749,15 @@ static struct pmc_x86_ops pmc_intel_ops = {
692 .max_events = ARRAY_SIZE(intel_perfmon_event_map), 749 .max_events = ARRAY_SIZE(intel_perfmon_event_map),
693}; 750};
694 751
752static struct pmc_x86_ops pmc_amd_ops = {
753 .save_disable_all = pmc_amd_save_disable_all,
754 .restore_all = pmc_amd_restore_all,
755 .eventsel = MSR_K7_EVNTSEL0,
756 .perfctr = MSR_K7_PERFCTR0,
757 .event_map = pmc_amd_event_map,
758 .max_events = ARRAY_SIZE(amd_perfmon_event_map),
759};
760
695static struct pmc_x86_ops *pmc_intel_init(void) 761static struct pmc_x86_ops *pmc_intel_init(void)
696{ 762{
697 union cpuid10_eax eax; 763 union cpuid10_eax eax;
@@ -719,6 +785,16 @@ static struct pmc_x86_ops *pmc_intel_init(void)
719 return &pmc_intel_ops; 785 return &pmc_intel_ops;
720} 786}
721 787
788static struct pmc_x86_ops *pmc_amd_init(void)
789{
790 nr_counters_generic = 4;
791 nr_counters_fixed = 0;
792
793 printk(KERN_INFO "AMD Performance Monitoring support detected.\n");
794
795 return &pmc_amd_ops;
796}
797
722void __init init_hw_perf_counters(void) 798void __init init_hw_perf_counters(void)
723{ 799{
724 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) 800 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
@@ -728,6 +804,9 @@ void __init init_hw_perf_counters(void)
728 case X86_VENDOR_INTEL: 804 case X86_VENDOR_INTEL:
729 pmc_ops = pmc_intel_init(); 805 pmc_ops = pmc_intel_init();
730 break; 806 break;
807 case X86_VENDOR_AMD:
808 pmc_ops = pmc_amd_init();
809 break;
731 } 810 }
732 if (!pmc_ops) 811 if (!pmc_ops)
733 return; 812 return;