Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/powerpc: Add Anton's null_syscall benchmark to the selftests

Pull in a version of Anton's null_syscall benchmark:
http://ozlabs.org/~anton/junkcode/null_syscall.c

Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Anton Blanchard <anton@au.ibm.com>
Signed-off-by: Rui Teng <rui.teng@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Anton Blanchard and committed by
Michael Ellerman
d8db9bc5 a25f0944

+159 -1
+1
tools/testing/selftests/powerpc/benchmarks/.gitignore
··· 2 2 context_switch 3 3 mmap_bench 4 4 futex_bench 5 + null_syscall
+1 -1
tools/testing/selftests/powerpc/benchmarks/Makefile
··· 1 - TEST_PROGS := gettimeofday context_switch mmap_bench futex_bench 1 + TEST_PROGS := gettimeofday context_switch mmap_bench futex_bench null_syscall 2 2 3 3 CFLAGS += -O2 4 4
+157
tools/testing/selftests/powerpc/benchmarks/null_syscall.c
··· 1 + /* 2 + * Test null syscall performance 3 + * 4 + * Copyright (C) 2009-2015 Anton Blanchard, IBM 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #define NR_LOOPS 10000000 13 + 14 + #include <string.h> 15 + #include <stdio.h> 16 + #include <stdlib.h> 17 + #include <unistd.h> 18 + #include <time.h> 19 + #include <sys/types.h> 20 + #include <sys/time.h> 21 + #include <signal.h> 22 + 23 + static volatile int soak_done; 24 + unsigned long long clock_frequency; 25 + unsigned long long timebase_frequency; 26 + double timebase_multiplier; 27 + 28 + static inline unsigned long long mftb(void) 29 + { 30 + unsigned long low; 31 + 32 + asm volatile("mftb %0" : "=r" (low)); 33 + 34 + return low; 35 + } 36 + 37 + static void sigalrm_handler(int unused) 38 + { 39 + soak_done = 1; 40 + } 41 + 42 + /* 43 + * Use a timer instead of busy looping on clock_gettime() so we don't 44 + * pollute profiles with glibc and VDSO hits. 45 + */ 46 + static void cpu_soak_usecs(unsigned long usecs) 47 + { 48 + struct itimerval val; 49 + 50 + memset(&val, 0, sizeof(val)); 51 + val.it_value.tv_usec = usecs; 52 + 53 + signal(SIGALRM, sigalrm_handler); 54 + setitimer(ITIMER_REAL, &val, NULL); 55 + 56 + while (1) { 57 + if (soak_done) 58 + break; 59 + } 60 + 61 + signal(SIGALRM, SIG_DFL); 62 + } 63 + 64 + /* 65 + * This only works with recent kernels where cpufreq modifies 66 + * /proc/cpuinfo dynamically. 67 + */ 68 + static void get_proc_frequency(void) 69 + { 70 + FILE *f; 71 + char line[128]; 72 + char *p, *end; 73 + unsigned long v; 74 + double d; 75 + char *override; 76 + 77 + /* Try to get out of low power/low frequency mode */ 78 + cpu_soak_usecs(0.25 * 1000000); 79 + 80 + f = fopen("/proc/cpuinfo", "r"); 81 + if (f == NULL) 82 + return; 83 + 84 + timebase_frequency = 0; 85 + 86 + while (fgets(line, sizeof(line), f) != NULL) { 87 + if (strncmp(line, "timebase", 8) == 0) { 88 + p = strchr(line, ':'); 89 + if (p != NULL) { 90 + v = strtoull(p + 1, &end, 0); 91 + if (end != p + 1) 92 + timebase_frequency = v; 93 + } 94 + } 95 + 96 + if (((strncmp(line, "clock", 5) == 0) || 97 + (strncmp(line, "cpu MHz", 7) == 0))) { 98 + p = strchr(line, ':'); 99 + if (p != NULL) { 100 + d = strtod(p + 1, &end); 101 + if (end != p + 1) { 102 + /* Find fastest clock frequency */ 103 + if ((d * 1000000ULL) > clock_frequency) 104 + clock_frequency = d * 1000000ULL; 105 + } 106 + } 107 + } 108 + } 109 + 110 + fclose(f); 111 + 112 + override = getenv("FREQUENCY"); 113 + if (override) 114 + clock_frequency = strtoull(override, NULL, 10); 115 + 116 + if (timebase_frequency) 117 + timebase_multiplier = (double)clock_frequency 118 + / timebase_frequency; 119 + else 120 + timebase_multiplier = 1; 121 + } 122 + 123 + static void do_null_syscall(unsigned long nr) 124 + { 125 + unsigned long i; 126 + 127 + for (i = 0; i < nr; i++) 128 + getppid(); 129 + } 130 + 131 + #define TIME(A, STR) \ 132 + 133 + int main(void) 134 + { 135 + unsigned long tb_start, tb_now; 136 + struct timespec tv_start, tv_now; 137 + unsigned long long elapsed_ns, elapsed_tb; 138 + 139 + get_proc_frequency(); 140 + 141 + clock_gettime(CLOCK_MONOTONIC, &tv_start); 142 + tb_start = mftb(); 143 + 144 + do_null_syscall(NR_LOOPS); 145 + 146 + clock_gettime(CLOCK_MONOTONIC, &tv_now); 147 + tb_now = mftb(); 148 + 149 + elapsed_ns = (tv_now.tv_sec - tv_start.tv_sec) * 1000000000ULL + 150 + (tv_now.tv_nsec - tv_start.tv_nsec); 151 + elapsed_tb = tb_now - tb_start; 152 + 153 + printf("%10.2f ns %10.2f cycles\n", (float)elapsed_ns / NR_LOOPS, 154 + (float)elapsed_tb * timebase_multiplier / NR_LOOPS); 155 + 156 + return 0; 157 + }