-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
526 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Author, target of blame: | ||
|
||
Austin Seipp <aseipp [@at] pobox [.dot] com> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Contributing | ||
|
||
## Commits | ||
|
||
Rules for contribution: | ||
|
||
* 80-character column maximum. | ||
* The first line of a commit message should be 73 columns max. | ||
* Try to make commits self contained. One thing at a time. | ||
If it's a branch, squash the commits together to make one. | ||
* Always run tests. If benchmarks regress, give OS information, | ||
and we'll discuss. | ||
* Always reference the issue you're working on in the bug tracker | ||
in your commit message, and if it fixes the issue, close it. | ||
|
||
You can use GitHub pull requests OR just email me patches directly | ||
(see `git format-patch --help`,) whatever you are more comfortable with. | ||
|
||
One nice aspect of submitting a pull request is that | ||
[travis-ci.org](http://travis-ci.org) bots will automatically merge, build | ||
and run tests against your commits, and continue as you update the request, | ||
so you can be sure you didn't typo stuff or something before a final merge. | ||
|
||
For multi-commit requests, I will often squash them into the smallest | ||
possible logical changes and commit with author attribution. | ||
|
||
### Notes on sign-offs and attributions, etc. | ||
|
||
When you commit, **please use -s to add a Signed-off-by line**. I manage | ||
the `Signed-off-by` line much like Git itself: by adding it, you make clear | ||
that the contributed code abides by the source code license. I'm pretty | ||
much always going to want you to do this. | ||
|
||
I normally merge commits manually and give the original author attribution | ||
via `git commit --author`. I also sign-off on it, and add an `Acked-by` field | ||
which basically states "this commit is not totally ludicrous." | ||
|
||
Other fields may be added in the same vein for attribution or other purposes | ||
(`Suggested-by`, `Reviewed-by`, etc.) | ||
|
||
## Hacker notes | ||
|
||
N/A. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
Copyright (c) 2013 Austin Seipp | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining | ||
a copy of this software and associated documentation files (the | ||
"Software"), to deal in the Software without restriction, including | ||
without limitation the rights to use, copy, modify, merge, publish, | ||
distribute, sublicense, and/or sell copies of the Software, and to | ||
permit persons to whom the Software is furnished to do so, subject to | ||
the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
all: ko/enable_arm_pmu.ko perf_arm_pmu perf_event_open | ||
perf_arm_pmu: perf_arm_pmu.c | ||
@echo CC perf_arm_pmu | ||
@$(CC) -O3 -std=gnu99 perf_arm_pmu.c -o perf_arm_pmu | ||
perf_event_open: perf_event_open.c | ||
@echo CC perf_event_open | ||
@$(CC) -O3 -std=gnu99 perf_event_open.c -o perf_event_open | ||
ko/enable_arm_pmu.ko: ko/enable_arm_pmu.c | ||
@echo KMOD ko/enable_arm_pmu.ko | ||
@$(MAKE) -C ko > /dev/null | ||
runtests: all | ||
@echo SUDO load-module | ||
@./load-module | ||
@./perf_arm_pmu 128 | ||
@./perf_event_open 128 | ||
@echo SUDO unload-module | ||
@./unload-module | ||
|
||
clean: | ||
@($(MAKE) -C ko clean > /dev/null) && rm -f perf_arm_pmu perf_event_open *.o *~ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# User-mode access to ARM PMU cycle counters | ||
|
||
This repository contains a kernel module and library. | ||
|
||
ARM performance monitor units (PMUs) are only available on ARMv7 machines. In | ||
general, this means you'll need a Cortex-A7 or better (A8, A9, A15, etc.) | ||
|
||
More details are available in [my blog post][blog]. | ||
|
||
[blog]: http://neocontra.blogspot.com/2013/05/user-mode-performance-counters-for.html | ||
|
||
# Testing | ||
|
||
To compile, load, test and remove the module, you can just run: | ||
|
||
``` | ||
$ sudo make runtests | ||
``` | ||
|
||
## Tested on | ||
|
||
* Samsung Chromebook | ||
* Exynos 5 Dual, 1.7gHz Cortex-A15 | ||
* Ubuntu 13.04 | ||
* ODROID-U2 | ||
* Exynos 4 Quad, 1.7gHz Cortex-A9 | ||
* Ubuntu/Linaro 12.10 derivative | ||
|
||
TBD: PandaBoard. | ||
|
||
# Join in | ||
|
||
Be sure to read the [contributing guidelines][contribute]. File bugs | ||
in the GitHub [issue tracker][]. | ||
|
||
Master [git repository][gh]: | ||
|
||
* `git clone https://github.com/thoughtpolice/enable_arm_pmu.git` | ||
|
||
There's also a [BitBucket mirror][bb]: | ||
|
||
* `git clone https://bitbucket.org/thoughtpolice/enable_arm_pmu.git` | ||
|
||
# Authors | ||
|
||
See [AUTHORS.txt](https://raw.github.com/thoughtpolice/enable_arm_pmu/master/AUTHORS.txt). | ||
|
||
# License | ||
|
||
MIT. See | ||
[LICENSE.txt](https://raw.github.com/thoughtpolice/enable_arm_pmu/master/LICENSE.txt) | ||
for terms of copyright and redistribution. | ||
|
||
[contribute]: https://github.com/thoughtpolice/enable_arm_pmu/blob/master/CONTRIBUTING.md | ||
[issue tracker]: http://github.com/thoughtpolice/enable_arm_pmu/issues | ||
[gh]: http://github.com/thoughtpolice/enable_arm_pmu | ||
[bb]: http://bitbucket.org/thoughtpolice/enable_arm_pmu |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
#ifndef ARMPMU_LIB_H | ||
#define ARMPMU_LIB_H | ||
|
||
static inline uint32_t | ||
rdtsc32(void) | ||
{ | ||
#if defined(__GNUC__) | ||
uint32_t r = 0; | ||
#if defined __aarch64__ | ||
asm volatile("mrs %0, pmccntr_el0" : "=r" (r)); | ||
#elif defined(__ARM_ARCH_7A__) | ||
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(r) ); | ||
#else | ||
#error Unsupported architecture/compiler! | ||
#endif | ||
return r; | ||
#endif | ||
} | ||
|
||
#define ARMV8_PMEVTYPER_P (1 << 31) /* EL1 modes filtering bit */ | ||
#define ARMV8_PMEVTYPER_U (1 << 30) /* EL0 filtering bit */ | ||
#define ARMV8_PMEVTYPER_NSK (1 << 29) /* Non-secure EL1 (kernel) modes filtering bit */ | ||
#define ARMV8_PMEVTYPER_NSU (1 << 28) /* Non-secure User mode filtering bit */ | ||
#define ARMV8_PMEVTYPER_NSH (1 << 27) /* Non-secure Hyp modes filtering bit */ | ||
#define ARMV8_PMEVTYPER_M (1 << 26) /* Secure EL3 filtering bit */ | ||
#define ARMV8_PMEVTYPER_MT (1 << 25) /* Multithreading */ | ||
#define ARMV8_PMEVTYPER_EVTCOUNT_MASK 0x3ff | ||
|
||
static inline void | ||
enable_pmu(uint32_t evtCount) | ||
{ | ||
#if defined(__GNUC__) && defined __aarch64__ | ||
evtCount &= ARMV8_PMEVTYPER_EVTCOUNT_MASK; | ||
asm volatile("isb"); | ||
/* Just use counter 0 */ | ||
asm volatile("msr pmevtyper0_el0, %0" : : "r" (evtCount)); | ||
/* Performance Monitors Count Enable Set register bit 30:1 disable, 31,1 enable */ | ||
uint32_t r = 0; | ||
|
||
asm volatile("mrs %0, pmcntenset_el0" : "=r" (r)); | ||
asm volatile("msr pmcntenset_el0, %0" : : "r" (r|1)); | ||
#else | ||
#error Unsupported architecture/compiler! | ||
#endif | ||
} | ||
|
||
static inline uint32_t | ||
read_pmu(void) | ||
{ | ||
#if defined(__GNUC__) && defined __aarch64__ | ||
uint32_t r = 0; | ||
asm volatile("mrs %0, pmevcntr0_el0" : "=r" (r)); | ||
return r; | ||
#else | ||
#error Unsupported architecture/compiler! | ||
#endif | ||
} | ||
|
||
static inline void | ||
disable_pmu(uint32_t evtCount) | ||
{ | ||
#if defined(__GNUC__) && defined __aarch64__ | ||
/* Performance Monitors Count Enable Set register: clear bit 0 */ | ||
uint32_t r = 0; | ||
|
||
asm volatile("mrs %0, pmcntenset_el0" : "=r" (r)); | ||
asm volatile("msr pmcntenset_el0, %0" : : "r" (r&&0xfffffffe)); | ||
#else | ||
#error Unsupported architecture/compiler! | ||
#endif | ||
} | ||
|
||
|
||
#endif /* ARMPMU_LIB_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
obj-m := enable_arm_pmu.o | ||
KDIR := /lib/modules/$(shell uname -r)/build | ||
PWD := $(shell pwd) | ||
|
||
all: | ||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules | ||
clean: | ||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/* | ||
* Enable user-mode ARM performance counter access. | ||
*/ | ||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/smp.h> | ||
|
||
/** -- Configuration stuff ------------------------------------------------- */ | ||
|
||
#define DRVR_NAME "enable_arm_pmu" | ||
|
||
#if !defined(__arm__) && !defined(__aarch64__) | ||
#error Module can only be compiled on ARM machines. | ||
#endif | ||
|
||
/** -- Initialization & boilerplate ---------------------------------------- */ | ||
#define ARMV8_PMCR_MASK 0x3f | ||
#define ARMV8_PMCR_E (1 << 0) /* Enable all counters */ | ||
#define ARMV8_PMCR_P (1 << 1) /* Reset all counters */ | ||
#define ARMV8_PMCR_C (1 << 2) /* Cycle counter reset */ | ||
#define ARMV8_PMCR_D (1 << 3) /* CCNT counts every 64th cpu cycle */ | ||
#define ARMV8_PMCR_X (1 << 4) /* Export to ETM */ | ||
#define ARMV8_PMCR_DP (1 << 5) /* Disable CCNT if non-invasive debug*/ | ||
#define ARMV8_PMCR_N_SHIFT 11 /* Number of counters supported */ | ||
#define ARMV8_PMCR_N_MASK 0x1f | ||
|
||
#define ARMV8_PMUSERENR_EN_EL0 (1 << 0) /* EL0 access enable */ | ||
#define ARMV8_PMUSERENR_CR (1 << 2) /* Cycle counter read enable */ | ||
#define ARMV8_PMUSERENR_ER (1 << 3) /* Event counter read enable */ | ||
|
||
#define ARMV8_PMCNTENSET_EL0_ENABLE (1<<31) /* *< Enable Perf count reg */ | ||
|
||
#define PERF_DEF_OPTS (1 | 16) | ||
#define PERF_OPT_RESET_CYCLES (2 | 4) | ||
#define PERF_OPT_DIV64 (8) | ||
|
||
static inline u32 armv8pmu_pmcr_read(void) | ||
{ | ||
u64 val=0; | ||
asm volatile("mrs %0, pmcr_el0" : "=r" (val)); | ||
return (u32)val; | ||
} | ||
static inline void armv8pmu_pmcr_write(u32 val) | ||
{ | ||
val &= ARMV8_PMCR_MASK; | ||
isb(); | ||
asm volatile("msr pmcr_el0, %0" : : "r" ((u64)val)); | ||
} | ||
|
||
static void | ||
enable_cpu_counters(void* data) | ||
{ | ||
printk(KERN_INFO "[" DRVR_NAME "] enabling user-mode PMU access on CPU #%d", | ||
smp_processor_id()); | ||
|
||
#if __aarch64__ | ||
/* Enable user-mode access to counters. */ | ||
asm volatile("msr pmuserenr_el0, %0" : : "r"((u64)ARMV8_PMUSERENR_EN_EL0|ARMV8_PMUSERENR_ER|ARMV8_PMUSERENR_CR)); | ||
/* Initialize & Reset PMNC: C and P bits. */ | ||
armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C); | ||
/* G4.4.11 | ||
* PMINTENSET, Performance Monitors Interrupt Enable Set register */ | ||
/* cycle counter overflow interrupt request is disabled */ | ||
asm volatile("msr pmintenset_el1, %0" : : "r" ((u64)(0 << 31))); | ||
/* Performance Monitors Count Enable Set register bit 30:0 disable, 31 enable */ | ||
asm volatile("msr pmcntenset_el0, %0" : : "r" (ARMV8_PMCNTENSET_EL0_ENABLE)); | ||
/* start*/ | ||
armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMCR_E); | ||
#elif defined(__ARM_ARCH_7A__) | ||
/* Enable user-mode access to counters. */ | ||
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: "r"(1)); | ||
/* Program PMU and enable all counters */ | ||
asm volatile("mcr p15, 0, %0, c9, c12, 0" :: "r"(PERF_DEF_OPTS)); | ||
asm volatile("mcr p15, 0, %0, c9, c12, 1" :: "r"(0x8000000f)); | ||
#else | ||
#error Unsupported Architecture | ||
#endif | ||
} | ||
|
||
static void | ||
disable_cpu_counters(void* data) | ||
{ | ||
printk(KERN_INFO "[" DRVR_NAME "] disabling user-mode PMU access on CPU #%d", | ||
smp_processor_id()); | ||
|
||
#if __aarch64__ | ||
/* Performance Monitors Count Enable Set register bit 31:0 disable, 1 enable */ | ||
asm volatile("msr pmcntenset_el0, %0" : : "r" (0<<31)); | ||
/* Note above statement does not really clearing register...refer to doc */ | ||
/* Program PMU and disable all counters */ | ||
armv8pmu_pmcr_write(armv8pmu_pmcr_read() |~ARMV8_PMCR_E); | ||
/* disable user-mode access to counters. */ | ||
asm volatile("msr pmuserenr_el0, %0" : : "r"((u64)0)); | ||
#elif defined(__ARM_ARCH_7A__) | ||
/* Program PMU and disable all counters */ | ||
asm volatile("mcr p15, 0, %0, c9, c12, 0" :: "r"(0)); | ||
asm volatile("mcr p15, 0, %0, c9, c12, 2" :: "r"(0x8000000f)); | ||
/* Disable user-mode access to counters. */ | ||
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: "r"(0)); | ||
#else | ||
#error Unsupported Architecture | ||
#endif | ||
} | ||
|
||
static int __init | ||
init(void) | ||
{ | ||
on_each_cpu(enable_cpu_counters, NULL, 1); | ||
printk(KERN_INFO "[" DRVR_NAME "] initialized"); | ||
return 0; | ||
} | ||
|
||
static void __exit | ||
fini(void) | ||
{ | ||
on_each_cpu(disable_cpu_counters, NULL, 1); | ||
printk(KERN_INFO "[" DRVR_NAME "] unloaded"); | ||
} | ||
|
||
MODULE_AUTHOR("Austin Seipp <aseipp@pobox.com>"); | ||
MODULE_LICENSE("Dual MIT/GPL"); | ||
MODULE_DESCRIPTION("Enables user-mode access to ARMv7 PMU counters"); | ||
MODULE_VERSION("0:0.1-dev"); | ||
module_init(init); | ||
module_exit(fini); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#!/bin/sh | ||
/sbin/insmod ./ko/enable_arm_pmu.ko || exit 1 |
Oops, something went wrong.