1 /* Measure nanosleep timer latency 2 * by: john stultz (john.stultz@linaro.org) 3 * (C) Copyright Linaro 2013 4 * Licensed under the GPLv2 5 * 6 * To build: 7 * $ gcc nsleep-lat.c -o nsleep-lat -lrt 8 * 9 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation, either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <time.h> 23 #include <sys/time.h> 24 #include <sys/timex.h> 25 #include <string.h> 26 #include <signal.h> 27 #include "../kselftest.h" 28 29 #define NSEC_PER_SEC 1000000000ULL 30 31 #define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */ 32 33 34 #define CLOCK_REALTIME 0 35 #define CLOCK_MONOTONIC 1 36 #define CLOCK_PROCESS_CPUTIME_ID 2 37 #define CLOCK_THREAD_CPUTIME_ID 3 38 #define CLOCK_MONOTONIC_RAW 4 39 #define CLOCK_REALTIME_COARSE 5 40 #define CLOCK_MONOTONIC_COARSE 6 41 #define CLOCK_BOOTTIME 7 42 #define CLOCK_REALTIME_ALARM 8 43 #define CLOCK_BOOTTIME_ALARM 9 44 #define CLOCK_HWSPECIFIC 10 45 #define CLOCK_TAI 11 46 #define NR_CLOCKIDS 12 47 48 #define UNSUPPORTED 0xf00f 49 50 char *clockstring(int clockid) 51 { 52 switch (clockid) { 53 case CLOCK_REALTIME: 54 return "CLOCK_REALTIME"; 55 case CLOCK_MONOTONIC: 56 return "CLOCK_MONOTONIC"; 57 case CLOCK_PROCESS_CPUTIME_ID: 58 return "CLOCK_PROCESS_CPUTIME_ID"; 59 case CLOCK_THREAD_CPUTIME_ID: 60 return "CLOCK_THREAD_CPUTIME_ID"; 61 case CLOCK_MONOTONIC_RAW: 62 return "CLOCK_MONOTONIC_RAW"; 63 case CLOCK_REALTIME_COARSE: 64 return "CLOCK_REALTIME_COARSE"; 65 case CLOCK_MONOTONIC_COARSE: 66 return "CLOCK_MONOTONIC_COARSE"; 67 case CLOCK_BOOTTIME: 68 return "CLOCK_BOOTTIME"; 69 case CLOCK_REALTIME_ALARM: 70 return "CLOCK_REALTIME_ALARM"; 71 case CLOCK_BOOTTIME_ALARM: 72 return "CLOCK_BOOTTIME_ALARM"; 73 case CLOCK_TAI: 74 return "CLOCK_TAI"; 75 }; 76 return "UNKNOWN_CLOCKID"; 77 } 78 79 struct timespec timespec_add(struct timespec ts, unsigned long long ns) 80 { 81 ts.tv_nsec += ns; 82 while (ts.tv_nsec >= NSEC_PER_SEC) { 83 ts.tv_nsec -= NSEC_PER_SEC; 84 ts.tv_sec++; 85 } 86 return ts; 87 } 88 89 90 long long timespec_sub(struct timespec a, struct timespec b) 91 { 92 long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec; 93 94 ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec; 95 return ret; 96 } 97 98 int nanosleep_lat_test(int clockid, long long ns) 99 { 100 struct timespec start, end, target; 101 long long latency = 0; 102 int i, count; 103 104 target.tv_sec = ns/NSEC_PER_SEC; 105 target.tv_nsec = ns%NSEC_PER_SEC; 106 107 if (clock_gettime(clockid, &start)) 108 return UNSUPPORTED; 109 if (clock_nanosleep(clockid, 0, &target, NULL)) 110 return UNSUPPORTED; 111 112 count = 10; 113 114 /* First check relative latency */ 115 clock_gettime(clockid, &start); 116 for (i = 0; i < count; i++) 117 clock_nanosleep(clockid, 0, &target, NULL); 118 clock_gettime(clockid, &end); 119 120 if (((timespec_sub(start, end)/count)-ns) > UNRESONABLE_LATENCY) { 121 printf("Large rel latency: %lld ns :", (timespec_sub(start, end)/count)-ns); 122 return -1; 123 } 124 125 /* Next check absolute latency */ 126 for (i = 0; i < count; i++) { 127 clock_gettime(clockid, &start); 128 target = timespec_add(start, ns); 129 clock_nanosleep(clockid, TIMER_ABSTIME, &target, NULL); 130 clock_gettime(clockid, &end); 131 latency += timespec_sub(target, end); 132 } 133 134 if (latency/count > UNRESONABLE_LATENCY) { 135 printf("Large abs latency: %lld ns :", latency/count); 136 return -1; 137 } 138 139 return 0; 140 } 141 142 143 144 int main(int argc, char **argv) 145 { 146 long long length; 147 int clockid, ret; 148 149 for (clockid = CLOCK_REALTIME; clockid < NR_CLOCKIDS; clockid++) { 150 151 /* Skip cputime clockids since nanosleep won't increment cputime */ 152 if (clockid == CLOCK_PROCESS_CPUTIME_ID || 153 clockid == CLOCK_THREAD_CPUTIME_ID || 154 clockid == CLOCK_HWSPECIFIC) 155 continue; 156 157 printf("nsleep latency %-26s ", clockstring(clockid)); 158 159 length = 10; 160 while (length <= (NSEC_PER_SEC * 10)) { 161 ret = nanosleep_lat_test(clockid, length); 162 if (ret) 163 break; 164 length *= 100; 165 166 } 167 168 if (ret == UNSUPPORTED) { 169 printf("[UNSUPPORTED]\n"); 170 continue; 171 } 172 if (ret < 0) { 173 printf("[FAILED]\n"); 174 return ksft_exit_fail(); 175 } 176 printf("[OK]\n"); 177 } 178 return ksft_exit_pass(); 179 } 180