/* Copyright (c) 2015, Linaro Limited * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Program to read perf counter on ARMv8 from userspace using mmap way */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #define barrier() asm volatile("dmb ish" ::: "memory") #define isb() asm volatile("isb" ::: "memory") static int fddev = -1; __attribute__((constructor)) static void init(void) { static struct perf_event_attr attr; attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CPU_CYCLES; fddev = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); } __attribute__((destructor)) static void fini(void) { close(fddev); } #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)); isb(); return ret; } static unsigned long mmap_read_self(void *addr) { struct perf_event_mmap_page *pc = addr; unsigned int seq, idx; unsigned long count; signed long pmc = 0; do { count = 0; seq = pc->lock; barrier(); idx = pc->index; if (idx) 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. */ static inline int loop(int* __restrict__ a, int* __restrict__ b, int n) { unsigned sum = 0; int i = 0; 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) { long long time_start = 0; long long time_end = 0; int *a = NULL; int *b = NULL; int len = 0; int i, 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); 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; } i = 0; start_count = stop_count = 0; /* --------------------Critical section-------------- */ start_count = mmap_read_self(addr); for (i = 0; i < 1000; i++) { 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, (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, (stop_count-start_count)/1000); munmap(addr, page_size); free(a); free(b); return 0; }