summaryrefslogtreecommitdiff
path: root/test.c
diff options
context:
space:
mode:
Diffstat (limited to 'test.c')
-rw-r--r--test.c170
1 files changed, 170 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/unistd.h>
+#include <sys/syscall.h>
+#include <sys/prctl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <linux/perf_event.h>
+
+#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 <num_pages>\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;
+}