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 * librttest.h 21 * 22 * DESCRIPTION 23 * A set of commonly used convenience functions for writing 24 * threaded realtime test cases. 25 * 26 * USAGE: 27 * To be included in testcases. 28 * 29 * AUTHOR 30 * Darren Hart <dvhltc (at) us.ibm.com> 31 * 32 * HISTORY 33 * 2006-Apr-26: Initial version by Darren Hart 34 * 2006-May-08: Added atomic_{inc,set,get}, thread struct, debug function, 35 * rt_init, buffered printing -- Vernon Mauery 36 * 2006-May-09: improved command line argument handling 37 * 2007-Jul-12: Added latency tracing functions -- Josh Triplett 38 * 2007-Jul-26: Renamed to librttest.h -- Josh Triplett 39 * 2009-Nov-4: TSC macros within another header -- Giuseppe Cavallaro 40 * 41 *****************************************************************************/ 42 43 #ifndef LIBRTTEST_H 44 #define LIBRTTEST_H 45 46 #include <sys/syscall.h> 47 #include <errno.h> 48 #include <getopt.h> 49 #include <math.h> 50 #include <pthread.h> 51 #include <sched.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <signal.h> 55 #include <string.h> 56 #include <time.h> 57 #include <unistd.h> 58 #include "list.h" 59 #include "realtime_config.h" 60 61 extern void setup(); 62 extern void cleanup(); 63 64 extern int optind, opterr, optopt; 65 extern char *optarg; 66 67 #define _MAXTHREADS 256 68 #define CALIBRATE_LOOPS 100000 69 unsigned long iters_per_us; 70 71 #define NS_PER_MS 1000000 72 #define NS_PER_US 1000 73 #define NS_PER_SEC 1000000000 74 #define US_PER_MS 1000 75 #define US_PER_SEC 1000000 76 #define MS_PER_SEC 1000 77 78 typedef unsigned long long nsec_t; 79 80 struct thread { 81 struct list_head _threads; 82 pthread_t pthread; 83 pthread_attr_t attr; 84 pthread_mutex_t mutex; 85 pthread_cond_t cond; 86 void *arg; 87 void *(*func)(void*); 88 int priority; 89 int policy; 90 int flags; 91 int id; 92 }; 93 typedef struct { volatile int counter; } atomic_t; 94 95 // flags for threads 96 #define THREAD_START 1 97 #define THREAD_QUIT 2 98 #define thread_quit(T) (((T)->flags) & THREAD_QUIT) 99 100 #define PRINT_BUFFER_SIZE (1024*1024*4) 101 #define ULL_MAX 18446744073709551615ULL // (1 << 64) - 1 102 103 extern pthread_mutex_t _buffer_mutex; 104 extern char * _print_buffer; 105 extern int _print_buffer_offset; 106 extern int _dbg_lvl; 107 extern double pass_criteria; 108 109 /* function prototypes */ 110 111 /* atomic_add - add integer to atomic variable and returns a value. 112 * i: integer value to add 113 * v: pointer of type atomic_t 114 */ 115 static inline int atomic_add(int i, atomic_t *v) 116 { 117 /* XXX (garrcoop): only available in later versions of gcc */ 118 #if HAVE___SYNC_ADD_AND_FETCH 119 return __sync_add_and_fetch(&v->counter, i); 120 #else 121 printf("%s: %s\n", __func__, strerror(ENOSYS)); 122 exit(1); 123 return -1; 124 #endif 125 } 126 /* atomic_inc: atomically increment the integer passed by reference 127 */ 128 static inline int atomic_inc(atomic_t *v) 129 { 130 return atomic_add(1, v); 131 } 132 133 /* atomic_get: atomically get the integer passed by reference 134 */ 135 //#define atomic_get(v) ((v)->counter) 136 static inline int atomic_get(atomic_t *v) 137 { 138 return v->counter; 139 } 140 141 /* atomic_set: atomically get the integer passed by reference 142 */ 143 //#define atomic_set(i,v) ((v)->counter = (i)) 144 static inline void atomic_set(int i, atomic_t *v) 145 { 146 v->counter = i; 147 } 148 149 /* buffer_init: initialize the buffered printing system 150 */ 151 void buffer_init(); 152 153 /* buffer_print: prints the contents of the buffer 154 */ 155 void buffer_print(); 156 157 /* buffer_fini: destroy the buffer 158 */ 159 void buffer_fini(); 160 161 /* debug: do debug prints at level L (see DBG_* below). If buffer_init 162 * has been called previously, this will print to the internal memory 163 * buffer rather than to stderr. 164 * L: debug level (see below) This will print if L is lower than _dbg_lvl 165 * A: format string (printf style) 166 * B: args to format string (printf style) 167 */ 168 static volatile int _debug_count = 0; 169 #define debug(L,A,B...) do {\ 170 if ((L) <= _dbg_lvl) {\ 171 pthread_mutex_lock(&_buffer_mutex);\ 172 if (_print_buffer) {\ 173 if (PRINT_BUFFER_SIZE - _print_buffer_offset < 1000)\ 174 buffer_print();\ 175 _print_buffer_offset += snprintf(&_print_buffer[_print_buffer_offset],\ 176 PRINT_BUFFER_SIZE - _print_buffer_offset, "%06d: "A, _debug_count++, ##B);\ 177 } else {\ 178 fprintf(stderr, "%06d: "A, _debug_count++, ##B);\ 179 }\ 180 pthread_mutex_unlock(&_buffer_mutex);\ 181 }\ 182 } while (0) 183 #define DBG_ERR 1 184 #define DBG_WARN 2 185 #define DBG_INFO 3 186 #define DBG_DEBUG 4 187 188 /* rt_help: print help for standard args */ 189 void rt_help(); 190 191 /* rt_init_long: initialize librttest 192 * options: pass in an getopt style string of options -- e.g. "ab:cd::e:" 193 * if this or parse_arg is null, no option parsing will be done 194 * on behalf of the calling program (only internal args will be parsed) 195 * longopts: a pointer to the first element of an array of struct option, the 196 * last entry must be set to all zeros. 197 * parse_arg: a function that will get called when one of the above 198 * options is encountered on the command line. It will be passed 199 * the option -- e.g. 'b' -- and the value. Something like: 200 * // assume we passed "af:z::" to rt_init 201 * int parse_my_options(int option, char *value) { 202 * int handled = 1; 203 * switch (option) { 204 * case 'a': 205 * alphanum = 1; 206 * break; 207 * case 'f': 208 * // we passed f: which means f has an argument 209 * freedom = strcpy(value); 210 * break; 211 * case 'z': 212 * // we passed z:: which means z has an optional argument 213 * if (value) 214 * zero_size = atoi(value); 215 * else 216 * zero_size++; 217 * default: 218 * handled = 0; 219 * } 220 * return handled; 221 * } 222 * argc: passed from main 223 * argv: passed from main 224 */ 225 int rt_init_long(const char *options, const struct option *longopts, 226 int (*parse_arg)(int option, char *value), 227 int argc, char *argv[]); 228 229 /* rt_init: same as rt_init_long with no long options */ 230 int rt_init(const char *options, int (*parse_arg)(int option, char *value), 231 int argc, char *argv[]); 232 233 int create_thread(void*(*func)(void*), void *arg, int prio, int policy); 234 235 /* create_fifo_thread: spawn a SCHED_FIFO thread with priority prio running 236 * func as the thread function with arg as it's parameter. 237 * func: 238 * arg: argument to func 239 * prio: 1-100, 100 being highest priority 240 */ 241 int create_fifo_thread(void*(*func)(void*), void *arg, int prio); 242 243 /* create_rr_thread: spawn a SCHED_RR thread with priority prio running 244 * func as the thread function with arg as it's parameter. 245 * func: 246 * arg: argument to func 247 * prio: 1-100, 100 being highest priority 248 */ 249 int create_rr_thread(void*(*func)(void*), void *arg, int prio); 250 251 /* create_other_thread: spawn a SCHED_OTHER thread 252 * func as the thread function with arg as it's parameter. 253 * func: 254 * arg: argument to func 255 */ 256 int create_other_thread(void*(*func)(void*), void *arg); 257 258 /* Change the priority of a running thread */ 259 int set_thread_priority(pthread_t pthread, int prio); 260 261 /* Change the priority of the current context (usually called from main()) 262 * and its policy to SCHED_FIFO 263 * prio: 1-99 264 */ 265 int set_priority(int prio); 266 267 /* all_threads_quit: signal all threads to quit */ 268 void all_threads_quit(void); 269 270 /* join_threads: wait for all threads to finish 271 * (calls all_threads_quit interally) 272 */ 273 void join_threads(); 274 275 /* get_thread: return a struct thread pointer from the list */ 276 struct thread * get_thread(int i); 277 278 /* signal thread i to quit and then call join */ 279 void join_thread(int i); 280 281 /* return the delta in ts_delta 282 * ts_end > ts_start 283 * if ts_delta is not null, the difference will be returned in it 284 */ 285 void ts_minus(struct timespec *ts_end, struct timespec *ts_start, struct timespec *ts_delta); 286 287 /* return the sum in ts_sum 288 * all arguments are not null 289 */ 290 void ts_plus(struct timespec *ts_a, struct timespec *ts_b, struct timespec *ts_sum); 291 292 /* put a ts into proper form (nsec < NS_PER_SEC) 293 * ts must not be null 294 */ 295 void ts_normalize(struct timespec *ts); 296 297 /* convert nanoseconds to a timespec 298 * ts must not be null 299 */ 300 void nsec_to_ts(nsec_t ns, struct timespec *ts); 301 302 /* convert a timespec to nanoseconds 303 * ts must not be null 304 */ 305 int ts_to_nsec(struct timespec *ts, nsec_t *ns); 306 307 /* return difference in microseconds */ 308 unsigned long long tsc_minus(unsigned long long tsc_start, unsigned long long tsc_end); 309 310 /* rt_nanosleep: sleep for ns nanoseconds using clock_nanosleep 311 */ 312 void rt_nanosleep(nsec_t ns); 313 314 /* rt_nanosleep: sleep until absolute time ns given in 315 * nanoseconds using clock_nanosleep 316 */ 317 void rt_nanosleep_until(nsec_t ns); 318 319 /* rt_gettime: get CLOCK_MONOTONIC time in nanoseconds 320 */ 321 nsec_t rt_gettime(); 322 323 /* busy_work_ms: do busy work for ms milliseconds 324 */ 325 void *busy_work_ms(int ms); 326 327 /* busy_work_us: do busy work for us microseconds 328 */ 329 void *busy_work_us(int us); 330 331 /* init_pi_mutex: initialize a pthread mutex to have PI support 332 */ 333 void init_pi_mutex(pthread_mutex_t *m); 334 335 /* latency_trace_enable: Enable latency tracing via sysctls. 336 */ 337 void latency_trace_enable(void); 338 339 /* latency_trace_start: Start tracing latency; call before running test. 340 */ 341 void latency_trace_start(void); 342 343 /* latency_trace_stop: Stop tracing latency; call immediately after observing 344 * excessive latency and stopping test. 345 */ 346 void latency_trace_stop(void); 347 348 /* latency_trace_print: Print latency trace information from 349 * /proc/latency_trace. 350 */ 351 void latency_trace_print(void); 352 353 #endif /* LIBRTTEST_H */ 354