Commit 6cbbb8e5 authored by Joanne Hugé's avatar Joanne Hugé

Add ftrace implementation from cyclictest

parent fda562fd
...@@ -4,6 +4,9 @@ PROG = clockres ...@@ -4,6 +4,9 @@ PROG = clockres
SRCDIR = ../src SRCDIR = ../src
SRCS = clockres.c SRCS = clockres.c
SRCS += tracer.c
SRCS += rt-utils.c
SRCS += rt-sched.c
OBJS = $(SRCS:%.c=%.o) OBJS = $(SRCS:%.c=%.o)
...@@ -12,6 +15,8 @@ CFLAGS += -MD -MP ...@@ -12,6 +15,8 @@ CFLAGS += -MD -MP
CFLAGS += -I $(SRCDIR) CFLAGS += -I $(SRCDIR)
CFLAGS += -std=gnu99 CFLAGS += -std=gnu99
CPPFLAGS = -D_GNU_SOURCE
LDFLAGS = -pthread LDFLAGS = -pthread
vpath %.c $(SRCDIR) vpath %.c $(SRCDIR)
......
#include <errno.h> #include <errno.h>
#include <error.h> #include <error.h>
#include <inttypes.h>
#include <pthread.h> #include <pthread.h>
#include <sched.h> #include <sched.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <stdint.h>
#include <inttypes.h> #include "tracer.h"
#define CLOCK_ID CLOCK_MONOTONIC #define CLOCK_ID CLOCK_MONOTONIC
#define NSEC_PER_SEC INT64_C(1000000000) #define NSEC_PER_SEC INT64_C(1000000000)
...@@ -30,7 +32,8 @@ typedef struct main_param { ...@@ -30,7 +32,8 @@ typedef struct main_param {
int refresh_rate; int refresh_rate;
} main_param_t; } main_param_t;
static void process_options(int argc, char *argv[], thread_param_t * param, main_param_t * main_param); static void process_options(int argc, char *argv[], thread_param_t *param,
main_param_t *main_param);
static inline uint64_t calcdiff_ns(struct timespec t1, struct timespec t2); static inline uint64_t calcdiff_ns(struct timespec t1, struct timespec t2);
static inline uint64_t max(uint64_t a, uint64_t b); static inline uint64_t max(uint64_t a, uint64_t b);
...@@ -38,13 +41,12 @@ static inline uint64_t min(uint64_t a, uint64_t b); ...@@ -38,13 +41,12 @@ static inline uint64_t min(uint64_t a, uint64_t b);
// Real-time thread // Real-time thread
static void *timerthread(void *p) { static void *timerthread(void *p) {
struct timespec previous, current; struct timespec previous, current;
struct sched_param priority; struct sched_param priority;
uint64_t diff; uint64_t diff;
thread_param_t * param = (thread_param_t *)p; thread_param_t *param = (thread_param_t *)p;
thread_stat_t * stat = &param->stat; thread_stat_t *stat = &param->stat;
priority.sched_priority = param->priority; priority.sched_priority = param->priority;
...@@ -54,10 +56,8 @@ static void *timerthread(void *p) { ...@@ -54,10 +56,8 @@ static void *timerthread(void *p) {
stat->max_res = 0; stat->max_res = 0;
stat->min_res = UINT64_MAX; stat->min_res = UINT64_MAX;
for(stat->nb_cycles = 0;; stat->nb_cycles++) { for (stat->nb_cycles = 0;; stat->nb_cycles++) {
if (param->max_cycles && (stat->nb_cycles >= param->max_cycles)) break;
if(param->max_cycles && (stat->nb_cycles >= param->max_cycles))
break;
clock_gettime(CLOCK_ID, &previous); clock_gettime(CLOCK_ID, &previous);
clock_gettime(CLOCK_ID, &current); clock_gettime(CLOCK_ID, &current);
...@@ -76,78 +76,72 @@ static void *timerthread(void *p) { ...@@ -76,78 +76,72 @@ static void *timerthread(void *p) {
// Main thread, has non-real time priority // Main thread, has non-real time priority
// Handles the IO and creates real time threads // Handles the IO and creates real time threads
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
pthread_t thread; pthread_t thread;
thread_param_t param; thread_param_t param;
main_param_t main_param; main_param_t main_param;
// Default values // Default values
param.interval= 1000; param.interval = 1000;
param.max_cycles = 100000; param.max_cycles = 100000;
param.priority = 99; param.priority = 99;
main_param.refresh_rate = 10000; main_param.refresh_rate = 10000;
process_options(argc, argv, &param, &main_param); process_options(argc, argv, &param, &main_param);
setup_tracer();
usleep(10000); usleep(10000);
if(pthread_create(&thread, NULL, timerthread, (void *)&param)) if (pthread_create(&thread, NULL, timerthread, (void *)&param))
error(EXIT_FAILURE, errno, "Couldn't create thread"); error(EXIT_FAILURE, errno, "Couldn't create thread");
for (;;) { for (;;) {
usleep(main_param.refresh_rate); usleep(main_param.refresh_rate);
printf("Maximum res: %" PRIu64 "ns (%d)", (param.stat.max_res), param.stat.nb_cycles); printf("Maximum res: %" PRIu64 "ns (%d)", (param.stat.max_res),
printf(", minimum res: %" PRIu64 "ns (%d)\n", (param.stat.min_res), param.stat.nb_cycles); param.stat.nb_cycles);
printf(", minimum res: %" PRIu64 "ns (%d)\n", (param.stat.min_res),
param.stat.nb_cycles);
if( param.max_cycles == param.stat.nb_cycles ) if (param.max_cycles == param.stat.nb_cycles) break;
break;
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
static void process_options(int argc, char *argv[], thread_param_t * param, main_param_t * main_param) { static void process_options(int argc, char *argv[], thread_param_t *param,
main_param_t *main_param) {
for(;;) { for (;;) {
int c = getopt(argc, argv, "l:p:i:r:"); int c = getopt(argc, argv, "l:p:i:r:");
if(c == -1) if (c == -1) break;
break;
switch (c) {
switch(c) { case 'p':
case 'p': param->priority = atoi(optarg);
param->priority = atoi(optarg); break;
break; case 'l':
case 'l': param->max_cycles = atoi(optarg);
param->max_cycles = atoi(optarg); break;
break; case 'i':
case 'i': param->interval = atoi(optarg);
param->interval = atoi(optarg); break;
break; case 'r':
case 'r': main_param->refresh_rate = atoi(optarg);
main_param->refresh_rate = atoi(optarg); break;
break; default:
default: exit(EXIT_FAILURE);
exit(EXIT_FAILURE); break;
break;
} }
} }
} }
static inline uint64_t calcdiff_ns(struct timespec t1, struct timespec t2) static inline uint64_t calcdiff_ns(struct timespec t1, struct timespec t2) {
{ uint64_t diff;
uint64_t diff; diff = NSEC_PER_SEC * (uint64_t)((int)t1.tv_sec - (int)t2.tv_sec);
diff = NSEC_PER_SEC * (uint64_t)((int) t1.tv_sec - (int) t2.tv_sec); diff += ((int)t1.tv_nsec - (int)t2.tv_nsec);
diff += ((int) t1.tv_nsec - (int) t2.tv_nsec); return diff;
return diff;
} }
static inline uint64_t max(uint64_t a, uint64_t b) { static inline uint64_t max(uint64_t a, uint64_t b) { return a > b ? a : b; }
return a > b ? a : b; static inline uint64_t min(uint64_t a, uint64_t b) { return a < b ? a : b; }
}
static inline uint64_t min(uint64_t a, uint64_t b) {
return a < b ? a : b;
}
/*
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 */
#include "tracer.h"
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <linux/unistd.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/sysinfo.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>
#include "rt-utils.h"
/*
* From cyclictest code source
*/
#define KVARS 32
#define KVARNAMELEN 32
#define KVALUELEN 32
static char *fileprefix;
static char *procfileprefix = "/proc/sys/kernel/";
static char *traceroptions = "trace_options";
static int trace_fd = -1;
static int kernvar(int mode, const char *name, char *value,
size_t sizeofvalue) {
char filename[128];
int retval = 1;
int path;
size_t len_prefix = strlen(fileprefix), len_name = strlen(name);
if (len_prefix + len_name + 1 > sizeof(filename)) {
errno = ENOMEM;
return 1;
}
memcpy(filename, fileprefix, len_prefix);
memcpy(filename + len_prefix, name, len_name + 1);
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;
}
static void setkernvar(const char *name, char *value) {
if (kernvar(O_WRONLY, name, value, strlen(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;
}
static void debugfs_prepare(void) {
if (mount_debugfs(NULL)) printf("could not mount debugfs");
fileprefix = get_debugfileprefix();
if (!trace_file_exists("tracing_enabled") && !trace_file_exists("tracing_on"))
printf(
"tracing_enabled or tracing_on not found\n, debug fs not mounted, "
"TRACERs not configured?\n");
}
void setup_tracer(void) {
debugfs_prepare();
int ret;
if (trace_file_exists("tracing_enabled") && !trace_file_exists("tracing_on"))
setkernvar("tracing_enabled", "1");
/* ftrace_enabled is a sysctl variable */
/* turn it on if you're doing anything but nop or event tracing */
fileprefix = procfileprefix;
setkernvar("ftrace_enabled", "0");
fileprefix = get_debugfileprefix();
// Clear old traces by setting tracer to nop first
ret = settracer("nop");
ret = settracer("function");
if (ret) fprintf(stderr, "Requested tracer not available\n");
setkernvar(traceroptions, "print-parent");
setkernvar(traceroptions, "latency-format");
setkernvar(traceroptions, "nosym-offset");
setkernvar(traceroptions, "nosym-addr");
setkernvar(traceroptions, "noverbose");
setkernvar("tracing_max_latency", "0");
if (trace_file_exists("latency_hist"))
setkernvar("latency_hist/wakeup/reset", "1");
/* 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");
if ((trace_fd = open(path, O_WRONLY)) == -1)
printf("unable to open %s for tracing", path);
}
tracing(1);
}
void tracing(int on) {
if (on)
write(trace_fd, "1", 1);
else
write(trace_fd, "0", 1);
}
#ifndef TRACER_H
#define TRACER_H
void setup_tracer(void);
void tracing(int on);
#endif
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