1 /****************************************************************************** 2 * 3 * Copyright International Business Machines Corp., 2006, 2008 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * NAME 20 * rdtsc-latency.c 21 * 22 * DESCRIPTION 23 * Simple program to measure the time between several pairs of calls to 24 * rdtsc(). Based off of gtod-latency.c 25 * 26 * USAGE: 27 * Use run_auto.sh script in current directory to build and run test. 28 * Use "-j" to enable jvm simulator. 29 * 30 * AUTHOR 31 * Darren Hart <dvhltc (at) us.ibm.com> 32 * 33 * HISTORY 34 * 2006-Nov-15: Initial version by Darren Hart <dvhltc (at) us.ibm.com> 35 * 36 *****************************************************************************/ 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <sys/time.h> 42 #include <sys/types.h> 43 #include <sched.h> 44 #include <errno.h> 45 #include <stdint.h> 46 #include <librttest.h> 47 #include <libtsc.h> 48 49 #define ITERATIONS 1000000 50 51 void usage(void) 52 { 53 rt_help(); 54 printf("rdtsc-latency specific options:\n"); 55 printf(" This testcase don't expect any commandline options\n"); 56 } 57 58 int parse_args(int c, char *v) 59 { 60 61 int handled = 1; 62 switch (c) { 63 case 'h': 64 usage(); 65 exit(0); 66 default: 67 handled = 0; 68 break; 69 } 70 return handled; 71 } 72 73 /* return difference in nanoseconds */ 74 unsigned long long tv_minus(struct timeval *tv_start, struct timeval *tv_end) 75 { 76 unsigned long long nsecs; 77 nsecs = (tv_end->tv_sec - tv_start->tv_sec) * 1000000000ULL; 78 nsecs += (tv_end->tv_usec - tv_start->tv_usec) * 1000; 79 return nsecs; 80 } 81 82 /* calculate the tsc period */ 83 unsigned long long tsc_period_ps(void) 84 { 85 struct timeval tv_start; 86 struct timeval tv_end; 87 unsigned long long tsc_start, tsc_end; 88 89 rdtscll(tsc_start); 90 gettimeofday(&tv_start, NULL); 91 sleep(1); 92 rdtscll(tsc_end); 93 gettimeofday(&tv_end, NULL); 94 95 return (1000 * tv_minus(&tv_start, &tv_end)) / tsc_minus(tsc_start, 96 tsc_end); 97 } 98 99 int main(int argc, char *argv[]) 100 { 101 int i, err; 102 unsigned long long deltas[ITERATIONS]; 103 unsigned long long max, min, avg, tsc_a, tsc_b, tsc_period; 104 struct sched_param param; 105 106 #ifdef TSC_UNSUPPORTED 107 printf("Error: test cannot be executed on an arch wihout TSC.\n"); 108 return ENOTSUP; 109 #endif 110 111 setup(); 112 113 rt_init("h", parse_args, argc, argv); 114 115 /* no arguments */ 116 if (argc > 1) { 117 fprintf(stderr, "%s accepts no arguments\n", argv[0]); 118 exit(1); 119 } 120 121 /* switch to SCHED_FIFO 99 */ 122 param.sched_priority = sched_get_priority_max(SCHED_FIFO); 123 err = sched_setscheduler(0, SCHED_FIFO, ¶m); 124 125 /* Check that the user has the appropriate privileges */ 126 if (err) { 127 if (errno == EPERM) { 128 fprintf(stderr, 129 "This program runs with a scheduling policy of SCHED_FIFO at priority %d\n", 130 param.sched_priority); 131 fprintf(stderr, 132 "You don't have the necessary privileges to create such a real-time process.\n"); 133 } else { 134 fprintf(stderr, "Failed to set scheduler, errno %d\n", 135 errno); 136 } 137 exit(1); 138 } 139 140 /* calculate the tsc period in picoseconds */ 141 tsc_period = tsc_period_ps(); 142 143 /* collect ITERATIONS pairs of gtod calls */ 144 max = min = avg = 0; 145 for (i = 0; i < ITERATIONS; i++) { 146 rdtscll(tsc_a); 147 rdtscll(tsc_b); 148 deltas[i] = (tsc_minus(tsc_a, tsc_b) * tsc_period) / 1000; /* tsc period is in ps */ 149 if (i == 0 || deltas[i] < min) 150 min = deltas[i]; 151 if (deltas[i] > max) 152 max = deltas[i]; 153 avg += deltas[i]; 154 } 155 avg /= ITERATIONS; 156 157 /* report on deltas */ 158 printf("Calculated tsc period = %llu ps\n", tsc_period); 159 printf("%d pairs of rdtsc() calls completed\n", ITERATIONS); 160 printf("Time between calls:\n"); 161 printf(" Max: %llu ns\n", max); 162 printf(" Min: %llu ns\n", min); 163 printf(" Avg: %llu ns\n", avg); 164 165 return 0; 166 } 167