summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--debian/changelog6
-rw-r--r--debian/patches/debian_adapt_errormsg_on_failure_to_open_device2
-rw-r--r--debian/patches/debian_has_recent_glibc2
-rw-r--r--debian/patches/fix_comment_about_realtime_group.patch2
-rw-r--r--debian/patches/install_hwlatdetect_into_sbindir6
-rw-r--r--debian/patches/manpage_pip_stress.patch2
-rw-r--r--rt-tests.spec-in38
-rw-r--r--src/cyclictest/cyclictest.c222
-rw-r--r--src/hackbench/hackbench.c58
-rw-r--r--src/include/rt-utils.h10
-rw-r--r--src/lib/rt-utils.c212
12 files changed, 452 insertions, 118 deletions
diff --git a/Makefile b/Makefile
index 59438e9..4038dcc 100644
--- a/Makefile
+++ b/Makefile
@@ -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, &param)) {
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;