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 } 158