/* * Copyright (C) 2009 Carsten Emde * Copyright (C) 2010 Clark Williams * * based on functions from cyclictest that has * (C) 2008-2009 Clark Williams * (C) 2005-2007 Thomas Gleixner */ #include #include #include #include #include #include #include #include #include #include #include /* 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) { info("debugfs mountpoint: %s\n", prefix); return 0; } if (!mountpoint) mountpoint = "/sys/kernel/debug"; sprintf(cmd, "mount -t debugfs debugfs %s", mountpoint); ret = system(cmd); if (ret != 0) { fprintf(stderr, "Error mounting debugfs at %s: %s\n", mountpoint, strerror(errno)); return -1; } return 0; } static char **tracer_list; static char *tracer_buffer; static int num_tracers; #define CHUNKSZ 1024 /* * return a list of the tracers configured into the running kernel */ int get_tracers(char ***list) { int ret; FILE *fp; char buffer[CHUNKSZ]; char *prefix = get_debugfileprefix(); char *tmpbuf = NULL; char *ptr; int tmpsz = 0; /* if we've already parse it, return what we have */ if (tracer_list) { *list = tracer_list; return num_tracers; } /* open the tracing file available_tracers */ sprintf(buffer, "%savailable_tracers", prefix); if ((fp = fopen(buffer, "r")) == NULL) fatal ("Can't open %s for reading\n", buffer); /* allocate initial buffer */ ptr = tmpbuf = malloc(CHUNKSZ); if (ptr == NULL) fatal("error allocating initial space for tracer list\n"); /* read in the list of available tracers */ while((ret = fread(buffer, sizeof(char), CHUNKSZ, fp))) { if ((ptr+ret+1) > (tmpbuf+tmpsz)) { tmpbuf = realloc(tmpbuf, tmpsz + CHUNKSZ); if (tmpbuf == NULL) fatal("error allocating space for list of valid tracers\n"); tmpsz += CHUNKSZ; } strncpy(ptr, buffer, ret); ptr += ret; } fclose(fp); if (tmpsz == 0) fatal("error reading available tracers\n"); tracer_buffer = tmpbuf; /* get a buffer for the pointers to tracers */ if (!(tracer_list = malloc(sizeof(char *)))) fatal ("error allocatinging tracer list buffer\n"); /* parse the buffer */ ptr = strtok(tmpbuf, " \t\n\r"); do { tracer_list[num_tracers++] = ptr; tracer_list = realloc(tracer_list, sizeof(char*)*(num_tracers+1)); tracer_list[num_tracers] = NULL; } while ((ptr = strtok(NULL, " \t\n\r")) != NULL); /* return the list and number of tracers */ *list = tracer_list; return num_tracers; } /* * return zero if tracername is not a valid tracer, non-zero if it is */ int valid_tracer(char *tracername) { char **list; int ntracers; int i; ntracers = get_tracers(&list); if (ntracers == 0 || tracername == NULL) return 0; for (i = 0; i < ntracers; i++) if (strncmp(list[i], tracername, strlen(list[i])) == 0) return 1; return 0; } /* * enable event tracepoint */ int setevent(char *event, char *val) { char *prefix = get_debugfileprefix(); char buffer[MAX_PATH]; int fd; int ret; sprintf(buffer, "%s%s", prefix, event); if ((fd = open(buffer, O_WRONLY)) < 0) { warn("unable to open %s\n", buffer); return -1; } if ((ret = write(fd, val, strlen(val))) < 0) { warn("unable to write %s to %s\n", val, buffer); close(fd); return -1; } close(fd); return 0; } int event_enable_all(void) { return setevent("events/enable", "1"); } int event_disable_all(void) { return setevent("events/enable", "0"); } int event_enable(char *event) { char path[MAX_PATH]; sprintf(path, "events/%s/enable", event); return setevent(path, "1"); } int event_disable(char *event) { char path[MAX_PATH]; sprintf(path, "events/%s/enable", event); return setevent(path, "0"); } int check_privs(void) { int policy = sched_getscheduler(0); 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, ¶m)) { 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); }