Home | History | Annotate | Download | only in include
      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