diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2011-12-02 10:32:10 +0100 |
---|---|---|
committer | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2011-12-02 10:40:57 +0100 |
commit | 6932f363c2fafb3849bb3eb0cfb768571646814d (patch) | |
tree | 07bb20ba31671531fc9caa05670f3190c5b7482d | |
parent | b1da9977f07c6c343c1fdb50c556cadfd5bcefd1 (diff) | |
parent | 5f1e84f8b015df3ff950056494134eca3f640d70 (diff) | |
download | rt-tests-6932f363c2fafb3849bb3eb0cfb768571646814d.tar.gz |
Merge tag 'v0.83' of git://github.com/clrkwllms/rt-tests
Notice: this object is not reachable from any branch.
debian/v0.83-1Further update changelog and refresh patches
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Notice: this object is not reachable from any branch.
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | debian/patches/debian_adapt_errormsg_on_failure_to_open_device | 2 | ||||
-rw-r--r-- | debian/patches/debian_has_recent_glibc | 2 | ||||
-rw-r--r-- | debian/patches/fix_comment_about_realtime_group.patch | 2 | ||||
-rw-r--r-- | debian/patches/install_hwlatdetect_into_sbindir | 6 | ||||
-rw-r--r-- | debian/patches/manpage_pip_stress.patch | 2 | ||||
-rw-r--r-- | rt-tests.spec-in | 38 | ||||
-rw-r--r-- | src/cyclictest/cyclictest.c | 222 | ||||
-rw-r--r-- | src/hackbench/hackbench.c | 58 | ||||
-rw-r--r-- | src/include/rt-utils.h | 10 | ||||
-rw-r--r-- | src/lib/rt-utils.c | 212 |
12 files changed, 452 insertions, 118 deletions
@@ -1,4 +1,4 @@ -VERSION_STRING = 0.74 +VERSION_STRING = 0.83 sources = cyclictest.c signaltest.c pi_stress.c rt-migrate-test.c \ ptsematest.c sigwaittest.c svsematest.c pmqtest.c sendme.c \ @@ -14,6 +14,12 @@ bindir ?= $(prefix)/bin mandir ?= $(prefix)/share/man srcdir ?= $(prefix)/src +machinetype = $(shell uname -m | \ + sed -e 's/i.86/i386/' -e 's/mips.*/mips/' -e 's/ppc.*/powerpc/') +ifneq ($(filter x86_64 i386 ia64 mips powerpc,$(machinetype)),) +NUMA := 1 +endif + CFLAGS = -D_GNU_SOURCE -Wall -Wno-nonnull -Isrc/include PYLIB := $(shell python -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib()') @@ -24,7 +30,7 @@ else CFLAGS += -O0 -g endif -ifdef NUMA +ifeq ($(NUMA),1) CFLAGS += -DNUMA NUMA_LIBS = -lnuma endif diff --git a/debian/changelog b/debian/changelog index 9469a18..61c3356 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +rt-tests (0.83-1) unstable; urgency=low + + * new upstream release + + -- Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Fri, 02 Dec 2011 10:40:15 +0100 + rt-tests (0.74-1) unstable; urgency=low * new upstream release diff --git a/debian/patches/debian_adapt_errormsg_on_failure_to_open_device b/debian/patches/debian_adapt_errormsg_on_failure_to_open_device index 62e0f70..473f149 100644 --- a/debian/patches/debian_adapt_errormsg_on_failure_to_open_device +++ b/debian/patches/debian_adapt_errormsg_on_failure_to_open_device @@ -10,7 +10,7 @@ Forwarded: not-needed --- a/src/backfire/sendme.c +++ b/src/backfire/sendme.c -@@ -212,9 +212,9 @@ +@@ -220,9 +220,9 @@ "try 'modprobe backfire'\n" "If the module backfire can't be loaded, " "it may need to be built first.\n" diff --git a/debian/patches/debian_has_recent_glibc b/debian/patches/debian_has_recent_glibc index bc86ff2..cfaa930 100644 --- a/debian/patches/debian_has_recent_glibc +++ b/debian/patches/debian_has_recent_glibc @@ -25,7 +25,7 @@ Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> DESTDIR ?= prefix ?= /usr/local bindir ?= $(prefix)/bin -@@ -69,19 +68,19 @@ +@@ -75,19 +74,19 @@ rt-migrate-test: rt-migrate-test.o $(CC) $(CFLAGS) -o $@ $^ $(LIBS) diff --git a/debian/patches/fix_comment_about_realtime_group.patch b/debian/patches/fix_comment_about_realtime_group.patch index 4dc03d4..6302d62 100644 --- a/debian/patches/fix_comment_about_realtime_group.patch +++ b/debian/patches/fix_comment_about_realtime_group.patch @@ -14,7 +14,7 @@ Closes: http://bugs.debian.org/619938 --- a/src/lib/rt-utils.c +++ b/src/lib/rt-utils.c -@@ -72,7 +72,8 @@ +@@ -264,7 +264,8 @@ param.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { fprintf(stderr, "Unable to change scheduling policy!\n"); diff --git a/debian/patches/install_hwlatdetect_into_sbindir b/debian/patches/install_hwlatdetect_into_sbindir index 444744e..8299b59 100644 --- a/debian/patches/install_hwlatdetect_into_sbindir +++ b/debian/patches/install_hwlatdetect_into_sbindir @@ -11,7 +11,7 @@ Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- a/Makefile +++ b/Makefile -@@ -11,13 +11,12 @@ +@@ -11,6 +11,7 @@ DESTDIR ?= prefix ?= /usr/local bindir ?= $(prefix)/bin @@ -19,6 +19,8 @@ Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> mandir ?= $(prefix)/share/man srcdir ?= $(prefix)/src +@@ -22,8 +23,6 @@ + CFLAGS = -D_GNU_SOURCE -Wall -Wno-nonnull -Isrc/include -PYLIB := $(shell python -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib()') @@ -26,7 +28,7 @@ Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> ifndef DEBUG CFLAGS += -O2 else -@@ -113,10 +112,7 @@ +@@ -119,10 +118,7 @@ mkdir -p "$(DESTDIR)$(bindir)" "$(DESTDIR)$(mandir)/man4" mkdir -p "$(DESTDIR)$(srcdir)" "$(DESTDIR)$(mandir)/man8" cp $(TARGETS) "$(DESTDIR)$(bindir)" diff --git a/debian/patches/manpage_pip_stress.patch b/debian/patches/manpage_pip_stress.patch index 7fce4c0..6c7c23f 100644 --- a/debian/patches/manpage_pip_stress.patch +++ b/debian/patches/manpage_pip_stress.patch @@ -41,7 +41,7 @@ Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +was written by John Kacur <jkacur@redhat.com>. --- a/Makefile +++ b/Makefile -@@ -118,6 +118,7 @@ +@@ -124,6 +124,7 @@ gzip src/backfire/backfire.4 -c >"$(DESTDIR)$(mandir)/man4/backfire.4.gz" gzip src/cyclictest/cyclictest.8 -c >"$(DESTDIR)$(mandir)/man8/cyclictest.8.gz" gzip src/pi_tests/pi_stress.8 -c >"$(DESTDIR)$(mandir)/man8/pi_stress.8.gz" diff --git a/rt-tests.spec-in b/rt-tests.spec-in index bbd164e..77a9a08 100644 --- a/rt-tests.spec-in +++ b/rt-tests.spec-in @@ -62,6 +62,44 @@ rm -rf $RPM_BUILD_ROOT /usr/share/man/man8/hackbench.8.gz %changelog +* Mon Sep 26 2011 Clark Williams <williams@redhat.com> - 0.83-1 +- modified Makefile to be smarter about building with NUMA + +* Wed Sep 21 2011 Clark Williams <williams@redhat.com> - 0.82-1 +- fix print that causes error in histogram processing + +* Tue Sep 20 2011 Clark Williams <williams@redhat.com> - 0.81-1 +- cleaned up previous hack for /dev/cpu_dma_latency interface + +* Tue Sep 20 2011 Clark Williams <williams@redhat.com> - 0.80-1 +- use /dev/cpu_dma_latency interface to prevent cstate transitions + in cyclictest + +* Thu Sep 15 2011 Clark Williams <williams@redhat.com> - 0.79-1 +- added signal_workers routine to hackbench +- added -F/--fifo option to hackbench + +* Wed Sep 14 2011 Clark Williams <williams@redhat.com> - 0.78-1 +- modified hackebench signal logic + +* Fri Sep 9 2011 Clark Williams <williams@redhat.com> - 0.77-1 +- removed tracemark functions (too much contention on multiprocessors) + +* Wed Sep 7 2011 Clark Williams <williams@redhat.com> - 0.76-1 +- only turn on /proc/sys/kernel/ftrace_enabled for a tracer that + needs it +- make sure to set current_tracer to function for -f switch + +* Fri Sep 2 2011 Clark Williams <williams@redhat.com> - 0.75-1 +- added utility routines for mounting debugfs and event/tracing manipulation +- from Steven Rostedt <srostedt@redhat.com>: + - allow events for all tracers + - Have -I and -P together also be -B + - do not touch tracing_thresh + - only check file descriptor in tracemark() function + - use interval on first loop instead of 1 second + - allow tracemark() to take variable args + * Thu Aug 18 2011 Clark Williams <williams@redhat.com> - 0.74-1 - changes to deal with 3.0 kernel - fixed buildrequires in specfile for Python diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c index 6be5521..731b4bd 100644 --- a/src/cyclictest/cyclictest.c +++ b/src/cyclictest/cyclictest.c @@ -13,6 +13,7 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> +#include <stdarg.h> #include <unistd.h> #include <fcntl.h> #include <getopt.h> @@ -105,15 +106,18 @@ extern int clock_nanosleep(clockid_t __clock_id, int __flags, #define KVARNAMELEN 32 #define KVALUELEN 32 +int enable_events; + enum { NOTRACE, - EVENTS, CTXTSWITCH, IRQSOFF, PREEMPTOFF, - IRQPREEMPTOFF, + PREEMPTIRQSOFF, WAKEUP, WAKEUPRT, + LATENCY, + FUNCTION, CUSTOM, }; @@ -154,7 +158,7 @@ struct thread_stat { static int shutdown; static int tracelimit = 0; -static int ftrace = 1; +static int ftrace = 0; static int kernelversion; static int verbose = 0; static int oscope_reduction = 1; @@ -172,6 +176,7 @@ static pthread_mutex_t refresh_on_max_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t break_thread_id_lock = PTHREAD_MUTEX_INITIALIZER; static pid_t break_thread_id = 0; +static uint64_t break_thread_value = 0; /* Backup of kernel variables that we modify */ static struct kvars { @@ -186,6 +191,39 @@ static char **traceptr; static int traceopt_count; static int traceopt_size; +static int latency_target_fd = -1; +static int32_t latency_target_value = 0; + +/* Latency trick + * if the file /dev/cpu_dma_latency exists, + * open it and write a zero into it. This will tell + * the power management system not to transition to + * a high cstate (in fact, the system acts like idle=poll) + * When the fd to /dev/cpu_dma_latency is closed, the behavior + * goes back to the system default. + * + * Documentation/power/pm_qos_interface.txt + */ +static void set_latency_target(void) +{ + struct stat s; + int ret; + + if (stat("/dev/cpu_dma_latency", &s) == 0) { + latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR); + if (latency_target_fd == -1) + return; + ret = write(latency_target_fd, &latency_target_value, 4); + if (ret == 0) { + printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno)); + close(latency_target_fd); + return; + } + printf("# /dev/cpu_dma_latency set to %dus\n", latency_target_value); + } +} + + enum kernelversion { KV_NOT_SUPPORTED, KV_26_LT18, @@ -203,7 +241,6 @@ static char functiontracer[MAX_PATH]; static char traceroptions[MAX_PATH]; static int trace_fd = -1; -static int tracemark_fd = -1; static int kernvar(int mode, const char *name, char *value, size_t sizeofvalue) { @@ -333,15 +370,6 @@ static int trace_file_exists(char *name) return stat(path, &sbuf) ? 0 : 1; } -static void tracemark(char *comment) -{ - /* bail out if we're not tracing */ - /* or if the kernel doesn't support trace_mark */ - if (!tracelimit || kernelversion < KV_26_33 || tracemark_fd < 0) - return; - write(tracemark_fd, comment, strlen(comment)); -} - void tracing(int on) { if (on) { @@ -369,44 +397,11 @@ void tracing(int on) static int settracer(char *tracer) { - char filename[MAX_PATH]; - char tracers[MAX_PATH]; - char *name; - FILE *fp; - int ret = -1; - int len; - const char *delim = " \t\n"; - char *prefix = get_debugfileprefix(); - - /* Make sure tracer is available */ - strncpy(filename, prefix, sizeof(filename)); - strncat(filename, "available_tracers", - sizeof(filename) - strlen(prefix)); - - fp = fopen(filename, "r"); - if (!fp) - return -1; - - if (!(len = fread(tracers, 1, sizeof(tracers), fp))) { - fclose(fp); - return -1; - } - tracers[len] = '\0'; - fclose(fp); - - name = strtok(tracers, delim); - while (name) { - if (strcmp(name, tracer) == 0) { - ret = 0; - break; - } - name = strtok(NULL, delim); - } - - if (!ret) + if (valid_tracer(tracer)) { setkernvar("current_tracer", tracer); - - return ret; + return 0; + } + return -1; } static void setup_tracer(void) @@ -414,6 +409,9 @@ static void setup_tracer(void) if (!tracelimit) return; + if (mount_debugfs(NULL)) + fatal("could not mount debugfs"); + if (kernelversion >= KV_26_33) { char testname[MAX_PATH]; @@ -427,30 +425,36 @@ static void setup_tracer(void) fileprefix = procfileprefix; if (kernelversion >= KV_26_33) { - char buffer[32]; int ret; if (trace_file_exists("tracing_enabled") && !trace_file_exists("tracing_on")) setkernvar("tracing_enabled", "1"); - sprintf(buffer, "%d", tracelimit); - setkernvar("tracing_thresh", buffer); - /* ftrace_enabled is a sysctl variable */ + /* turn it on if you're doing anything but nop or event tracing */ + fileprefix = procfileprefix; - if (ftrace) + if (tracetype) setkernvar("ftrace_enabled", "1"); else setkernvar("ftrace_enabled", "0"); fileprefix = get_debugfileprefix(); + /* + * Set default tracer to nop. + * this also has the nice side effect of clearing out + * old traces. + */ + ret = settracer("nop"); + switch (tracetype) { case NOTRACE: - if (ftrace) - ret = settracer(functiontracer); - else - ret = 0; + /* no tracer specified, use events */ + enable_events = 1; + break; + case FUNCTION: + ret = settracer("function"); break; case IRQSOFF: ret = settracer("irqsoff"); @@ -458,16 +462,17 @@ static void setup_tracer(void) case PREEMPTOFF: ret = settracer("preemptoff"); break; - case IRQPREEMPTOFF: + case PREEMPTIRQSOFF: ret = settracer("preemptirqsoff"); break; - case EVENTS: - /* per rostedt: use nop tracer with event tracing */ - setkernvar("events/enable", "1"); - ret = settracer("nop"); - break; case CTXTSWITCH: - ret = settracer("sched_switch"); + if (valid_tracer("sched_switch")) + ret = settracer("sched_switch"); + else { + if ((ret = event_enable("sched/sched_wakeup"))) + break; + ret = event_enable("sched/sched_switch"); + } break; case WAKEUP: ret = settracer("wakeup"); @@ -488,6 +493,10 @@ static void setup_tracer(void) break; } + if (enable_events) + /* turn on all events */ + event_enable_all(); + if (ret) fprintf(stderr, "Requested tracer '%s' not available\n", tracer); @@ -523,13 +532,6 @@ static void setup_tracer(void) fatal("unable to open %s for tracing", path); } - /* open the tracemark file descriptor */ - if (tracemark_fd == -1) { - char path[MAX_PATH]; - strcat(strcpy(path, fileprefix), "trace_marker"); - if ((tracemark_fd = open(path, O_WRONLY)) == -1) - warn("unable to open trace_marker file: %s\n", path); - } } else { setkernvar("trace_all_cpus", "1"); setkernvar("trace_freerunning", "1"); @@ -643,8 +645,11 @@ void *timerthread(void *param) /* Get current time */ clock_gettime(par->clock, &now); + next = now; - next.tv_sec++; + next.tv_sec += interval.tv_sec; + next.tv_nsec += interval.tv_nsec; + tsnorm(&next); if (duration) { memset(&stop, 0, sizeof(stop)); /* grrr */ @@ -672,8 +677,6 @@ void *timerthread(void *param) stat->threadstarted++; - tracemark("entering time loop"); - while (!shutdown) { uint64_t diff; @@ -719,8 +722,6 @@ void *timerthread(void *param) clock_gettime(par->clock, &now); - tracemark("out of critical loop, calculating"); - if (use_nsecs) diff = calcdiff_ns(now, next); else @@ -739,12 +740,12 @@ void *timerthread(void *param) if (!stopped && tracelimit && (diff > tracelimit)) { stopped++; - tracemark("hit latency threshold"); tracing(0); shutdown++; pthread_mutex_lock(&break_thread_id_lock); if (break_thread_id == 0) break_thread_id = stat->tid; + break_thread_value = diff; pthread_mutex_unlock(&break_thread_id_lock); } stat->act = diff; @@ -772,7 +773,6 @@ void *timerthread(void *param) if (par->max_cycles && par->max_cycles == stat->cycles) break; - tracemark("heading back to sleep"); } out: @@ -983,9 +983,10 @@ static void process_options (int argc, char *argv[]) {"traceopt", required_argument, NULL, 'O'}, {"smp", no_argument, NULL, 'S'}, {"numa", no_argument, NULL, 'U'}, + {"latency", required_argument, NULL, 'e'}, {NULL, 0, NULL, 0} }; - int c = getopt_long(argc, argv, "a::b:Bc:Cd:Efh:H:i:Il:MnNo:O:p:PmqrsSt::uUvD:wWT:y:", + int c = getopt_long(argc, argv, "a::b:Bc:Cd:Efh:H:i:Il:MnNo:O:p:PmqrsSt::uUvD:wWT:y:e:", long_options, &option_index); if (c == -1) break; @@ -1006,16 +1007,24 @@ static void process_options (int argc, char *argv[]) } break; case 'b': tracelimit = atoi(optarg); break; - case 'B': tracetype = IRQPREEMPTOFF; break; + case 'B': tracetype = PREEMPTIRQSOFF; break; case 'c': clocksel = atoi(optarg); break; case 'C': tracetype = CTXTSWITCH; break; case 'd': distance = atoi(optarg); break; - case 'E': tracetype = EVENTS; break; - case 'f': ftrace = 1; break; + case 'E': enable_events = 1; break; + case 'f': tracetype = FUNCTION; ftrace = 1; break; case 'H': histofall = 1; /* fall through */ case 'h': histogram = atoi(optarg); break; case 'i': interval = atoi(optarg); break; - case 'I': tracetype = IRQSOFF; break; + case 'I': + if (tracetype == PREEMPTOFF) { + tracetype = PREEMPTIRQSOFF; + strncpy(tracer, "preemptirqsoff", sizeof(tracer)); + } else { + tracetype = IRQSOFF; + strncpy(tracer, "irqsoff", sizeof(tracer)); + } + break; case 'l': max_cycles = atoi(optarg); break; case 'n': use_nanosleep = MODE_CLOCK_NANOSLEEP; break; case 'N': use_nsecs = 1; break; @@ -1026,7 +1035,15 @@ static void process_options (int argc, char *argv[]) if (policy != SCHED_FIFO && policy != SCHED_RR) policy = SCHED_FIFO; break; - case 'P': tracetype = PREEMPTOFF; break; + case 'P': + if (tracetype == IRQSOFF) { + tracetype = PREEMPTIRQSOFF; + strncpy(tracer, "preemptirqsoff", sizeof(tracer)); + } else { + tracetype = PREEMPTOFF; + strncpy(tracer, "preemptoff", sizeof(tracer)); + } + break; case 'q': quiet = 1; break; case 'r': timermode = TIMER_RELTIME; break; case 's': use_system = MODE_SYS_OFFSET; break; @@ -1076,6 +1093,13 @@ static void process_options (int argc, char *argv[]) warn("ignoring --numa or -U\n"); #endif break; + case 'e': /* power management latency target value */ + /* note: default is 0 (zero) */ + latency_target_value = atoi(optarg); + if (latency_target_value < 0) + latency_target_value = 0; + break; + case '?': display_help(0); break; } } @@ -1321,13 +1345,15 @@ int main(int argc, char **argv) /* Checks if numa is on, program exits if numa on but not available */ numa_on_and_available(); - /* lock all memory (prevent paging) */ + /* lock all memory (prevent swapping) */ if (lockall) if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { perror("mlockall"); goto out; } + /* use the /dev/cpu_dma_latency trick if it's there */ + set_latency_target(); kernelversion = check_kernel(); @@ -1340,7 +1366,7 @@ int main(int argc, char **argv) warn("High resolution timers not available\n"); mode = use_nanosleep + use_system; - + sigemptyset(&sigset); sigaddset(&sigset, signum); sigprocmask (SIG_BLOCK, &sigset, NULL); @@ -1533,8 +1559,10 @@ int main(int argc, char **argv) if (tracelimit) { print_tids(parameters, num_threads); - if (break_thread_id) + if (break_thread_id) { printf("# Break thread: %d\n", break_thread_id); + printf("# Break value: %lu\n", break_thread_value); + } } @@ -1555,12 +1583,20 @@ int main(int argc, char **argv) if (tracelimit) tracing(0); + /* close any tracer file descriptors */ - if (tracemark_fd >= 0) - close(tracemark_fd); if (trace_fd >= 0) close(trace_fd); + /* turn off all events */ + event_disable_all(); + + /* turn off the function tracer */ + fileprefix = procfileprefix; + if (tracetype) + setkernvar("ftrace_enabled", "0"); + fileprefix = get_debugfileprefix(); + /* unlock everything */ if (lockall) munlockall(); @@ -1569,5 +1605,9 @@ int main(int argc, char **argv) if (kernelversion < KV_26_33) restorekernvars(); + /* close the latency_target_fd if it's open */ + if (latency_target_fd >= 0) + close(latency_target_fd); + exit(ret); } diff --git a/src/hackbench/hackbench.c b/src/hackbench/hackbench.c index 03b74b0..8baeb23 100644 --- a/src/hackbench/hackbench.c +++ b/src/hackbench/hackbench.c @@ -28,16 +28,21 @@ #include <getopt.h> #include <signal.h> #include <setjmp.h> +#include <sched.h> static unsigned int datasize = 100; static unsigned int loops = 100; static unsigned int num_groups = 10; static unsigned int num_fds = 20; +static unsigned int fifo = 0; /* * 0 means thread mode and others mean process (default) */ -static unsigned int process_mode = 1; +#define THREAD_MODE 0 +#define PROCESS_MODE 1 + +static unsigned int process_mode = PROCESS_MODE; static int use_pipes = 0; @@ -159,7 +164,7 @@ static void *receiver(struct receiver_context* ctx) unsigned int i; reset_worker_signals(); - if (process_mode) + if (process_mode == PROCESS_MODE) close(ctx->in_fds[1]); /* Wait for start... */ @@ -192,7 +197,7 @@ childinfo_t create_worker(void *ctx, void *(*func)(void *)) pid_t childpid; switch (process_mode) { - case 1: /* process mode */ + case PROCESS_MODE: /* process mode */ /* Fork the sender/receiver child. */ switch ((childpid = fork())) { case -1: @@ -206,7 +211,7 @@ childinfo_t create_worker(void *ctx, void *(*func)(void *)) child.pid = childpid; break; - case 0: /* threaded mode */ + case THREAD_MODE: /* threaded mode */ if (pthread_attr_init(&attr) != 0) { sneeze("pthread_attr_init()"); child.error = -1; @@ -231,6 +236,15 @@ childinfo_t create_worker(void *ctx, void *(*func)(void *)) return child; } +void signal_workers(childinfo_t *children, unsigned int num_children) +{ + int i; + printf("signaling %d worker threads to terminate\n", num_children); + for (i=0; i < num_children; i++) { + kill(children[i].pid, SIGTERM); + } +} + unsigned int reap_workers(childinfo_t *child, unsigned int totchld, unsigned int dokill) { unsigned int i, rc = 0; @@ -240,13 +254,13 @@ unsigned int reap_workers(childinfo_t *child, unsigned int totchld, unsigned int if (dokill) { fprintf(stderr, "sending SIGTERM to all child processes\n"); signal(SIGTERM, SIG_IGN); - kill(0, SIGTERM); + signal_workers(child, totchld); } for( i = 0; i < totchld; i++ ) { int pid; switch( process_mode ) { - case 1: /* process mode */ + case PROCESS_MODE: /* process mode */ fflush(stdout); pid = wait(&status); if (pid == -1 && errno == ECHILD) @@ -254,7 +268,7 @@ unsigned int reap_workers(childinfo_t *child, unsigned int totchld, unsigned int if (!WIFEXITED(status)) rc++; break; - case 0: /* threaded mode */ + case THREAD_MODE: /* threaded mode */ err = pthread_join(child[i].threadid, &thr_status); if( err != 0 ) { sneeze("pthread_join()"); @@ -307,7 +321,7 @@ static unsigned int group(childinfo_t *child, return (i > 0 ? i-1 : 0); } snd_ctx->out_fds[i] = fds[1]; - if (process_mode) + if (process_mode == PROCESS_MODE) close(fds[0]); } @@ -324,7 +338,7 @@ static unsigned int group(childinfo_t *child, } /* Close the fds we have left */ - if (process_mode) + if (process_mode == PROCESS_MODE) for (i = 0; i < num_fds; i++) close(snd_ctx->out_fds[i]); @@ -347,11 +361,12 @@ static void process_options (int argc, char *argv[]) {"fds", required_argument, NULL, 'f'}, {"threads", no_argument, NULL, 'T'}, {"processes", no_argument, NULL, 'P'}, + {"fifo", no_argument, NULL, 'F'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; - int c = getopt_long(argc, argv, "ps:l:g:f:TPh", + int c = getopt_long(argc, argv, "ps:l:g:f:TPFh", longopts, &optind); if (c == -1) { break; @@ -390,10 +405,14 @@ static void process_options (int argc, char *argv[]) break; case 'T': - process_mode = 0; + process_mode = THREAD_MODE; break; case 'P': - process_mode = 1; + process_mode = PROCESS_MODE; + break; + + case 'F': + fifo = 1; break; case 'h': @@ -423,11 +442,12 @@ int main(int argc, char *argv[]) struct timeval start, stop, diff; int readyfds[2], wakefds[2]; char dummy; + struct sched_param sp; process_options (argc, argv); printf("Running in %s mode with %d groups using %d file descriptors each (== %d tasks)\n", - (process_mode == 0 ? "threaded" : "process"), + (process_mode == THREAD_MODE ? "threaded" : "process"), num_groups, 2*num_fds, num_groups*(num_fds*2)); printf("Each sender will pass %d messages of %d bytes\n", loops, datasize); fflush(NULL); @@ -455,6 +475,13 @@ int main(int argc, char *argv[]) } total_children += c; } + if (fifo) { + /* make main a realtime task so that we can manage the workers */ + sp.sched_priority = 1; + if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) + barf("can't change to fifo in main"); + } + /* Wait for everyone to be ready */ for (i = 0; i < total_children; i++) if (read(readyfds[0], &dummy, 1) != 1) { @@ -470,8 +497,11 @@ int main(int argc, char *argv[]) barf("Writing to start senders"); } } - else + else { fprintf(stderr, "longjmp'ed out, reaping children\n"); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + } /* Reap them all */ reap_workers(child_tab, total_children, signal_caught); diff --git a/src/include/rt-utils.h b/src/include/rt-utils.h index 68857f3..316b09c 100644 --- a/src/include/rt-utils.h +++ b/src/include/rt-utils.h @@ -8,8 +8,18 @@ int check_privs(void); char *get_debugfileprefix(void); +int mount_debugfs(char *); +int get_tracers(char ***); +int valid_tracer(char *); + +int setevent(char *event, char *val); +int event_enable(char *event); +int event_disable(char *event); +int event_enable_all(void); +int event_disable_all(void); void warn(char *fmt, ...); void fatal(char *fmt, ...); +void info(char *fmt, ...); #endif /* __RT_UTILS.H */ diff --git a/src/lib/rt-utils.c b/src/lib/rt-utils.c index da27a3a..ec71dbd 100644 --- a/src/lib/rt-utils.c +++ b/src/lib/rt-utils.c @@ -11,6 +11,11 @@ #include <string.h> #include <sched.h> #include <stdarg.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> #include "rt-utils.h" static char debugfileprefix[MAX_PATH]; @@ -23,33 +28,220 @@ char *get_debugfileprefix(void) char type[100]; FILE *fp; int size; + int found = 0; + struct stat s; if (debugfileprefix[0] != '\0') - return debugfileprefix; + goto out; + /* look in the "standard" mount point first */ + if ((stat("/sys/kernel/debug/tracing", &s) == 0) && S_ISDIR(s.st_mode)) { + strcpy(debugfileprefix, "/sys/kernel/debug/tracing/"); + goto out; + } + + /* now look in the "other standard" place */ + if ((stat("/debug/tracing", &s) == 0) && S_ISDIR(s.st_mode)) { + strcpy(debugfileprefix, "/debug/tracing/"); + goto out; + } + + /* oh well, parse /proc/mounts and see if it's there */ if ((fp = fopen("/proc/mounts","r")) == NULL) - return debugfileprefix; + goto out; while (fscanf(fp, "%*s %" STR(MAX_PATH) "s %99s %*s %*d %*d\n", debugfileprefix, type) == 2) { - if (strcmp(type, "debugfs") == 0) + if (strcmp(type, "debugfs") == 0) { + found = 1; + break; + } + /* stupid check for systemd-style autofs mount */ + if ((strcmp(debugfileprefix, "/sys/kernel/debug") == 0) && + (strcmp(type, "systemd") == 0)) { + found = 1; break; + } } fclose(fp); - if (strcmp(type, "debugfs") != 0) { + if (!found) { debugfileprefix[0] = '\0'; - return debugfileprefix; + goto out; } size = sizeof(debugfileprefix) - strlen(debugfileprefix); strncat(debugfileprefix, "/tracing/", size); +out: return debugfileprefix; } +int mount_debugfs(char *path) +{ + char *mountpoint = path; + char cmd[MAX_PATH]; + char *prefix; + int ret; + + /* if it's already mounted just return */ + prefix = get_debugfileprefix(); + if (strlen(prefix) != 0) { + info("debugfs mountpoint: %s\n", prefix); + return 0; + } + if (!mountpoint) + mountpoint = "/sys/kernel/debug"; + + sprintf(cmd, "mount -t debugfs debugfs %s", mountpoint); + ret = system(cmd); + if (ret != 0) { + fprintf(stderr, "Error mounting debugfs at %s: %s\n", mountpoint, strerror(errno)); + return -1; + } + return 0; + +} + +static char **tracer_list; +static char *tracer_buffer; +static int num_tracers; +#define CHUNKSZ 1024 + +/* + * return a list of the tracers configured into the running kernel + */ + +int get_tracers(char ***list) +{ + int ret; + FILE *fp; + char buffer[CHUNKSZ]; + char *prefix = get_debugfileprefix(); + char *tmpbuf = NULL; + char *ptr; + int tmpsz = 0; + + /* if we've already parse it, return what we have */ + if (tracer_list) { + *list = tracer_list; + return num_tracers; + } + + /* open the tracing file available_tracers */ + sprintf(buffer, "%savailable_tracers", prefix); + if ((fp = fopen(buffer, "r")) == NULL) + fatal ("Can't open %s for reading\n", buffer); + + /* allocate initial buffer */ + ptr = tmpbuf = malloc(CHUNKSZ); + if (ptr == NULL) + fatal("error allocating initial space for tracer list\n"); + + /* read in the list of available tracers */ + while((ret = fread(buffer, sizeof(char), CHUNKSZ, fp))) { + if ((ptr+ret+1) > (tmpbuf+tmpsz)) { + tmpbuf = realloc(tmpbuf, tmpsz + CHUNKSZ); + if (tmpbuf == NULL) + fatal("error allocating space for list of valid tracers\n"); + tmpsz += CHUNKSZ; + } + strncpy(ptr, buffer, ret); + ptr += ret; + } + fclose(fp); + if (tmpsz == 0) + fatal("error reading available tracers\n"); + + tracer_buffer = tmpbuf; + + /* get a buffer for the pointers to tracers */ + if (!(tracer_list = malloc(sizeof(char *)))) + fatal ("error allocatinging tracer list buffer\n"); + + /* parse the buffer */ + ptr = strtok(tmpbuf, " \t\n\r"); + do { + tracer_list[num_tracers++] = ptr; + tracer_list = realloc(tracer_list, sizeof(char*)*(num_tracers+1)); + tracer_list[num_tracers] = NULL; + } while ((ptr = strtok(NULL, " \t\n\r")) != NULL); + + /* return the list and number of tracers */ + *list = tracer_list; + return num_tracers; +} + + +/* + * return zero if tracername is not a valid tracer, non-zero if it is + */ + +int valid_tracer(char *tracername) +{ + char **list; + int ntracers; + int i; + + ntracers = get_tracers(&list); + if (ntracers == 0 || tracername == NULL) + return 0; + for (i = 0; i < ntracers; i++) + if (strncmp(list[i], tracername, strlen(list[i])) == 0) + return 1; + return 0; +} + +/* + * enable event tracepoint + */ +int setevent(char *event, char *val) +{ + char *prefix = get_debugfileprefix(); + char buffer[MAX_PATH]; + int fd; + int ret; + + sprintf(buffer, "%s%s", prefix, event); + if ((fd = open(buffer, O_WRONLY)) < 0) { + warn("unable to open %s\n", buffer); + return -1; + } + if ((ret = write(fd, val, strlen(val))) < 0) { + warn("unable to write %s to %s\n", val, buffer); + close(fd); + return -1; + } + close(fd); + return 0; +} + +int event_enable_all(void) +{ + return setevent("events/enable", "1"); +} + +int event_disable_all(void) +{ + return setevent("events/enable", "0"); +} + +int event_enable(char *event) +{ + char path[MAX_PATH]; + sprintf(path, "events/%s/enable", event); + return setevent(path, "1"); +} + +int event_disable(char *event) +{ + char path[MAX_PATH]; + sprintf(path, "events/%s/enable", event); + return setevent(path, "0"); +} + int check_privs(void) { int policy = sched_getscheduler(0); @@ -80,6 +272,16 @@ int check_privs(void) return sched_setscheduler(0, policy, &old_param); } +void info(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fputs("INFO: ", stderr); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + void warn(char *fmt, ...) { va_list ap; |