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