diff options
author | Clark Williams <williams@redhat.com> | 2009-12-21 10:27:18 -0600 |
---|---|---|
committer | Clark Williams <williams@redhat.com> | 2009-12-21 10:27:18 -0600 |
commit | 1c3c9e34d65b6774e9f56d9d49fdbe101d42dc6c (patch) | |
tree | e97090d7bc7dceb1634e6b82b03aea5988af47b8 | |
parent | ff74d0eb70973fb13811eeb17be8f596291a9d7c (diff) | |
download | rt-tests-1c3c9e34d65b6774e9f56d9d49fdbe101d42dc6c.tar.gz |
convert source back to unix text (was DOS text)
Somehow the last set of tests added got converted to DOS text
(CRLF line terminators). Change them back
Signed-off-by: Clark Williams <williams@redhat.com>
-rw-r--r-- | src/backfire/Makefile | 28 | ||||
-rw-r--r-- | src/backfire/backfire.c | 300 | ||||
-rw-r--r-- | src/backfire/sendme.c | 582 | ||||
-rw-r--r-- | src/backfire/version.h | 2 | ||||
-rw-r--r-- | src/ptsematest/Makefile | 32 | ||||
-rw-r--r-- | src/ptsematest/ptsematest.c | 846 | ||||
-rw-r--r-- | src/sigwaittest/Makefile | 34 | ||||
-rw-r--r-- | src/sigwaittest/sigwaittest.c | 1236 | ||||
-rw-r--r-- | src/svsematest/Makefile | 32 | ||||
-rw-r--r-- | src/svsematest/svsematest.c | 1408 |
10 files changed, 2250 insertions, 2250 deletions
diff --git a/src/backfire/Makefile b/src/backfire/Makefile index 33a0e02..b5d2b3e 100644 --- a/src/backfire/Makefile +++ b/src/backfire/Makefile @@ -1,14 +1,14 @@ -obj-m := backfire.o
-
-all: modules modules_install
- @echo Done
-
-modules:
- make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
-
-modules_install:
- make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules_install
-
-clean:
- make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
- @rm -f *.o Module.markers modules.order
+obj-m := backfire.o + +all: modules modules_install + @echo Done + +modules: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +modules_install: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules_install + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + @rm -f *.o Module.markers modules.order diff --git a/src/backfire/backfire.c b/src/backfire/backfire.c index 699031a..d737347 100644 --- a/src/backfire/backfire.c +++ b/src/backfire/backfire.c @@ -1,150 +1,150 @@ -/*
- * backfire - send signal back to caller
- *
- * Copyright (C) 2007 Carsten Emde <C.Emde@osadl.org>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#include <linux/module.h>
-
-#include <linux/sched.h>
-#include <linux/cpumask.h>
-#include <linux/time.h>
-#include <linux/smp_lock.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#define BACKFIRE_MINOR MISC_DYNAMIC_MINOR
-
-static spinlock_t backfire_state_lock = SPIN_LOCK_UNLOCKED;
-static int backfire_open_cnt; /* #times opened */
-static int backfire_open_mode; /* special open modes */
-static struct timeval sendtime; /* when the most recent signal was sent */
-#define BACKFIRE_WRITE 1 /* opened for writing (exclusive) */
-#define BACKFIRE_EXCL 2 /* opened with O_EXCL */
-
-/*
- * These are the file operation function for user access to /dev/backfire
- */
-static ssize_t
-backfire_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
- return snprintf(buf, count, "%d,%d\n", (int) sendtime.tv_sec,
- (int) sendtime.tv_usec);
-}
-
-static ssize_t
-backfire_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
- int signo;
- struct pid *pid;
-
- if (sscanf(buf, "%d", &signo) >= 1) {
- if (signo > 0 && signo < 32) {
- pid = get_pid(task_pid(current));
- do_gettimeofday(&sendtime);
- kill_pid(pid, signo, 1);
- } else
- printk(KERN_ERR "Invalid signal no. %d\n", signo);
- }
- return strlen(buf);
-}
-
-static int
-backfire_open(struct inode *inode, struct file *file)
-{
- spin_lock(&backfire_state_lock);
-
- if ((backfire_open_cnt && (file->f_flags & O_EXCL)) ||
- (backfire_open_mode & BACKFIRE_EXCL)) {
- spin_unlock(&backfire_state_lock);
- return -EBUSY;
- }
-
- if (file->f_flags & O_EXCL)
- backfire_open_mode |= BACKFIRE_EXCL;
- if (file->f_mode & 2)
- backfire_open_mode |= BACKFIRE_WRITE;
- backfire_open_cnt++;
-
- spin_unlock(&backfire_state_lock);
-
- return 0;
-}
-
-static int
-backfire_release(struct inode *inode, struct file *file)
-{
- spin_lock(&backfire_state_lock);
-
- backfire_open_cnt--;
-
- if (backfire_open_cnt == 1 && backfire_open_mode & BACKFIRE_EXCL)
- backfire_open_mode &= ~BACKFIRE_EXCL;
- if (file->f_mode & 2)
- backfire_open_mode &= ~BACKFIRE_WRITE;
-
- spin_unlock(&backfire_state_lock);
-
- return 0;
-}
-
-static struct file_operations backfire_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = backfire_open,
- .read = backfire_read,
- .write = backfire_write,
- .release = backfire_release,
-};
-
-static struct miscdevice backfire_dev = {
- BACKFIRE_MINOR,
- "backfire",
- &backfire_fops
-};
-
-static int __init backfire_init(void)
-{
- int ret;
-
- ret = misc_register(&backfire_dev);
- if (ret)
- printk(KERN_ERR "backfire: can't register dynamic misc device\n");
- else
- printk(KERN_INFO "backfire driver v__VERSION_STRING__ misc device %d\n",
- backfire_dev.minor);
- return ret;
-}
-
-static void __exit backfire_exit(void)
-{
- misc_deregister(&backfire_dev);
-}
-
-module_init(backfire_init);
-module_exit(backfire_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Carsten Emde <C.Emde@osadl.org>");
-MODULE_DESCRIPTION("Send signal back to caller");
+/* + * backfire - send signal back to caller + * + * Copyright (C) 2007 Carsten Emde <C.Emde@osadl.org> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <linux/module.h> + +#include <linux/sched.h> +#include <linux/cpumask.h> +#include <linux/time.h> +#include <linux/smp_lock.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/miscdevice.h> +#include <linux/proc_fs.h> +#include <linux/spinlock.h> + +#include <asm/uaccess.h> +#include <asm/system.h> + +#define BACKFIRE_MINOR MISC_DYNAMIC_MINOR + +static spinlock_t backfire_state_lock = SPIN_LOCK_UNLOCKED; +static int backfire_open_cnt; /* #times opened */ +static int backfire_open_mode; /* special open modes */ +static struct timeval sendtime; /* when the most recent signal was sent */ +#define BACKFIRE_WRITE 1 /* opened for writing (exclusive) */ +#define BACKFIRE_EXCL 2 /* opened with O_EXCL */ + +/* + * These are the file operation function for user access to /dev/backfire + */ +static ssize_t +backfire_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return snprintf(buf, count, "%d,%d\n", (int) sendtime.tv_sec, + (int) sendtime.tv_usec); +} + +static ssize_t +backfire_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + int signo; + struct pid *pid; + + if (sscanf(buf, "%d", &signo) >= 1) { + if (signo > 0 && signo < 32) { + pid = get_pid(task_pid(current)); + do_gettimeofday(&sendtime); + kill_pid(pid, signo, 1); + } else + printk(KERN_ERR "Invalid signal no. %d\n", signo); + } + return strlen(buf); +} + +static int +backfire_open(struct inode *inode, struct file *file) +{ + spin_lock(&backfire_state_lock); + + if ((backfire_open_cnt && (file->f_flags & O_EXCL)) || + (backfire_open_mode & BACKFIRE_EXCL)) { + spin_unlock(&backfire_state_lock); + return -EBUSY; + } + + if (file->f_flags & O_EXCL) + backfire_open_mode |= BACKFIRE_EXCL; + if (file->f_mode & 2) + backfire_open_mode |= BACKFIRE_WRITE; + backfire_open_cnt++; + + spin_unlock(&backfire_state_lock); + + return 0; +} + +static int +backfire_release(struct inode *inode, struct file *file) +{ + spin_lock(&backfire_state_lock); + + backfire_open_cnt--; + + if (backfire_open_cnt == 1 && backfire_open_mode & BACKFIRE_EXCL) + backfire_open_mode &= ~BACKFIRE_EXCL; + if (file->f_mode & 2) + backfire_open_mode &= ~BACKFIRE_WRITE; + + spin_unlock(&backfire_state_lock); + + return 0; +} + +static struct file_operations backfire_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = backfire_open, + .read = backfire_read, + .write = backfire_write, + .release = backfire_release, +}; + +static struct miscdevice backfire_dev = { + BACKFIRE_MINOR, + "backfire", + &backfire_fops +}; + +static int __init backfire_init(void) +{ + int ret; + + ret = misc_register(&backfire_dev); + if (ret) + printk(KERN_ERR "backfire: can't register dynamic misc device\n"); + else + printk(KERN_INFO "backfire driver v__VERSION_STRING__ misc device %d\n", + backfire_dev.minor); + return ret; +} + +static void __exit backfire_exit(void) +{ + misc_deregister(&backfire_dev); +} + +module_init(backfire_init); +module_exit(backfire_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Carsten Emde <C.Emde@osadl.org>"); +MODULE_DESCRIPTION("Send signal back to caller"); diff --git a/src/backfire/sendme.c b/src/backfire/sendme.c index 190dbf5..3736ddb 100644 --- a/src/backfire/sendme.c +++ b/src/backfire/sendme.c @@ -1,291 +1,291 @@ -/*
- * sendme.c
- *
- * Copyright (C) 2009 Carsten Emde <C.Emde@osadl.org>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-#define __USE_GNU
-#include <fcntl.h>
-#include <getopt.h>
-#include <signal.h>
-#include <sched.h>
-#include <string.h>
-#include <time.h>
-#include "rt-utils.h"
-
-#define _GNU_SOURCE
-#include <utmpx.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-
-#define USEC_PER_SEC 1000000
-#define NSEC_PER_SEC 1000000000
-
-#define SIGTEST SIGHUP
-
-enum {
- AFFINITY_UNSPECIFIED,
- AFFINITY_SPECIFIED,
- AFFINITY_USECURRENT
-};
-static int setaffinity = AFFINITY_UNSPECIFIED;
-
-static int affinity;
-static int tracelimit;
-static int priority;
-static int shutdown;
-static int max_cycles;
-static volatile struct timeval after;
-static int interval = 1000;
-
-static int kernvar(int mode, const char *name, char *value, size_t sizeofvalue)
-{
- char filename[128];
- char *fileprefix = get_debugfileprefix();
- int retval = 1;
- int path;
-
- strncpy(filename, fileprefix, sizeof(filename));
- strncat(filename, name, sizeof(filename) - strlen(fileprefix));
- path = open(filename, mode);
- if (path >= 0) {
- if (mode == O_RDONLY) {
- int got;
- if ((got = read(path, value, sizeofvalue)) > 0) {
- retval = 0;
- value[got-1] = '\0';
- }
- } else if (mode == O_WRONLY) {
- if (write(path, value, sizeofvalue) == sizeofvalue)
- retval = 0;
- }
- close(path);
- }
- return retval;
-}
-
-void signalhandler(int signo)
-{
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
- after = tv;
- if (signo == SIGINT || signo == SIGTERM)
- shutdown = 1;
-}
-
-void stop_tracing(void)
-{
- kernvar(O_WRONLY, "tracing_enabled", "0", 1);
-}
-
-static void display_help(void)
-{
- printf("sendme V %1.2f\n", VERSION_STRING);
- puts("Usage: sendme <options>");
- puts("Function: send a signal from driver to userspace");
- puts(
- "Options:\n"
- "-a [NUM] --affinity pin to current processor\n"
- " with NUM pin to processor NUM\n"
- "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n"
- "-i INTV --interval=INTV base interval of thread in us default=1000\n"
- "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n"
- "-p PRIO --prio=PRIO priority\n");
- exit(1);
-}
-
-static void process_options (int argc, char *argv[])
-{
- int error = 0;
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"affinity", optional_argument, NULL, 'a'},
- {"breaktrace", required_argument, NULL, 'b'},
- {"interval", required_argument, NULL, 'i'},
- {"loops", required_argument, NULL, 'l'},
- {"priority", required_argument, NULL, 'p'},
- {"help", no_argument, NULL, '?'},
- {NULL, 0, NULL, 0}
- };
- int c = getopt_long (argc, argv, "a::b:i:l:p:",
- long_options, &option_index);
- if (c == -1)
- break;
- switch (c) {
- case 'a':
- if (optarg != NULL) {
- affinity = atoi(optarg);
- setaffinity = AFFINITY_SPECIFIED;
- } else if (optind < argc && atoi(argv[optind])) {
- affinity = atoi(argv[optind]);
- setaffinity = AFFINITY_SPECIFIED;
- } else
- setaffinity = AFFINITY_USECURRENT;
- break;
- case 'b': tracelimit = atoi(optarg); break;
- case 'i': interval = atoi(optarg); break;
- case 'l': max_cycles = atoi(optarg); break;
- case 'p': priority = atoi(optarg); break;
- case '?': error = 1; break;
- }
- }
-
- if (setaffinity == AFFINITY_SPECIFIED) {
- if (affinity < 0)
- error = 1;
- if (affinity >= max_cpus) {
- fprintf(stderr, "ERROR: CPU #%d not found, only %d CPUs available\n",
- affinity, max_cpus);
- error = 1;
- }
- }
-
- if (priority < 0 || priority > 99)
- error = 1;
-
- if (error)
- display_help ();
-}
-
-int main(int argc, char *argv[])
-{
- int path;
- cpu_set_t mask;
- int policy = SCHED_FIFO;
- struct sched_param schedp;
- struct flock fl;
- int retval = 0;
-
- process_options(argc, argv);
-
- if (check_privs())
- return 1;
-
- if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
- perror("mlockall");
- return 1;
- }
-
- memset(&schedp, 0, sizeof(schedp));
- schedp.sched_priority = priority;
- sched_setscheduler(0, policy, &schedp);
-
- if (setaffinity != AFFINITY_UNSPECIFIED) {
- CPU_ZERO(&mask);
- if (setaffinity == AFFINITY_USECURRENT)
- affinity = sched_getcpu();
- CPU_SET(affinity, &mask);
- if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
- fprintf(stderr, "WARNING: Could not set CPU affinity "
- "to CPU #%d\n", affinity);
- }
-
- path = open("/dev/backfire", O_RDWR);
- if (path < 0) {
- fprintf(stderr, "ERROR: Could not access backfire device, "
- "try 'modprobe backfire'\n");
- return 1;
- }
- fl.l_type = F_WRLCK;
- fl.l_whence = SEEK_SET;
- fl.l_start = 0;
- fl.l_len = 1;
- if (fcntl(path, F_SETLK, &fl) == -1) {
- fprintf(stderr, "ERRROR: backfire device locked\n");
- retval = 1;
- } else {
- char sigtest[8];
- char timestamp[32];
- struct timeval before, sendtime, diff;
- unsigned int diffno = 0;
- unsigned int mindiff1 = UINT_MAX, maxdiff1 = 0;
- unsigned int mindiff2 = UINT_MAX, maxdiff2 = 0;
- double sumdiff1 = 0.0, sumdiff2 = 0.0;
-
- if (tracelimit)
- kernvar(O_WRONLY, "tracing_enabled", "1", 1);
-
- sprintf(sigtest, "%d", SIGTEST);
- signal(SIGTEST, signalhandler);
- signal(SIGINT, signalhandler);
- signal(SIGTERM, signalhandler);
-
- while (1) {
- struct timespec ts;
-
- ts.tv_sec = interval / USEC_PER_SEC;
- ts.tv_nsec = (interval % USEC_PER_SEC) * 1000;
-
- gettimeofday(&before, NULL);
- write(path, sigtest, strlen(sigtest));
- while (after.tv_sec == 0);
- read(path, timestamp, sizeof(timestamp));
- if (sscanf(timestamp, "%lu,%lu\n", &sendtime.tv_sec,
- &sendtime.tv_usec) != 2)
- break;
- diffno++;
- if(max_cycles && diffno >= max_cycles)
- shutdown = 1;
-
- printf("Samples: %8d\n", diffno);
- timersub(&sendtime, &before, &diff);
- if (diff.tv_usec < mindiff1)
- mindiff1 = diff.tv_usec;
- if (diff.tv_usec > maxdiff1)
- maxdiff1 = diff.tv_usec;
- sumdiff1 += (double) diff.tv_usec;
- printf("To: Min %4d, Cur %4d, Avg %4d, Max %4d\n",
- mindiff1, (int) diff.tv_usec,
- (int) ((sumdiff1 / diffno) + 0.5),
- maxdiff1);
-
- timersub(&after, &sendtime, &diff);
- if (diff.tv_usec < mindiff2)
- mindiff2 = diff.tv_usec;
- if (diff.tv_usec > maxdiff2)
- maxdiff2 = diff.tv_usec;
- sumdiff2 += (double) diff.tv_usec;
- printf("From: Min %4d, Cur %4d, Avg %4d, Max %4d\n",
- mindiff2, (int) diff.tv_usec,
- (int) ((sumdiff2 / diffno) + 0.5),
- maxdiff2);
- after.tv_sec = 0;
- if ((tracelimit && diff.tv_usec > tracelimit) ||
- shutdown) {
- if (tracelimit)
- stop_tracing();
- break;
- }
- nanosleep(&ts, NULL);
- printf("\033[3A");
- }
- }
-
- close(path);
- return retval;
-}
+/* + * sendme.c + * + * Copyright (C) 2009 Carsten Emde <C.Emde@osadl.org> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#define __USE_GNU +#include <fcntl.h> +#include <getopt.h> +#include <signal.h> +#include <sched.h> +#include <string.h> +#include <time.h> +#include "rt-utils.h" + +#define _GNU_SOURCE +#include <utmpx.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/mman.h> + +#define USEC_PER_SEC 1000000 +#define NSEC_PER_SEC 1000000000 + +#define SIGTEST SIGHUP + +enum { + AFFINITY_UNSPECIFIED, + AFFINITY_SPECIFIED, + AFFINITY_USECURRENT +}; +static int setaffinity = AFFINITY_UNSPECIFIED; + +static int affinity; +static int tracelimit; +static int priority; +static int shutdown; +static int max_cycles; +static volatile struct timeval after; +static int interval = 1000; + +static int kernvar(int mode, const char *name, char *value, size_t sizeofvalue) +{ + char filename[128]; + char *fileprefix = get_debugfileprefix(); + int retval = 1; + int path; + + strncpy(filename, fileprefix, sizeof(filename)); + strncat(filename, name, sizeof(filename) - strlen(fileprefix)); + path = open(filename, mode); + if (path >= 0) { + if (mode == O_RDONLY) { + int got; + if ((got = read(path, value, sizeofvalue)) > 0) { + retval = 0; + value[got-1] = '\0'; + } + } else if (mode == O_WRONLY) { + if (write(path, value, sizeofvalue) == sizeofvalue) + retval = 0; + } + close(path); + } + return retval; +} + +void signalhandler(int signo) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + after = tv; + if (signo == SIGINT || signo == SIGTERM) + shutdown = 1; +} + +void stop_tracing(void) +{ + kernvar(O_WRONLY, "tracing_enabled", "0", 1); +} + +static void display_help(void) +{ + printf("sendme V %1.2f\n", VERSION_STRING); + puts("Usage: sendme <options>"); + puts("Function: send a signal from driver to userspace"); + puts( + "Options:\n" + "-a [NUM] --affinity pin to current processor\n" + " with NUM pin to processor NUM\n" + "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n" + "-i INTV --interval=INTV base interval of thread in us default=1000\n" + "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n" + "-p PRIO --prio=PRIO priority\n"); + exit(1); +} + +static void process_options (int argc, char *argv[]) +{ + int error = 0; + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + + for (;;) { + int option_index = 0; + /** Options for getopt */ + static struct option long_options[] = { + {"affinity", optional_argument, NULL, 'a'}, + {"breaktrace", required_argument, NULL, 'b'}, + {"interval", required_argument, NULL, 'i'}, + {"loops", required_argument, NULL, 'l'}, + {"priority", required_argument, NULL, 'p'}, + {"help", no_argument, NULL, '?'}, + {NULL, 0, NULL, 0} + }; + int c = getopt_long (argc, argv, "a::b:i:l:p:", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'a': + if (optarg != NULL) { + affinity = atoi(optarg); + setaffinity = AFFINITY_SPECIFIED; + } else if (optind < argc && atoi(argv[optind])) { + affinity = atoi(argv[optind]); + setaffinity = AFFINITY_SPECIFIED; + } else + setaffinity = AFFINITY_USECURRENT; + break; + case 'b': tracelimit = atoi(optarg); break; + case 'i': interval = atoi(optarg); break; + case 'l': max_cycles = atoi(optarg); break; + case 'p': priority = atoi(optarg); break; + case '?': error = 1; break; + } + } + + if (setaffinity == AFFINITY_SPECIFIED) { + if (affinity < 0) + error = 1; + if (affinity >= max_cpus) { + fprintf(stderr, "ERROR: CPU #%d not found, only %d CPUs available\n", + affinity, max_cpus); + error = 1; + } + } + + if (priority < 0 || priority > 99) + error = 1; + + if (error) + display_help (); +} + +int main(int argc, char *argv[]) +{ + int path; + cpu_set_t mask; + int policy = SCHED_FIFO; + struct sched_param schedp; + struct flock fl; + int retval = 0; + + process_options(argc, argv); + + if (check_privs()) + return 1; + + if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { + perror("mlockall"); + return 1; + } + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = priority; + sched_setscheduler(0, policy, &schedp); + + if (setaffinity != AFFINITY_UNSPECIFIED) { + CPU_ZERO(&mask); + if (setaffinity == AFFINITY_USECURRENT) + affinity = sched_getcpu(); + CPU_SET(affinity, &mask); + if (sched_setaffinity(0, sizeof(mask), &mask) == -1) + fprintf(stderr, "WARNING: Could not set CPU affinity " + "to CPU #%d\n", affinity); + } + + path = open("/dev/backfire", O_RDWR); + if (path < 0) { + fprintf(stderr, "ERROR: Could not access backfire device, " + "try 'modprobe backfire'\n"); + return 1; + } + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 1; + if (fcntl(path, F_SETLK, &fl) == -1) { + fprintf(stderr, "ERRROR: backfire device locked\n"); + retval = 1; + } else { + char sigtest[8]; + char timestamp[32]; + struct timeval before, sendtime, diff; + unsigned int diffno = 0; + unsigned int mindiff1 = UINT_MAX, maxdiff1 = 0; + unsigned int mindiff2 = UINT_MAX, maxdiff2 = 0; + double sumdiff1 = 0.0, sumdiff2 = 0.0; + + if (tracelimit) + kernvar(O_WRONLY, "tracing_enabled", "1", 1); + + sprintf(sigtest, "%d", SIGTEST); + signal(SIGTEST, signalhandler); + signal(SIGINT, signalhandler); + signal(SIGTERM, signalhandler); + + while (1) { + struct timespec ts; + + ts.tv_sec = interval / USEC_PER_SEC; + ts.tv_nsec = (interval % USEC_PER_SEC) * 1000; + + gettimeofday(&before, NULL); + write(path, sigtest, strlen(sigtest)); + while (after.tv_sec == 0); + read(path, timestamp, sizeof(timestamp)); + if (sscanf(timestamp, "%lu,%lu\n", &sendtime.tv_sec, + &sendtime.tv_usec) != 2) + break; + diffno++; + if(max_cycles && diffno >= max_cycles) + shutdown = 1; + + printf("Samples: %8d\n", diffno); + timersub(&sendtime, &before, &diff); + if (diff.tv_usec < mindiff1) + mindiff1 = diff.tv_usec; + if (diff.tv_usec > maxdiff1) + maxdiff1 = diff.tv_usec; + sumdiff1 += (double) diff.tv_usec; + printf("To: Min %4d, Cur %4d, Avg %4d, Max %4d\n", + mindiff1, (int) diff.tv_usec, + (int) ((sumdiff1 / diffno) + 0.5), + maxdiff1); + + timersub(&after, &sendtime, &diff); + if (diff.tv_usec < mindiff2) + mindiff2 = diff.tv_usec; + if (diff.tv_usec > maxdiff2) + maxdiff2 = diff.tv_usec; + sumdiff2 += (double) diff.tv_usec; + printf("From: Min %4d, Cur %4d, Avg %4d, Max %4d\n", + mindiff2, (int) diff.tv_usec, + (int) ((sumdiff2 / diffno) + 0.5), + maxdiff2); + after.tv_sec = 0; + if ((tracelimit && diff.tv_usec > tracelimit) || + shutdown) { + if (tracelimit) + stop_tracing(); + break; + } + nanosleep(&ts, NULL); + printf("\033[3A"); + } + } + + close(path); + return retval; +} diff --git a/src/backfire/version.h b/src/backfire/version.h index cbe3858..669b388 100644 --- a/src/backfire/version.h +++ b/src/backfire/version.h @@ -1 +1 @@ -#define VERSION "0.5"
+#define VERSION "0.5" diff --git a/src/ptsematest/Makefile b/src/ptsematest/Makefile index c0bfa7c..dc12bc2 100644 --- a/src/ptsematest/Makefile +++ b/src/ptsematest/Makefile @@ -1,16 +1,16 @@ -CFLAGS += -Wall -O2
-LDFLAGS += -lpthread
-
-all: ptsematest
- @echo Done
-
-ptsematest.o: ptsematest.c
-
-ptsematest:
-
-clean:
- @rm -f *.o
-
-tar: clean
- @rm -f ptsematest
- $(shell bn=`basename $$PWD`; cd ..; tar -zcf $$bn.tgz $$bn)
+CFLAGS += -Wall -O2 +LDFLAGS += -lpthread + +all: ptsematest + @echo Done + +ptsematest.o: ptsematest.c + +ptsematest: + +clean: + @rm -f *.o + +tar: clean + @rm -f ptsematest + $(shell bn=`basename $$PWD`; cd ..; tar -zcf $$bn.tgz $$bn) diff --git a/src/ptsematest/ptsematest.c b/src/ptsematest/ptsematest.c index c4426f3..aaae92a 100644 --- a/src/ptsematest/ptsematest.c +++ b/src/ptsematest/ptsematest.c @@ -1,423 +1,423 @@ -/*
- * ptsematest.c
- *
- * Copyright (C) 2009 Carsten Emde <C.Emde@osadl.org>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-#include <linux/unistd.h>
-#include <utmpx.h>
-#include "rt-utils.h"
-
-#define __USE_GNU
-#include <pthread.h>
-
-#define gettid() syscall(__NR_gettid)
-
-#define USEC_PER_SEC 1000000
-
-enum {
- AFFINITY_UNSPECIFIED,
- AFFINITY_SPECIFIED,
- AFFINITY_USEALL
-};
-
-static pthread_mutex_t *testmutex;
-static pthread_mutex_t *syncmutex;
-
-struct params {
- int num;
- int cpu;
- int priority;
- int affinity;
- int sender;
- int samples;
- int max_cycles;
- int tracelimit;
- int tid;
- int shutdown;
- int stopped;
- struct timespec delay;
- unsigned int mindiff, maxdiff;
- double sumdiff;
- struct timeval unblocked, received, diff;
- pthread_t threadid;
- struct params *neighbor;
- char error[MAX_PATH * 2];
-};
-
-void *semathread(void *param)
-{
- int mustgetcpu = 0;
- int first = 1;
- struct params *par = param;
- cpu_set_t mask;
- int policy = SCHED_FIFO;
- struct sched_param schedp;
-
- memset(&schedp, 0, sizeof(schedp));
- schedp.sched_priority = par->priority;
- sched_setscheduler(0, policy, &schedp);
-
- if (par->cpu != -1) {
- CPU_ZERO(&mask);
- CPU_SET(par->cpu, &mask);
- if(sched_setaffinity(0, sizeof(mask), &mask) == -1)
- fprintf(stderr, "WARNING: Could not set CPU affinity "
- "to CPU #%d\n", par->cpu);
- } else
- mustgetcpu = 1;
-
- par->tid = gettid();
-
- while (!par->shutdown) {
- if (par->sender) {
- pthread_mutex_lock(&syncmutex[par->num]);
-
- /* Release lock: Start of latency measurement ... */
- gettimeofday(&par->unblocked, NULL);
- pthread_mutex_unlock(&testmutex[par->num]);
- par->samples++;
- if(par->max_cycles && par->samples >= par->max_cycles)
- par->shutdown = 1;
- if (mustgetcpu) {
- par->cpu = sched_getcpu();
- }
- } else {
- /* Receiver */
- if (!first) {
- pthread_mutex_lock(&syncmutex[par->num]);
- first = 1;
- }
- pthread_mutex_lock(&testmutex[par->num]);
-
- /* ... Got the lock: End of latency measurement */
- gettimeofday(&par->received, NULL);
- par->samples++;
- timersub(&par->received, &par->neighbor->unblocked,
- &par->diff);
-
- if (par->diff.tv_usec < par->mindiff)
- par->mindiff = par->diff.tv_usec;
- if (par->diff.tv_usec > par->maxdiff)
- par->maxdiff = par->diff.tv_usec;
- par->sumdiff += (double) par->diff.tv_usec;
- if (par->tracelimit && par->maxdiff > par->tracelimit) {
- char tracing_enabled_file[MAX_PATH];
-
- strcpy(tracing_enabled_file, get_debugfileprefix());
- strcat(tracing_enabled_file, "tracing_enabled");
- int tracing_enabled =
- open(tracing_enabled_file, O_WRONLY);
- if (tracing_enabled >= 0) {
- write(tracing_enabled, "0", 1);
- close(tracing_enabled);
- } else
- snprintf(par->error, sizeof(par->error),
- "Could not access %s\n",
- tracing_enabled_file);
- par->shutdown = 1;
- par->neighbor->shutdown = 1;
- }
-
- if (par->max_cycles && par->samples >= par->max_cycles)
- par->shutdown = 1;
- if (mustgetcpu) {
- par->cpu = sched_getcpu();
- }
- nanosleep(&par->delay, NULL);
- pthread_mutex_unlock(&syncmutex[par->num]);
- }
- }
- par->stopped = 1;
- return NULL;
-}
-
-
-static void display_help(void)
-{
- printf("ptsematest V %1.2f\n", VERSION_STRING);
- puts("Usage: ptsematest <options>");
- puts("Function: test POSIX threads mutex latency");
- puts(
- "Options:\n"
- "-a [NUM] --affinity run thread #N on processor #N, if possible\n"
- " with NUM pin all threads to the processor NUM\n"
- "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n"
- "-d DIST --distance=DIST distance of thread intervals in us default=500\n"
- "-i INTV --interval=INTV base interval of thread in us default=1000\n"
- "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n"
- "-p PRIO --prio=PRIO priority\n"
- "-t --threads one thread per available processor\n"
- "-t [NUM] --threads=NUM number of threads:\n"
- " without NUM, threads = max_cpus\n"
- " without -t default = 1\n");
- exit(1);
-}
-
-
-static int setaffinity = AFFINITY_UNSPECIFIED;
-static int affinity;
-static int tracelimit;
-static int priority;
-static int num_threads = 1;
-static int max_cycles;
-static int interval = 1000;
-static int distance = 500;
-
-static void process_options (int argc, char *argv[])
-{
- int error = 0;
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"affinity", optional_argument, NULL, 'a'},
- {"breaktrace", required_argument, NULL, 'b'},
- {"distance", required_argument, NULL, 'd'},
- {"interval", required_argument, NULL, 'i'},
- {"loops", required_argument, NULL, 'l'},
- {"priority", required_argument, NULL, 'p'},
- {"threads", optional_argument, NULL, 't'},
- {"help", no_argument, NULL, '?'},
- {NULL, 0, NULL, 0}
- };
- int c = getopt_long (argc, argv, "a::b:d:i:l:p:t::",
- long_options, &option_index);
- if (c == -1)
- break;
- switch (c) {
- case 'a':
- if (optarg != NULL) {
- affinity = atoi(optarg);
- setaffinity = AFFINITY_SPECIFIED;
- } else if (optind<argc && atoi(argv[optind])) {
- affinity = atoi(argv[optind]);
- setaffinity = AFFINITY_SPECIFIED;
- } else {
- setaffinity = AFFINITY_USEALL;
- }
- break;
- case 'b': tracelimit = atoi(optarg); break;
- case 'd': distance = atoi(optarg); break;
- case 'i': interval = atoi(optarg); break;
- case 'l': max_cycles = atoi(optarg); break;
- case 'p': priority = atoi(optarg); break;
- case 't':
- if (optarg != NULL)
- num_threads = atoi(optarg);
- else if (optind<argc && atoi(argv[optind]))
- num_threads = atoi(argv[optind]);
- else
- num_threads = max_cpus;
- break;
- case '?': error = 1; break;
- }
- }
-
- if (setaffinity == AFFINITY_SPECIFIED) {
- if (affinity < 0)
- error = 1;
- if (affinity >= max_cpus) {
- fprintf(stderr, "ERROR: CPU #%d not found, only %d CPUs available\n",
- affinity, max_cpus);
- error = 1;
- }
- }
-
- if (num_threads < 0 || num_threads > 255)
- error = 1;
-
- if (priority < 0 || priority > 99)
- error = 1;
-
- if (num_threads < 1)
- error = 1;
-
- if (error)
- display_help ();
-}
-
-
-static int volatile shutdown;
-
-static void sighand(int sig)
-{
- shutdown = 1;
-}
-
-int main(int argc, char *argv[])
-{
- int i;
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
- int oldsamples = 1;
- struct params *receiver = NULL;
- struct params *sender = NULL;
- sigset_t sigset;
- struct timespec maindelay;
-
- process_options(argc, argv);
-
- if (check_privs())
- return 1;
-
- if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
- perror("mlockall");
- return 1;
- }
-
- signal(SIGINT, sighand);
- signal(SIGTERM, sighand);
-
- receiver = calloc(num_threads, sizeof(struct params));
- sender = calloc(num_threads, sizeof(struct params));
- if (receiver == NULL || sender == NULL)
- goto nomem;
-
- testmutex = (pthread_mutex_t *) calloc(num_threads, sizeof(pthread_mutex_t));
- syncmutex = (pthread_mutex_t *) calloc(num_threads, sizeof(pthread_mutex_t));
- if (testmutex == NULL || syncmutex == NULL)
- goto nomem;
-
- for (i = 0; i < num_threads; i++) {
- receiver[i].mindiff = UINT_MAX;
- receiver[i].maxdiff = 0;
- receiver[i].sumdiff = 0.0;
-
-
- pthread_mutex_init(&testmutex[i], NULL);
- pthread_mutex_init(&syncmutex[i], NULL);
-
- /* Wait on first attempt */
- pthread_mutex_lock(&testmutex[i]);
-
- receiver[i].num = i;
- receiver[i].cpu = i;
- switch (setaffinity) {
- case AFFINITY_UNSPECIFIED: receiver[i].cpu = -1; break;
- case AFFINITY_SPECIFIED: receiver[i].cpu = affinity; break;
- case AFFINITY_USEALL: receiver[i].cpu = i % max_cpus; break;
- }
- receiver[i].priority = priority;
- receiver[i].tracelimit = tracelimit;
- if (priority > 0)
- priority--;
- receiver[i].delay.tv_sec = interval / USEC_PER_SEC;
- receiver[i].delay.tv_nsec = (interval % USEC_PER_SEC) * 1000;
- interval += distance;
- receiver[i].max_cycles = max_cycles;
- receiver[i].sender = 0;
- receiver[i].neighbor = &sender[i];
- pthread_create(&receiver[i].threadid, NULL, semathread, &receiver[i]);
- memcpy(&sender[i], &receiver[i], sizeof(receiver[0]));
- sender[i].sender = 1;
- sender[i].neighbor = &receiver[i];
- pthread_create(&sender[i].threadid, NULL, semathread, &sender[i]);
- }
-
- maindelay.tv_sec = 0;
- maindelay.tv_nsec = 50000000; /* 50 ms */
-
- while (!shutdown) {
- int printed;
- int errorlines = 0;
-
- for (i = 0; i < num_threads; i++)
- shutdown |= receiver[i].shutdown | sender[i].shutdown;
-
- if (receiver[0].samples > oldsamples || shutdown) {
- for (i = 0; i < num_threads; i++) {
- printf("#%1d: ID%d, P%d, CPU%d, I%ld; #%1d: ID%d, P%d, CPU%d, Cycles %d\n",
- i*2, receiver[i].tid, receiver[i].priority, receiver[i].cpu,
- receiver[i].delay.tv_nsec / 1000,
- i*2+1, sender[i].tid, sender[i].priority, sender[i].cpu,
- sender[i].samples);
- }
- for (i = 0; i < num_threads; i++) {
- printf("#%d -> #%d, Min %4d, Cur %4d, Avg %4d, Max %4d\n",
- i*2+1, i*2,
- receiver[i].mindiff, (int) receiver[i].diff.tv_usec,
- (int) ((receiver[i].sumdiff / receiver[i].samples) + 0.5),
- receiver[i].maxdiff);
- if (receiver[i].error[0] != '\0') {
- printf(receiver[i].error);
- errorlines++;
- receiver[i].error[0] = '\0';
- }
- if (sender[i].error[0] != '\0') {
- printf(sender[i].error);
- errorlines++;
- receiver[i].error[0] = '\0';
- }
- }
- printed = 1;
- } else
- printed = 0;
-
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGTERM);
- sigaddset(&sigset, SIGINT);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- nanosleep(&maindelay, NULL);
-
- sigemptyset(&sigset);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- if (printed && !shutdown)
- printf("\033[%dA", num_threads*2 + errorlines);
- }
-
- for (i = 0; i < num_threads; i++) {
- receiver[i].shutdown = 1;
- sender[i].shutdown = 1;
- pthread_mutex_unlock(&testmutex[i]);
- pthread_mutex_unlock(&syncmutex[i]);
- }
- nanosleep(&receiver[0].delay, NULL);
-
- for (i = 0; i < num_threads; i++) {
- if (!receiver[i].stopped)
- pthread_kill(receiver[i].threadid, SIGTERM);
- if (!sender[i].stopped)
- pthread_kill(sender[i].threadid, SIGTERM);
- }
-
- for (i = 0; i < num_threads; i++) {
- pthread_mutex_destroy(&testmutex[i]);
- pthread_mutex_destroy(&syncmutex[i]);
- }
-
- nomem:
-
- return 0;
-}
+/* + * ptsematest.c + * + * Copyright (C) 2009 Carsten Emde <C.Emde@osadl.org> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <fcntl.h> +#include <getopt.h> +#include <signal.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <linux/unistd.h> +#include <utmpx.h> +#include "rt-utils.h" + +#define __USE_GNU +#include <pthread.h> + +#define gettid() syscall(__NR_gettid) + +#define USEC_PER_SEC 1000000 + +enum { + AFFINITY_UNSPECIFIED, + AFFINITY_SPECIFIED, + AFFINITY_USEALL +}; + +static pthread_mutex_t *testmutex; +static pthread_mutex_t *syncmutex; + +struct params { + int num; + int cpu; + int priority; + int affinity; + int sender; + int samples; + int max_cycles; + int tracelimit; + int tid; + int shutdown; + int stopped; + struct timespec delay; + unsigned int mindiff, maxdiff; + double sumdiff; + struct timeval unblocked, received, diff; + pthread_t threadid; + struct params *neighbor; + char error[MAX_PATH * 2]; +}; + +void *semathread(void *param) +{ + int mustgetcpu = 0; + int first = 1; + struct params *par = param; + cpu_set_t mask; + int policy = SCHED_FIFO; + struct sched_param schedp; + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = par->priority; + sched_setscheduler(0, policy, &schedp); + + if (par->cpu != -1) { + CPU_ZERO(&mask); + CPU_SET(par->cpu, &mask); + if(sched_setaffinity(0, sizeof(mask), &mask) == -1) + fprintf(stderr, "WARNING: Could not set CPU affinity " + "to CPU #%d\n", par->cpu); + } else + mustgetcpu = 1; + + par->tid = gettid(); + + while (!par->shutdown) { + if (par->sender) { + pthread_mutex_lock(&syncmutex[par->num]); + + /* Release lock: Start of latency measurement ... */ + gettimeofday(&par->unblocked, NULL); + pthread_mutex_unlock(&testmutex[par->num]); + par->samples++; + if(par->max_cycles && par->samples >= par->max_cycles) + par->shutdown = 1; + if (mustgetcpu) { + par->cpu = sched_getcpu(); + } + } else { + /* Receiver */ + if (!first) { + pthread_mutex_lock(&syncmutex[par->num]); + first = 1; + } + pthread_mutex_lock(&testmutex[par->num]); + + /* ... Got the lock: End of latency measurement */ + gettimeofday(&par->received, NULL); + par->samples++; + timersub(&par->received, &par->neighbor->unblocked, + &par->diff); + + if (par->diff.tv_usec < par->mindiff) + par->mindiff = par->diff.tv_usec; + if (par->diff.tv_usec > par->maxdiff) + par->maxdiff = par->diff.tv_usec; + par->sumdiff += (double) par->diff.tv_usec; + if (par->tracelimit && par->maxdiff > par->tracelimit) { + char tracing_enabled_file[MAX_PATH]; + + strcpy(tracing_enabled_file, get_debugfileprefix()); + strcat(tracing_enabled_file, "tracing_enabled"); + int tracing_enabled = + open(tracing_enabled_file, O_WRONLY); + if (tracing_enabled >= 0) { + write(tracing_enabled, "0", 1); + close(tracing_enabled); + } else + snprintf(par->error, sizeof(par->error), + "Could not access %s\n", + tracing_enabled_file); + par->shutdown = 1; + par->neighbor->shutdown = 1; + } + + if (par->max_cycles && par->samples >= par->max_cycles) + par->shutdown = 1; + if (mustgetcpu) { + par->cpu = sched_getcpu(); + } + nanosleep(&par->delay, NULL); + pthread_mutex_unlock(&syncmutex[par->num]); + } + } + par->stopped = 1; + return NULL; +} + + +static void display_help(void) +{ + printf("ptsematest V %1.2f\n", VERSION_STRING); + puts("Usage: ptsematest <options>"); + puts("Function: test POSIX threads mutex latency"); + puts( + "Options:\n" + "-a [NUM] --affinity run thread #N on processor #N, if possible\n" + " with NUM pin all threads to the processor NUM\n" + "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n" + "-d DIST --distance=DIST distance of thread intervals in us default=500\n" + "-i INTV --interval=INTV base interval of thread in us default=1000\n" + "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n" + "-p PRIO --prio=PRIO priority\n" + "-t --threads one thread per available processor\n" + "-t [NUM] --threads=NUM number of threads:\n" + " without NUM, threads = max_cpus\n" + " without -t default = 1\n"); + exit(1); +} + + +static int setaffinity = AFFINITY_UNSPECIFIED; +static int affinity; +static int tracelimit; +static int priority; +static int num_threads = 1; +static int max_cycles; +static int interval = 1000; +static int distance = 500; + +static void process_options (int argc, char *argv[]) +{ + int error = 0; + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + + for (;;) { + int option_index = 0; + /** Options for getopt */ + static struct option long_options[] = { + {"affinity", optional_argument, NULL, 'a'}, + {"breaktrace", required_argument, NULL, 'b'}, + {"distance", required_argument, NULL, 'd'}, + {"interval", required_argument, NULL, 'i'}, + {"loops", required_argument, NULL, 'l'}, + {"priority", required_argument, NULL, 'p'}, + {"threads", optional_argument, NULL, 't'}, + {"help", no_argument, NULL, '?'}, + {NULL, 0, NULL, 0} + }; + int c = getopt_long (argc, argv, "a::b:d:i:l:p:t::", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'a': + if (optarg != NULL) { + affinity = atoi(optarg); + setaffinity = AFFINITY_SPECIFIED; + } else if (optind<argc && atoi(argv[optind])) { + affinity = atoi(argv[optind]); + setaffinity = AFFINITY_SPECIFIED; + } else { + setaffinity = AFFINITY_USEALL; + } + break; + case 'b': tracelimit = atoi(optarg); break; + case 'd': distance = atoi(optarg); break; + case 'i': interval = atoi(optarg); break; + case 'l': max_cycles = atoi(optarg); break; + case 'p': priority = atoi(optarg); break; + case 't': + if (optarg != NULL) + num_threads = atoi(optarg); + else if (optind<argc && atoi(argv[optind])) + num_threads = atoi(argv[optind]); + else + num_threads = max_cpus; + break; + case '?': error = 1; break; + } + } + + if (setaffinity == AFFINITY_SPECIFIED) { + if (affinity < 0) + error = 1; + if (affinity >= max_cpus) { + fprintf(stderr, "ERROR: CPU #%d not found, only %d CPUs available\n", + affinity, max_cpus); + error = 1; + } + } + + if (num_threads < 0 || num_threads > 255) + error = 1; + + if (priority < 0 || priority > 99) + error = 1; + + if (num_threads < 1) + error = 1; + + if (error) + display_help (); +} + + +static int volatile shutdown; + +static void sighand(int sig) +{ + shutdown = 1; +} + +int main(int argc, char *argv[]) +{ + int i; + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + int oldsamples = 1; + struct params *receiver = NULL; + struct params *sender = NULL; + sigset_t sigset; + struct timespec maindelay; + + process_options(argc, argv); + + if (check_privs()) + return 1; + + if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { + perror("mlockall"); + return 1; + } + + signal(SIGINT, sighand); + signal(SIGTERM, sighand); + + receiver = calloc(num_threads, sizeof(struct params)); + sender = calloc(num_threads, sizeof(struct params)); + if (receiver == NULL || sender == NULL) + goto nomem; + + testmutex = (pthread_mutex_t *) calloc(num_threads, sizeof(pthread_mutex_t)); + syncmutex = (pthread_mutex_t *) calloc(num_threads, sizeof(pthread_mutex_t)); + if (testmutex == NULL || syncmutex == NULL) + goto nomem; + + for (i = 0; i < num_threads; i++) { + receiver[i].mindiff = UINT_MAX; + receiver[i].maxdiff = 0; + receiver[i].sumdiff = 0.0; + + + pthread_mutex_init(&testmutex[i], NULL); + pthread_mutex_init(&syncmutex[i], NULL); + + /* Wait on first attempt */ + pthread_mutex_lock(&testmutex[i]); + + receiver[i].num = i; + receiver[i].cpu = i; + switch (setaffinity) { + case AFFINITY_UNSPECIFIED: receiver[i].cpu = -1; break; + case AFFINITY_SPECIFIED: receiver[i].cpu = affinity; break; + case AFFINITY_USEALL: receiver[i].cpu = i % max_cpus; break; + } + receiver[i].priority = priority; + receiver[i].tracelimit = tracelimit; + if (priority > 0) + priority--; + receiver[i].delay.tv_sec = interval / USEC_PER_SEC; + receiver[i].delay.tv_nsec = (interval % USEC_PER_SEC) * 1000; + interval += distance; + receiver[i].max_cycles = max_cycles; + receiver[i].sender = 0; + receiver[i].neighbor = &sender[i]; + pthread_create(&receiver[i].threadid, NULL, semathread, &receiver[i]); + memcpy(&sender[i], &receiver[i], sizeof(receiver[0])); + sender[i].sender = 1; + sender[i].neighbor = &receiver[i]; + pthread_create(&sender[i].threadid, NULL, semathread, &sender[i]); + } + + maindelay.tv_sec = 0; + maindelay.tv_nsec = 50000000; /* 50 ms */ + + while (!shutdown) { + int printed; + int errorlines = 0; + + for (i = 0; i < num_threads; i++) + shutdown |= receiver[i].shutdown | sender[i].shutdown; + + if (receiver[0].samples > oldsamples || shutdown) { + for (i = 0; i < num_threads; i++) { + printf("#%1d: ID%d, P%d, CPU%d, I%ld; #%1d: ID%d, P%d, CPU%d, Cycles %d\n", + i*2, receiver[i].tid, receiver[i].priority, receiver[i].cpu, + receiver[i].delay.tv_nsec / 1000, + i*2+1, sender[i].tid, sender[i].priority, sender[i].cpu, + sender[i].samples); + } + for (i = 0; i < num_threads; i++) { + printf("#%d -> #%d, Min %4d, Cur %4d, Avg %4d, Max %4d\n", + i*2+1, i*2, + receiver[i].mindiff, (int) receiver[i].diff.tv_usec, + (int) ((receiver[i].sumdiff / receiver[i].samples) + 0.5), + receiver[i].maxdiff); + if (receiver[i].error[0] != '\0') { + printf(receiver[i].error); + errorlines++; + receiver[i].error[0] = '\0'; + } + if (sender[i].error[0] != '\0') { + printf(sender[i].error); + errorlines++; + receiver[i].error[0] = '\0'; + } + } + printed = 1; + } else + printed = 0; + + sigemptyset(&sigset); + sigaddset(&sigset, SIGTERM); + sigaddset(&sigset, SIGINT); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + nanosleep(&maindelay, NULL); + + sigemptyset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + if (printed && !shutdown) + printf("\033[%dA", num_threads*2 + errorlines); + } + + for (i = 0; i < num_threads; i++) { + receiver[i].shutdown = 1; + sender[i].shutdown = 1; + pthread_mutex_unlock(&testmutex[i]); + pthread_mutex_unlock(&syncmutex[i]); + } + nanosleep(&receiver[0].delay, NULL); + + for (i = 0; i < num_threads; i++) { + if (!receiver[i].stopped) + pthread_kill(receiver[i].threadid, SIGTERM); + if (!sender[i].stopped) + pthread_kill(sender[i].threadid, SIGTERM); + } + + for (i = 0; i < num_threads; i++) { + pthread_mutex_destroy(&testmutex[i]); + pthread_mutex_destroy(&syncmutex[i]); + } + + nomem: + + return 0; +} diff --git a/src/sigwaittest/Makefile b/src/sigwaittest/Makefile index 521daeb..697e3d5 100644 --- a/src/sigwaittest/Makefile +++ b/src/sigwaittest/Makefile @@ -1,17 +1,17 @@ -CFLAGS += -Wall -O2
-LDFLAGS += -lpthread -lrt
-
-all: sigwaittest
- @echo Done
-
-sigwaittest.o: sigwaittest.c
-
-sigwaittest:
-
-clean:
- @rm -f *.o
-
-tar: clean
- @rm -f sigwaittest
- $(shell bn=`basename $$PWD`; cd ..; tar -zcf $$bn.tgz $$bn)
-
+CFLAGS += -Wall -O2 +LDFLAGS += -lpthread -lrt + +all: sigwaittest + @echo Done + +sigwaittest.o: sigwaittest.c + +sigwaittest: + +clean: + @rm -f *.o + +tar: clean + @rm -f sigwaittest + $(shell bn=`basename $$PWD`; cd ..; tar -zcf $$bn.tgz $$bn) + diff --git a/src/sigwaittest/sigwaittest.c b/src/sigwaittest/sigwaittest.c index 740e13d..adb51cf 100644 --- a/src/sigwaittest/sigwaittest.c +++ b/src/sigwaittest/sigwaittest.c @@ -1,618 +1,618 @@ -/*
- * sigwaittest.c
- *
- * Copyright (C) 2009 Carsten Emde <C.Emde@osadl.org>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <getopt.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <utmpx.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <linux/unistd.h>
-#include <utmpx.h>
-#include "rt-utils.h"
-
-#define __USE_GNU
-#include <pthread.h>
-
-#define gettid() syscall(__NR_gettid)
-
-#define USEC_PER_SEC 1000000
-
-enum {
- AFFINITY_UNSPECIFIED,
- AFFINITY_SPECIFIED,
- AFFINITY_USEALL
-};
-
-struct params {
- int num;
- int num_threads;
- int cpu;
- int priority;
- int affinity;
- int sender;
- int samples;
- int max_cycles;
- int tracelimit;
- int tid;
- pid_t pid;
- int shutdown;
- int stopped;
- struct timespec delay;
- unsigned int mindiff, maxdiff;
- double sumdiff;
- struct timeval unblocked, received, diff;
- pthread_t threadid;
- struct params *neighbor;
- char error[MAX_PATH * 2];
-};
-
-static int mustfork;
-static int wasforked;
-static int wasforked_sender = -1;
-static int wasforked_threadno = -1;
-static int tracelimit;
-
-void *semathread(void *param)
-{
- int mustgetcpu = 0;
- struct params *par = param;
- cpu_set_t mask;
- int policy = SCHED_FIFO;
- struct sched_param schedp;
-
- memset(&schedp, 0, sizeof(schedp));
- schedp.sched_priority = par->priority;
- sched_setscheduler(0, policy, &schedp);
-
- if (par->cpu != -1) {
- CPU_ZERO(&mask);
- CPU_SET(par->cpu, &mask);
- if(sched_setaffinity(0, sizeof(mask), &mask) == -1)
- fprintf(stderr, "WARNING: Could not set CPU affinity "
- "to CPU #%d\n", par->cpu);
- } else {
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
- if (max_cpus > 1)
- mustgetcpu = 1;
- else
- par->cpu = 0;
- }
-
- if (!wasforked)
- par->tid = gettid();
-
- while (!par->shutdown) {
- int sig;
- int first = 1;
- sigset_t sigset;
- struct params *neighbor = NULL;
-
- if (par->sender) {
- if (wasforked)
- neighbor = par - par->num_threads;
- else
- neighbor = par->neighbor;
- if (first) {
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGUSR1);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
- first = 0;
- }
-
- /* Sending signal: Start of latency measurement ... */
- gettimeofday(&par->unblocked, NULL);
- if (wasforked)
- kill(neighbor->pid, SIGUSR2);
- else
- pthread_kill(neighbor->threadid, SIGUSR2);
- par->samples++;
- if(par->max_cycles && par->samples >= par->max_cycles)
- par->shutdown = 1;
-
- if (mustgetcpu) {
- par->cpu = sched_getcpu();
- }
- sigwait(&sigset, &sig);
- } else {
- /* Receiver */
- if (wasforked)
- neighbor = par + par->num_threads;
- else
- neighbor = par->neighbor;
- if (first) {
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGUSR2);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
- first = 0;
- }
- sigwait(&sigset, &sig);
-
- /* ... Signal received: End of latency measurement */
- gettimeofday(&par->received, NULL);
- par->samples++;
- if (par->max_cycles && par->samples >= par->max_cycles)
- par->shutdown = 1;
-
- if (mustgetcpu) {
- par->cpu = sched_getcpu();
- }
- /*
- * Latency is the time spent between sending and
- * receiving the signal.
- */
- timersub(&par->received, &neighbor->unblocked,
- &par->diff);
-
- if (par->diff.tv_usec < par->mindiff)
- par->mindiff = par->diff.tv_usec;
- if (par->diff.tv_usec > par->maxdiff)
- par->maxdiff = par->diff.tv_usec;
- par->sumdiff += (double) par->diff.tv_usec;
- if (par->tracelimit && par->maxdiff > par->tracelimit) {
- char tracing_enabled_file[MAX_PATH];
-
- strcpy(tracing_enabled_file, get_debugfileprefix());
- strcat(tracing_enabled_file, "tracing_enabled");
- int tracing_enabled =
- open(tracing_enabled_file, O_WRONLY);
- if (tracing_enabled >= 0) {
- write(tracing_enabled, "0", 1);
- close(tracing_enabled);
- } else
- snprintf(par->error, sizeof(par->error),
- "Could not access %s\n",
- tracing_enabled_file);
- par->shutdown = 1;
- neighbor->shutdown = 1;
- }
-
- nanosleep(&par->delay, NULL);
-
- if (wasforked)
- kill(neighbor->pid, SIGUSR1);
- else
- pthread_kill(neighbor->threadid, SIGUSR1);
- }
- }
- par->stopped = 1;
- return NULL;
-}
-
-
-static void display_help(void)
-{
- printf("sigwaittest V %1.2f\n", VERSION_STRING);
- puts("Usage: sigwaittest <options>");
- puts("Function: test sigwait() latency");
- puts(
- "Options:\n"
- "-a [NUM] --affinity run thread #N on processor #N, if possible\n"
- " with NUM pin all threads to the processor NUM\n"
- "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n"
- "-d DIST --distance=DIST distance of thread intervals in us default=500\n"
- "-f --fork fork new processes instead of creating threads\n"
- "-i INTV --interval=INTV base interval of thread in us default=1000\n"
- "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n"
- "-p PRIO --prio=PRIO priority\n"
- "-t --threads one thread per available processor\n"
- "-t [NUM] --threads=NUM number of threads:\n"
- " without NUM, threads = max_cpus\n"
- " without -t default = 1\n");
- exit(1);
-}
-
-
-static int setaffinity = AFFINITY_UNSPECIFIED;
-static int affinity;
-static int priority;
-static int num_threads = 1;
-static int max_cycles;
-static int interval = 1000;
-static int distance = 500;
-
-static void process_options (int argc, char *argv[])
-{
- int error = 0;
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
- int thistracelimit = 0;
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"affinity", optional_argument, NULL, 'a'},
- {"breaktrace", required_argument, NULL, 'b'},
- {"distance", required_argument, NULL, 'd'},
- {"fork", optional_argument, NULL, 'f'},
- {"interval", required_argument, NULL, 'i'},
- {"loops", required_argument, NULL, 'l'},
- {"priority", required_argument, NULL, 'p'},
- {"threads", optional_argument, NULL, 't'},
- {"help", no_argument, NULL, '?'},
- {NULL, 0, NULL, 0}
- };
- int c = getopt_long (argc, argv, "a::b:d:f::i:l:p:t::",
- long_options, &option_index);
- if (c == -1)
- break;
- switch (c) {
- case 'a':
- if (optarg != NULL) {
- affinity = atoi(optarg);
- setaffinity = AFFINITY_SPECIFIED;
- } else if (optind<argc && atoi(argv[optind])) {
- affinity = atoi(argv[optind]);
- setaffinity = AFFINITY_SPECIFIED;
- } else {
- setaffinity = AFFINITY_USEALL;
- }
- break;
- case 'b': thistracelimit = atoi(optarg); break;
- case 'd': distance = atoi(optarg); break;
- case 'f':
- if (optarg != NULL) {
- wasforked = 1;
- if (optarg[0] == 's')
- wasforked_sender = 1;
- else if (optarg[0] == 'r')
- wasforked_sender = 0;
- wasforked_threadno = atoi(optarg+1);
- } else
- mustfork = 1;
- break;
- case 'i': interval = atoi(optarg); break;
- case 'l': max_cycles = atoi(optarg); break;
- case 'p': priority = atoi(optarg); break;
- case 't':
- if (optarg != NULL)
- num_threads = atoi(optarg);
- else if (optind<argc && atoi(argv[optind]))
- num_threads = atoi(argv[optind]);
- else
- num_threads = max_cpus;
- break;
- case '?': error = 1; break;
- }
- }
-
- if (!wasforked) {
- if (setaffinity == AFFINITY_SPECIFIED) {
- if (affinity < 0)
- error = 1;
- if (affinity >= max_cpus) {
- fprintf(stderr, "ERROR: CPU #%d not found, "
- "only %d CPUs available\n",
- affinity, max_cpus);
- error = 1;
- }
- }
-
- if (num_threads < 1 || num_threads > 255)
- error = 1;
-
- if (priority < 0 || priority > 99)
- error = 1;
-
- tracelimit = thistracelimit;
- }
- if (error)
- display_help ();
-}
-
-
-static int volatile mustshutdown;
-
-static void sighand(int sig)
-{
- mustshutdown = 1;
-}
-
-
-int main(int argc, char *argv[])
-{
- int i, totalsize = 0;
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
- int oldsamples = 1;
- struct params *receiver = NULL;
- struct params *sender = NULL;
- sigset_t sigset;
- void *param = NULL;
- char f_opt[8];
- struct timespec launchdelay, maindelay;
-
- process_options(argc, argv);
-
- if (check_privs())
- return 1;
-
- if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
- perror("mlockall");
- return 1;
- }
-
- if (mustfork) {
- int shmem;
-
- /*
- * In fork mode (-f), the shared memory contains two
- * subsequent arrays, receiver[num_threads] and
- * sender[num_threads].
- */
- totalsize = num_threads * sizeof(struct params) * 2;
-
- shm_unlink("/sigwaittest");
- shmem = shm_open("/sigwaittest", O_CREAT|O_EXCL|O_RDWR,
- S_IRUSR|S_IWUSR);
- if (shmem < 0) {
- fprintf(stderr, "Could not create shared memory\n");
- return 1;
- }
- ftruncate(shmem, totalsize);
- param = mmap(0, totalsize, PROT_READ|PROT_WRITE, MAP_SHARED,
- shmem, 0);
- if (param == MAP_FAILED) {
- fprintf(stderr, "Could not map shared memory\n");
- close(shmem);
- return 1;
- }
-
- receiver = (struct params *) param;
- sender = receiver + num_threads;
- } else if (wasforked) {
- struct stat buf;
- int shmem, totalsize, expect_totalsize;
-
- if (wasforked_threadno == -1 || wasforked_sender == -1) {
- fprintf(stderr, "Invalid fork option\n");
- return 1;
- }
- shmem = shm_open("/sigwaittest", O_RDWR, S_IRUSR|S_IWUSR);
- if (fstat(shmem, &buf)) {
- fprintf(stderr,
- "Could not determine shared memory size\n");
- close(shmem);
- return 1;
- }
- totalsize = buf.st_size;
- param = mmap(0, totalsize, PROT_READ|PROT_WRITE, MAP_SHARED,
- shmem, 0);
- close(shmem);
- if (param == MAP_FAILED) {
- fprintf(stderr, "Could not map shared memory\n");
- return 1;
- }
-
- receiver = (struct params *) param;
- expect_totalsize = receiver->num_threads *
- sizeof(struct params) * 2;
- if (totalsize != expect_totalsize) {
- fprintf(stderr, "Memory size problem (expected %d, "
- "found %d\n", expect_totalsize, totalsize);
- munmap(param, totalsize);
- return 1;
- }
- sender = receiver + receiver->num_threads;
- if (wasforked_sender)
- semathread(sender + wasforked_threadno);
- else
- semathread(receiver + wasforked_threadno);
- munmap(param, totalsize);
- return 0;
- }
-
- signal(SIGINT, sighand);
- signal(SIGTERM, sighand);
- sigemptyset(&sigset);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- if (!mustfork && !wasforked) {
- receiver = calloc(num_threads, sizeof(struct params));
- sender = calloc(num_threads, sizeof(struct params));
- if (receiver == NULL || sender == NULL)
- goto nomem;
- }
-
- launchdelay.tv_sec = 0;
- launchdelay.tv_nsec = 10000000; /* 10 ms */
-
- maindelay.tv_sec = 0;
- maindelay.tv_nsec = 50000000; /* 50 ms */
-
- for (i = 0; i < num_threads; i++) {
- receiver[i].mindiff = UINT_MAX;
- receiver[i].maxdiff = 0;
- receiver[i].sumdiff = 0.0;
-
- receiver[i].num = i;
- receiver[i].cpu = i;
- receiver[i].priority = priority;
- receiver[i].tracelimit = tracelimit;
- if (priority > 0)
- priority--;
- switch (setaffinity) {
- case AFFINITY_UNSPECIFIED: receiver[i].cpu = -1; break;
- case AFFINITY_SPECIFIED: receiver[i].cpu = affinity; break;
- case AFFINITY_USEALL: receiver[i].cpu = i % max_cpus; break;
- }
- receiver[i].delay.tv_sec = interval / USEC_PER_SEC;
- receiver[i].delay.tv_nsec = (interval % USEC_PER_SEC) * 1000;
- interval += distance;
- receiver[i].max_cycles = max_cycles;
- receiver[i].sender = 0;
- receiver[i].neighbor = &sender[i];
- if (mustfork) {
- pid_t pid = fork();
- if (pid == -1) {
- fprintf(stderr, "Could not fork\n");
- return 1;
- } else if (pid == 0) {
- char *args[3];
-
- receiver[i].num_threads = num_threads;
- receiver[i].pid = getpid();
- sprintf(f_opt, "-fr%d", i);
- args[0] = argv[0];
- args[1] = f_opt;
- args[2] = NULL;
- execvp(args[0], args);
- fprintf(stderr,
- "Could not execute receiver child process "
- "#%d\n", i);
- }
- } else
- pthread_create(&receiver[i].threadid, NULL,
- semathread, &receiver[i]);
-
- nanosleep(&launchdelay, NULL);
-
- memcpy(&sender[i], &receiver[i], sizeof(receiver[0]));
- sender[i].sender = 1;
- sender[i].neighbor = &receiver[i];
- if (mustfork) {
- pid_t pid = fork();
- if (pid == -1) {
- fprintf(stderr, "Could not fork\n");
- return 1;
- } else if (pid == 0) {
- char *args[3];
-
- sender[i].num_threads = num_threads;
- sender[i].pid = getpid();
- sprintf(f_opt, "-fs%d", i);
- args[0] = argv[0];
- args[1] = f_opt;
- args[2] = NULL;
- execvp(args[0], args);
- fprintf(stderr,
- "Could not execute sender child process "
- "#%d\n", i);
- }
- } else
- pthread_create(&sender[i].threadid, NULL, semathread,
- &sender[i]);
- }
-
- while (!mustshutdown) {
- int printed;
- int errorlines = 0;
-
- for (i = 0; i < num_threads; i++)
- mustshutdown |= receiver[i].shutdown |
- sender[i].shutdown;
-
- if (receiver[0].samples > oldsamples || mustshutdown) {
- for (i = 0; i < num_threads; i++) {
- int receiver_pid, sender_pid;
- if (mustfork) {
- receiver_pid = receiver[i].pid;
- sender_pid = sender[i].pid;
- } else {
- receiver_pid = receiver[i].tid;
- sender_pid = sender[i].tid;
- }
- printf("#%1d: ID%d, P%d, CPU%d, I%ld; #%1d: "
- "ID%d, P%d, CPU%d, Cycles %d\n",
- i*2, receiver_pid, receiver[i].priority,
- receiver[i].cpu, receiver[i].delay.tv_nsec /
- 1000, i*2+1, sender_pid, sender[i].priority,
- sender[i].cpu, sender[i].samples);
- }
- for (i = 0; i < num_threads; i++) {
- if (receiver[i].mindiff == -1)
- printf("#%d -> #%d (not yet ready)\n",
- i*2+1, i*2);
- else
- printf("#%d -> #%d, Min %4d, Cur %4d, "
- "Avg %4d, Max %4d\n",
- i*2+1, i*2, receiver[i].mindiff,
- (int) receiver[i].diff.tv_usec,
- (int) ((receiver[i].sumdiff /
- receiver[i].samples) + 0.5),
- receiver[i].maxdiff);
- if (receiver[i].error[0] != '\0') {
- printf(receiver[i].error);
- receiver[i].error[0] = '\0';
- errorlines++;
- }
- if (sender[i].error[0] != '\0') {
- printf(sender[i].error);
- sender[i].error[0] = '\0';
- errorlines++;
- }
- }
- printed = 1;
- } else
- printed = 0;
-
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGTERM);
- sigaddset(&sigset, SIGINT);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- nanosleep(&maindelay, NULL);
-
- sigemptyset(&sigset);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- if (printed && !mustshutdown)
- printf("\033[%dA", num_threads*2 + errorlines);
- }
-
- for (i = 0; i < num_threads; i++) {
- receiver[i].shutdown = 1;
- sender[i].shutdown = 1;
- }
- nanosleep(&receiver[0].delay, NULL);
-
- for (i = 0; i < num_threads; i++) {
- if (!receiver[i].stopped) {
- if (mustfork)
- kill(receiver[i].pid, SIGTERM);
- else
- pthread_kill(receiver[i].threadid, SIGTERM);
- }
- if (!sender[i].stopped) {
- if (mustfork)
- kill(sender[i].pid, SIGTERM);
- else
- pthread_kill(sender[i].threadid, SIGTERM);
- }
- }
-
- nomem:
- if (mustfork) {
- munmap(param, totalsize);
- shm_unlink("/sigwaittest");
- }
-
- return 0;
-}
+/* + * sigwaittest.c + * + * Copyright (C) 2009 Carsten Emde <C.Emde@osadl.org> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <limits.h> +#include <getopt.h> +#include <signal.h> +#include <string.h> +#include <time.h> +#include <utmpx.h> +#include <sys/types.h> +#include <sys/time.h> +#include <linux/unistd.h> +#include <utmpx.h> +#include "rt-utils.h" + +#define __USE_GNU +#include <pthread.h> + +#define gettid() syscall(__NR_gettid) + +#define USEC_PER_SEC 1000000 + +enum { + AFFINITY_UNSPECIFIED, + AFFINITY_SPECIFIED, + AFFINITY_USEALL +}; + +struct params { + int num; + int num_threads; + int cpu; + int priority; + int affinity; + int sender; + int samples; + int max_cycles; + int tracelimit; + int tid; + pid_t pid; + int shutdown; + int stopped; + struct timespec delay; + unsigned int mindiff, maxdiff; + double sumdiff; + struct timeval unblocked, received, diff; + pthread_t threadid; + struct params *neighbor; + char error[MAX_PATH * 2]; +}; + +static int mustfork; +static int wasforked; +static int wasforked_sender = -1; +static int wasforked_threadno = -1; +static int tracelimit; + +void *semathread(void *param) +{ + int mustgetcpu = 0; + struct params *par = param; + cpu_set_t mask; + int policy = SCHED_FIFO; + struct sched_param schedp; + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = par->priority; + sched_setscheduler(0, policy, &schedp); + + if (par->cpu != -1) { + CPU_ZERO(&mask); + CPU_SET(par->cpu, &mask); + if(sched_setaffinity(0, sizeof(mask), &mask) == -1) + fprintf(stderr, "WARNING: Could not set CPU affinity " + "to CPU #%d\n", par->cpu); + } else { + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + + if (max_cpus > 1) + mustgetcpu = 1; + else + par->cpu = 0; + } + + if (!wasforked) + par->tid = gettid(); + + while (!par->shutdown) { + int sig; + int first = 1; + sigset_t sigset; + struct params *neighbor = NULL; + + if (par->sender) { + if (wasforked) + neighbor = par - par->num_threads; + else + neighbor = par->neighbor; + if (first) { + sigemptyset(&sigset); + sigaddset(&sigset, SIGUSR1); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + first = 0; + } + + /* Sending signal: Start of latency measurement ... */ + gettimeofday(&par->unblocked, NULL); + if (wasforked) + kill(neighbor->pid, SIGUSR2); + else + pthread_kill(neighbor->threadid, SIGUSR2); + par->samples++; + if(par->max_cycles && par->samples >= par->max_cycles) + par->shutdown = 1; + + if (mustgetcpu) { + par->cpu = sched_getcpu(); + } + sigwait(&sigset, &sig); + } else { + /* Receiver */ + if (wasforked) + neighbor = par + par->num_threads; + else + neighbor = par->neighbor; + if (first) { + sigemptyset(&sigset); + sigaddset(&sigset, SIGUSR2); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + first = 0; + } + sigwait(&sigset, &sig); + + /* ... Signal received: End of latency measurement */ + gettimeofday(&par->received, NULL); + par->samples++; + if (par->max_cycles && par->samples >= par->max_cycles) + par->shutdown = 1; + + if (mustgetcpu) { + par->cpu = sched_getcpu(); + } + /* + * Latency is the time spent between sending and + * receiving the signal. + */ + timersub(&par->received, &neighbor->unblocked, + &par->diff); + + if (par->diff.tv_usec < par->mindiff) + par->mindiff = par->diff.tv_usec; + if (par->diff.tv_usec > par->maxdiff) + par->maxdiff = par->diff.tv_usec; + par->sumdiff += (double) par->diff.tv_usec; + if (par->tracelimit && par->maxdiff > par->tracelimit) { + char tracing_enabled_file[MAX_PATH]; + + strcpy(tracing_enabled_file, get_debugfileprefix()); + strcat(tracing_enabled_file, "tracing_enabled"); + int tracing_enabled = + open(tracing_enabled_file, O_WRONLY); + if (tracing_enabled >= 0) { + write(tracing_enabled, "0", 1); + close(tracing_enabled); + } else + snprintf(par->error, sizeof(par->error), + "Could not access %s\n", + tracing_enabled_file); + par->shutdown = 1; + neighbor->shutdown = 1; + } + + nanosleep(&par->delay, NULL); + + if (wasforked) + kill(neighbor->pid, SIGUSR1); + else + pthread_kill(neighbor->threadid, SIGUSR1); + } + } + par->stopped = 1; + return NULL; +} + + +static void display_help(void) +{ + printf("sigwaittest V %1.2f\n", VERSION_STRING); + puts("Usage: sigwaittest <options>"); + puts("Function: test sigwait() latency"); + puts( + "Options:\n" + "-a [NUM] --affinity run thread #N on processor #N, if possible\n" + " with NUM pin all threads to the processor NUM\n" + "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n" + "-d DIST --distance=DIST distance of thread intervals in us default=500\n" + "-f --fork fork new processes instead of creating threads\n" + "-i INTV --interval=INTV base interval of thread in us default=1000\n" + "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n" + "-p PRIO --prio=PRIO priority\n" + "-t --threads one thread per available processor\n" + "-t [NUM] --threads=NUM number of threads:\n" + " without NUM, threads = max_cpus\n" + " without -t default = 1\n"); + exit(1); +} + + +static int setaffinity = AFFINITY_UNSPECIFIED; +static int affinity; +static int priority; +static int num_threads = 1; +static int max_cycles; +static int interval = 1000; +static int distance = 500; + +static void process_options (int argc, char *argv[]) +{ + int error = 0; + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + int thistracelimit = 0; + + for (;;) { + int option_index = 0; + /** Options for getopt */ + static struct option long_options[] = { + {"affinity", optional_argument, NULL, 'a'}, + {"breaktrace", required_argument, NULL, 'b'}, + {"distance", required_argument, NULL, 'd'}, + {"fork", optional_argument, NULL, 'f'}, + {"interval", required_argument, NULL, 'i'}, + {"loops", required_argument, NULL, 'l'}, + {"priority", required_argument, NULL, 'p'}, + {"threads", optional_argument, NULL, 't'}, + {"help", no_argument, NULL, '?'}, + {NULL, 0, NULL, 0} + }; + int c = getopt_long (argc, argv, "a::b:d:f::i:l:p:t::", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'a': + if (optarg != NULL) { + affinity = atoi(optarg); + setaffinity = AFFINITY_SPECIFIED; + } else if (optind<argc && atoi(argv[optind])) { + affinity = atoi(argv[optind]); + setaffinity = AFFINITY_SPECIFIED; + } else { + setaffinity = AFFINITY_USEALL; + } + break; + case 'b': thistracelimit = atoi(optarg); break; + case 'd': distance = atoi(optarg); break; + case 'f': + if (optarg != NULL) { + wasforked = 1; + if (optarg[0] == 's') + wasforked_sender = 1; + else if (optarg[0] == 'r') + wasforked_sender = 0; + wasforked_threadno = atoi(optarg+1); + } else + mustfork = 1; + break; + case 'i': interval = atoi(optarg); break; + case 'l': max_cycles = atoi(optarg); break; + case 'p': priority = atoi(optarg); break; + case 't': + if (optarg != NULL) + num_threads = atoi(optarg); + else if (optind<argc && atoi(argv[optind])) + num_threads = atoi(argv[optind]); + else + num_threads = max_cpus; + break; + case '?': error = 1; break; + } + } + + if (!wasforked) { + if (setaffinity == AFFINITY_SPECIFIED) { + if (affinity < 0) + error = 1; + if (affinity >= max_cpus) { + fprintf(stderr, "ERROR: CPU #%d not found, " + "only %d CPUs available\n", + affinity, max_cpus); + error = 1; + } + } + + if (num_threads < 1 || num_threads > 255) + error = 1; + + if (priority < 0 || priority > 99) + error = 1; + + tracelimit = thistracelimit; + } + if (error) + display_help (); +} + + +static int volatile mustshutdown; + +static void sighand(int sig) +{ + mustshutdown = 1; +} + + +int main(int argc, char *argv[]) +{ + int i, totalsize = 0; + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + int oldsamples = 1; + struct params *receiver = NULL; + struct params *sender = NULL; + sigset_t sigset; + void *param = NULL; + char f_opt[8]; + struct timespec launchdelay, maindelay; + + process_options(argc, argv); + + if (check_privs()) + return 1; + + if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { + perror("mlockall"); + return 1; + } + + if (mustfork) { + int shmem; + + /* + * In fork mode (-f), the shared memory contains two + * subsequent arrays, receiver[num_threads] and + * sender[num_threads]. + */ + totalsize = num_threads * sizeof(struct params) * 2; + + shm_unlink("/sigwaittest"); + shmem = shm_open("/sigwaittest", O_CREAT|O_EXCL|O_RDWR, + S_IRUSR|S_IWUSR); + if (shmem < 0) { + fprintf(stderr, "Could not create shared memory\n"); + return 1; + } + ftruncate(shmem, totalsize); + param = mmap(0, totalsize, PROT_READ|PROT_WRITE, MAP_SHARED, + shmem, 0); + if (param == MAP_FAILED) { + fprintf(stderr, "Could not map shared memory\n"); + close(shmem); + return 1; + } + + receiver = (struct params *) param; + sender = receiver + num_threads; + } else if (wasforked) { + struct stat buf; + int shmem, totalsize, expect_totalsize; + + if (wasforked_threadno == -1 || wasforked_sender == -1) { + fprintf(stderr, "Invalid fork option\n"); + return 1; + } + shmem = shm_open("/sigwaittest", O_RDWR, S_IRUSR|S_IWUSR); + if (fstat(shmem, &buf)) { + fprintf(stderr, + "Could not determine shared memory size\n"); + close(shmem); + return 1; + } + totalsize = buf.st_size; + param = mmap(0, totalsize, PROT_READ|PROT_WRITE, MAP_SHARED, + shmem, 0); + close(shmem); + if (param == MAP_FAILED) { + fprintf(stderr, "Could not map shared memory\n"); + return 1; + } + + receiver = (struct params *) param; + expect_totalsize = receiver->num_threads * + sizeof(struct params) * 2; + if (totalsize != expect_totalsize) { + fprintf(stderr, "Memory size problem (expected %d, " + "found %d\n", expect_totalsize, totalsize); + munmap(param, totalsize); + return 1; + } + sender = receiver + receiver->num_threads; + if (wasforked_sender) + semathread(sender + wasforked_threadno); + else + semathread(receiver + wasforked_threadno); + munmap(param, totalsize); + return 0; + } + + signal(SIGINT, sighand); + signal(SIGTERM, sighand); + sigemptyset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + if (!mustfork && !wasforked) { + receiver = calloc(num_threads, sizeof(struct params)); + sender = calloc(num_threads, sizeof(struct params)); + if (receiver == NULL || sender == NULL) + goto nomem; + } + + launchdelay.tv_sec = 0; + launchdelay.tv_nsec = 10000000; /* 10 ms */ + + maindelay.tv_sec = 0; + maindelay.tv_nsec = 50000000; /* 50 ms */ + + for (i = 0; i < num_threads; i++) { + receiver[i].mindiff = UINT_MAX; + receiver[i].maxdiff = 0; + receiver[i].sumdiff = 0.0; + + receiver[i].num = i; + receiver[i].cpu = i; + receiver[i].priority = priority; + receiver[i].tracelimit = tracelimit; + if (priority > 0) + priority--; + switch (setaffinity) { + case AFFINITY_UNSPECIFIED: receiver[i].cpu = -1; break; + case AFFINITY_SPECIFIED: receiver[i].cpu = affinity; break; + case AFFINITY_USEALL: receiver[i].cpu = i % max_cpus; break; + } + receiver[i].delay.tv_sec = interval / USEC_PER_SEC; + receiver[i].delay.tv_nsec = (interval % USEC_PER_SEC) * 1000; + interval += distance; + receiver[i].max_cycles = max_cycles; + receiver[i].sender = 0; + receiver[i].neighbor = &sender[i]; + if (mustfork) { + pid_t pid = fork(); + if (pid == -1) { + fprintf(stderr, "Could not fork\n"); + return 1; + } else if (pid == 0) { + char *args[3]; + + receiver[i].num_threads = num_threads; + receiver[i].pid = getpid(); + sprintf(f_opt, "-fr%d", i); + args[0] = argv[0]; + args[1] = f_opt; + args[2] = NULL; + execvp(args[0], args); + fprintf(stderr, + "Could not execute receiver child process " + "#%d\n", i); + } + } else + pthread_create(&receiver[i].threadid, NULL, + semathread, &receiver[i]); + + nanosleep(&launchdelay, NULL); + + memcpy(&sender[i], &receiver[i], sizeof(receiver[0])); + sender[i].sender = 1; + sender[i].neighbor = &receiver[i]; + if (mustfork) { + pid_t pid = fork(); + if (pid == -1) { + fprintf(stderr, "Could not fork\n"); + return 1; + } else if (pid == 0) { + char *args[3]; + + sender[i].num_threads = num_threads; + sender[i].pid = getpid(); + sprintf(f_opt, "-fs%d", i); + args[0] = argv[0]; + args[1] = f_opt; + args[2] = NULL; + execvp(args[0], args); + fprintf(stderr, + "Could not execute sender child process " + "#%d\n", i); + } + } else + pthread_create(&sender[i].threadid, NULL, semathread, + &sender[i]); + } + + while (!mustshutdown) { + int printed; + int errorlines = 0; + + for (i = 0; i < num_threads; i++) + mustshutdown |= receiver[i].shutdown | + sender[i].shutdown; + + if (receiver[0].samples > oldsamples || mustshutdown) { + for (i = 0; i < num_threads; i++) { + int receiver_pid, sender_pid; + if (mustfork) { + receiver_pid = receiver[i].pid; + sender_pid = sender[i].pid; + } else { + receiver_pid = receiver[i].tid; + sender_pid = sender[i].tid; + } + printf("#%1d: ID%d, P%d, CPU%d, I%ld; #%1d: " + "ID%d, P%d, CPU%d, Cycles %d\n", + i*2, receiver_pid, receiver[i].priority, + receiver[i].cpu, receiver[i].delay.tv_nsec / + 1000, i*2+1, sender_pid, sender[i].priority, + sender[i].cpu, sender[i].samples); + } + for (i = 0; i < num_threads; i++) { + if (receiver[i].mindiff == -1) + printf("#%d -> #%d (not yet ready)\n", + i*2+1, i*2); + else + printf("#%d -> #%d, Min %4d, Cur %4d, " + "Avg %4d, Max %4d\n", + i*2+1, i*2, receiver[i].mindiff, + (int) receiver[i].diff.tv_usec, + (int) ((receiver[i].sumdiff / + receiver[i].samples) + 0.5), + receiver[i].maxdiff); + if (receiver[i].error[0] != '\0') { + printf(receiver[i].error); + receiver[i].error[0] = '\0'; + errorlines++; + } + if (sender[i].error[0] != '\0') { + printf(sender[i].error); + sender[i].error[0] = '\0'; + errorlines++; + } + } + printed = 1; + } else + printed = 0; + + sigemptyset(&sigset); + sigaddset(&sigset, SIGTERM); + sigaddset(&sigset, SIGINT); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + nanosleep(&maindelay, NULL); + + sigemptyset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + if (printed && !mustshutdown) + printf("\033[%dA", num_threads*2 + errorlines); + } + + for (i = 0; i < num_threads; i++) { + receiver[i].shutdown = 1; + sender[i].shutdown = 1; + } + nanosleep(&receiver[0].delay, NULL); + + for (i = 0; i < num_threads; i++) { + if (!receiver[i].stopped) { + if (mustfork) + kill(receiver[i].pid, SIGTERM); + else + pthread_kill(receiver[i].threadid, SIGTERM); + } + if (!sender[i].stopped) { + if (mustfork) + kill(sender[i].pid, SIGTERM); + else + pthread_kill(sender[i].threadid, SIGTERM); + } + } + + nomem: + if (mustfork) { + munmap(param, totalsize); + shm_unlink("/sigwaittest"); + } + + return 0; +} diff --git a/src/svsematest/Makefile b/src/svsematest/Makefile index aab2da0..da8d32d 100644 --- a/src/svsematest/Makefile +++ b/src/svsematest/Makefile @@ -1,16 +1,16 @@ -CFLAGS += -Wall -O2
-LDFLAGS += -lpthread -lrt
-
-all: svsematest
- @echo Done
-
-svsematest.o: svsematest.c
-
-svsematest:
-
-clean:
- @rm -f *.o
-
-tar: clean
- @rm -f svsematest
- $(shell bn=`basename $$PWD`; cd ..; tar -zcf $$bn.tgz $$bn)
+CFLAGS += -Wall -O2 +LDFLAGS += -lpthread -lrt + +all: svsematest + @echo Done + +svsematest.o: svsematest.c + +svsematest: + +clean: + @rm -f *.o + +tar: clean + @rm -f svsematest + $(shell bn=`basename $$PWD`; cd ..; tar -zcf $$bn.tgz $$bn) diff --git a/src/svsematest/svsematest.c b/src/svsematest/svsematest.c index 3f1ea48..50224de 100644 --- a/src/svsematest/svsematest.c +++ b/src/svsematest/svsematest.c @@ -1,704 +1,704 @@ -/*
- * svsematest.c
- *
- * Copyright (C) 2009 Carsten Emde <C.Emde@osadl.org>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-#define __USE_GNU
-#include <fcntl.h>
-#include <getopt.h>
-#include <pthread.h>
-#include <signal.h>
-#include <sched.h>
-#include <string.h>
-#include <time.h>
-#include <utmpx.h>
-
-#include <linux/unistd.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/sem.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-#include "rt-utils.h"
-
-#define HAS_SCHED_GETCPU
-
-#define gettid() syscall(__NR_gettid)
-#ifndef HAS_SCHED_GETCPU
-#define getcpu(cpu, node, cache) syscall(__NR_getcpu, cpu, node, cache)
-#endif
-
-#define USEC_PER_SEC 1000000
-
-#define SEM_WAIT_FOR_RECEIVER 0
-#define SEM_WAIT_FOR_SENDER 1
-
-#define SEM_LOCK -1
-#define SEM_UNLOCK 1
-
-enum {
- AFFINITY_UNSPECIFIED,
- AFFINITY_SPECIFIED,
- AFFINITY_USEALL
-};
-
-struct params {
- int num;
- int num_threads;
- int cpu;
- int priority;
- int affinity;
- int semid;
- int sender;
- int samples;
- int max_cycles;
- int tracelimit;
- int tid;
- pid_t pid;
- int shutdown;
- int stopped;
- struct timespec delay;
- unsigned int mindiff, maxdiff;
- double sumdiff;
- struct timeval unblocked, received, diff;
- pthread_t threadid;
- struct params *neighbor;
- char error[MAX_PATH * 2];
-};
-
-static int mustfork;
-static int wasforked;
-static int wasforked_sender = -1;
-static int wasforked_threadno = -1;
-static int tracelimit;
-
-void *semathread(void *param)
-{
- int mustgetcpu = 0;
- struct params *par = param;
- cpu_set_t mask;
- int policy = SCHED_FIFO;
- struct sched_param schedp;
- struct sembuf sb = { 0, 0, 0};
- sigset_t sigset;
-
- sigemptyset(&sigset);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- memset(&schedp, 0, sizeof(schedp));
- schedp.sched_priority = par->priority;
- sched_setscheduler(0, policy, &schedp);
-
- if (par->cpu != -1) {
- CPU_ZERO(&mask);
- CPU_SET(par->cpu, &mask);
- if(sched_setaffinity(0, sizeof(mask), &mask) == -1)
- snprintf(par->error, sizeof(par->error),
- "WARNING: Could not set CPU affinity "
- "to CPU #%d\n", par->cpu);
- } else {
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
-
- if (max_cpus > 1)
- mustgetcpu = 1;
- else
- par->cpu = 0;
- }
-
- if (!wasforked)
- par->tid = gettid();
-
- while (!par->shutdown) {
- if (par->sender) {
- sb.sem_num = SEM_WAIT_FOR_SENDER;
- sb.sem_op = SEM_UNLOCK;
- /*
- * Unlocking the semaphore:
- * Start of latency measurement ...
- */
- gettimeofday(&par->unblocked, NULL);
- semop(par->semid, &sb, 1);
- par->samples++;
- if(par->max_cycles && par->samples >= par->max_cycles)
- par->shutdown = 1;
-
- if (mustgetcpu) {
-#ifdef HAS_SCHED_GETCPU
- par->cpu = sched_getcpu();
-#else
- int c, s;
- s = getcpu(&c, NULL, NULL);
- par->cpu = (s == -1) ? s : c;
-#endif
- }
-
- sb.sem_num = SEM_WAIT_FOR_RECEIVER;
- sb.sem_op = SEM_LOCK;
- semop(par->semid, &sb, 1);
-
- sb.sem_num = SEM_WAIT_FOR_SENDER;
- sb.sem_op = SEM_LOCK;
- semop(par->semid, &sb, 1);
- } else {
- /* Receiver */
- struct params *neighbor;
-
- if (wasforked)
- neighbor = par + par->num_threads;
- else
- neighbor = par->neighbor;
-
- sb.sem_num = SEM_WAIT_FOR_SENDER;
- sb.sem_op = SEM_LOCK;
- semop(par->semid, &sb, 1);
-
- /*
- * ... We got the lock:
- * End of latency measurement
- */
- gettimeofday(&par->received, NULL);
- par->samples++;
- if (par->max_cycles && par->samples >= par->max_cycles)
- par->shutdown = 1;
-
- if (mustgetcpu) {
-#ifdef HAS_SCHED_GETCPU
- par->cpu = sched_getcpu();
-#else
- int c, s;
- s = getcpu(&c, NULL, NULL);
- par->cpu = (s == -1) ? s : c;
-#endif
- }
-
- timersub(&par->received, &neighbor->unblocked,
- &par->diff);
-
- if (par->diff.tv_usec < par->mindiff)
- par->mindiff = par->diff.tv_usec;
- if (par->diff.tv_usec > par->maxdiff)
- par->maxdiff = par->diff.tv_usec;
- par->sumdiff += (double) par->diff.tv_usec;
- if (par->tracelimit && par->maxdiff > par->tracelimit) {
- char tracing_enabled_file[MAX_PATH];
-
- strcpy(tracing_enabled_file, get_debugfileprefix());
- strcat(tracing_enabled_file, "tracing_enabled");
- int tracing_enabled =
- open(tracing_enabled_file, O_WRONLY);
- if (tracing_enabled >= 0) {
- write(tracing_enabled, "0", 1);
- close(tracing_enabled);
- } else
- snprintf(par->error, sizeof(par->error),
- "Could not access %s\n",
- tracing_enabled_file);
- par->shutdown = 1;
- neighbor->shutdown = 1;
- }
-
- sb.sem_num = SEM_WAIT_FOR_RECEIVER;
- sb.sem_op = SEM_UNLOCK;
- semop(par->semid, &sb, 1);
-
- nanosleep(&par->delay, NULL);
-
- sb.sem_num = SEM_WAIT_FOR_SENDER;
- sb.sem_op = SEM_UNLOCK;
- semop(par->semid, &sb, 1);
- }
- }
- if (par->sender) {
- sb.sem_num = SEM_WAIT_FOR_SENDER;
- sb.sem_op = SEM_UNLOCK;
- semop(par->semid, &sb, 1);
-
- sb.sem_num = SEM_WAIT_FOR_RECEIVER;
- sb.sem_op = SEM_UNLOCK;
- semop(par->semid, &sb, 1);
- }
- par->stopped = 1;
- return NULL;
-}
-
-
-union semun {
- int val; /* Value for SETVAL */
- struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
- unsigned short *array; /* Array for GETALL, SETALL */
- struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
-};
-
-
-static void display_help(void)
-{
- printf("svsematest V %1.2f\n", VERSION_STRING);
- puts("Usage: svsematest <options>");
- puts("Function: test SYSV semaphore latency");
- puts(
- "Options:\n"
- "-a [NUM] --affinity run thread #N on processor #N, if possible\n"
- " with NUM pin all threads to the processor NUM\n"
- "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n"
- "-d DIST --distance=DIST distance of thread intervals in us default=500\n"
- "-f --fork fork new processes instead of creating threads\n"
- "-i INTV --interval=INTV base interval of thread in us default=1000\n"
- "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n"
- "-p PRIO --prio=PRIO priority\n"
- "-t --threads one thread per available processor\n"
- "-t [NUM] --threads=NUM number of threads:\n"
- " without NUM, threads = max_cpus\n"
- " without -t default = 1\n");
- exit(1);
-}
-
-
-static int setaffinity = AFFINITY_UNSPECIFIED;
-static int affinity;
-static int priority;
-static int num_threads = 1;
-static int max_cycles;
-static int interval = 1000;
-static int distance = 500;
-
-static void process_options (int argc, char *argv[])
-{
- int error = 0;
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
- int thistracelimit = 0;
-
- for (;;) {
- int option_index = 0;
- /** Options for getopt */
- static struct option long_options[] = {
- {"affinity", optional_argument, NULL, 'a'},
- {"breaktrace", required_argument, NULL, 'b'},
- {"distance", required_argument, NULL, 'd'},
- {"fork", optional_argument, NULL, 'f'},
- {"interval", required_argument, NULL, 'i'},
- {"loops", required_argument, NULL, 'l'},
- {"priority", required_argument, NULL, 'p'},
- {"threads", optional_argument, NULL, 't'},
- {"help", no_argument, NULL, '?'},
- {NULL, 0, NULL, 0}
- };
- int c = getopt_long (argc, argv, "a::b:d:f::i:l:p:t::",
- long_options, &option_index);
- if (c == -1)
- break;
- switch (c) {
- case 'a':
- if (optarg != NULL) {
- affinity = atoi(optarg);
- setaffinity = AFFINITY_SPECIFIED;
- } else if (optind<argc && atoi(argv[optind])) {
- affinity = atoi(argv[optind]);
- setaffinity = AFFINITY_SPECIFIED;
- } else {
- setaffinity = AFFINITY_USEALL;
- }
- break;
- case 'b': thistracelimit = atoi(optarg); break;
- case 'd': distance = atoi(optarg); break;
- case 'f':
- if (optarg != NULL) {
- wasforked = 1;
- if (optarg[0] == 's')
- wasforked_sender = 1;
- else if (optarg[0] == 'r')
- wasforked_sender = 0;
- wasforked_threadno = atoi(optarg+1);
- } else
- mustfork = 1;
- break;
- case 'i': interval = atoi(optarg); break;
- case 'l': max_cycles = atoi(optarg); break;
- case 'p': priority = atoi(optarg); break;
- case 't':
- if (optarg != NULL)
- num_threads = atoi(optarg);
- else if (optind<argc && atoi(argv[optind]))
- num_threads = atoi(argv[optind]);
- else
- num_threads = max_cpus;
- break;
- case '?': error = 1; break;
- }
- }
-
- if (!wasforked) {
- if (setaffinity == AFFINITY_SPECIFIED) {
- if (affinity < 0)
- error = 1;
- if (affinity >= max_cpus) {
- fprintf(stderr, "ERROR: CPU #%d not found, "
- "only %d CPUs available\n",
- affinity, max_cpus);
- error = 1;
- }
- }
-
- if (num_threads < 1 || num_threads > 255)
- error = 1;
-
- if (priority < 0 || priority > 99)
- error = 1;
-
- tracelimit = thistracelimit;
- }
- if (error)
- display_help ();
-}
-
-
-static int volatile mustshutdown;
-
-static void sighand(int sig)
-{
- mustshutdown = 1;
-}
-
-int main(int argc, char *argv[])
-{
- char *myfile;
- int i, totalsize = 0;
- int max_cpus = sysconf(_SC_NPROCESSORS_CONF);
- int oldsamples = 1;
- key_t key;
- union semun args;
- struct params *receiver = NULL;
- struct params *sender = NULL;
- sigset_t sigset;
- void *param = NULL;
- char f_opt[8];
- struct timespec launchdelay, maindelay;
-
- myfile = getenv("_");
- if (myfile == NULL)
- myfile = argv[0];
-
- process_options(argc, argv);
-
- if (check_privs())
- return 1;
-
- if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
- perror("mlockall");
- return 1;
- }
-
- if (mustfork) {
- int shmem;
-
- /*
- * In fork mode (-f), the shared memory contains two
- * subsequent arrays, receiver[num_threads] and
- * sender[num_threads].
- */
- totalsize = num_threads * sizeof(struct params) * 2;
-
- shm_unlink("/sigwaittest");
- shmem = shm_open("/sigwaittest", O_CREAT|O_EXCL|O_RDWR,
- S_IRUSR|S_IWUSR);
- if (shmem < 0) {
- fprintf(stderr, "Could not create shared memory\n");
- return 1;
- }
- ftruncate(shmem, totalsize);
- param = mmap(0, totalsize, PROT_READ|PROT_WRITE, MAP_SHARED,
- shmem, 0);
- if (param == MAP_FAILED) {
- fprintf(stderr, "Could not map shared memory\n");
- close(shmem);
- return 1;
- }
-
- receiver = (struct params *) param;
- sender = receiver + num_threads;
- } else if (wasforked) {
- struct stat buf;
- int shmem, totalsize, expect_totalsize;
-
- if (wasforked_threadno == -1 || wasforked_sender == -1) {
- fprintf(stderr, "Invalid fork option\n");
- return 1;
- }
- shmem = shm_open("/sigwaittest", O_RDWR, S_IRUSR|S_IWUSR);
- if (fstat(shmem, &buf)) {
- fprintf(stderr,
- "Could not determine shared memory size\n");
- close(shmem);
- return 1;
- }
- totalsize = buf.st_size;
- param = mmap(0, totalsize, PROT_READ|PROT_WRITE, MAP_SHARED,
- shmem, 0);
- close(shmem);
- if (param == MAP_FAILED) {
- fprintf(stderr, "Could not map shared memory\n");
- return 1;
- }
-
- receiver = (struct params *) param;
- expect_totalsize = receiver->num_threads *
- sizeof(struct params) * 2;
- if (totalsize != expect_totalsize) {
- fprintf(stderr, "Memory size problem (expected %d, "
- "found %d\n", expect_totalsize, totalsize);
- munmap(param, totalsize);
- return 1;
- }
- sender = receiver + receiver->num_threads;
- if (wasforked_sender)
- semathread(sender + wasforked_threadno);
- else
- semathread(receiver + wasforked_threadno);
- munmap(param, totalsize);
- return 0;
- }
-
- signal(SIGINT, sighand);
- signal(SIGTERM, sighand);
-
- sigemptyset(&sigset);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- if (!mustfork && !wasforked) {
- receiver = calloc(num_threads, sizeof(struct params));
- sender = calloc(num_threads, sizeof(struct params));
- if (receiver == NULL || sender == NULL)
- goto nomem;
- }
-
- launchdelay.tv_sec = 0;
- launchdelay.tv_nsec = 10000000; /* 10 ms */
-
- maindelay.tv_sec = 0;
- maindelay.tv_nsec = 50000000; /* 50 ms */
-
- for (i = 0; i < num_threads; i++) {
- struct sembuf sb = { 0, 0, 0};
-
- receiver[i].mindiff = UINT_MAX;
- receiver[i].maxdiff = 0;
- receiver[i].sumdiff = 0.0;
-
- if ((key = ftok(myfile, i)) == -1) {
- perror("ftok");
- goto nosem;
- }
-
- if ((receiver[i].semid = semget(key, 2, 0666 | IPC_CREAT)) == -1) {
- perror("semget");
- goto nosem;
- }
-
- args.val = 1;
- if (semctl(receiver[i].semid, SEM_WAIT_FOR_RECEIVER, SETVAL, args) == -1) {
- perror("semctl sema #0");
- goto nosem;
- }
-
- if (semctl(receiver[i].semid, SEM_WAIT_FOR_SENDER, SETVAL, args) == -1) {
- perror("semctl sema #1");
- goto nosem;
- }
-
- sb.sem_num = SEM_WAIT_FOR_RECEIVER;
- sb.sem_op = SEM_LOCK;
- semop(receiver[i].semid, &sb, 1);
-
- sb.sem_num = SEM_WAIT_FOR_SENDER;
- sb.sem_op = SEM_LOCK;
- semop(receiver[i].semid, &sb, 1);
-
- receiver[i].cpu = i;
- switch (setaffinity) {
- case AFFINITY_UNSPECIFIED: receiver[i].cpu = -1; break;
- case AFFINITY_SPECIFIED: receiver[i].cpu = affinity; break;
- case AFFINITY_USEALL: receiver[i].cpu = i % max_cpus; break;
- }
- receiver[i].priority = priority;
- receiver[i].tracelimit = tracelimit;
- if (priority > 0)
- priority--;
- receiver[i].delay.tv_sec = interval / USEC_PER_SEC;
- receiver[i].delay.tv_nsec = (interval % USEC_PER_SEC) * 1000;
- interval += distance;
- receiver[i].max_cycles = max_cycles;
- receiver[i].sender = 0;
- receiver[i].neighbor = &sender[i];
- if (mustfork) {
- pid_t pid = fork();
- if (pid == -1) {
- fprintf(stderr, "Could not fork\n");
- return 1;
- } else if (pid == 0) {
- char *args[3];
-
- receiver[i].num_threads = num_threads;
- receiver[i].pid = getpid();
- sprintf(f_opt, "-fr%d", i);
- args[0] = argv[0];
- args[1] = f_opt;
- args[2] = NULL;
- execvp(args[0], args);
- fprintf(stderr,
- "Could not execute receiver child process "
- "#%d\n", i);
- }
- } else
- pthread_create(&receiver[i].threadid, NULL,
- semathread, &receiver[i]);
-
- nanosleep(&launchdelay, NULL);
-
- memcpy(&sender[i], &receiver[i], sizeof(receiver[0]));
- sender[i].sender = 1;
- sender[i].neighbor = &receiver[i];
- if (mustfork) {
- pid_t pid = fork();
- if (pid == -1) {
- fprintf(stderr, "Could not fork\n");
- return 1;
- } else if (pid == 0) {
- char *args[3];
-
- sender[i].num_threads = num_threads;
- sender[i].pid = getpid();
- sprintf(f_opt, "-fs%d", i);
- args[0] = argv[0];
- args[1] = f_opt;
- args[2] = NULL;
- execvp(args[0], args);
- fprintf(stderr,
- "Could not execute sender child process "
- "#%d\n", i);
- }
- } else
- pthread_create(&sender[i].threadid, NULL, semathread,
- &sender[i]);
- }
-
- while (!mustshutdown) {
- int printed;
- int errorlines = 0;
-
- for (i = 0; i < num_threads; i++)
- mustshutdown |= receiver[i].shutdown |
- sender[i].shutdown;
-
- if (receiver[0].samples > oldsamples || mustshutdown) {
- for (i = 0; i < num_threads; i++) {
- int receiver_pid, sender_pid;
-
- if (mustfork) {
- receiver_pid = receiver[i].pid;
- sender_pid = sender[i].pid;
- } else {
- receiver_pid = receiver[i].tid;
- sender_pid = sender[i].tid;
- }
- printf("#%1d: ID%d, P%d, CPU%d, I%ld; #%1d: "
- "ID%d, P%d, CPU%d, Cycles %d\n",
- i*2, receiver_pid, receiver[i].priority,
- receiver[i].cpu, receiver[i].delay.tv_nsec /
- 1000, i*2+1, sender_pid, sender[i].priority,
- sender[i].cpu, sender[i].samples);
- }
- for (i = 0; i < num_threads; i++) {
- if (receiver[i].mindiff == -1)
- printf("#%d -> #%d (not yet ready)\n",
- i*2+1, i*2);
- else
- printf("#%d -> #%d, Min %4d, Cur %4d, "
- "Avg %4d, Max %4d\n",
- i*2+1, i*2, receiver[i].mindiff,
- (int) receiver[i].diff.tv_usec,
- (int) ((receiver[i].sumdiff /
- receiver[i].samples) + 0.5),
- receiver[i].maxdiff);
- if (receiver[i].error[0] != '\0') {
- printf(receiver[i].error);
- receiver[i].error[0] = '\0';
- errorlines++;
- }
- if (sender[i].error[0] != '\0') {
- printf(sender[i].error);
- sender[i].error[0] = '\0';
- errorlines++;
- }
- }
- printed = 1;
- } else
- printed = 0;
-
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGTERM);
- sigaddset(&sigset, SIGINT);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- nanosleep(&maindelay, NULL);
-
- sigemptyset(&sigset);
- pthread_sigmask(SIG_SETMASK, &sigset, NULL);
-
- if (printed && !mustshutdown)
- printf("\033[%dA", num_threads*2 + errorlines);
- }
-
- for (i = 0; i < num_threads; i++) {
- receiver[i].shutdown = 1;
- sender[i].shutdown = 1;
- }
- nanosleep(&receiver[0].delay, NULL);
-
- for (i = 0; i < num_threads; i++) {
- if (!receiver[i].stopped) {
- if (mustfork)
- kill(receiver[i].pid, SIGTERM);
- else
- pthread_kill(receiver[i].threadid, SIGTERM);
- }
- if (!sender[i].stopped) {
- if (mustfork)
- kill(sender[i].pid, SIGTERM);
- else
- pthread_kill(sender[i].threadid, SIGTERM);
- }
- }
-
- nosem:
- for (i = 0; i < num_threads; i++)
- semctl(receiver[i].semid, -1, IPC_RMID);
-
- nomem:
- if (mustfork) {
- munmap(param, totalsize);
- shm_unlink("/sigwaittest");
- }
-
- return 0;
-}
+/* + * svsematest.c + * + * Copyright (C) 2009 Carsten Emde <C.Emde@osadl.org> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#define __USE_GNU +#include <fcntl.h> +#include <getopt.h> +#include <pthread.h> +#include <signal.h> +#include <sched.h> +#include <string.h> +#include <time.h> +#include <utmpx.h> + +#include <linux/unistd.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sem.h> +#include <sys/time.h> +#include <sys/mman.h> +#include "rt-utils.h" + +#define HAS_SCHED_GETCPU + +#define gettid() syscall(__NR_gettid) +#ifndef HAS_SCHED_GETCPU +#define getcpu(cpu, node, cache) syscall(__NR_getcpu, cpu, node, cache) +#endif + +#define USEC_PER_SEC 1000000 + +#define SEM_WAIT_FOR_RECEIVER 0 +#define SEM_WAIT_FOR_SENDER 1 + +#define SEM_LOCK -1 +#define SEM_UNLOCK 1 + +enum { + AFFINITY_UNSPECIFIED, + AFFINITY_SPECIFIED, + AFFINITY_USEALL +}; + +struct params { + int num; + int num_threads; + int cpu; + int priority; + int affinity; + int semid; + int sender; + int samples; + int max_cycles; + int tracelimit; + int tid; + pid_t pid; + int shutdown; + int stopped; + struct timespec delay; + unsigned int mindiff, maxdiff; + double sumdiff; + struct timeval unblocked, received, diff; + pthread_t threadid; + struct params *neighbor; + char error[MAX_PATH * 2]; +}; + +static int mustfork; +static int wasforked; +static int wasforked_sender = -1; +static int wasforked_threadno = -1; +static int tracelimit; + +void *semathread(void *param) +{ + int mustgetcpu = 0; + struct params *par = param; + cpu_set_t mask; + int policy = SCHED_FIFO; + struct sched_param schedp; + struct sembuf sb = { 0, 0, 0}; + sigset_t sigset; + + sigemptyset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + memset(&schedp, 0, sizeof(schedp)); + schedp.sched_priority = par->priority; + sched_setscheduler(0, policy, &schedp); + + if (par->cpu != -1) { + CPU_ZERO(&mask); + CPU_SET(par->cpu, &mask); + if(sched_setaffinity(0, sizeof(mask), &mask) == -1) + snprintf(par->error, sizeof(par->error), + "WARNING: Could not set CPU affinity " + "to CPU #%d\n", par->cpu); + } else { + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + + if (max_cpus > 1) + mustgetcpu = 1; + else + par->cpu = 0; + } + + if (!wasforked) + par->tid = gettid(); + + while (!par->shutdown) { + if (par->sender) { + sb.sem_num = SEM_WAIT_FOR_SENDER; + sb.sem_op = SEM_UNLOCK; + /* + * Unlocking the semaphore: + * Start of latency measurement ... + */ + gettimeofday(&par->unblocked, NULL); + semop(par->semid, &sb, 1); + par->samples++; + if(par->max_cycles && par->samples >= par->max_cycles) + par->shutdown = 1; + + if (mustgetcpu) { +#ifdef HAS_SCHED_GETCPU + par->cpu = sched_getcpu(); +#else + int c, s; + s = getcpu(&c, NULL, NULL); + par->cpu = (s == -1) ? s : c; +#endif + } + + sb.sem_num = SEM_WAIT_FOR_RECEIVER; + sb.sem_op = SEM_LOCK; + semop(par->semid, &sb, 1); + + sb.sem_num = SEM_WAIT_FOR_SENDER; + sb.sem_op = SEM_LOCK; + semop(par->semid, &sb, 1); + } else { + /* Receiver */ + struct params *neighbor; + + if (wasforked) + neighbor = par + par->num_threads; + else + neighbor = par->neighbor; + + sb.sem_num = SEM_WAIT_FOR_SENDER; + sb.sem_op = SEM_LOCK; + semop(par->semid, &sb, 1); + + /* + * ... We got the lock: + * End of latency measurement + */ + gettimeofday(&par->received, NULL); + par->samples++; + if (par->max_cycles && par->samples >= par->max_cycles) + par->shutdown = 1; + + if (mustgetcpu) { +#ifdef HAS_SCHED_GETCPU + par->cpu = sched_getcpu(); +#else + int c, s; + s = getcpu(&c, NULL, NULL); + par->cpu = (s == -1) ? s : c; +#endif + } + + timersub(&par->received, &neighbor->unblocked, + &par->diff); + + if (par->diff.tv_usec < par->mindiff) + par->mindiff = par->diff.tv_usec; + if (par->diff.tv_usec > par->maxdiff) + par->maxdiff = par->diff.tv_usec; + par->sumdiff += (double) par->diff.tv_usec; + if (par->tracelimit && par->maxdiff > par->tracelimit) { + char tracing_enabled_file[MAX_PATH]; + + strcpy(tracing_enabled_file, get_debugfileprefix()); + strcat(tracing_enabled_file, "tracing_enabled"); + int tracing_enabled = + open(tracing_enabled_file, O_WRONLY); + if (tracing_enabled >= 0) { + write(tracing_enabled, "0", 1); + close(tracing_enabled); + } else + snprintf(par->error, sizeof(par->error), + "Could not access %s\n", + tracing_enabled_file); + par->shutdown = 1; + neighbor->shutdown = 1; + } + + sb.sem_num = SEM_WAIT_FOR_RECEIVER; + sb.sem_op = SEM_UNLOCK; + semop(par->semid, &sb, 1); + + nanosleep(&par->delay, NULL); + + sb.sem_num = SEM_WAIT_FOR_SENDER; + sb.sem_op = SEM_UNLOCK; + semop(par->semid, &sb, 1); + } + } + if (par->sender) { + sb.sem_num = SEM_WAIT_FOR_SENDER; + sb.sem_op = SEM_UNLOCK; + semop(par->semid, &sb, 1); + + sb.sem_num = SEM_WAIT_FOR_RECEIVER; + sb.sem_op = SEM_UNLOCK; + semop(par->semid, &sb, 1); + } + par->stopped = 1; + return NULL; +} + + +union semun { + int val; /* Value for SETVAL */ + struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ + unsigned short *array; /* Array for GETALL, SETALL */ + struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */ +}; + + +static void display_help(void) +{ + printf("svsematest V %1.2f\n", VERSION_STRING); + puts("Usage: svsematest <options>"); + puts("Function: test SYSV semaphore latency"); + puts( + "Options:\n" + "-a [NUM] --affinity run thread #N on processor #N, if possible\n" + " with NUM pin all threads to the processor NUM\n" + "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n" + "-d DIST --distance=DIST distance of thread intervals in us default=500\n" + "-f --fork fork new processes instead of creating threads\n" + "-i INTV --interval=INTV base interval of thread in us default=1000\n" + "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n" + "-p PRIO --prio=PRIO priority\n" + "-t --threads one thread per available processor\n" + "-t [NUM] --threads=NUM number of threads:\n" + " without NUM, threads = max_cpus\n" + " without -t default = 1\n"); + exit(1); +} + + +static int setaffinity = AFFINITY_UNSPECIFIED; +static int affinity; +static int priority; +static int num_threads = 1; +static int max_cycles; +static int interval = 1000; +static int distance = 500; + +static void process_options (int argc, char *argv[]) +{ + int error = 0; + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + int thistracelimit = 0; + + for (;;) { + int option_index = 0; + /** Options for getopt */ + static struct option long_options[] = { + {"affinity", optional_argument, NULL, 'a'}, + {"breaktrace", required_argument, NULL, 'b'}, + {"distance", required_argument, NULL, 'd'}, + {"fork", optional_argument, NULL, 'f'}, + {"interval", required_argument, NULL, 'i'}, + {"loops", required_argument, NULL, 'l'}, + {"priority", required_argument, NULL, 'p'}, + {"threads", optional_argument, NULL, 't'}, + {"help", no_argument, NULL, '?'}, + {NULL, 0, NULL, 0} + }; + int c = getopt_long (argc, argv, "a::b:d:f::i:l:p:t::", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'a': + if (optarg != NULL) { + affinity = atoi(optarg); + setaffinity = AFFINITY_SPECIFIED; + } else if (optind<argc && atoi(argv[optind])) { + affinity = atoi(argv[optind]); + setaffinity = AFFINITY_SPECIFIED; + } else { + setaffinity = AFFINITY_USEALL; + } + break; + case 'b': thistracelimit = atoi(optarg); break; + case 'd': distance = atoi(optarg); break; + case 'f': + if (optarg != NULL) { + wasforked = 1; + if (optarg[0] == 's') + wasforked_sender = 1; + else if (optarg[0] == 'r') + wasforked_sender = 0; + wasforked_threadno = atoi(optarg+1); + } else + mustfork = 1; + break; + case 'i': interval = atoi(optarg); break; + case 'l': max_cycles = atoi(optarg); break; + case 'p': priority = atoi(optarg); break; + case 't': + if (optarg != NULL) + num_threads = atoi(optarg); + else if (optind<argc && atoi(argv[optind])) + num_threads = atoi(argv[optind]); + else + num_threads = max_cpus; + break; + case '?': error = 1; break; + } + } + + if (!wasforked) { + if (setaffinity == AFFINITY_SPECIFIED) { + if (affinity < 0) + error = 1; + if (affinity >= max_cpus) { + fprintf(stderr, "ERROR: CPU #%d not found, " + "only %d CPUs available\n", + affinity, max_cpus); + error = 1; + } + } + + if (num_threads < 1 || num_threads > 255) + error = 1; + + if (priority < 0 || priority > 99) + error = 1; + + tracelimit = thistracelimit; + } + if (error) + display_help (); +} + + +static int volatile mustshutdown; + +static void sighand(int sig) +{ + mustshutdown = 1; +} + +int main(int argc, char *argv[]) +{ + char *myfile; + int i, totalsize = 0; + int max_cpus = sysconf(_SC_NPROCESSORS_CONF); + int oldsamples = 1; + key_t key; + union semun args; + struct params *receiver = NULL; + struct params *sender = NULL; + sigset_t sigset; + void *param = NULL; + char f_opt[8]; + struct timespec launchdelay, maindelay; + + myfile = getenv("_"); + if (myfile == NULL) + myfile = argv[0]; + + process_options(argc, argv); + + if (check_privs()) + return 1; + + if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { + perror("mlockall"); + return 1; + } + + if (mustfork) { + int shmem; + + /* + * In fork mode (-f), the shared memory contains two + * subsequent arrays, receiver[num_threads] and + * sender[num_threads]. + */ + totalsize = num_threads * sizeof(struct params) * 2; + + shm_unlink("/sigwaittest"); + shmem = shm_open("/sigwaittest", O_CREAT|O_EXCL|O_RDWR, + S_IRUSR|S_IWUSR); + if (shmem < 0) { + fprintf(stderr, "Could not create shared memory\n"); + return 1; + } + ftruncate(shmem, totalsize); + param = mmap(0, totalsize, PROT_READ|PROT_WRITE, MAP_SHARED, + shmem, 0); + if (param == MAP_FAILED) { + fprintf(stderr, "Could not map shared memory\n"); + close(shmem); + return 1; + } + + receiver = (struct params *) param; + sender = receiver + num_threads; + } else if (wasforked) { + struct stat buf; + int shmem, totalsize, expect_totalsize; + + if (wasforked_threadno == -1 || wasforked_sender == -1) { + fprintf(stderr, "Invalid fork option\n"); + return 1; + } + shmem = shm_open("/sigwaittest", O_RDWR, S_IRUSR|S_IWUSR); + if (fstat(shmem, &buf)) { + fprintf(stderr, + "Could not determine shared memory size\n"); + close(shmem); + return 1; + } + totalsize = buf.st_size; + param = mmap(0, totalsize, PROT_READ|PROT_WRITE, MAP_SHARED, + shmem, 0); + close(shmem); + if (param == MAP_FAILED) { + fprintf(stderr, "Could not map shared memory\n"); + return 1; + } + + receiver = (struct params *) param; + expect_totalsize = receiver->num_threads * + sizeof(struct params) * 2; + if (totalsize != expect_totalsize) { + fprintf(stderr, "Memory size problem (expected %d, " + "found %d\n", expect_totalsize, totalsize); + munmap(param, totalsize); + return 1; + } + sender = receiver + receiver->num_threads; + if (wasforked_sender) + semathread(sender + wasforked_threadno); + else + semathread(receiver + wasforked_threadno); + munmap(param, totalsize); + return 0; + } + + signal(SIGINT, sighand); + signal(SIGTERM, sighand); + + sigemptyset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + if (!mustfork && !wasforked) { + receiver = calloc(num_threads, sizeof(struct params)); + sender = calloc(num_threads, sizeof(struct params)); + if (receiver == NULL || sender == NULL) + goto nomem; + } + + launchdelay.tv_sec = 0; + launchdelay.tv_nsec = 10000000; /* 10 ms */ + + maindelay.tv_sec = 0; + maindelay.tv_nsec = 50000000; /* 50 ms */ + + for (i = 0; i < num_threads; i++) { + struct sembuf sb = { 0, 0, 0}; + + receiver[i].mindiff = UINT_MAX; + receiver[i].maxdiff = 0; + receiver[i].sumdiff = 0.0; + + if ((key = ftok(myfile, i)) == -1) { + perror("ftok"); + goto nosem; + } + + if ((receiver[i].semid = semget(key, 2, 0666 | IPC_CREAT)) == -1) { + perror("semget"); + goto nosem; + } + + args.val = 1; + if (semctl(receiver[i].semid, SEM_WAIT_FOR_RECEIVER, SETVAL, args) == -1) { + perror("semctl sema #0"); + goto nosem; + } + + if (semctl(receiver[i].semid, SEM_WAIT_FOR_SENDER, SETVAL, args) == -1) { + perror("semctl sema #1"); + goto nosem; + } + + sb.sem_num = SEM_WAIT_FOR_RECEIVER; + sb.sem_op = SEM_LOCK; + semop(receiver[i].semid, &sb, 1); + + sb.sem_num = SEM_WAIT_FOR_SENDER; + sb.sem_op = SEM_LOCK; + semop(receiver[i].semid, &sb, 1); + + receiver[i].cpu = i; + switch (setaffinity) { + case AFFINITY_UNSPECIFIED: receiver[i].cpu = -1; break; + case AFFINITY_SPECIFIED: receiver[i].cpu = affinity; break; + case AFFINITY_USEALL: receiver[i].cpu = i % max_cpus; break; + } + receiver[i].priority = priority; + receiver[i].tracelimit = tracelimit; + if (priority > 0) + priority--; + receiver[i].delay.tv_sec = interval / USEC_PER_SEC; + receiver[i].delay.tv_nsec = (interval % USEC_PER_SEC) * 1000; + interval += distance; + receiver[i].max_cycles = max_cycles; + receiver[i].sender = 0; + receiver[i].neighbor = &sender[i]; + if (mustfork) { + pid_t pid = fork(); + if (pid == -1) { + fprintf(stderr, "Could not fork\n"); + return 1; + } else if (pid == 0) { + char *args[3]; + + receiver[i].num_threads = num_threads; + receiver[i].pid = getpid(); + sprintf(f_opt, "-fr%d", i); + args[0] = argv[0]; + args[1] = f_opt; + args[2] = NULL; + execvp(args[0], args); + fprintf(stderr, + "Could not execute receiver child process " + "#%d\n", i); + } + } else + pthread_create(&receiver[i].threadid, NULL, + semathread, &receiver[i]); + + nanosleep(&launchdelay, NULL); + + memcpy(&sender[i], &receiver[i], sizeof(receiver[0])); + sender[i].sender = 1; + sender[i].neighbor = &receiver[i]; + if (mustfork) { + pid_t pid = fork(); + if (pid == -1) { + fprintf(stderr, "Could not fork\n"); + return 1; + } else if (pid == 0) { + char *args[3]; + + sender[i].num_threads = num_threads; + sender[i].pid = getpid(); + sprintf(f_opt, "-fs%d", i); + args[0] = argv[0]; + args[1] = f_opt; + args[2] = NULL; + execvp(args[0], args); + fprintf(stderr, + "Could not execute sender child process " + "#%d\n", i); + } + } else + pthread_create(&sender[i].threadid, NULL, semathread, + &sender[i]); + } + + while (!mustshutdown) { + int printed; + int errorlines = 0; + + for (i = 0; i < num_threads; i++) + mustshutdown |= receiver[i].shutdown | + sender[i].shutdown; + + if (receiver[0].samples > oldsamples || mustshutdown) { + for (i = 0; i < num_threads; i++) { + int receiver_pid, sender_pid; + + if (mustfork) { + receiver_pid = receiver[i].pid; + sender_pid = sender[i].pid; + } else { + receiver_pid = receiver[i].tid; + sender_pid = sender[i].tid; + } + printf("#%1d: ID%d, P%d, CPU%d, I%ld; #%1d: " + "ID%d, P%d, CPU%d, Cycles %d\n", + i*2, receiver_pid, receiver[i].priority, + receiver[i].cpu, receiver[i].delay.tv_nsec / + 1000, i*2+1, sender_pid, sender[i].priority, + sender[i].cpu, sender[i].samples); + } + for (i = 0; i < num_threads; i++) { + if (receiver[i].mindiff == -1) + printf("#%d -> #%d (not yet ready)\n", + i*2+1, i*2); + else + printf("#%d -> #%d, Min %4d, Cur %4d, " + "Avg %4d, Max %4d\n", + i*2+1, i*2, receiver[i].mindiff, + (int) receiver[i].diff.tv_usec, + (int) ((receiver[i].sumdiff / + receiver[i].samples) + 0.5), + receiver[i].maxdiff); + if (receiver[i].error[0] != '\0') { + printf(receiver[i].error); + receiver[i].error[0] = '\0'; + errorlines++; + } + if (sender[i].error[0] != '\0') { + printf(sender[i].error); + sender[i].error[0] = '\0'; + errorlines++; + } + } + printed = 1; + } else + printed = 0; + + sigemptyset(&sigset); + sigaddset(&sigset, SIGTERM); + sigaddset(&sigset, SIGINT); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + nanosleep(&maindelay, NULL); + + sigemptyset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, NULL); + + if (printed && !mustshutdown) + printf("\033[%dA", num_threads*2 + errorlines); + } + + for (i = 0; i < num_threads; i++) { + receiver[i].shutdown = 1; + sender[i].shutdown = 1; + } + nanosleep(&receiver[0].delay, NULL); + + for (i = 0; i < num_threads; i++) { + if (!receiver[i].stopped) { + if (mustfork) + kill(receiver[i].pid, SIGTERM); + else + pthread_kill(receiver[i].threadid, SIGTERM); + } + if (!sender[i].stopped) { + if (mustfork) + kill(sender[i].pid, SIGTERM); + else + pthread_kill(sender[i].threadid, SIGTERM); + } + } + + nosem: + for (i = 0; i < num_threads; i++) + semctl(receiver[i].semid, -1, IPC_RMID); + + nomem: + if (mustfork) { + munmap(param, totalsize); + shm_unlink("/sigwaittest"); + } + + return 0; +} |