You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
354 lines
10 KiB
354 lines
10 KiB
/******************************************************************************
|
|
*
|
|
* Copyright © International Business Machines Corp., 2006-2008
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
|
* the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* NAME
|
|
* librttest.h
|
|
*
|
|
* DESCRIPTION
|
|
* A set of commonly used convenience functions for writing
|
|
* threaded realtime test cases.
|
|
*
|
|
* USAGE:
|
|
* To be included in testcases.
|
|
*
|
|
* AUTHOR
|
|
* Darren Hart <dvhltc@us.ibm.com>
|
|
*
|
|
* HISTORY
|
|
* 2006-Apr-26: Initial version by Darren Hart
|
|
* 2006-May-08: Added atomic_{inc,set,get}, thread struct, debug function,
|
|
* rt_init, buffered printing -- Vernon Mauery
|
|
* 2006-May-09: improved command line argument handling
|
|
* 2007-Jul-12: Added latency tracing functions -- Josh Triplett
|
|
* 2007-Jul-26: Renamed to librttest.h -- Josh Triplett
|
|
* 2009-Nov-4: TSC macros within another header -- Giuseppe Cavallaro
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#ifndef LIBRTTEST_H
|
|
#define LIBRTTEST_H
|
|
|
|
#include <sys/syscall.h>
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
#include <math.h>
|
|
#include <pthread.h>
|
|
#include <sched.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include "list.h"
|
|
#include "realtime_config.h"
|
|
|
|
extern void setup();
|
|
extern void cleanup();
|
|
|
|
extern int optind, opterr, optopt;
|
|
extern char *optarg;
|
|
|
|
#define _MAXTHREADS 256
|
|
#define CALIBRATE_LOOPS 100000
|
|
unsigned long iters_per_us;
|
|
|
|
#define NS_PER_MS 1000000
|
|
#define NS_PER_US 1000
|
|
#define NS_PER_SEC 1000000000
|
|
#define US_PER_MS 1000
|
|
#define US_PER_SEC 1000000
|
|
#define MS_PER_SEC 1000
|
|
|
|
typedef unsigned long long nsec_t;
|
|
|
|
struct thread {
|
|
struct list_head _threads;
|
|
pthread_t pthread;
|
|
pthread_attr_t attr;
|
|
pthread_mutex_t mutex;
|
|
pthread_cond_t cond;
|
|
void *arg;
|
|
void *(*func)(void*);
|
|
int priority;
|
|
int policy;
|
|
int flags;
|
|
int id;
|
|
};
|
|
typedef struct { volatile int counter; } atomic_t;
|
|
|
|
// flags for threads
|
|
#define THREAD_START 1
|
|
#define THREAD_QUIT 2
|
|
#define thread_quit(T) (((T)->flags) & THREAD_QUIT)
|
|
|
|
#define PRINT_BUFFER_SIZE (1024*1024*4)
|
|
#define ULL_MAX 18446744073709551615ULL // (1 << 64) - 1
|
|
|
|
extern pthread_mutex_t _buffer_mutex;
|
|
extern char * _print_buffer;
|
|
extern int _print_buffer_offset;
|
|
extern int _dbg_lvl;
|
|
extern double pass_criteria;
|
|
|
|
/* function prototypes */
|
|
|
|
/* atomic_add - add integer to atomic variable and returns a value.
|
|
* i: integer value to add
|
|
* v: pointer of type atomic_t
|
|
*/
|
|
static inline int atomic_add(int i, atomic_t *v)
|
|
{
|
|
/* XXX (garrcoop): only available in later versions of gcc */
|
|
#if HAVE___SYNC_ADD_AND_FETCH
|
|
return __sync_add_and_fetch(&v->counter, i);
|
|
#else
|
|
printf("%s: %s\n", __func__, strerror(ENOSYS));
|
|
exit(1);
|
|
return -1;
|
|
#endif
|
|
}
|
|
/* atomic_inc: atomically increment the integer passed by reference
|
|
*/
|
|
static inline int atomic_inc(atomic_t *v)
|
|
{
|
|
return atomic_add(1, v);
|
|
}
|
|
|
|
/* atomic_get: atomically get the integer passed by reference
|
|
*/
|
|
//#define atomic_get(v) ((v)->counter)
|
|
static inline int atomic_get(atomic_t *v)
|
|
{
|
|
return v->counter;
|
|
}
|
|
|
|
/* atomic_set: atomically get the integer passed by reference
|
|
*/
|
|
//#define atomic_set(i,v) ((v)->counter = (i))
|
|
static inline void atomic_set(int i, atomic_t *v)
|
|
{
|
|
v->counter = i;
|
|
}
|
|
|
|
/* buffer_init: initialize the buffered printing system
|
|
*/
|
|
void buffer_init();
|
|
|
|
/* buffer_print: prints the contents of the buffer
|
|
*/
|
|
void buffer_print();
|
|
|
|
/* buffer_fini: destroy the buffer
|
|
*/
|
|
void buffer_fini();
|
|
|
|
/* debug: do debug prints at level L (see DBG_* below). If buffer_init
|
|
* has been called previously, this will print to the internal memory
|
|
* buffer rather than to stderr.
|
|
* L: debug level (see below) This will print if L is lower than _dbg_lvl
|
|
* A: format string (printf style)
|
|
* B: args to format string (printf style)
|
|
*/
|
|
static volatile int _debug_count = 0;
|
|
#define debug(L,A,B...) do {\
|
|
if ((L) <= _dbg_lvl) {\
|
|
pthread_mutex_lock(&_buffer_mutex);\
|
|
if (_print_buffer) {\
|
|
if (PRINT_BUFFER_SIZE - _print_buffer_offset < 1000)\
|
|
buffer_print();\
|
|
_print_buffer_offset += snprintf(&_print_buffer[_print_buffer_offset],\
|
|
PRINT_BUFFER_SIZE - _print_buffer_offset, "%06d: "A, _debug_count++, ##B);\
|
|
} else {\
|
|
fprintf(stderr, "%06d: "A, _debug_count++, ##B);\
|
|
}\
|
|
pthread_mutex_unlock(&_buffer_mutex);\
|
|
}\
|
|
} while (0)
|
|
#define DBG_ERR 1
|
|
#define DBG_WARN 2
|
|
#define DBG_INFO 3
|
|
#define DBG_DEBUG 4
|
|
|
|
/* rt_help: print help for standard args */
|
|
void rt_help();
|
|
|
|
/* rt_init_long: initialize librttest
|
|
* options: pass in an getopt style string of options -- e.g. "ab:cd::e:"
|
|
* if this or parse_arg is null, no option parsing will be done
|
|
* on behalf of the calling program (only internal args will be parsed)
|
|
* longopts: a pointer to the first element of an array of struct option, the
|
|
* last entry must be set to all zeros.
|
|
* parse_arg: a function that will get called when one of the above
|
|
* options is encountered on the command line. It will be passed
|
|
* the option -- e.g. 'b' -- and the value. Something like:
|
|
* // assume we passed "af:z::" to rt_init
|
|
* int parse_my_options(int option, char *value) {
|
|
* int handled = 1;
|
|
* switch (option) {
|
|
* case 'a':
|
|
* alphanum = 1;
|
|
* break;
|
|
* case 'f':
|
|
* // we passed f: which means f has an argument
|
|
* freedom = strcpy(value);
|
|
* break;
|
|
* case 'z':
|
|
* // we passed z:: which means z has an optional argument
|
|
* if (value)
|
|
* zero_size = atoi(value);
|
|
* else
|
|
* zero_size++;
|
|
* default:
|
|
* handled = 0;
|
|
* }
|
|
* return handled;
|
|
* }
|
|
* argc: passed from main
|
|
* argv: passed from main
|
|
*/
|
|
int rt_init_long(const char *options, const struct option *longopts,
|
|
int (*parse_arg)(int option, char *value),
|
|
int argc, char *argv[]);
|
|
|
|
/* rt_init: same as rt_init_long with no long options */
|
|
int rt_init(const char *options, int (*parse_arg)(int option, char *value),
|
|
int argc, char *argv[]);
|
|
|
|
int create_thread(void*(*func)(void*), void *arg, int prio, int policy);
|
|
|
|
/* create_fifo_thread: spawn a SCHED_FIFO thread with priority prio running
|
|
* func as the thread function with arg as it's parameter.
|
|
* func:
|
|
* arg: argument to func
|
|
* prio: 1-100, 100 being highest priority
|
|
*/
|
|
int create_fifo_thread(void*(*func)(void*), void *arg, int prio);
|
|
|
|
/* create_rr_thread: spawn a SCHED_RR thread with priority prio running
|
|
* func as the thread function with arg as it's parameter.
|
|
* func:
|
|
* arg: argument to func
|
|
* prio: 1-100, 100 being highest priority
|
|
*/
|
|
int create_rr_thread(void*(*func)(void*), void *arg, int prio);
|
|
|
|
/* create_other_thread: spawn a SCHED_OTHER thread
|
|
* func as the thread function with arg as it's parameter.
|
|
* func:
|
|
* arg: argument to func
|
|
*/
|
|
int create_other_thread(void*(*func)(void*), void *arg);
|
|
|
|
/* Change the priority of a running thread */
|
|
int set_thread_priority(pthread_t pthread, int prio);
|
|
|
|
/* Change the priority of the current context (usually called from main())
|
|
* and its policy to SCHED_FIFO
|
|
* prio: 1-99
|
|
*/
|
|
int set_priority(int prio);
|
|
|
|
/* all_threads_quit: signal all threads to quit */
|
|
void all_threads_quit(void);
|
|
|
|
/* join_threads: wait for all threads to finish
|
|
* (calls all_threads_quit interally)
|
|
*/
|
|
void join_threads();
|
|
|
|
/* get_thread: return a struct thread pointer from the list */
|
|
struct thread * get_thread(int i);
|
|
|
|
/* signal thread i to quit and then call join */
|
|
void join_thread(int i);
|
|
|
|
/* return the delta in ts_delta
|
|
* ts_end > ts_start
|
|
* if ts_delta is not null, the difference will be returned in it
|
|
*/
|
|
void ts_minus(struct timespec *ts_end, struct timespec *ts_start, struct timespec *ts_delta);
|
|
|
|
/* return the sum in ts_sum
|
|
* all arguments are not null
|
|
*/
|
|
void ts_plus(struct timespec *ts_a, struct timespec *ts_b, struct timespec *ts_sum);
|
|
|
|
/* put a ts into proper form (nsec < NS_PER_SEC)
|
|
* ts must not be null
|
|
*/
|
|
void ts_normalize(struct timespec *ts);
|
|
|
|
/* convert nanoseconds to a timespec
|
|
* ts must not be null
|
|
*/
|
|
void nsec_to_ts(nsec_t ns, struct timespec *ts);
|
|
|
|
/* convert a timespec to nanoseconds
|
|
* ts must not be null
|
|
*/
|
|
int ts_to_nsec(struct timespec *ts, nsec_t *ns);
|
|
|
|
/* return difference in microseconds */
|
|
unsigned long long tsc_minus(unsigned long long tsc_start, unsigned long long tsc_end);
|
|
|
|
/* rt_nanosleep: sleep for ns nanoseconds using clock_nanosleep
|
|
*/
|
|
void rt_nanosleep(nsec_t ns);
|
|
|
|
/* rt_nanosleep: sleep until absolute time ns given in
|
|
* nanoseconds using clock_nanosleep
|
|
*/
|
|
void rt_nanosleep_until(nsec_t ns);
|
|
|
|
/* rt_gettime: get CLOCK_MONOTONIC time in nanoseconds
|
|
*/
|
|
nsec_t rt_gettime();
|
|
|
|
/* busy_work_ms: do busy work for ms milliseconds
|
|
*/
|
|
void *busy_work_ms(int ms);
|
|
|
|
/* busy_work_us: do busy work for us microseconds
|
|
*/
|
|
void *busy_work_us(int us);
|
|
|
|
/* init_pi_mutex: initialize a pthread mutex to have PI support
|
|
*/
|
|
void init_pi_mutex(pthread_mutex_t *m);
|
|
|
|
/* latency_trace_enable: Enable latency tracing via sysctls.
|
|
*/
|
|
void latency_trace_enable(void);
|
|
|
|
/* latency_trace_start: Start tracing latency; call before running test.
|
|
*/
|
|
void latency_trace_start(void);
|
|
|
|
/* latency_trace_stop: Stop tracing latency; call immediately after observing
|
|
* excessive latency and stopping test.
|
|
*/
|
|
void latency_trace_stop(void);
|
|
|
|
/* latency_trace_print: Print latency trace information from
|
|
* /proc/latency_trace.
|
|
*/
|
|
void latency_trace_print(void);
|
|
|
|
#endif /* LIBRTTEST_H */
|