Commit a7d3c837 authored by Joanne Hugé's avatar Joanne Hugé

Remove unnecessary files and latency threshold

parent c853fbf8
......@@ -5,8 +5,6 @@ SRCDIR = ../src
SRCS = clockres.c
SRCS += tracer.c
SRCS += rt-utils.c
SRCS += rt-sched.c
OBJS = $(SRCS:%.c=%.o)
......
......@@ -25,6 +25,7 @@ typedef struct thread_param {
int priority;
int max_cycles;
uint64_t interval;
uint64_t latency_threshold;
thread_stat_t stat;
} thread_param_t;
......@@ -69,6 +70,8 @@ static void *timerthread(void *p) {
stat->max_res = max(stat->max_res, diff);
stat->min_res = min(stat->min_res, diff);
if( diff > param->latency_threshold ) break;
usleep(param->interval);
}
......@@ -105,6 +108,7 @@ int main(int argc, char *argv[]) {
param.stat.nb_cycles);
if (param.max_cycles == param.stat.nb_cycles) break;
if (param.stat.max_res >= param.latency_threshold) break;
}
tracing(0);
......@@ -115,7 +119,7 @@ int main(int argc, char *argv[]) {
static void process_options(int argc, char *argv[], thread_param_t *param,
main_param_t *main_param) {
for (;;) {
int c = getopt(argc, argv, "l:p:i:r:");
int c = getopt(argc, argv, "l:p:i:r:b:");
if (c == -1) break;
......@@ -129,6 +133,9 @@ static void process_options(int argc, char *argv[], thread_param_t *param,
case 'i':
param->interval = atoi(optarg);
break;
case 'b':
param->latency_threshold = atoi(optarg);
break;
case 'r':
main_param->refresh_rate = atoi(optarg);
break;
......
/*
rt-sched.h - sched_setattr() and sched_getattr() API
(C) Dario Faggioli <raistlin@linux.it>, 2009, 2010
Copyright (C) 2014 BMW Car IT GmbH, Daniel Wagner <daniel.wagner@bmw-carit.de
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA */
/* This file is based on Dario Faggioli's libdl. Eventually it will be
replaced by a proper implemenation of this API. */
#include <unistd.h>
#include <sys/syscall.h>
#include "rt-sched.h"
int sched_setattr(pid_t pid,
const struct sched_attr *attr,
unsigned int flags)
{
return syscall(__NR_sched_setattr, pid, attr, flags);
}
int sched_getattr(pid_t pid,
struct sched_attr *attr,
unsigned int size,
unsigned int flags)
{
return syscall(__NR_sched_getattr, pid, attr, size, flags);
}
/*
rt-sched.h - sched_setattr() and sched_getattr() API
(C) Dario Faggioli <raistlin@linux.it>, 2009, 2010
Copyright (C) 2014 BMW Car IT GmbH, Daniel Wagner <daniel.wagner@bmw-carit.de
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA */
/* This file is based on Dario Faggioli's libdl. Eventually it will be
replaced by a proper implemenation of this API. */
#ifndef __RT_SCHED_H__
#define __RT_SCHED_H__
#include <stdint.h>
#include <sys/types.h>
#ifndef SCHED_DEADLINE
#define SCHED_DEADLINE 6
#endif
#ifdef __x86_64__
#define __NR_sched_setattr 314
#define __NR_sched_getattr 315
#endif
#ifdef __i386__
#define __NR_sched_setattr 351
#define __NR_sched_getattr 352
#endif
#ifdef __arm__
#ifndef __NR_sched_setattr
#define __NR_sched_setattr 380
#endif
#ifndef __NR_sched_getattr
#define __NR_sched_getattr 381
#endif
#endif
#ifdef __tilegx__
#define __NR_sched_setattr 274
#define __NR_sched_getattr 275
#endif
struct sched_attr {
uint32_t size;
uint32_t sched_policy;
uint64_t sched_flags;
/* SCHED_NORMAL, SCHED_BATCH */
int32_t sched_nice;
/* SCHED_FIFO, SCHED_RR */
uint32_t sched_priority;
/* SCHED_DEADLINE */
uint64_t sched_runtime;
uint64_t sched_deadline;
uint64_t sched_period;
};
int sched_setattr(pid_t pid,
const struct sched_attr *attr,
unsigned int flags);
int sched_getattr(pid_t pid,
struct sched_attr *attr,
unsigned int size,
unsigned int flags);
#endif /* __RT_SCHED_H__ */
/*
* Copyright (C) 2009 Carsten Emde <carsten.emde@osadl.org>
* Copyright (C) 2010 Clark Williams <williams@redhat.com>
* Copyright (C) 2015 John Kacur <jkacur@redhat.com>
*
* based on functions from cyclictest that has
* (C) 2008-2009 Clark Williams <williams@redhat.com>
* (C) 2005-2007 Thomas Gleixner <tglx@linutronix.de>
*/
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_gettid definitions */
#include "rt-utils.h"
#include "rt-sched.h"
#include "error.h"
static char debugfileprefix[MAX_PATH];
/*
* Finds the tracing directory in a mounted debugfs
*/
char *get_debugfileprefix(void)
{
char type[100];
FILE *fp;
int size;
int found = 0;
struct stat s;
if (debugfileprefix[0] != '\0')
goto out;
/* look in the "standard" mount point first */
if ((stat("/sys/kernel/debug/tracing", &s) == 0) && S_ISDIR(s.st_mode)) {
strcpy(debugfileprefix, "/sys/kernel/debug/tracing/");
goto out;
}
/* now look in the "other standard" place */
if ((stat("/debug/tracing", &s) == 0) && S_ISDIR(s.st_mode)) {
strcpy(debugfileprefix, "/debug/tracing/");
goto out;
}
/* oh well, parse /proc/mounts and see if it's there */
if ((fp = fopen("/proc/mounts", "r")) == NULL)
goto out;
while (fscanf(fp, "%*s %"
STR(MAX_PATH)
"s %99s %*s %*d %*d\n",
debugfileprefix, type) == 2) {
if (strcmp(type, "debugfs") == 0) {
found = 1;
break;
}
/* stupid check for systemd-style autofs mount */
if ((strcmp(debugfileprefix, "/sys/kernel/debug") == 0) &&
(strcmp(type, "systemd") == 0)) {
found = 1;
break;
}
}
fclose(fp);
if (!found) {
debugfileprefix[0] = '\0';
goto out;
}
size = sizeof(debugfileprefix) - strlen(debugfileprefix);
strncat(debugfileprefix, "/tracing/", size);
out:
return debugfileprefix;
}
int mount_debugfs(char *path)
{
char *mountpoint = path;
char cmd[MAX_PATH];
char *prefix;
int ret;
/* if it's already mounted just return */
prefix = get_debugfileprefix();
if (strlen(prefix) != 0) {
printf("debugfs mountpoint: %s\n", prefix);
return 0;
}
if (!mountpoint)
mountpoint = "/sys/kernel/debug";
sprintf(cmd, "mount -t debugfs debugfs %s", mountpoint);
ret = system(cmd);
if (ret != 0) {
fprintf(stderr, "Error mounting debugfs at %s: %s\n",
mountpoint, strerror(errno));
return -1;
}
return 0;
}
static char **tracer_list;
static char *tracer_buffer;
static int num_tracers;
#define CHUNKSZ 1024
/*
* return a list of the tracers configured into the running kernel
*/
int get_tracers(char ***list)
{
int ret;
FILE *fp;
char buffer[CHUNKSZ];
char *prefix = get_debugfileprefix();
char *tmpbuf = NULL;
char *ptr;
int tmpsz = 0;
/* if we've already parse it, return what we have */
if (tracer_list) {
*list = tracer_list;
return num_tracers;
}
/* open the tracing file available_tracers */
sprintf(buffer, "%savailable_tracers", prefix);
if ((fp = fopen(buffer, "r")) == NULL)
printf("Can't open %s for reading\n", buffer);
/* allocate initial buffer */
ptr = tmpbuf = malloc(CHUNKSZ);
if (ptr == NULL)
printf("error allocating initial space for tracer list\n");
/* read in the list of available tracers */
while ((ret = fread(buffer, sizeof(char), CHUNKSZ, fp))) {
if ((ptr+ret+1) > (tmpbuf+tmpsz)) {
tmpbuf = realloc(tmpbuf, tmpsz + CHUNKSZ);
if (tmpbuf == NULL)
printf("error allocating space for list of valid tracers\n");
tmpsz += CHUNKSZ;
}
strncpy(ptr, buffer, ret);
ptr += ret;
}
fclose(fp);
if (tmpsz == 0)
printf("error reading available tracers\n");
tracer_buffer = tmpbuf;
/* get a buffer for the pointers to tracers */
if (!(tracer_list = malloc(sizeof(char *))))
printf("error allocatinging tracer list buffer\n");
/* parse the buffer */
ptr = strtok(tmpbuf, " \t\n\r");
do {
tracer_list[num_tracers++] = ptr;
tracer_list = realloc(tracer_list, sizeof(char*)*(num_tracers+1));
tracer_list[num_tracers] = NULL;
} while ((ptr = strtok(NULL, " \t\n\r")) != NULL);
/* return the list and number of tracers */
*list = tracer_list;
return num_tracers;
}
/*
* return zero if tracername is not a valid tracer, non-zero if it is
*/
int valid_tracer(char *tracername)
{
char **list;
int ntracers;
int i;
ntracers = get_tracers(&list);
if (ntracers == 0 || tracername == NULL)
return 0;
for (i = 0; i < ntracers; i++)
if (strncmp(list[i], tracername, strlen(list[i])) == 0)
return 1;
return 0;
}
/*
* enable event tracepoint
*/
int setevent(char *event, char *val)
{
char *prefix = get_debugfileprefix();
char buffer[MAX_PATH];
int fd;
int ret;
sprintf(buffer, "%s%s", prefix, event);
if ((fd = open(buffer, O_WRONLY)) < 0) {
printf("unable to open %s\n", buffer);
return -1;
}
if ((ret = write(fd, val, strlen(val))) < 0) {
printf("unable to write %s to %s\n", val, buffer);
close(fd);
return -1;
}
close(fd);
return 0;
}
int event_enable_all(void)
{
return setevent("events/enable", "1");
}
int event_disable_all(void)
{
return setevent("events/enable", "0");
}
int event_enable(char *event)
{
char path[MAX_PATH];
sprintf(path, "events/%s/enable", event);
return setevent(path, "1");
}
int event_disable(char *event)
{
char path[MAX_PATH];
sprintf(path, "events/%s/enable", event);
return setevent(path, "0");
}
int check_privs(void)
{
int policy = sched_getscheduler(0);
struct sched_param param, old_param;
/* if we're already running a realtime scheduler
* then we *should* be able to change things later
*/
if (policy == SCHED_FIFO || policy == SCHED_RR)
return 0;
/* first get the current parameters */
if (sched_getparam(0, &old_param)) {
fprintf(stderr, "unable to get scheduler parameters\n");
return 1;
}
param = old_param;
/* try to change to SCHED_FIFO */
param.sched_priority = 1;
if (sched_setscheduler(0, SCHED_FIFO, &param)) {
fprintf(stderr, "Unable to change scheduling policy!\n");
fprintf(stderr, "either run as root or join realtime group\n");
return 1;
}
/* we're good; change back and return success */
return sched_setscheduler(0, policy, &old_param);
}
const char *policy_to_string(int policy)
{
switch (policy) {
case SCHED_OTHER:
return "SCHED_OTHER";
case SCHED_FIFO:
return "SCHED_FIFO";
case SCHED_RR:
return "SCHED_RR";
case SCHED_BATCH:
return "SCHED_BATCH";
case SCHED_IDLE:
return "SCHED_IDLE";
case SCHED_DEADLINE:
return "SCHED_DEADLINE";
}
return "unknown";
}
uint32_t string_to_policy(const char *str)
{
if (!strcmp(str, "other"))
return SCHED_OTHER;
else if (!strcmp(str, "fifo"))
return SCHED_FIFO;
else if (!strcmp(str, "rr"))
return SCHED_RR;
else if (!strcmp(str, "batch"))
return SCHED_BATCH;
else if (!strcmp(str, "idle"))
return SCHED_IDLE;
else if (!strcmp(str, "deadline"))
return SCHED_DEADLINE;
return 0;
}
pid_t gettid(void)
{
return syscall(SYS_gettid);
}
#ifndef __RT_UTILS_H
#define __RT_UTILS_H
#include <stdint.h>
#define _STR(x) #x
#define STR(x) _STR(x)
#define MAX_PATH 256
int check_privs(void);
char *get_debugfileprefix(void);
int mount_debugfs(char *);
int get_tracers(char ***);
int valid_tracer(char *);
int setevent(char *event, char *val);
int event_enable(char *event);
int event_disable(char *event);
int event_enable_all(void);
int event_disable_all(void);
const char *policy_to_string(int policy);
uint32_t string_to_policy(const char *str);
pid_t gettid(void);
#endif /* __RT_UTILS.H */
/*
* A numa library for cyclictest.
* The functions here are designed to work whether cyclictest has been
* compiled with numa support or not, and whether the user uses the --numa
* option or not.
* They should also work correctly with older versions of the numactl lib
* such as the one found on RHEL5, or with the newer version 2 and above.
*
* The difference in behavior hinges on whether LIBNUMA_API_VERSION >= 2,
* in which case we will employ the bitmask affinity behavior -or-
* either LIBNUMA_API_VERSION < 2 or NUMA support is missing altogether,
* in which case we retain the older affinity behavior which can either
* specify a single CPU core or else use all cores.
*
* (C) 2010 John Kacur <jkacur@redhat.com>
* (C) 2010 Clark Williams <williams@redhat.com>
*
*/
#ifndef _RT_NUMA_H
#define _RT_NUMA_H
#include "rt-utils.h"
#include "error.h"
static int numa = 0;
#ifdef NUMA
#include <numa.h>
#ifndef LIBNUMA_API_VERSION
#define LIBNUMA_API_VERSION 1
#endif
static void *
threadalloc(size_t size, int node)
{
if (node == -1)
return malloc(size);
return numa_alloc_onnode(size, node);
}
static void
threadfree(void *ptr, size_t size, int node)
{
if (node == -1)
free(ptr);
else
numa_free(ptr, size);
}
static void rt_numa_set_numa_run_on_node(int node, int cpu)
{
int res;
res = numa_run_on_node(node);
if (res)
warn("Could not set NUMA node %d for thread %d: %s\n",
node, cpu, strerror(errno));
return;
}
static void *rt_numa_numa_alloc_onnode(size_t size, int node, int cpu)
{
void *stack;
stack = numa_alloc_onnode(size, node);
if (stack == NULL)
fatal("failed to allocate %d bytes on node %d for cpu %d\n",
size, node, cpu);
return stack;
}
#if LIBNUMA_API_VERSION >= 2
/*
* Use new bit mask CPU affinity behavior
*/
static int rt_numa_numa_node_of_cpu(int cpu)
{
int node;
node = numa_node_of_cpu(cpu);
if (node == -1)
fatal("invalid cpu passed to numa_node_of_cpu(%d)\n", cpu);
return node;
}
static inline unsigned int rt_numa_bitmask_isbitset( const struct bitmask *mask,
unsigned long i)
{
return numa_bitmask_isbitset(mask,i);
}
static inline struct bitmask* rt_numa_parse_cpustring(const char* s,
int max_cpus)
{
#ifdef HAVE_PARSE_CPUSTRING_ALL /* Currently not defined anywhere. No
autotools build. */
return numa_parse_cpustring_all(s);
#else
/* We really need numa_parse_cpustring_all(), so we can assign threads
* to cores which are part of an isolcpus set, but early 2.x versions of
* libnuma do not have this function. A work around should be to run
* your command with e.g. taskset -c 9-15 <command>
*/
return numa_parse_cpustring((char *)s);
#endif
}
static inline void rt_bitmask_free(struct bitmask *mask)
{
numa_bitmask_free(mask);
}
#else /* LIBNUMA_API_VERSION == 1 */
struct bitmask {
unsigned long size; /* number of bits in the map */
unsigned long *maskp;
};
#define BITS_PER_LONG (8*sizeof(long))
/*
* Map legacy CPU affinity behavior onto bit mask infrastructure
*/
static int rt_numa_numa_node_of_cpu(int cpu)
{
unsigned char cpumask[256];
int node, idx, bit;
int max_node, max_cpus;
max_node = numa_max_node();
max_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if (cpu > max_cpus) {
errno = EINVAL;
return -1;
}
/* calculate bitmask index and relative bit position of cpu */
idx = cpu / 8;
bit = cpu % 8;
for (node = 0; node <= max_node; node++) {
if (numa_node_to_cpus(node, (void *) cpumask, sizeof(cpumask)))
return -1;
if (cpumask[idx] & (1<<bit))
return node;
}
errno = EINVAL;
return -1;
}
static inline unsigned int rt_numa_bitmask_isbitset( const struct bitmask *mask,
unsigned long i)
{
long bit = mask->maskp[i/BITS_PER_LONG] & (1<<(i % BITS_PER_LONG));
return (bit != 0);
}
static inline struct bitmask* rt_numa_parse_cpustring(const char* s,
int max_cpus)
{
int cpu;
struct bitmask *mask = NULL;
cpu = atoi(s);
if (0 <= cpu && cpu < max_cpus) {
mask = malloc(sizeof(*mask));
if (mask) {
/* Round up to integral number of longs to contain
* max_cpus bits */
int nlongs = (max_cpus+BITS_PER_LONG-1)/BITS_PER_LONG;
mask->maskp = calloc(nlongs, sizeof(long));
if (mask->maskp) {
mask->maskp[cpu/BITS_PER_LONG] |=
(1UL << (cpu % BITS_PER_LONG));
mask->size = max_cpus;
} else {
free(mask);
mask = NULL;
}
}
}
return mask;
}
static inline void rt_bitmask_free(struct bitmask *mask)
{
free(mask->maskp);
free(mask);
}
#endif /* LIBNUMA_API_VERSION */
static void numa_on_and_available()
{
if (numa && (numa_available() == -1))
fatal("--numa specified and numa functions not available.\n");
}
#else /* ! NUMA */
struct bitmask {
unsigned long size; /* number of bits in the map */
unsigned long *maskp;
};
#define BITS_PER_LONG (8*sizeof(long))
static inline void *threadalloc(size_t size, int n) { return malloc(size); }
static inline void threadfree(void *ptr, size_t s, int n) { free(ptr); }
static inline void rt_numa_set_numa_run_on_node(int n, int c) { }
static inline int rt_numa_numa_node_of_cpu(int cpu) { return -1; }
static void *rt_numa_numa_alloc_onnode(size_t s, int n, int c) { return NULL; }
/*
* Map legacy CPU affinity behavior onto bit mask infrastructure
*/
static inline unsigned int rt_numa_bitmask_isbitset( const struct bitmask *mask,
unsigned long i)
{
long bit = mask->maskp[i/BITS_PER_LONG] & (1<<(i % BITS_PER_LONG));
return (bit != 0);
}
static inline struct bitmask* rt_numa_parse_cpustring(const char* s,
int max_cpus)
{
int cpu;
struct bitmask *mask = NULL;
cpu = atoi(s);
if (0 <= cpu && cpu < max_cpus) {
mask = malloc(sizeof(*mask));
if (mask) {
/* Round up to integral number of longs to contain
* max_cpus bits */
int nlongs = (max_cpus+BITS_PER_LONG-1)/BITS_PER_LONG;
mask->maskp = calloc(nlongs, sizeof(unsigned long));
if (mask->maskp) {
mask->maskp[cpu/BITS_PER_LONG] |=
(1UL << (cpu % BITS_PER_LONG));
mask->size = max_cpus;
} else {
free(mask);
mask = NULL;
}
}
}
return mask;
}
static inline void rt_bitmask_free(struct bitmask *mask)
{
free(mask->maskp);
free(mask);
}
static void numa_on_and_available()
{
if (numa) /* NUMA is not defined here */
fatal("--numa specified and numa functions not available.\n");
}
#endif /* NUMA */
/*
* Any behavioral differences above are transparent to these functions
*/
/** Returns number of bits set in mask. */
static inline unsigned int rt_numa_bitmask_count(const struct bitmask *mask)
{
unsigned int num_bits = 0, i;
for (i = 0; i < mask->size; i++) {
if (rt_numa_bitmask_isbitset(mask, i))
num_bits++;
}
/* Could stash this instead of recomputing every time. */
return num_bits;
}
#endif /* _RT_NUMA_H */
......@@ -26,8 +26,6 @@
#include <time.h>
#include <unistd.h>
#include "rt-utils.h"
/*
* From cyclictest code source
*/
......@@ -36,6 +34,8 @@
#define KVARNAMELEN 32
#define KVALUELEN 32
#define MAX_PATH 255
static char *fileprefix;
static char *procfileprefix = "/proc/sys/kernel/";
static char *debugfileprefix = "/sys/kernel/debug/tracing/";
......@@ -72,22 +72,6 @@ static void setkernvar(const char *name, char *value) {
fprintf(stderr, "could not set %s to %s\n", name, value);
}
static int trace_file_exists(char *name) {
struct stat sbuf;
char *tracing_prefix = get_debugfileprefix();
char path[MAX_PATH];
strcat(strcpy(path, tracing_prefix), name);
return stat(path, &sbuf) ? 0 : 1;
}
static int settracer(char *tracer) {
if (valid_tracer(tracer)) {
setkernvar("current_tracer", tracer);
return 0;
}
return -1;
}
void setup_tracer(void) {
fileprefix = procfileprefix;
......@@ -95,17 +79,14 @@ void setup_tracer(void) {
fileprefix = debugfileprefix;
// Clear old traces by setting tracer to nop first
settracer("nop");
settracer("function");
setkernvar("current_tracer", "nop");
setkernvar("current_tracer", "function");
/* open the tracing on file descriptor */
if (trace_fd == -1) {
char path[MAX_PATH];
strcpy(path, fileprefix);
if (trace_file_exists("tracing_on"))
strcat(path, "tracing_on");
else
strcat(path, "tracing_enabled");
strcat(path, "tracing_on");
if ((trace_fd = open(path, O_WRONLY)) == -1)
printf("unable to open %s for tracing", path);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment