Imported Upstream version 20091031
[ltp-debian.git] / testcases / realtime / include / librttest.h
blob74e760ce37cbec9afaf353b63b0b2cbc279d969f
1 /******************************************************************************
3 * Copyright © International Business Machines Corp., 2006-2008
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * NAME
20 * librttest.h
22 * DESCRIPTION
23 * A set of commonly used convenience functions for writing
24 * threaded realtime test cases.
26 * USAGE:
27 * To be included in testcases.
29 * AUTHOR
30 * Darren Hart <dvhltc@us.ibm.com>
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
40 *****************************************************************************/
42 #ifndef LIBRTTEST_H
43 #define LIBRTTEST_H
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <signal.h>
48 #include <time.h>
49 #include <string.h>
50 #include <pthread.h>
51 #include <sched.h>
52 #include <errno.h>
53 #include <unistd.h>
54 #include <getopt.h>
55 #include <sys/syscall.h>
56 #include <math.h>
57 #include "list.h"
58 #include "realtime_config.h"
60 extern void setup();
61 extern void cleanup();
63 extern int optind, opterr, optopt;
64 extern char *optarg;
66 #define _MAXTHREADS 256
67 #define CALIBRATE_LOOPS 100000
68 unsigned long iters_per_us;
70 #define NS_PER_MS 1000000
71 #define NS_PER_US 1000
72 #define NS_PER_SEC 1000000000
73 #define US_PER_MS 1000
74 #define US_PER_SEC 1000000
75 #define MS_PER_SEC 1000
77 typedef unsigned long long nsec_t;
79 struct thread {
80 struct list_head _threads;
81 pthread_t pthread;
82 pthread_attr_t attr;
83 pthread_mutex_t mutex;
84 pthread_cond_t cond;
85 void *arg;
86 void *(*func)(void*);
87 int priority;
88 int policy;
89 int flags;
90 int id;
92 typedef struct { volatile int counter; } atomic_t;
94 // flags for threads
95 #define THREAD_START 1
96 #define THREAD_QUIT 2
97 #define thread_quit(T) (((T)->flags) & THREAD_QUIT)
99 #define PRINT_BUFFER_SIZE (1024*1024*4)
101 /* TSC macros */
102 #define ULL_MAX 18446744073709551615ULL // (1 << 64) - 1
103 #if defined(__i386__)
104 #define rdtscll(val) __asm__ __volatile__("rdtsc" : "=A" (val))
105 #elif defined(__x86_64__)
106 #define rdtscll(val) \
107 do { \
108 uint32_t low, high; \
109 __asm__ __volatile__ ("rdtsc" : "=a" (low), "=d" (high)); \
110 val = (uint64_t)high << 32 | low; \
111 } while(0)
112 #elif defined(__powerpc__)
113 #if defined(__powerpc64__) /* 64bit version */
114 #define rdtscll(val) \
115 do { \
116 __asm__ __volatile__ ("mfspr %0, 268" : "=r" (val)); \
117 } while(0)
118 #else /*__powerpc__ 32bit version */
119 #define rdtscll(val) \
120 do { \
121 uint32_t tbhi, tblo ; \
122 __asm__ __volatile__ ("mftbu %0" : "=r" (tbhi)); \
123 __asm__ __volatile__ ("mftbl %0" : "=r" (tblo)); \
124 val = 1000 * ((uint64_t) tbhi << 32) | tblo; \
125 } while(0)
126 #endif
127 #else
128 #error
129 #endif
131 extern pthread_mutex_t _buffer_mutex;
132 extern char * _print_buffer;
133 extern int _print_buffer_offset;
134 extern int _dbg_lvl;
135 extern double pass_criteria;
137 /* function prototypes */
139 /* atomic_add - add integer to atomic variable
140 * i: integer value to add
141 * v: pointer of type atomic_t
143 static inline int atomic_add(int i, atomic_t *v)
145 #if defined(__x86_64__) || defined(__i386__)
146 int __i;
147 __i = i;
148 asm volatile(
149 "lock; xaddl %0, %1;"
150 :"=r"(i)
151 :"m"(v->counter), "0"(i));
152 return i + __i;
153 #elif defined(__powerpc__)
154 #define ISYNC_ON_SMP "\n\tisync\n"
155 #define LWSYNC_ON_SMP __stringify(LWSYNC) "\n"
156 int t;
157 asm volatile(
158 " lwsync \n\
159 1: lwarx %0,0,%2 # atomic_add_return \n\
160 add %0,%1,%0\n\
161 stwcx. %0,0,%2 \n\
162 bne- 1b"
163 ISYNC_ON_SMP
164 : "=&r" (t)
165 : "r" (i), "r" (&v->counter)
166 : "cc", "memory");
168 return t;
169 #else
170 #error
171 #endif
174 /* atomic_inc: atomically increment the integer passed by reference
176 static inline int atomic_inc(atomic_t *v)
178 return atomic_add(1, v);
181 /* atomic_get: atomically get the integer passed by reference
183 //#define atomic_get(v) ((v)->counter)
184 static inline int atomic_get(atomic_t *v)
186 return v->counter;
189 /* atomic_set: atomically get the integer passed by reference
191 //#define atomic_set(i,v) ((v)->counter = (i))
192 static inline void atomic_set(int i, atomic_t *v)
194 v->counter = i;
197 /* buffer_init: initialize the buffered printing system
199 void buffer_init();
201 /* buffer_print: prints the contents of the buffer
203 void buffer_print();
205 /* buffer_fini: destroy the buffer
207 void buffer_fini();
209 /* debug: do debug prints at level L (see DBG_* below). If buffer_init
210 * has been called previously, this will print to the internal memory
211 * buffer rather than to stderr.
212 * L: debug level (see below) This will print if L is lower than _dbg_lvl
213 * A: format string (printf style)
214 * B: args to format string (printf style)
216 static volatile int _debug_count = 0;
217 #define debug(L,A,B...) do {\
218 if ((L) <= _dbg_lvl) {\
219 pthread_mutex_lock(&_buffer_mutex);\
220 if (_print_buffer) {\
221 if (PRINT_BUFFER_SIZE - _print_buffer_offset < 1000)\
222 buffer_print();\
223 _print_buffer_offset += snprintf(&_print_buffer[_print_buffer_offset],\
224 PRINT_BUFFER_SIZE - _print_buffer_offset, "%06d: "A, _debug_count++, ##B);\
225 } else {\
226 fprintf(stderr, "%06d: "A, _debug_count++, ##B);\
228 pthread_mutex_unlock(&_buffer_mutex);\
230 } while(0)
231 #define DBG_ERR 1
232 #define DBG_WARN 2
233 #define DBG_INFO 3
234 #define DBG_DEBUG 4
236 /* rt_help: print help for standard args */
237 void rt_help();
239 /* rt_init_long: initialize librttest
240 * options: pass in an getopt style string of options -- e.g. "ab:cd::e:"
241 * if this or parse_arg is null, no option parsing will be done
242 * on behalf of the calling program (only internal args will be parsed)
243 * longopts: a pointer to the first element of an array of struct option, the
244 * last entry must be set to all zeros.
245 * parse_arg: a function that will get called when one of the above
246 * options is encountered on the command line. It will be passed
247 * the option -- e.g. 'b' -- and the value. Something like:
248 * // assume we passed "af:z::" to rt_init
249 * int parse_my_options(int option, char *value) {
250 * int handled = 1;
251 * switch (option) {
252 * case 'a':
253 * alphanum = 1;
254 * break;
255 * case 'f':
256 * // we passed f: which means f has an argument
257 * freedom = strcpy(value);
258 * break;
259 * case 'z':
260 * // we passed z:: which means z has an optional argument
261 * if (value)
262 * zero_size = atoi(value);
263 * else
264 * zero_size++;
265 * default:
266 * handled = 0;
268 * return handled;
269 * }
270 * argc: passed from main
271 * argv: passed from main
273 int rt_init_long(const char *options, const struct option *longopts,
274 int (*parse_arg)(int option, char *value),
275 int argc, char *argv[]);
277 /* rt_init: same as rt_init_long with no long options */
278 int rt_init(const char *options, int (*parse_arg)(int option, char *value),
279 int argc, char *argv[]);
281 int create_thread(void*(*func)(void*), void *arg, int prio, int policy);
283 /* create_fifo_thread: spawn a SCHED_FIFO thread with priority prio running
284 * func as the thread function with arg as it's parameter.
285 * func:
286 * arg: argument to func
287 * prio: 1-100, 100 being highest priority
289 int create_fifo_thread(void*(*func)(void*), void *arg, int prio);
291 /* create_rr_thread: spawn a SCHED_RR thread with priority prio running
292 * func as the thread function with arg as it's parameter.
293 * func:
294 * arg: argument to func
295 * prio: 1-100, 100 being highest priority
297 int create_rr_thread(void*(*func)(void*), void *arg, int prio);
299 /* create_other_thread: spawn a SCHED_OTHER thread
300 * func as the thread function with arg as it's parameter.
301 * func:
302 * arg: argument to func
304 int create_other_thread(void*(*func)(void*), void *arg);
306 /* Change the priority of a running thread */
307 int set_thread_priority(pthread_t pthread, int prio);
309 /* Change the priority of the current context (usually called from main())
310 * and its policy to SCHED_FIFO
311 * prio: 1-99
313 int set_priority(int prio);
315 /* all_threads_quit: signal all threads to quit */
316 void all_threads_quit(void);
318 /* join_threads: wait for all threads to finish
319 * (calls all_threads_quit interally)
321 void join_threads();
323 /* get_thread: return a struct thread pointer from the list */
324 struct thread * get_thread(int i);
326 /* signal thread i to quit and then call join */
327 void join_thread(int i);
329 /* return the delta in ts_delta
330 * ts_end > ts_start
331 * if ts_delta is not null, the difference will be returned in it
333 void ts_minus(struct timespec *ts_end, struct timespec *ts_start, struct timespec *ts_delta);
335 /* return the sum in ts_sum
336 * all arguments are not null
338 void ts_plus(struct timespec *ts_a, struct timespec *ts_b, struct timespec *ts_sum);
340 /* put a ts into proper form (nsec < NS_PER_SEC)
341 * ts must not be null
343 void ts_normalize(struct timespec *ts);
345 /* convert nanoseconds to a timespec
346 * ts must not be null
348 void nsec_to_ts(nsec_t ns, struct timespec *ts);
350 /* convert a timespec to nanoseconds
351 * ts must not be null
353 int ts_to_nsec(struct timespec *ts, nsec_t *ns);
355 /* return difference in microseconds */
356 unsigned long long tsc_minus(unsigned long long tsc_start, unsigned long long tsc_end);
358 /* rt_nanosleep: sleep for ns nanoseconds using clock_nanosleep
360 void rt_nanosleep(nsec_t ns);
362 /* rt_nanosleep: sleep until absolute time ns given in
363 * nanoseconds using clock_nanosleep
365 void rt_nanosleep_until(nsec_t ns);
367 /* rt_gettime: get CLOCK_MONOTONIC time in nanoseconds
369 nsec_t rt_gettime();
371 /* busy_work_ms: do busy work for ms milliseconds
373 void *busy_work_ms(int ms);
375 /* busy_work_us: do busy work for us microseconds
377 void *busy_work_us(int us);
379 /* init_pi_mutex: initialize a pthread mutex to have PI support
381 void init_pi_mutex(pthread_mutex_t *m);
383 /* latency_trace_enable: Enable latency tracing via sysctls.
385 void latency_trace_enable(void);
387 /* latency_trace_start: Start tracing latency; call before running test.
389 void latency_trace_start(void);
391 /* latency_trace_stop: Stop tracing latency; call immediately after observing
392 * excessive latency and stopping test.
394 void latency_trace_stop(void);
396 /* latency_trace_print: Print latency trace information from
397 * /proc/latency_trace.
399 void latency_trace_print(void);
401 #endif /* LIBRTTEST_H */