diff options
author | Yogesh Tillu <yogesh.tillu@linaro.org> | 2015-04-13 13:12:57 +0530 |
---|---|---|
committer | Yogesh Tillu <yogesh.tillu@linaro.org> | 2015-04-15 08:02:18 +0530 |
commit | c2d000e20ceac2a1d8e6111f5a01def9dc294d0b (patch) | |
tree | a049bea2c2d41df81448573dda32ce7b3881880a | |
parent | 5bfdec46898d6e9ce6cd9371fcf676ce1856c14e (diff) |
perf_rc_mmap:
Added support for all perf hw counter
Added getopt support for argument
Added print_usage for help
Reviewed-by: Anders Roxell <anders.roxell@linaro.org>
Signed-off-by: Yogesh Tillu <yogesh.tillu@linaro.org>
-rw-r--r-- | perf_rc_mmap.c | 109 |
1 files changed, 80 insertions, 29 deletions
diff --git a/perf_rc_mmap.c b/perf_rc_mmap.c index 2c404dc..180ddd7 100644 --- a/perf_rc_mmap.c +++ b/perf_rc_mmap.c @@ -20,29 +20,42 @@ #include <sys/mman.h> #include <errno.h> #include <string.h> -#define barrier() asm volatile("dmb ish" ::: "memory") -#define isb() asm volatile("isb" ::: "memory") +#include <getopt.h> +#define barrier() asm volatile("dmb ish" : : : "memory") +#define isb() asm volatile("isb" : : : "memory") +#define ARMV8_PMCNTENSET_EL0_ENABLE (1<<31) /**< Enable Perf count reg */ static int fddev = -1; -__attribute__((constructor)) static void -init(void) +static unsigned long page_size; + +static int counter_init(unsigned int counter) { static struct perf_event_attr attr; attr.type = PERF_TYPE_HARDWARE; - attr.config = PERF_COUNT_HW_CPU_CYCLES; + if (counter < 0 || counter > PERF_COUNT_HW_MAX) + return -1; + + attr.config = counter; fddev = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); -} + if (fddev == -1) { + fprintf(stderr, + "Error opening perf_event_open for counter %llx\n", + attr.config); + return -1; + } -__attribute__((destructor)) static void -fini(void) -{ - close(fddev); + return 0; } -#define ARMV8_PMCNTENSET_EL0_ENABLE (1<<31) /**< Enable Perf count reg */ static unsigned long rdpmc(unsigned int counter) { unsigned long int ret; - asm volatile("mrs %0, pmccntr_el0" : "=r" (ret)); + if (counter == PERF_COUNT_HW_CPU_CYCLES) + asm volatile("mrs %0, pmccntr_el0" : "=r" (ret)); + else { + asm volatile("msr pmselr_el0, %0" : : "r" ((counter-1))); + asm volatile("mrs %0, pmxevcntr_el0" : "=r" (ret)); + } + isb(); return ret; } @@ -62,11 +75,12 @@ static unsigned long mmap_read_self(void *addr) pmc = rdpmc(idx - 1); barrier(); } while (pc->lock != seq); + count = pmc; return count; } -/* Simple loop body to keep things interested. Make sure it gets inlined. */ +/* loop body to keep things interested. Make sure it gets inlined. */ static inline int loop(int* __restrict__ a, int* __restrict__ b, int n) { @@ -75,44 +89,74 @@ loop(int* __restrict__ a, int* __restrict__ b, int n) for (i = 0; i < n; ++i) if (a[i] > b[i]) sum += a[i] + 5; + return sum; } -static unsigned long page_size; - -int main(int ac, char **av) +void print_usage(char *argv) { - long long time_start = 0; - long long time_end = 0; + printf("Usage: %s -c perf_hw_counter -n length\n" + "%s - read perf hardware counters from userspace\n\n" + "-c\t perf_hw_counter is enum value of hw counter for platform\n" + "Refer to 'enum perf_hw_id'[file <linux/perf_event.h>] for hw\n" + "counter enum value in range of 0 to PERF_COUNT_HW_MAX\n" + "-n\t Length size array will implement busyloop\n" + "e.g.\n" + "\t%s -c 0 -n 64\n", argv, argv, argv); +} +int main(int ac, char *argv[]) +{ + int option = 0; int *a = NULL; int *b = NULL; - int len = 0; - int i, sum = 0; + int len = -1, cnt = -1; + int i, result, sum = 0; void *addr; /* mmaped address */ unsigned long start_count, stop_count; - if (ac != 2) - return -1; - len = atoi(av[1]); - printf("%s: len = %d\n", av[0], len); + + while ((option = getopt(ac, argv, "c:n:")) != -1) { + switch (option) { + case 'c': + cnt = atoi(optarg); + break; + case 'n': + len = atoi(optarg); + break; + default: + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + if (len == -1 || cnt == -1) { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + + if (counter_init(cnt) < 0) { + printf("Error: Counter Invalid\n"); + print_usage(argv[0]); + exit(EXIT_FAILURE); + } a = malloc(len*sizeof(*a)); b = malloc(len*sizeof(*b)); - for (i = 0; i < len; ++i) { a[i] = i+128; b[i] = i+64; } page_size = sysconf(_SC_PAGESIZE); - /*Allocate memory for the page size */ addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fddev, 0); if (addr == (void *)(-1)) { printf("Error: mmap() syscall returned with (%s)\n", strerror(errno)); - return 0; + print_usage(argv[0]); + exit(EXIT_FAILURE); } + i = 0; start_count = stop_count = 0; /* --------------------Critical section-------------- */ @@ -121,21 +165,28 @@ int main(int ac, char **av) sum = loop(a, b, len); mmap_read_self(addr); } + stop_count = mmap_read_self(addr); /* --------------------End Critical section-------------- */ - printf("sum=%d Avg count [ Loop + Read ] is = %ld\n", sum, + result = (stop_count-start_count)/1000; + printf("\nsum=%d Avg count [ Loop + Read ] = %ld\n", sum, (stop_count-start_count)/1000); start_count = stop_count = 0; /* --------------------Critical section-------------- */ start_count = mmap_read_self(addr); for (i = 0; i < 1000; i++) sum = loop(a, b, len); + stop_count = mmap_read_self(addr); /* --------------------End Critical section-------------- */ - printf("sum=%d Avg count [ Loop ] \t is = %ld\n", sum, + printf("sum=%d Avg count [ Loop ] = %ld\n", sum, (stop_count-start_count)/1000); + printf("\n--------------------------------------------------------\n"); + printf("\tDelay[cpucycles]=%d", result-((stop_count-start_count)/1000)); + printf("\n--------------------------------------------------------\n"); munmap(addr, page_size); free(a); free(b); + close(fddev); return 0; } |