From d106235f5eebe280f4f820fc29bb5d8708e2f54d Mon Sep 17 00:00:00 2001 From: Matt Turner Date: Mon, 23 May 2016 18:10:11 -0700 Subject: Initial import --- test.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 test.c (limited to 'test.c') diff --git a/test.c b/test.c new file mode 100644 index 0000000..e322754 --- /dev/null +++ b/test.c @@ -0,0 +1,170 @@ +/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __NR_perf_event_open +#error __NR_perf_event_open not defined. +#endif + +#define PAGE_SIZE 8192 + +#define NUM_TIMES 100000 + +static const char *event_name[] = { + "cycles", + "instructions", + "cache-misses", + "mbox-replays" +}; + +static inline int +sys_perf_event_open(struct perf_event_attr *attr, + pid_t pid, int cpu, int group_fd, unsigned long flags) +{ + attr->size = sizeof(*attr); + return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); +} + +void clear_page(void *page); + +char *src __attribute__((used)); + +int +main(int argc, char *argv[]) +{ + struct perf_event_attr *attr; + int fd[4]; + char *ptr; + int num_pages; + + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + num_pages = atoi(argv[1]); + + /* Sanity test to ensure a whole page is cleared, and nothing more */ + if (posix_memalign((void **)&src, PAGE_SIZE, 3 * PAGE_SIZE)) + return 1; + + memset(src, 0xff, 3 * PAGE_SIZE); + + mprotect(src + 0 * PAGE_SIZE, PAGE_SIZE, PROT_NONE); + mprotect(src + 2 * PAGE_SIZE, PAGE_SIZE, PROT_NONE); + + clear_page(src + PAGE_SIZE); + + mprotect(src + 0 * PAGE_SIZE, PAGE_SIZE, PROT_READ); + mprotect(src + 2 * PAGE_SIZE, PAGE_SIZE, PROT_READ); + + if ((ptr = memchr(src + 0 * PAGE_SIZE, 0x00, PAGE_SIZE)) != NULL) { + fprintf(stderr, "Sanity test failed: page 0 cleared at byte %lu\n", + ptr - (src + 0 * PAGE_SIZE)); + return 1; + } + if ((ptr = memchr(src + 1 * PAGE_SIZE, 0xff, PAGE_SIZE)) != NULL) { + fprintf(stderr, "Sanity test failed: page 1 not cleared at byte %lu\n", + ptr - (src + 1 * PAGE_SIZE)); + return 1; + } + if ((ptr = memchr(src + 2 * PAGE_SIZE, 0x00, PAGE_SIZE)) != NULL) { + fprintf(stderr, "Sanity test failed: page 2 cleared at byte %lu\n", + ptr - (src + 2 * PAGE_SIZE)); + return 1; + } + free(src); + + /* Setup */ + if (posix_memalign((void **)&src, PAGE_SIZE, num_pages * PAGE_SIZE + 1)) + return 1; + memset(src, 0xff, num_pages * PAGE_SIZE + 1); + + attr = calloc(4, sizeof(*attr)); + if (src == NULL || attr == NULL) + return 1; + + attr[0].type = PERF_TYPE_HARDWARE; + attr[0].config = PERF_COUNT_HW_CPU_CYCLES; + attr[0].read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING; + attr[0].disabled = 1; + + attr[1].type = PERF_TYPE_HARDWARE; + attr[1].config = PERF_COUNT_HW_INSTRUCTIONS; + attr[1].read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING; + attr[1].disabled = 1; + + attr[2].type = PERF_TYPE_HARDWARE; + attr[2].read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING; + attr[2].config = PERF_COUNT_HW_CACHE_MISSES; + attr[2].disabled = 1; + + attr[3].type = PERF_TYPE_RAW; + attr[3].config = 4; + attr[3].read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING; + attr[3].disabled = 1; + + for (int i = 0; i < 4; i++) { + fd[i] = sys_perf_event_open(attr + i, 0, -1, -1, 0); + if (fd[i] < 0) { + perror("perf_open event"); + return 1; + } + } + + /* Benchmark */ + prctl(PR_TASK_PERF_EVENTS_ENABLE); + + for (int i = 0; i < NUM_TIMES; i++) { + for (int j = 0; j < num_pages; j++) { + clear_page(src + j * PAGE_SIZE); + } + } + + prctl(PR_TASK_PERF_EVENTS_DISABLE); + + /* Verify */ + if ((ptr = memchr(src, 0xff, num_pages * PAGE_SIZE + 1)) != + (src + num_pages * PAGE_SIZE)) { + fprintf(stderr, "Failed to clear at byte %lu\n", ptr - src); + return 1; + } + + for (int i = 0; i < 4; i++) { + unsigned long count[3]; + + if (read(fd[i], count, 3 * sizeof(__u64)) != 3 * sizeof(__u64)) + perror("read of event failed"); + printf("%20s: ", event_name[i]); + + if (count[2] == 0) { + printf("not counted\n"); + } else if (count[2] < count[1]) { + printf("%10lu (scaled from %3.1f%%)\n", + (unsigned long)((double)count[0] * count[1] / count[2] / NUM_TIMES + 0.5), + 100.0 * (double)count[2] / count[1]); + } else { + printf("%lu\n", count[0] / NUM_TIMES); + } + + close(fd[i]); + } + + free(src); + free(attr); + + return 0; +} -- cgit v1.2.3