diff options
author | Jaswinder Singh Rajput <jaswinderrajput@gmail.com> | 2009-02-27 09:45:14 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-28 04:38:32 -0500 |
commit | f87ad35d37fa543925210550f7db20a54c83ed70 (patch) | |
tree | 97ceff0080ac183f9416176b558d46271a044bdc /arch/x86/kernel/cpu/perf_counter.c | |
parent | b56a3802dc6df29aa27d2c12edf420258091ad66 (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.c | 83 |
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 | */ | ||
79 | static 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 | |||
89 | static 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 | ||
206 | static 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 | |||
187 | u64 hw_perf_save_disable(void) | 222 | u64 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 | ||
236 | static 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 | |||
201 | void hw_perf_restore(u64 ctrl) | 250 | void 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 | ||
752 | static 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 | |||
695 | static struct pmc_x86_ops *pmc_intel_init(void) | 761 | static 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 | ||
788 | static 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 | |||
722 | void __init init_hw_perf_counters(void) | 798 | void __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; |