staticconstchar * const queue_full_warning = "Could not queue trace for printing. It is likely that events happen faster\n" "than what they can be printed. Probably partly because of random sleeping\n";
staticconstchar * const no_tracer_msg = "Could not find any tracers! Running this program as root may help!\n";
staticconstchar * const no_latency_tr_msg = "No latency tracers are supported by your kernel!\n";
struct policy { constchar *name; int policy; int default_pri;
};
/* * The default tracer will be the first on this list that is supported by the * currently running Linux kernel.
*/ staticconstchar * const relevant_tracers[] = { "preemptirqsoff", "preemptoff", "irqsoff", "wakeup", "wakeup_rt", "wakeup_dl",
NULL
};
/* This is the list of tracers for which random sleep makes sense */ staticconstchar * const random_tracers[] = { "preemptirqsoff", "preemptoff", "irqsoff",
NULL
};
name = strsignal(signal); if (name == NULL)
printf("Received signal %d\n", signal); else
printf("Received signal %d (%s)\n", signal, name);
cleanup_exit(EXIT_SUCCESS);
}
static __always_inline void check_signals(void)
{ int signal = signal_flag;
if (unlikely(signal))
process_signal(signal);
}
static __always_inline void get_time_in_future(struct timespec *future, long time_us)
{ long nsec;
clock_gettime_or_die(CLOCK_MONOTONIC, &now); if (now.tv_sec > time->tv_sec) returntrue; if (now.tv_sec < time->tv_sec) returnfalse; return (now.tv_nsec >= time->tv_nsec);
}
staticbool mutex_trylock_limit(pthread_mutex_t *mutex, int time_ms)
{ long time_us = time_ms * USEC_PER_MSEC; struct timespec limit;
get_time_in_future(&limit, time_us); do {
errno = pthread_mutex_trylock(mutex); if (errno && errno != EBUSY)
err(EXIT_FAILURE, "pthread_mutex_trylock() failed");
} while (errno && !time_has_passed(&limit)); return errno == 0;
}
staticvoid restore_trace_opts(conststruct ftrace_state *state, constbool *cur)
{ int i; int r;
for (i = 0; i < OPTIDX_NR; i++) if (state->opt_valid[i] && state->opt[i] != cur[i]) {
r = set_trace_opt(optstr[i], state->opt[i]); if (r < 0)
warnx("Failed to restore the %s option to %s",
optstr[i], bool2str(state->opt[i])); elseif (verbose_ftrace())
printf("Restored the %s option in %s to %s\n",
optstr[i], TR_OPTIONS,
bool2str(state->opt[i]));
}
}
staticchar *read_file(constchar *file, enum errhandling h)
{ int psize; char *r; staticconstchar *emsg = "Failed to read the %s file";
r = tracefs_instance_file_read(NULL, file, &psize); if (!r) { if (h) {
warn(emsg, file); if (h == ERR_CLEANUP)
cleanup_exit(EXIT_FAILURE);
} else
errx(EXIT_FAILURE, emsg, file);
}
/* * We try the print_mtx for 1 sec in order to avoid garbled * output if possible, but if it cannot be obtained we proceed anyway.
*/
mutex_trylock_limit(&print_mtx, TRY_PRINTMUTEX_MS);
maxlat = read_file(TR_MAXLAT, ERR_WARN); if (maxlat) {
printf("The maximum detected latency was: %sus\n", maxlat);
free(maxlat);
}
restore_ftrace(); /* * We do not need to unlock the print_mtx here because we will exit at * the end of this function. Unlocking print_mtx causes problems if a * print thread happens to be waiting for the mutex because we have * just changed the ftrace settings to the original and thus the * print thread would output incorrect data from ftrace.
*/ exit(status);
}
if (printout) {
msg->len = 0; if (unlikely(size > PROB_TABLE_MAX_SIZE))
bytes = snprintf(msg->buf, sizeof(msg->buf), "Cannot increase probability table to %d (maximum size reached)\n", size); else
bytes = snprintf(msg->buf, sizeof(msg->buf), "Increasing probability table to %d\n", size); if (bytes < 0)
warn("snprintf() failed"); else
msg->len = bytes;
}
if (unlikely(size < 0)) { /* Should never happen */
warnx("Bad program state at %s:%d", __FILE__, __LINE__);
cleanup_exit(EXIT_FAILURE); return;
}
sleeptable.size = size;
sleeptable.table = &probabilities[PROB_TABLE_MAX_SIZE - size];
}
staticvoid init_probabilities(void)
{ int i; int j = 1000;
for (i = 0; i < PROB_TABLE_MAX_SIZE; i++) {
probabilities[i] = 1000 / j;
j--;
}
mutex_init(&sleeptable.mutex, NULL);
}
staticint table_get_probability(conststruct entry *req, struct short_msg *msg)
{ int diff = req->ticket - req->ticket_completed_ref; int rval = 0;
static __always_inline int queue_nr_free(conststruct queue *q)
{ int nr_free = QUEUE_SIZE - queue_len(q);
/* * If there is only one slot left we will anyway lie and claim that the * queue is full because adding an element will make it appear empty
*/ if (nr_free == 1)
nr_free = 0; return nr_free;
}
for (i = 0; random_tracers[i]; i++) if (!strcmp(name, random_tracers[i])) returntrue; returnfalse;
}
staticvoid show_available(void)
{ char **tracers; int found = 0; int i;
tracers = tracefs_tracers(NULL); for (i = 0; tracers && tracers[i]; i++) { if (is_relevant_tracer(tracers[i]))
found++;
}
if (!tracers) {
warnx("%s", no_tracer_msg); return;
}
if (!found) {
warnx("%s", no_latency_tr_msg);
tracefs_list_free(tracers); return;
}
printf("The following latency tracers are available on your system:\n"); for (i = 0; tracers[i]; i++) { if (is_relevant_tracer(tracers[i]))
printf("%s\n", tracers[i]);
}
tracefs_list_free(tracers);
}
if (bytes < 0) {
warn("snprintf() failed"); return;
}
p += bytes;
bufspace -= bytes;
bytes_tot += bytes;
bytes = snprintf(p, bufspace, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> BEGIN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"
);
if (bytes < 0) {
warn("snprintf() failed"); return;
}
p += bytes;
bufspace -= bytes;
bytes_tot += bytes;
do {
bytes = read(trace_fd, p, bufspace); if (bytes < 0) { if (errno == EINTR) continue;
warn("read() failed on %s", debug_tracefile); if (unlikely(close(trace_fd) != 0))
warn("close() failed on %s", debug_tracefile); return;
} if (bytes == 0) break;
p += bytes;
bufspace -= bytes;
bytes_tot += bytes;
} while (true);
if (unlikely(close(trace_fd) != 0))
warn("close() failed on %s", debug_tracefile);
printstate_cnt_dec(); /* Add the reserve space back to the budget for the final string */
bufspace += reserve;
bytes = snprintf(p, bufspace, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
if (bytes < 0) {
warn("snprintf() failed"); return;
}
bytes_tot += bytes;
/* These prints could happen concurrently */
mutex_lock(&print_mtx);
write_or_die(fd_stdout, buffer, bytes_tot);
mutex_unlock(&print_mtx);
}
staticchar *get_no_opt(constchar *opt)
{ char *no_opt; int s;
s = strlen(opt) + strlen(OPT_NO_PREFIX) + 1; /* We may be called from cleanup_exit() via set_trace_opt() */
no_opt = malloc_or_die_nocleanup(s);
strcpy(no_opt, OPT_NO_PREFIX);
strcat(no_opt, opt); return no_opt;
}
staticchar *find_next_optstr(constchar *allopt, constchar **next)
{ constchar *begin; constchar *end; char *r; int s = 0;
if (allopt == NULL) return NULL;
for (begin = allopt; *begin != '\0'; begin++) { if (isgraph(*begin)) break;
}
do {
str = find_next_optstr(next, &next); if (str == NULL) break; if (!strcmp(str, opt)) {
*found = true;
rval = true;
free(str); break;
} if (!strcmp(str, no_opt)) {
*found = true;
rval = false;
free(str); break;
}
free(str);
} while (true);
free(no_opt);
return rval;
}
staticint set_trace_opt(constchar *opt, bool value)
{ char *str; int r;
if (value)
str = strdup(opt); else
str = get_no_opt(opt);
r = tracefs_instance_file_write(NULL, TR_OPTIONS, str);
free(str); return r;
}
void save_trace_opts(struct ftrace_state *state)
{ char *allopt; int psize; int i;
allopt = tracefs_instance_file_read(NULL, TR_OPTIONS, &psize); if (!allopt)
errx(EXIT_FAILURE, "Failed to read the %s file\n", TR_OPTIONS);
for (i = 0; i < OPTIDX_NR; i++)
state->opt[i] = get_trace_opt(allopt, optstr[i],
&state->opt_valid[i]);
free(allopt);
}
staticvoid write_file(constchar *file, constchar *cur, constchar *new, enum errhandling h)
{ int r; staticconstchar *emsg = "Failed to write to the %s file!";
/* Do nothing if we now that the current and new value are equal */ if (cur && !needs_change(cur, new)) return;
r = tracefs_instance_file_write(NULL, file, new); if (r < 0) { if (h) {
warnx(emsg, file); if (h == ERR_CLEANUP)
cleanup_exit(EXIT_FAILURE);
} else
errx(EXIT_FAILURE, emsg, file);
} if (verbose_ftrace()) {
mutex_lock(&print_mtx);
printf("%s was set to %s\n", file, new);
mutex_unlock(&print_mtx);
}
}
if (needs_change(tracer, NOP_TRACER)) {
mutex_lock(&print_mtx); if (force_tracer) {
printf( "The %s tracer is already in use but proceeding anyway!\n",
tracer);
} else {
printf( "The %s tracer is already in use, cowardly bailing out!\n" "This could indicate that another program or instance is tracing.\n" "Use the -F [--force] option to disregard the current tracer.\n", tracer); exit(0);
}
mutex_unlock(&print_mtx);
need_nop = true;
}
if (need_nop)
write_file(TR_CURRENT, NULL, NOP_TRACER, ERR_EXIT);
mutex_unlock(&save_state.mutex);
}
void set_trace_opts(struct ftrace_state *state, bool *new)
{ int i; int r;
/* * We only set options if we earlier detected that the option exists in * the trace_options file and that the wanted setting is different from * the one we saw in save_and_disable_tracer()
*/ for (i = 0; i < OPTIDX_NR; i++) if (state->opt_valid[i] &&
state->opt[i] != new[i]) {
r = set_trace_opt(optstr[i], new[i]); if (r < 0) {
warnx("Failed to set the %s option to %s",
optstr[i], bool2str(new[i]));
cleanup_exit(EXIT_FAILURE);
} if (verbose_ftrace()) {
mutex_lock(&print_mtx);
printf("%s in %s was set to %s\n", optstr[i],
TR_OPTIONS, bool2str(new[i]));
mutex_unlock(&print_mtx);
}
}
}
if (ifd < 0)
err(EXIT_FAILURE, "inotify_init() failed!");
if (setup_ftrace) { /* * We must disable the tracer before resetting the max_latency
*/
save_and_disable_tracer(); /* * We must reset the max_latency before the inotify_add_watch() * call.
*/
reset_max_latency();
}
if (srand48_r(*rseed, &drandbuf) != 0) {
warn("srand48_r() failed!\n");
cleanup_exit(EXIT_FAILURE);
}
buffer = malloc_or_die(bufspace);
while (true) {
req = queue_wait_for_entry(&printqueue);
clock_gettime_or_die(CLOCK_MONOTONIC, ×tamp);
mutex_lock(&printstate.mutex); if (prev_req_won_race(&req)) {
printstate_mark_req_completed(&req);
mutex_unlock(&printstate.mutex); if (verbose_lostevent())
print_lostmessage(×tamp, buffer, bufspace,
&req, "print loop"); continue;
}
mutex_unlock(&printstate.mutex);
/* * Toss a coin to decide if we want to sleep before printing * out the backtrace. The reason for this is that opening * /sys/kernel/tracing/trace will cause a blackout of * hundreds of ms, where no latencies will be noted by the * latency tracer. Thus by randomly sleeping we try to avoid * missing traces systematically due to this. With this option * we will sometimes get the first latency, some other times * some of the later ones, in case of closely spaced traces.
*/ if (trace_enable && use_random_sleep) {
slept = 0;
prob = table_get_probability(&req, &resize_msg); if (!toss_coin(&drandbuf, prob))
slept = go_to_sleep(&req); if (slept >= 0) { /* A print is ongoing */
printstate_cnt_inc(); /* * We will do the printout below so we have to * mark it as completed while we still have the * mutex.
*/
mutex_lock(&printstate.mutex);
printstate_mark_req_completed(&req);
mutex_unlock(&printstate.mutex);
}
} if (trace_enable) { /* * slept < 0 means that we detected another * notification in go_to_sleep() above
*/ if (slept >= 0) /* * N.B. printstate_cnt_dec(); will be called * inside print_tracefile()
*/
print_tracefile(&resize_msg, ×tamp, buffer,
bufspace, slept, &req); else
print_skipmessage(&resize_msg, ×tamp,
buffer, bufspace, &req, true);
} else {
print_skipmessage(&resize_msg, ×tamp, buffer,
bufspace, &req, false);
}
} return NULL;
}
staticvoid start_printthread(void)
{ unsignedint i; long *seed; int ufd;
ufd = open(DEV_URANDOM, O_RDONLY); if (nr_threads > MAX_THREADS) {
warnx( "Number of requested print threads was %d, max number is %d\n",
nr_threads, MAX_THREADS);
nr_threads = MAX_THREADS;
} for (i = 0; i < nr_threads; i++) {
seed = malloc_or_die(sizeof(*seed)); if (ufd < 0 ||
read(ufd, seed, sizeof(*seed)) != sizeof(*seed)) {
printf( "Warning! Using trivial random number seed, since %s not available\n",
DEV_URANDOM);
fflush(stdout);
*seed = i;
}
errno = pthread_create(&printthread[i], NULL, do_printloop,
seed); if (errno)
err(EXIT_FAILURE, "pthread_create()");
} if (ufd > 0 && close(ufd) != 0)
warn("close() failed");
}
staticvoid show_usage(void)
{
printf( "Usage: %s [OPTION]...\n\n" "Collect closely occurring latencies from %s\n" "with any of the following tracers: preemptirqsoff, preemptoff, irqsoff, " "wakeup,\nwakeup_dl, or wakeup_rt.\n\n"
"The occurrence of a latency is detected by monitoring the file\n" "%s with inotify.\n\n"
"The following options are supported:\n\n"
"-l, --list\t\tList the latency tracers that are supported by the\n" "\t\t\tcurrently running Linux kernel. If you don't see the\n" "\t\t\ttracer that you want, you will probably need to\n" "\t\t\tchange your kernel config and build a new kernel.\n\n"
"-t, --tracer TR\t\tUse the tracer TR. The default is to use the first\n" "\t\t\ttracer that is supported by the kernel in the following\n" "\t\t\torder of precedence:\n\n" "\t\t\tpreemptirqsoff\n" "\t\t\tpreemptoff\n" "\t\t\tirqsoff\n" "\t\t\twakeup\n" "\t\t\twakeup_rt\n" "\t\t\twakeup_dl\n" "\n" "\t\t\tIf TR is not on the list above, then a warning will be\n" "\t\t\tprinted.\n\n"
"-F, --force\t\tProceed even if another ftrace tracer is active. Without\n" "\t\t\tthis option, the program will refuse to start tracing if\n" "\t\t\tany other tracer than the nop tracer is active.\n\n"
"-s, --threshold TH\tConfigure ftrace to use a threshold of TH microseconds\n" "\t\t\tfor the tracer. The default is 0, which means that\n" "\t\t\ttracing_max_latency will be used. tracing_max_latency is\n" "\t\t\tset to 0 when the program is started and contains the\n" "\t\t\tmaximum of the latencies that have been encountered.\n\n"
"-f, --function\t\tEnable the function-trace option in trace_options. With\n" "\t\t\tthis option, ftrace will trace the functions that are\n" "\t\t\texecuted during a latency, without it we only get the\n" "\t\t\tbeginning, end, and backtrace.\n\n"
"-g, --graph\t\tEnable the display-graph option in trace_option. This\n" "\t\t\toption causes ftrace to show the graph of how functions\n" "\t\t\tare calling other functions.\n\n"
"-c, --policy POL\tRun the program with scheduling policy POL. POL can be\n" "\t\t\tother, batch, idle, rr or fifo. The default is rr. When\n" "\t\t\tusing rr or fifo, remember that these policies may cause\n" "\t\t\tother tasks to experience latencies.\n\n"
"-p, --priority PRI\tRun the program with priority PRI. The acceptable range\n" "\t\t\tof PRI depends on the scheduling policy.\n\n"
"-n, --notrace\t\tIf latency is detected, do not print out the content of\n" "\t\t\tthe trace file to standard output\n\n"
"-t, --threads NRTHR\tRun NRTHR threads for printing. Default is %d.\n\n"
"-r, --random\t\tArbitrarily sleep a certain amount of time, default\n" "\t\t\t%ld ms, before reading the trace file. The\n" "\t\t\tprobabilities for sleep are chosen so that the\n" "\t\t\tprobability of obtaining any of a cluster of closely\n" "\t\t\toccurring latencies are equal, i.e. we will randomly\n" "\t\t\tchoose which one we collect from the trace file.\n\n" "\t\t\tThis option is probably only useful with the irqsoff,\n" "\t\t\tpreemptoff, and preemptirqsoff tracers.\n\n"
"-a, --nrlat NRLAT\tFor the purpose of arbitrary delay, assume that there\n" "\t\t\tare no more than NRLAT clustered latencies. If NRLAT\n" "\t\t\tlatencies are detected during a run, this value will\n" "\t\t\tautomatically be increased to NRLAT + 1 and then to\n" "\t\t\tNRLAT + 2 and so on. The default is %d. This option\n" "\t\t\timplies -r. We need to know this number in order to\n" "\t\t\tbe able to calculate the probabilities of sleeping.\n" "\t\t\tSpecifically, the probabilities of not sleeping, i.e. to\n" "\t\t\tdo an immediate printout will be:\n\n" "\t\t\t1/NRLAT 1/(NRLAT - 1) ... 1/3 1/2 1\n\n" "\t\t\tThe probability of sleeping will be:\n\n" "\t\t\t1 - P, where P is from the series above\n\n" "\t\t\tThis descending probability will cause us to choose\n" "\t\t\tan occurrence at random. Observe that the final\n" "\t\t\tprobability is 0, it is when we reach this probability\n" "\t\t\tthat we increase NRLAT automatically. As an example,\n" "\t\t\twith the default value of 2, the probabilities will be:\n\n" "\t\t\t1/2 0\n\n" "\t\t\tThis means, when a latency is detected we will sleep\n" "\t\t\twith 50%% probability. If we ever detect another latency\n" "\t\t\tduring the sleep period, then the probability of sleep\n" "\t\t\twill be 0%% and the table will be expanded to:\n\n" "\t\t\t1/3 1/2 0\n\n"
"-v, --verbose\t\tIncrease the verbosity. If this option is given once,\n" "\t\t\tthen print a message every time that the NRLAT value\n" "\t\t\tis automatically increased. It also causes a message to\n" "\t\t\tbe printed when the ftrace settings are changed. If this\n" "\t\t\toption is given at least twice, then also print a\n" "\t\t\twarning for lost events.\n\n"
"-u, --time TIME\t\tArbitrarily sleep for a specified time TIME ms before\n" "\t\t\tprinting out the trace from the trace file. The default\n" "\t\t\tis %ld ms. This option implies -r.\n\n"
"-x, --no-ftrace\t\tDo not configure ftrace. This assume that the user\n" "\t\t\tconfigures the ftrace files in sysfs such as\n" "\t\t\t/sys/kernel/tracing/current_tracer or equivalent.\n\n"
"-i, --tracefile FILE\tUse FILE as trace file. The default is\n" "\t\t\t%s.\n" "\t\t\tThis options implies -x\n\n"
staticvoid find_tracefiles(void)
{
debug_tracefile_dflt = tracefs_get_tracing_file("trace"); if (debug_tracefile_dflt == NULL) { /* This is needed in show_usage() */
debug_tracefile_dflt = DEBUG_NOFILE;
}
debug_maxlat_dflt = tracefs_get_tracing_file("tracing_max_latency"); if (debug_maxlat_dflt == NULL) { /* This is needed in show_usage() */
debug_maxlat_dflt = DEBUG_NOFILE;
}
/* * We must do this before parsing the arguments because show_usage() * needs to display these.
*/
find_tracefiles();
while (true) {
c = getopt_long(argc, argv, "lt:Fs:fgc:p:hnra:e:u:vxi:m:",
long_options, &option_idx); if (c == -1) break;
switch (c) { case'l':
show_available(); exit(0); break; case't':
current_tracer = strdup(optarg); if (!is_relevant_tracer(current_tracer)) {
warnx("%s is not a known latency tracer!\n",
current_tracer);
}
valid = tracer_valid(current_tracer, ¬racer); if (notracer)
errx(EXIT_FAILURE, "%s", no_tracer_msg); if (!valid)
errx(EXIT_FAILURE, "The tracer %s is not supported by your kernel!\n", current_tracer); break; case'F':
force_tracer = true; break; case's':
check_alldigits(optarg, "-s [--threshold]");
threshold = strdup(optarg); break; case'f':
use_options[OPTIDX_FUNC_TR] = true; break; case'g':
use_options[OPTIDX_DISP_GR] = true; break; case'c':
p = policy_from_name(optarg); if (p != NULL) {
sched_policy = p->policy;
sched_policy_set = true; if (!sched_pri_set) {
sched_pri = p->default_pri;
sched_pri_set = true;
}
} else {
warnx("Unknown scheduling %s\n", optarg);
show_usage(); exit(0);
} break; case'p':
check_alldigits(optarg, "-p [--priority]");
sched_pri = atoi(optarg);
sched_pri_set = true; break; case'h':
show_usage(); exit(0); break; case'n':
trace_enable = false;
use_random_sleep = false; break; case'e':
check_alldigits(optarg, "-e [--threads]");
value = atoi(optarg); if (value > 0)
nr_threads = value; else {
warnx("NRTHR must be > 0\n");
show_usage(); exit(0);
} break; case'u':
check_alldigits(optarg, "-u [--time]");
value = atoi(optarg); if (value < 0) {
warnx("TIME must be >= 0\n");
show_usage(); exit(0);
}
trace_enable = true;
use_random_sleep = true;
sleep_time = value * USEC_PER_MSEC; break; case'v':
verbosity++; break; case'r':
trace_enable = true;
use_random_sleep = true; break; case'a':
check_alldigits(optarg, "-a [--nrlat]");
value = atoi(optarg); if (value <= 0) {
warnx("NRLAT must be > 0\n");
show_usage(); exit(0);
}
trace_enable = true;
use_random_sleep = true;
table_startsize = value; break; case'x':
setup_ftrace = false; break; case'i':
setup_ftrace = false;
debug_tracefile = strdup(optarg); break; case'm':
setup_ftrace = false;
debug_maxlat = strdup(optarg); break; default:
show_usage(); exit(0); break;
}
}
if (setup_ftrace) { if (!current_tracer) {
current_tracer = find_default_tracer(); if (!current_tracer)
errx(EXIT_FAILURE, "No default tracer found and tracer not specified\n");
}
if (use_random_sleep && !random_makes_sense(current_tracer)) {
warnx("WARNING: The tracer is %s and random sleep has",
current_tracer);
fprintf(stderr, "been enabled. Random sleep is intended for the following tracers:\n"); for (i = 0; random_tracers[i]; i++)
fprintf(stderr, "%s\n", random_tracers[i]);
fprintf(stderr, "\n");
}
}
if (debug_tracefile == DEBUG_NOFILE ||
debug_maxlat == DEBUG_NOFILE)
errx(EXIT_FAILURE, "Could not find tracing directory e.g. /sys/kernel/tracing\n");
if (!sched_policy_set) {
sched_policy = SCHED_RR;
sched_policy_set = true; if (!sched_pri_set) {
sched_pri = RT_DEFAULT_PRI;
sched_pri_set = true;
}
}
max = sched_get_priority_max(sched_policy);
min = sched_get_priority_min(sched_policy);
if (sched_pri < min) {
printf( "ATTENTION: Increasing priority to minimum, which is %d\n", min);
sched_pri = min;
} if (sched_pri > max) {
printf( "ATTENTION: Reducing priority to maximum, which is %d\n", max);
sched_pri = max;
}
}
staticvoid show_params(void)
{
printf( "\n" "Running with scheduling policy %s and priority %d. Using %d print threads.\n",
policy_name(sched_policy), sched_pri, nr_threads); if (trace_enable) { if (use_random_sleep) {
printf( "%s will be printed with random delay\n" "Start size of the probability table:\t\t\t%d\n" "Print a message when the prob. table changes size:\t%s\n" "Print a warning when an event has been lost:\t\t%s\n" "Sleep time is:\t\t\t\t\t\t%ld ms\n",
debug_tracefile,
table_startsize,
bool2str(verbose_sizechange()),
bool2str(verbose_lostevent()),
sleep_time / USEC_PER_MSEC);
} else {
printf("%s will be printed immediately\n",
debug_tracefile);
}
} else {
printf("%s will not be printed\n",
debug_tracefile);
} if (setup_ftrace) {
printf("Tracer:\t\t\t\t\t\t\t%s\n" "%s option:\t\t\t\t\t%s\n" "%s option:\t\t\t\t\t%s\n",
current_tracer,
optstr[OPTIDX_FUNC_TR],
bool2str(use_options[OPTIDX_FUNC_TR]),
optstr[OPTIDX_DISP_GR],
bool2str(use_options[OPTIDX_DISP_GR])); if (!strcmp(threshold, "0"))
printf("Threshold:\t\t\t\t\t\ttracing_max_latency\n"); else
printf("Threshold:\t\t\t\t\t\t%s\n", threshold);
}
printf("\n");
}
int main(int argc, char *argv[])
{
init_save_state();
signal_blocking(SIG_BLOCK);
setup_sig_handler();
open_stdout();