1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2017, 2018, 2019, 2021 BMW Car IT GmbH
4  * Author: Viktor Rosendahl (viktor.rosendahl@bmw.de)
5  */
6 
7 #define _GNU_SOURCE
8 #define _POSIX_C_SOURCE 200809L
9 
10 #include <ctype.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <err.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <getopt.h>
20 #include <sched.h>
21 #include <linux/unistd.h>
22 #include <signal.h>
23 #include <sys/inotify.h>
24 #include <unistd.h>
25 #include <pthread.h>
26 #include <tracefs.h>
27 
28 static const char *prg_name;
29 static const char *prg_unknown = "unknown program name";
30 
31 static int fd_stdout;
32 
33 static int sched_policy;
34 static bool sched_policy_set;
35 
36 static int sched_pri;
37 static bool sched_pri_set;
38 
39 static bool trace_enable = true;
40 static bool setup_ftrace = true;
41 static bool use_random_sleep;
42 
43 #define TRACE_OPTS				\
44 	C(FUNC_TR, "function-trace"),		\
45 	C(DISP_GR, "display-graph"),		\
46 	C(NR,       NULL)
47 
48 #undef C
49 #define C(a, b) OPTIDX_##a
50 
51 enum traceopt {
52 	TRACE_OPTS
53 };
54 
55 #undef C
56 #define C(a, b)  b
57 
58 static const char *const optstr[] = {
59 	TRACE_OPTS
60 };
61 
62 enum errhandling {
63 	ERR_EXIT = 0,
64 	ERR_WARN,
65 	ERR_CLEANUP,
66 };
67 
68 static bool use_options[OPTIDX_NR];
69 
70 static char inotify_buffer[655360];
71 
72 #define likely(x)      __builtin_expect(!!(x), 1)
73 #define unlikely(x)    __builtin_expect(!!(x), 0)
74 #define bool2str(x)    (x ? "true":"false")
75 
76 #define DEFAULT_NR_PRINTER_THREADS (3)
77 static unsigned int nr_threads = DEFAULT_NR_PRINTER_THREADS;
78 
79 #define DEFAULT_TABLE_SIZE (2)
80 static unsigned int table_startsize = DEFAULT_TABLE_SIZE;
81 
82 static int verbosity;
83 
84 #define verbose_sizechange() (verbosity >= 1)
85 #define verbose_lostevent()  (verbosity >= 2)
86 #define verbose_ftrace()     (verbosity >= 1)
87 
88 #define was_changed(ORIG, CUR) (strcmp(ORIG, CUR) != 0)
89 #define needs_change(CUR, WANTED) (strcmp(CUR, WANTED) != 0)
90 
91 static const char *debug_tracefile;
92 static const char *debug_tracefile_dflt;
93 static const char *debug_maxlat;
94 static const char *debug_maxlat_dflt;
95 static const char * const DEBUG_NOFILE = "[file not found]";
96 
97 static const char * const TR_MAXLAT  = "tracing_max_latency";
98 static const char * const TR_THRESH  = "tracing_thresh";
99 static const char * const TR_CURRENT = "current_tracer";
100 static const char * const TR_OPTIONS = "trace_options";
101 
102 static const char * const NOP_TRACER = "nop";
103 
104 static const char * const OPT_NO_PREFIX = "no";
105 
106 #define DFLT_THRESHOLD_US "0"
107 static const char *threshold = DFLT_THRESHOLD_US;
108 
109 #define DEV_URANDOM     "/dev/urandom"
110 #define RT_DEFAULT_PRI (99)
111 #define DEFAULT_PRI    (0)
112 
113 #define USEC_PER_MSEC (1000L)
114 #define NSEC_PER_USEC (1000L)
115 #define NSEC_PER_MSEC (USEC_PER_MSEC * NSEC_PER_USEC)
116 
117 #define MSEC_PER_SEC (1000L)
118 #define USEC_PER_SEC (USEC_PER_MSEC * MSEC_PER_SEC)
119 #define NSEC_PER_SEC (NSEC_PER_MSEC * MSEC_PER_SEC)
120 
121 #define SLEEP_TIME_MS_DEFAULT (1000L)
122 #define TRY_PRINTMUTEX_MS (1000)
123 
124 static long sleep_time = (USEC_PER_MSEC * SLEEP_TIME_MS_DEFAULT);
125 
126 static const char * const queue_full_warning =
127 "Could not queue trace for printing. It is likely that events happen faster\n"
128 "than what they can be printed. Probably partly because of random sleeping\n";
129 
130 static const char * const no_tracer_msg =
131 "Could not find any tracers! Running this program as root may help!\n";
132 
133 static const char * const no_latency_tr_msg =
134 "No latency tracers are supported by your kernel!\n";
135 
136 struct policy {
137 	const char *name;
138 	int policy;
139 	int default_pri;
140 };
141 
142 static const struct policy policies[] = {
143 	{ "other", SCHED_OTHER, DEFAULT_PRI    },
144 	{ "batch", SCHED_BATCH, DEFAULT_PRI    },
145 	{ "idle",  SCHED_IDLE,  DEFAULT_PRI    },
146 	{ "rr",    SCHED_RR,    RT_DEFAULT_PRI },
147 	{ "fifo",  SCHED_FIFO,  RT_DEFAULT_PRI },
148 	{ NULL,    0,           DEFAULT_PRI    }
149 };
150 
151 /*
152  * The default tracer will be the first on this list that is supported by the
153  * currently running Linux kernel.
154  */
155 static const char * const relevant_tracers[] = {
156 	"preemptirqsoff",
157 	"preemptoff",
158 	"irqsoff",
159 	"wakeup",
160 	"wakeup_rt",
161 	"wakeup_dl",
162 	NULL
163 };
164 
165 /* This is the list of tracers for which random sleep makes sense */
166 static const char * const random_tracers[] = {
167 	"preemptirqsoff",
168 	"preemptoff",
169 	"irqsoff",
170 	NULL
171 };
172 
173 static const char *current_tracer;
174 static bool force_tracer;
175 
176 struct ftrace_state {
177 	char *tracer;
178 	char *thresh;
179 	bool opt[OPTIDX_NR];
180 	bool opt_valid[OPTIDX_NR];
181 	pthread_mutex_t mutex;
182 };
183 
184 struct entry {
185 	int ticket;
186 	int ticket_completed_ref;
187 };
188 
189 struct print_state {
190 	int ticket_counter;
191 	int ticket_completed;
192 	pthread_mutex_t mutex;
193 	pthread_cond_t cond;
194 	int cnt;
195 	pthread_mutex_t cnt_mutex;
196 };
197 
198 struct short_msg {
199 	char buf[160];
200 	int len;
201 };
202 
203 static struct print_state printstate;
204 static struct ftrace_state save_state;
205 volatile sig_atomic_t signal_flag;
206 
207 #define PROB_TABLE_MAX_SIZE (1000)
208 
209 int probabilities[PROB_TABLE_MAX_SIZE];
210 
211 struct sleep_table {
212 	int *table;
213 	int size;
214 	pthread_mutex_t mutex;
215 };
216 
217 static struct sleep_table sleeptable;
218 
219 #define QUEUE_SIZE (10)
220 
221 struct queue {
222 	struct entry entries[QUEUE_SIZE];
223 	int next_prod_idx;
224 	int next_cons_idx;
225 	pthread_mutex_t mutex;
226 	pthread_cond_t cond;
227 };
228 
229 #define MAX_THREADS (40)
230 
231 struct queue printqueue;
232 pthread_t printthread[MAX_THREADS];
233 pthread_mutex_t print_mtx;
234 #define PRINT_BUFFER_SIZE (16 * 1024 * 1024)
235 
236 static void cleanup_exit(int status);
237 static int set_trace_opt(const char *opt, bool value);
238 
malloc_or_die(size_t size)239 static __always_inline void *malloc_or_die(size_t size)
240 {
241 	void *ptr = malloc(size);
242 
243 	if (unlikely(ptr == NULL)) {
244 		warn("malloc() failed");
245 		cleanup_exit(EXIT_FAILURE);
246 	}
247 	return ptr;
248 }
249 
malloc_or_die_nocleanup(size_t size)250 static __always_inline void *malloc_or_die_nocleanup(size_t size)
251 {
252 	void *ptr = malloc(size);
253 
254 	if (unlikely(ptr == NULL))
255 		err(0, "malloc() failed");
256 	return ptr;
257 }
258 
write_or_die(int fd,const char * buf,size_t count)259 static __always_inline void write_or_die(int fd, const char *buf, size_t count)
260 {
261 	ssize_t r;
262 
263 	do {
264 		r = write(fd, buf, count);
265 		if (unlikely(r < 0)) {
266 			if (errno == EINTR)
267 				continue;
268 			warn("write() failed");
269 			cleanup_exit(EXIT_FAILURE);
270 		}
271 		count -= r;
272 		buf += r;
273 	} while (count > 0);
274 }
275 
clock_gettime_or_die(clockid_t clk_id,struct timespec * tp)276 static __always_inline void clock_gettime_or_die(clockid_t clk_id,
277 						 struct timespec *tp)
278 {
279 	int r = clock_gettime(clk_id, tp);
280 
281 	if (unlikely(r != 0))
282 		err(EXIT_FAILURE, "clock_gettime() failed");
283 }
284 
sigemptyset_or_die(sigset_t * s)285 static __always_inline void sigemptyset_or_die(sigset_t *s)
286 {
287 	if (unlikely(sigemptyset(s) != 0)) {
288 		warn("sigemptyset() failed");
289 		cleanup_exit(EXIT_FAILURE);
290 	}
291 }
292 
sigaddset_or_die(sigset_t * s,int signum)293 static __always_inline void sigaddset_or_die(sigset_t *s, int signum)
294 {
295 	if (unlikely(sigaddset(s, signum) != 0)) {
296 		warn("sigemptyset() failed");
297 		cleanup_exit(EXIT_FAILURE);
298 	}
299 }
300 
sigaction_or_die(int signum,const struct sigaction * act,struct sigaction * oldact)301 static __always_inline void sigaction_or_die(int signum,
302 					     const struct sigaction *act,
303 					     struct sigaction *oldact)
304 {
305 	if (unlikely(sigaction(signum, act, oldact) != 0)) {
306 		warn("sigaction() failed");
307 		cleanup_exit(EXIT_FAILURE);
308 	}
309 }
310 
open_stdout(void)311 static void open_stdout(void)
312 {
313 	if (setvbuf(stdout, NULL, _IONBF, 0) != 0)
314 		err(EXIT_FAILURE, "setvbuf() failed");
315 	fd_stdout = fileno(stdout);
316 	if (fd_stdout < 0)
317 		err(EXIT_FAILURE, "fileno() failed");
318 }
319 
320 /*
321  * It's not worth it to call cleanup_exit() from mutex functions because
322  * cleanup_exit() uses mutexes.
323  */
mutex_lock(pthread_mutex_t * mtx)324 static __always_inline void mutex_lock(pthread_mutex_t *mtx)
325 {
326 	errno = pthread_mutex_lock(mtx);
327 	if (unlikely(errno))
328 		err(EXIT_FAILURE, "pthread_mutex_lock() failed");
329 }
330 
331 
mutex_unlock(pthread_mutex_t * mtx)332 static __always_inline void mutex_unlock(pthread_mutex_t *mtx)
333 {
334 	errno = pthread_mutex_unlock(mtx);
335 	if (unlikely(errno))
336 		err(EXIT_FAILURE, "pthread_mutex_unlock() failed");
337 }
338 
cond_signal(pthread_cond_t * cond)339 static __always_inline void cond_signal(pthread_cond_t *cond)
340 {
341 	errno = pthread_cond_signal(cond);
342 	if (unlikely(errno))
343 		err(EXIT_FAILURE, "pthread_cond_signal() failed");
344 }
345 
cond_wait(pthread_cond_t * restrict cond,pthread_mutex_t * restrict mutex)346 static __always_inline void cond_wait(pthread_cond_t *restrict cond,
347 				      pthread_mutex_t *restrict mutex)
348 {
349 	errno = pthread_cond_wait(cond, mutex);
350 	if (unlikely(errno))
351 		err(EXIT_FAILURE, "pthread_cond_wait() failed");
352 }
353 
cond_broadcast(pthread_cond_t * cond)354 static __always_inline void cond_broadcast(pthread_cond_t *cond)
355 {
356 	errno = pthread_cond_broadcast(cond);
357 	if (unlikely(errno))
358 		err(EXIT_FAILURE, "pthread_cond_broadcast() failed");
359 }
360 
361 static __always_inline void
mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)362 mutex_init(pthread_mutex_t *mutex,
363 	   const pthread_mutexattr_t *attr)
364 {
365 	errno = pthread_mutex_init(mutex, attr);
366 	if (errno)
367 		err(EXIT_FAILURE, "pthread_mutex_init() failed");
368 }
369 
mutexattr_init(pthread_mutexattr_t * attr)370 static __always_inline void mutexattr_init(pthread_mutexattr_t *attr)
371 {
372 	errno = pthread_mutexattr_init(attr);
373 	if (errno)
374 		err(EXIT_FAILURE, "pthread_mutexattr_init() failed");
375 }
376 
mutexattr_destroy(pthread_mutexattr_t * attr)377 static __always_inline void mutexattr_destroy(pthread_mutexattr_t *attr)
378 {
379 	errno = pthread_mutexattr_destroy(attr);
380 	if (errno)
381 		err(EXIT_FAILURE, "pthread_mutexattr_destroy() failed");
382 }
383 
mutexattr_settype(pthread_mutexattr_t * attr,int type)384 static __always_inline void mutexattr_settype(pthread_mutexattr_t *attr,
385 					      int type)
386 {
387 	errno = pthread_mutexattr_settype(attr, type);
388 	if (errno)
389 		err(EXIT_FAILURE, "pthread_mutexattr_settype() failed");
390 }
391 
condattr_init(pthread_condattr_t * attr)392 static __always_inline void condattr_init(pthread_condattr_t *attr)
393 {
394 	errno = pthread_condattr_init(attr);
395 	if (errno)
396 		err(EXIT_FAILURE, "pthread_condattr_init() failed");
397 }
398 
condattr_destroy(pthread_condattr_t * attr)399 static __always_inline void condattr_destroy(pthread_condattr_t *attr)
400 {
401 	errno = pthread_condattr_destroy(attr);
402 	if (errno)
403 		err(EXIT_FAILURE, "pthread_condattr_destroy() failed");
404 }
405 
condattr_setclock(pthread_condattr_t * attr,clockid_t clock_id)406 static __always_inline void condattr_setclock(pthread_condattr_t *attr,
407 					      clockid_t clock_id)
408 {
409 	errno = pthread_condattr_setclock(attr, clock_id);
410 	if (unlikely(errno))
411 		err(EXIT_FAILURE, "pthread_condattr_setclock() failed");
412 }
413 
cond_init(pthread_cond_t * cond,const pthread_condattr_t * attr)414 static __always_inline void cond_init(pthread_cond_t *cond,
415 				      const pthread_condattr_t *attr)
416 {
417 	errno = pthread_cond_init(cond, attr);
418 	if (errno)
419 		err(EXIT_FAILURE, "pthread_cond_init() failed");
420 }
421 
422 static __always_inline int
cond_timedwait(pthread_cond_t * restrict cond,pthread_mutex_t * restrict mutex,const struct timespec * restrict abstime)423 cond_timedwait(pthread_cond_t *restrict cond,
424 	       pthread_mutex_t *restrict mutex,
425 	       const struct timespec *restrict abstime)
426 {
427 	errno = pthread_cond_timedwait(cond, mutex, abstime);
428 	if (errno && errno != ETIMEDOUT)
429 		err(EXIT_FAILURE, "pthread_cond_timedwait() failed");
430 	return errno;
431 }
432 
init_printstate(void)433 static void init_printstate(void)
434 {
435 	pthread_condattr_t cattr;
436 
437 	printstate.ticket_counter = 0;
438 	printstate.ticket_completed = 0;
439 	printstate.cnt = 0;
440 
441 	mutex_init(&printstate.mutex, NULL);
442 
443 	condattr_init(&cattr);
444 	condattr_setclock(&cattr, CLOCK_MONOTONIC);
445 	cond_init(&printstate.cond, &cattr);
446 	condattr_destroy(&cattr);
447 }
448 
init_print_mtx(void)449 static void init_print_mtx(void)
450 {
451 	pthread_mutexattr_t mattr;
452 
453 	mutexattr_init(&mattr);
454 	mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
455 	mutex_init(&print_mtx, &mattr);
456 	mutexattr_destroy(&mattr);
457 
458 }
459 
signal_blocking(int how)460 static void signal_blocking(int how)
461 {
462 	sigset_t s;
463 
464 	sigemptyset_or_die(&s);
465 	sigaddset_or_die(&s, SIGHUP);
466 	sigaddset_or_die(&s, SIGTERM);
467 	sigaddset_or_die(&s, SIGINT);
468 
469 	errno = pthread_sigmask(how, &s, NULL);
470 	if (unlikely(errno)) {
471 		warn("pthread_sigmask() failed");
472 		cleanup_exit(EXIT_FAILURE);
473 	}
474 }
475 
signal_handler(int num)476 static void signal_handler(int num)
477 {
478 	signal_flag = num;
479 }
480 
setup_sig_handler(void)481 static void setup_sig_handler(void)
482 {
483 	struct sigaction sa;
484 
485 	memset(&sa, 0, sizeof(sa));
486 	sa.sa_handler = signal_handler;
487 
488 	sigaction_or_die(SIGHUP, &sa, NULL);
489 	sigaction_or_die(SIGTERM, &sa, NULL);
490 	sigaction_or_die(SIGINT, &sa, NULL);
491 }
492 
process_signal(int signal)493 static void process_signal(int signal)
494 {
495 	char *name;
496 
497 	name = strsignal(signal);
498 	if (name == NULL)
499 		printf("Received signal %d\n", signal);
500 	else
501 		printf("Received signal %d (%s)\n", signal, name);
502 	cleanup_exit(EXIT_SUCCESS);
503 }
504 
check_signals(void)505 static __always_inline void check_signals(void)
506 {
507 	int signal = signal_flag;
508 
509 	if (unlikely(signal))
510 		process_signal(signal);
511 }
512 
get_time_in_future(struct timespec * future,long time_us)513 static __always_inline void get_time_in_future(struct timespec *future,
514 					       long time_us)
515 {
516 	long nsec;
517 
518 	clock_gettime_or_die(CLOCK_MONOTONIC, future);
519 	future->tv_sec += time_us / USEC_PER_SEC;
520 	nsec = future->tv_nsec + (time_us * NSEC_PER_USEC) % NSEC_PER_SEC;
521 	if (nsec >= NSEC_PER_SEC) {
522 		future->tv_nsec = nsec % NSEC_PER_SEC;
523 		future->tv_sec += 1;
524 	}
525 }
526 
time_has_passed(const struct timespec * time)527 static __always_inline bool time_has_passed(const struct timespec *time)
528 {
529 	struct timespec now;
530 
531 	clock_gettime_or_die(CLOCK_MONOTONIC, &now);
532 	if (now.tv_sec > time->tv_sec)
533 		return true;
534 	if (now.tv_sec < time->tv_sec)
535 		return false;
536 	return (now.tv_nsec >= time->tv_nsec);
537 }
538 
mutex_trylock_limit(pthread_mutex_t * mutex,int time_ms)539 static bool mutex_trylock_limit(pthread_mutex_t *mutex, int time_ms)
540 {
541 	long time_us = time_ms * USEC_PER_MSEC;
542 	struct timespec limit;
543 
544 	get_time_in_future(&limit, time_us);
545 	do {
546 		errno =  pthread_mutex_trylock(mutex);
547 		if (errno && errno != EBUSY)
548 			err(EXIT_FAILURE, "pthread_mutex_trylock() failed");
549 	} while (errno && !time_has_passed(&limit));
550 	return errno == 0;
551 }
552 
restore_trace_opts(const struct ftrace_state * state,const bool * cur)553 static void restore_trace_opts(const struct ftrace_state *state,
554 				const bool *cur)
555 {
556 	int i;
557 	int r;
558 
559 	for (i = 0; i < OPTIDX_NR; i++)
560 		if (state->opt_valid[i] && state->opt[i] != cur[i]) {
561 			r = set_trace_opt(optstr[i], state->opt[i]);
562 			if (r < 0)
563 				warnx("Failed to restore the %s option to %s",
564 				      optstr[i], bool2str(state->opt[i]));
565 			else if (verbose_ftrace())
566 				printf("Restored the %s option in %s to %s\n",
567 				       optstr[i], TR_OPTIONS,
568 				       bool2str(state->opt[i]));
569 		}
570 }
571 
read_file(const char * file,enum errhandling h)572 static char *read_file(const char *file, enum errhandling h)
573 {
574 	int psize;
575 	char *r;
576 	static const char *emsg = "Failed to read the %s file";
577 
578 	r = tracefs_instance_file_read(NULL, file, &psize);
579 	if (!r) {
580 		if (h) {
581 			warn(emsg, file);
582 			if (h == ERR_CLEANUP)
583 				cleanup_exit(EXIT_FAILURE);
584 		} else
585 			errx(EXIT_FAILURE, emsg, file);
586 	}
587 
588 	if (r && r[psize - 1] == '\n')
589 		r[psize - 1] = '\0';
590 	return r;
591 }
592 
restore_file(const char * file,char ** saved,const char * cur)593 static void restore_file(const char *file, char **saved, const char *cur)
594 {
595 	if (*saved && was_changed(*saved, cur)) {
596 		if (tracefs_instance_file_write(NULL, file, *saved) < 0)
597 			warnx("Failed to restore %s to %s!", file, *saved);
598 		else if (verbose_ftrace())
599 			printf("Restored %s to %s\n", file, *saved);
600 		free(*saved);
601 		*saved = NULL;
602 	}
603 }
604 
restore_ftrace(void)605 static void restore_ftrace(void)
606 {
607 	mutex_lock(&save_state.mutex);
608 
609 	restore_file(TR_CURRENT, &save_state.tracer, current_tracer);
610 	restore_file(TR_THRESH, &save_state.thresh, threshold);
611 	restore_trace_opts(&save_state, use_options);
612 
613 	mutex_unlock(&save_state.mutex);
614 }
615 
cleanup_exit(int status)616 static void cleanup_exit(int status)
617 {
618 	char *maxlat;
619 
620 	if (!setup_ftrace)
621 		exit(status);
622 
623 	/*
624 	 * We try the print_mtx for 1 sec in order to avoid garbled
625 	 * output if possible, but if it cannot be obtained we proceed anyway.
626 	 */
627 	mutex_trylock_limit(&print_mtx, TRY_PRINTMUTEX_MS);
628 
629 	maxlat = read_file(TR_MAXLAT, ERR_WARN);
630 	if (maxlat) {
631 		printf("The maximum detected latency was: %sus\n", maxlat);
632 		free(maxlat);
633 	}
634 
635 	restore_ftrace();
636 	/*
637 	 * We do not need to unlock the print_mtx here because we will exit at
638 	 * the end of this function. Unlocking print_mtx causes problems if a
639 	 * print thread happens to be waiting for the mutex because we have
640 	 * just changed the ftrace settings to the original and thus the
641 	 * print thread would output incorrect data from ftrace.
642 	 */
643 	exit(status);
644 }
645 
init_save_state(void)646 static void init_save_state(void)
647 {
648 	pthread_mutexattr_t mattr;
649 
650 	mutexattr_init(&mattr);
651 	mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
652 	mutex_init(&save_state.mutex, &mattr);
653 	mutexattr_destroy(&mattr);
654 
655 	save_state.tracer = NULL;
656 	save_state.thresh = NULL;
657 	save_state.opt_valid[OPTIDX_FUNC_TR] = false;
658 	save_state.opt_valid[OPTIDX_DISP_GR] = false;
659 }
660 
printstate_next_ticket(struct entry * req)661 static int printstate_next_ticket(struct entry *req)
662 {
663 	int r;
664 
665 	r = ++(printstate.ticket_counter);
666 	req->ticket = r;
667 	req->ticket_completed_ref = printstate.ticket_completed;
668 	cond_broadcast(&printstate.cond);
669 	return r;
670 }
671 
672 static __always_inline
printstate_mark_req_completed(const struct entry * req)673 void printstate_mark_req_completed(const struct entry *req)
674 {
675 	if (req->ticket > printstate.ticket_completed)
676 		printstate.ticket_completed = req->ticket;
677 }
678 
679 static __always_inline
printstate_has_new_req_arrived(const struct entry * req)680 bool printstate_has_new_req_arrived(const struct entry *req)
681 {
682 	return (printstate.ticket_counter != req->ticket);
683 }
684 
printstate_cnt_inc(void)685 static __always_inline int printstate_cnt_inc(void)
686 {
687 	int value;
688 
689 	mutex_lock(&printstate.cnt_mutex);
690 	value = ++printstate.cnt;
691 	mutex_unlock(&printstate.cnt_mutex);
692 	return value;
693 }
694 
printstate_cnt_dec(void)695 static __always_inline int printstate_cnt_dec(void)
696 {
697 	int value;
698 
699 	mutex_lock(&printstate.cnt_mutex);
700 	value = --printstate.cnt;
701 	mutex_unlock(&printstate.cnt_mutex);
702 	return value;
703 }
704 
printstate_cnt_read(void)705 static __always_inline int printstate_cnt_read(void)
706 {
707 	int value;
708 
709 	mutex_lock(&printstate.cnt_mutex);
710 	value = printstate.cnt;
711 	mutex_unlock(&printstate.cnt_mutex);
712 	return value;
713 }
714 
715 static __always_inline
prev_req_won_race(const struct entry * req)716 bool prev_req_won_race(const struct entry *req)
717 {
718 	return (printstate.ticket_completed != req->ticket_completed_ref);
719 }
720 
sleeptable_resize(int size,bool printout,struct short_msg * msg)721 static void sleeptable_resize(int size, bool printout, struct short_msg *msg)
722 {
723 	int bytes;
724 
725 	if (printout) {
726 		msg->len = 0;
727 		if (unlikely(size > PROB_TABLE_MAX_SIZE))
728 			bytes = snprintf(msg->buf, sizeof(msg->buf),
729 "Cannot increase probability table to %d (maximum size reached)\n", size);
730 		else
731 			bytes = snprintf(msg->buf, sizeof(msg->buf),
732 "Increasing probability table to %d\n", size);
733 		if (bytes < 0)
734 			warn("snprintf() failed");
735 		else
736 			msg->len = bytes;
737 	}
738 
739 	if (unlikely(size < 0)) {
740 		/* Should never happen */
741 		warnx("Bad program state at %s:%d", __FILE__, __LINE__);
742 		cleanup_exit(EXIT_FAILURE);
743 		return;
744 	}
745 	sleeptable.size = size;
746 	sleeptable.table = &probabilities[PROB_TABLE_MAX_SIZE - size];
747 }
748 
init_probabilities(void)749 static void init_probabilities(void)
750 {
751 	int i;
752 	int j = 1000;
753 
754 	for (i = 0; i < PROB_TABLE_MAX_SIZE; i++) {
755 		probabilities[i] = 1000 / j;
756 		j--;
757 	}
758 	mutex_init(&sleeptable.mutex, NULL);
759 }
760 
table_get_probability(const struct entry * req,struct short_msg * msg)761 static int table_get_probability(const struct entry *req,
762 				 struct short_msg *msg)
763 {
764 	int diff = req->ticket - req->ticket_completed_ref;
765 	int rval = 0;
766 
767 	msg->len = 0;
768 	diff--;
769 	/* Should never happen...*/
770 	if (unlikely(diff < 0)) {
771 		warnx("Programmer assumption error at %s:%d\n", __FILE__,
772 		      __LINE__);
773 		cleanup_exit(EXIT_FAILURE);
774 	}
775 	mutex_lock(&sleeptable.mutex);
776 	if (diff >= (sleeptable.size - 1)) {
777 		rval = sleeptable.table[sleeptable.size - 1];
778 		sleeptable_resize(sleeptable.size + 1, verbose_sizechange(),
779 				  msg);
780 	} else {
781 		rval = sleeptable.table[diff];
782 	}
783 	mutex_unlock(&sleeptable.mutex);
784 	return rval;
785 }
786 
init_queue(struct queue * q)787 static void init_queue(struct queue *q)
788 {
789 	q->next_prod_idx = 0;
790 	q->next_cons_idx = 0;
791 	mutex_init(&q->mutex, NULL);
792 	errno = pthread_cond_init(&q->cond, NULL);
793 	if (errno)
794 		err(EXIT_FAILURE, "pthread_cond_init() failed");
795 }
796 
queue_len(const struct queue * q)797 static __always_inline int queue_len(const struct queue *q)
798 {
799 	if (q->next_prod_idx >= q->next_cons_idx)
800 		return q->next_prod_idx - q->next_cons_idx;
801 	else
802 		return QUEUE_SIZE - q->next_cons_idx + q->next_prod_idx;
803 }
804 
queue_nr_free(const struct queue * q)805 static __always_inline int queue_nr_free(const struct queue *q)
806 {
807 	int nr_free = QUEUE_SIZE - queue_len(q);
808 
809 	/*
810 	 * If there is only one slot left we will anyway lie and claim that the
811 	 * queue is full because adding an element will make it appear empty
812 	 */
813 	if (nr_free == 1)
814 		nr_free = 0;
815 	return nr_free;
816 }
817 
queue_idx_inc(int * idx)818 static __always_inline void queue_idx_inc(int *idx)
819 {
820 	*idx = (*idx + 1) % QUEUE_SIZE;
821 }
822 
queue_push_to_back(struct queue * q,const struct entry * e)823 static __always_inline void queue_push_to_back(struct queue *q,
824 					      const struct entry *e)
825 {
826 	q->entries[q->next_prod_idx] = *e;
827 	queue_idx_inc(&q->next_prod_idx);
828 }
829 
queue_pop_from_front(struct queue * q)830 static __always_inline struct entry queue_pop_from_front(struct queue *q)
831 {
832 	struct entry e = q->entries[q->next_cons_idx];
833 
834 	queue_idx_inc(&q->next_cons_idx);
835 	return e;
836 }
837 
queue_cond_signal(struct queue * q)838 static __always_inline void queue_cond_signal(struct queue *q)
839 {
840 	cond_signal(&q->cond);
841 }
842 
queue_cond_wait(struct queue * q)843 static __always_inline void queue_cond_wait(struct queue *q)
844 {
845 	cond_wait(&q->cond, &q->mutex);
846 }
847 
queue_try_to_add_entry(struct queue * q,const struct entry * e)848 static __always_inline int queue_try_to_add_entry(struct queue *q,
849 						  const struct entry *e)
850 {
851 	int r = 0;
852 
853 	mutex_lock(&q->mutex);
854 	if (queue_nr_free(q) > 0) {
855 		queue_push_to_back(q, e);
856 		cond_signal(&q->cond);
857 	} else
858 		r = -1;
859 	mutex_unlock(&q->mutex);
860 	return r;
861 }
862 
queue_wait_for_entry(struct queue * q)863 static struct entry queue_wait_for_entry(struct queue *q)
864 {
865 	struct entry e;
866 
867 	mutex_lock(&q->mutex);
868 	while (true) {
869 		if (queue_len(&printqueue) > 0) {
870 			e = queue_pop_from_front(q);
871 			break;
872 		}
873 		queue_cond_wait(q);
874 	}
875 	mutex_unlock(&q->mutex);
876 
877 	return e;
878 }
879 
policy_from_name(const char * name)880 static const struct policy *policy_from_name(const char *name)
881 {
882 	const struct policy *p = &policies[0];
883 
884 	while (p->name != NULL) {
885 		if (!strcmp(name, p->name))
886 			return p;
887 		p++;
888 	}
889 	return NULL;
890 }
891 
policy_name(int policy)892 static const char *policy_name(int policy)
893 {
894 	const struct policy *p = &policies[0];
895 	static const char *rval = "unknown";
896 
897 	while (p->name != NULL) {
898 		if (p->policy == policy)
899 			return p->name;
900 		p++;
901 	}
902 	return rval;
903 }
904 
is_relevant_tracer(const char * name)905 static bool is_relevant_tracer(const char *name)
906 {
907 	unsigned int i;
908 
909 	for (i = 0; relevant_tracers[i]; i++)
910 		if (!strcmp(name, relevant_tracers[i]))
911 			return true;
912 	return false;
913 }
914 
random_makes_sense(const char * name)915 static bool random_makes_sense(const char *name)
916 {
917 	unsigned int i;
918 
919 	for (i = 0; random_tracers[i]; i++)
920 		if (!strcmp(name, random_tracers[i]))
921 			return true;
922 	return false;
923 }
924 
show_available(void)925 static void show_available(void)
926 {
927 	char **tracers;
928 	int found = 0;
929 	int i;
930 
931 	tracers = tracefs_tracers(NULL);
932 	for (i = 0; tracers && tracers[i]; i++) {
933 		if (is_relevant_tracer(tracers[i]))
934 			found++;
935 	}
936 
937 	if (!tracers) {
938 		warnx("%s", no_tracer_msg);
939 		return;
940 	}
941 
942 	if (!found) {
943 		warnx("%s", no_latency_tr_msg);
944 		tracefs_list_free(tracers);
945 		return;
946 	}
947 
948 	printf("The following latency tracers are available on your system:\n");
949 	for (i = 0; tracers[i]; i++) {
950 		if (is_relevant_tracer(tracers[i]))
951 			printf("%s\n", tracers[i]);
952 	}
953 	tracefs_list_free(tracers);
954 }
955 
tracer_valid(const char * name,bool * notracer)956 static bool tracer_valid(const char *name, bool *notracer)
957 {
958 	char **tracers;
959 	int i;
960 	bool rval = false;
961 
962 	*notracer = false;
963 	tracers = tracefs_tracers(NULL);
964 	if (!tracers) {
965 		*notracer = true;
966 		return false;
967 	}
968 	for (i = 0; tracers[i]; i++)
969 		if (!strcmp(tracers[i], name)) {
970 			rval = true;
971 			break;
972 		}
973 	tracefs_list_free(tracers);
974 	return rval;
975 }
976 
find_default_tracer(void)977 static const char *find_default_tracer(void)
978 {
979 	int i;
980 	bool notracer;
981 	bool valid;
982 
983 	for (i = 0; relevant_tracers[i]; i++) {
984 		valid = tracer_valid(relevant_tracers[i], &notracer);
985 		if (notracer)
986 			errx(EXIT_FAILURE, "%s", no_tracer_msg);
987 		if (valid)
988 			return relevant_tracers[i];
989 	}
990 	return NULL;
991 }
992 
toss_coin(struct drand48_data * buffer,unsigned int prob)993 static bool toss_coin(struct drand48_data *buffer, unsigned int prob)
994 {
995 	long r;
996 
997 	if (unlikely(lrand48_r(buffer, &r))) {
998 		warnx("lrand48_r() failed");
999 		cleanup_exit(EXIT_FAILURE);
1000 	}
1001 	r = r % 1000L;
1002 	if (r < prob)
1003 		return true;
1004 	else
1005 		return false;
1006 }
1007 
1008 
go_to_sleep(const struct entry * req)1009 static long go_to_sleep(const struct entry *req)
1010 {
1011 	struct timespec future;
1012 	long delay = sleep_time;
1013 
1014 	get_time_in_future(&future, delay);
1015 
1016 	mutex_lock(&printstate.mutex);
1017 	while (!printstate_has_new_req_arrived(req)) {
1018 		cond_timedwait(&printstate.cond, &printstate.mutex, &future);
1019 		if (time_has_passed(&future))
1020 			break;
1021 	}
1022 
1023 	if (printstate_has_new_req_arrived(req))
1024 		delay = -1;
1025 	mutex_unlock(&printstate.mutex);
1026 
1027 	return delay;
1028 }
1029 
1030 
set_priority(void)1031 static void set_priority(void)
1032 {
1033 	int r;
1034 	pid_t pid;
1035 	struct sched_param param;
1036 
1037 	memset(&param, 0, sizeof(param));
1038 	param.sched_priority = sched_pri;
1039 
1040 	pid = getpid();
1041 	r = sched_setscheduler(pid, sched_policy, &param);
1042 
1043 	if (r != 0)
1044 		err(EXIT_FAILURE, "sched_setscheduler() failed");
1045 }
1046 
latency_collector_gettid(void)1047 pid_t latency_collector_gettid(void)
1048 {
1049 	return (pid_t) syscall(__NR_gettid);
1050 }
1051 
print_priority(void)1052 static void print_priority(void)
1053 {
1054 	pid_t tid;
1055 	int policy;
1056 	int r;
1057 	struct sched_param param;
1058 
1059 	tid = latency_collector_gettid();
1060 	r = pthread_getschedparam(pthread_self(), &policy, &param);
1061 	if (r != 0) {
1062 		warn("pthread_getschedparam() failed");
1063 		cleanup_exit(EXIT_FAILURE);
1064 	}
1065 	mutex_lock(&print_mtx);
1066 	printf("Thread %d runs with scheduling policy %s and priority %d\n",
1067 	       tid, policy_name(policy), param.sched_priority);
1068 	mutex_unlock(&print_mtx);
1069 }
1070 
1071 static __always_inline
__print_skipmessage(const struct short_msg * resize_msg,const struct timespec * timestamp,char * buffer,size_t bufspace,const struct entry * req,bool excuse,const char * str)1072 void __print_skipmessage(const struct short_msg *resize_msg,
1073 			 const struct timespec *timestamp, char *buffer,
1074 			 size_t bufspace, const struct entry *req, bool excuse,
1075 			 const char *str)
1076 {
1077 	ssize_t bytes = 0;
1078 	char *p = &buffer[0];
1079 	long us, sec;
1080 	int r;
1081 
1082 	sec = timestamp->tv_sec;
1083 	us = timestamp->tv_nsec / 1000;
1084 
1085 	if (resize_msg != NULL && resize_msg->len > 0) {
1086 		strncpy(p, resize_msg->buf, resize_msg->len);
1087 		bytes += resize_msg->len;
1088 		p += resize_msg->len;
1089 		bufspace -= resize_msg->len;
1090 	}
1091 
1092 	if (excuse)
1093 		r = snprintf(p, bufspace,
1094 "%ld.%06ld Latency %d printout skipped due to %s\n",
1095 			     sec, us, req->ticket, str);
1096 	else
1097 		r = snprintf(p, bufspace, "%ld.%06ld Latency %d detected\n",
1098 			    sec, us, req->ticket);
1099 
1100 	if (r < 0)
1101 		warn("snprintf() failed");
1102 	else
1103 		bytes += r;
1104 
1105 	/* These prints could happen concurrently */
1106 	mutex_lock(&print_mtx);
1107 	write_or_die(fd_stdout, buffer, bytes);
1108 	mutex_unlock(&print_mtx);
1109 }
1110 
print_skipmessage(const struct short_msg * resize_msg,const struct timespec * timestamp,char * buffer,size_t bufspace,const struct entry * req,bool excuse)1111 static void print_skipmessage(const struct short_msg *resize_msg,
1112 			      const struct timespec *timestamp, char *buffer,
1113 			      size_t bufspace, const struct entry *req,
1114 			      bool excuse)
1115 {
1116 	__print_skipmessage(resize_msg, timestamp, buffer, bufspace, req,
1117 			    excuse, "random delay");
1118 }
1119 
print_lostmessage(const struct timespec * timestamp,char * buffer,size_t bufspace,const struct entry * req,const char * reason)1120 static void print_lostmessage(const struct timespec *timestamp, char *buffer,
1121 			      size_t bufspace, const struct entry *req,
1122 			      const char *reason)
1123 {
1124 	__print_skipmessage(NULL, timestamp, buffer, bufspace, req, true,
1125 			    reason);
1126 }
1127 
print_tracefile(const struct short_msg * resize_msg,const struct timespec * timestamp,char * buffer,size_t bufspace,long slept,const struct entry * req)1128 static void print_tracefile(const struct short_msg *resize_msg,
1129 			    const struct timespec *timestamp, char *buffer,
1130 			    size_t bufspace, long slept,
1131 			    const struct entry *req)
1132 {
1133 	static const int reserve = 256;
1134 	char *p = &buffer[0];
1135 	ssize_t bytes = 0;
1136 	ssize_t bytes_tot = 0;
1137 	long us, sec;
1138 	long slept_ms;
1139 	int trace_fd;
1140 
1141 	/* Save some space for the final string and final null char */
1142 	bufspace = bufspace - reserve - 1;
1143 
1144 	if (resize_msg != NULL && resize_msg->len > 0) {
1145 		bytes = resize_msg->len;
1146 		strncpy(p, resize_msg->buf, bytes);
1147 		bytes_tot += bytes;
1148 		p += bytes;
1149 		bufspace -= bytes;
1150 	}
1151 
1152 	trace_fd = open(debug_tracefile, O_RDONLY);
1153 
1154 	if (trace_fd < 0) {
1155 		warn("open() failed on %s", debug_tracefile);
1156 		return;
1157 	}
1158 
1159 	sec = timestamp->tv_sec;
1160 	us = timestamp->tv_nsec / 1000;
1161 
1162 	if (slept != 0) {
1163 		slept_ms = slept / 1000;
1164 		bytes = snprintf(p, bufspace,
1165 "%ld.%06ld Latency %d randomly sleep for %ld ms before print\n",
1166 				 sec, us, req->ticket, slept_ms);
1167 	} else {
1168 		bytes = snprintf(p, bufspace,
1169 				 "%ld.%06ld Latency %d immediate print\n", sec,
1170 				 us, req->ticket);
1171 	}
1172 
1173 	if (bytes < 0) {
1174 		warn("snprintf() failed");
1175 		return;
1176 	}
1177 	p += bytes;
1178 	bufspace -= bytes;
1179 	bytes_tot += bytes;
1180 
1181 	bytes = snprintf(p, bufspace,
1182 ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> BEGIN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"
1183 		);
1184 
1185 	if (bytes < 0) {
1186 		warn("snprintf() failed");
1187 		return;
1188 	}
1189 
1190 	p += bytes;
1191 	bufspace -= bytes;
1192 	bytes_tot += bytes;
1193 
1194 	do {
1195 		bytes = read(trace_fd, p, bufspace);
1196 		if (bytes < 0) {
1197 			if (errno == EINTR)
1198 				continue;
1199 			warn("read() failed on %s", debug_tracefile);
1200 			if (unlikely(close(trace_fd) != 0))
1201 				warn("close() failed on %s", debug_tracefile);
1202 			return;
1203 		}
1204 		if (bytes == 0)
1205 			break;
1206 		p += bytes;
1207 		bufspace -= bytes;
1208 		bytes_tot += bytes;
1209 	} while (true);
1210 
1211 	if (unlikely(close(trace_fd) != 0))
1212 		warn("close() failed on %s", debug_tracefile);
1213 
1214 	printstate_cnt_dec();
1215 	/* Add the reserve space back to the budget for the final string */
1216 	bufspace += reserve;
1217 
1218 	bytes = snprintf(p, bufspace,
1219 			 ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
1220 
1221 	if (bytes < 0) {
1222 		warn("snprintf() failed");
1223 		return;
1224 	}
1225 
1226 	bytes_tot += bytes;
1227 
1228 	/* These prints could happen concurrently */
1229 	mutex_lock(&print_mtx);
1230 	write_or_die(fd_stdout, buffer, bytes_tot);
1231 	mutex_unlock(&print_mtx);
1232 }
1233 
get_no_opt(const char * opt)1234 static char *get_no_opt(const char *opt)
1235 {
1236 	char *no_opt;
1237 	int s;
1238 
1239 	s = strlen(opt) + strlen(OPT_NO_PREFIX) + 1;
1240 	/* We may be called from cleanup_exit() via set_trace_opt() */
1241 	no_opt = malloc_or_die_nocleanup(s);
1242 	strcpy(no_opt, OPT_NO_PREFIX);
1243 	strcat(no_opt, opt);
1244 	return no_opt;
1245 }
1246 
find_next_optstr(const char * allopt,const char ** next)1247 static char *find_next_optstr(const char *allopt, const char **next)
1248 {
1249 	const char *begin;
1250 	const char *end;
1251 	char *r;
1252 	int s = 0;
1253 
1254 	if (allopt == NULL)
1255 		return NULL;
1256 
1257 	for (begin = allopt; *begin != '\0'; begin++) {
1258 		if (isgraph(*begin))
1259 			break;
1260 	}
1261 
1262 	if (*begin == '\0')
1263 		return NULL;
1264 
1265 	for (end = begin; *end != '\0' && isgraph(*end); end++)
1266 		s++;
1267 
1268 	r = malloc_or_die_nocleanup(s + 1);
1269 	strncpy(r, begin, s);
1270 	r[s] = '\0';
1271 	*next = begin + s;
1272 	return r;
1273 }
1274 
get_trace_opt(const char * allopt,const char * opt,bool * found)1275 static bool get_trace_opt(const char *allopt, const char *opt, bool *found)
1276 {
1277 	*found = false;
1278 	char *no_opt;
1279 	char *str;
1280 	const char *next = allopt;
1281 	bool rval = false;
1282 
1283 	no_opt = get_no_opt(opt);
1284 
1285 	do {
1286 		str = find_next_optstr(next, &next);
1287 		if (str == NULL)
1288 			break;
1289 		if (!strcmp(str, opt)) {
1290 			*found = true;
1291 			rval = true;
1292 			free(str);
1293 			break;
1294 		}
1295 		if (!strcmp(str, no_opt)) {
1296 			*found = true;
1297 			rval = false;
1298 			free(str);
1299 			break;
1300 		}
1301 		free(str);
1302 	} while (true);
1303 	free(no_opt);
1304 
1305 	return rval;
1306 }
1307 
set_trace_opt(const char * opt,bool value)1308 static int set_trace_opt(const char *opt, bool value)
1309 {
1310 	char *str;
1311 	int r;
1312 
1313 	if (value)
1314 		str = strdup(opt);
1315 	else
1316 		str = get_no_opt(opt);
1317 
1318 	r = tracefs_instance_file_write(NULL, TR_OPTIONS, str);
1319 	free(str);
1320 	return r;
1321 }
1322 
save_trace_opts(struct ftrace_state * state)1323 void save_trace_opts(struct ftrace_state *state)
1324 {
1325 	char *allopt;
1326 	int psize;
1327 	int i;
1328 
1329 	allopt = tracefs_instance_file_read(NULL, TR_OPTIONS, &psize);
1330 	if (!allopt)
1331 		errx(EXIT_FAILURE, "Failed to read the %s file\n", TR_OPTIONS);
1332 
1333 	for (i = 0; i < OPTIDX_NR; i++)
1334 		state->opt[i] = get_trace_opt(allopt, optstr[i],
1335 					      &state->opt_valid[i]);
1336 
1337 	free(allopt);
1338 }
1339 
write_file(const char * file,const char * cur,const char * new,enum errhandling h)1340 static void write_file(const char *file, const char *cur, const char *new,
1341 		       enum errhandling h)
1342 {
1343 	int r;
1344 	static const char *emsg = "Failed to write to the %s file!";
1345 
1346 	/* Do nothing if we now that the current and new value are equal */
1347 	if (cur && !needs_change(cur, new))
1348 		return;
1349 
1350 	r = tracefs_instance_file_write(NULL, file, new);
1351 	if (r < 0) {
1352 		if (h) {
1353 			warnx(emsg, file);
1354 			if (h == ERR_CLEANUP)
1355 				cleanup_exit(EXIT_FAILURE);
1356 		} else
1357 			errx(EXIT_FAILURE, emsg, file);
1358 	}
1359 	if (verbose_ftrace()) {
1360 		mutex_lock(&print_mtx);
1361 		printf("%s was set to %s\n", file, new);
1362 		mutex_unlock(&print_mtx);
1363 	}
1364 }
1365 
reset_max_latency(void)1366 static void reset_max_latency(void)
1367 {
1368 	write_file(TR_MAXLAT, NULL, "0", ERR_CLEANUP);
1369 }
1370 
save_and_disable_tracer(void)1371 static void save_and_disable_tracer(void)
1372 {
1373 	char *orig_th;
1374 	char *tracer;
1375 	bool need_nop = false;
1376 
1377 	mutex_lock(&save_state.mutex);
1378 
1379 	save_trace_opts(&save_state);
1380 	tracer = read_file(TR_CURRENT, ERR_EXIT);
1381 	orig_th = read_file(TR_THRESH, ERR_EXIT);
1382 
1383 	if (needs_change(tracer, NOP_TRACER)) {
1384 		mutex_lock(&print_mtx);
1385 		if (force_tracer) {
1386 			printf(
1387 				"The %s tracer is already in use but proceeding anyway!\n",
1388 				tracer);
1389 		} else {
1390 			printf(
1391 				"The %s tracer is already in use, cowardly bailing out!\n"
1392 				"This could indicate that another program or instance is tracing.\n"
1393 				"Use the -F [--force] option to disregard the current tracer.\n", tracer);
1394 			exit(0);
1395 		}
1396 		mutex_unlock(&print_mtx);
1397 		need_nop = true;
1398 	}
1399 
1400 	save_state.tracer =  tracer;
1401 	save_state.thresh = orig_th;
1402 
1403 	if (need_nop)
1404 		write_file(TR_CURRENT, NULL, NOP_TRACER, ERR_EXIT);
1405 
1406 	mutex_unlock(&save_state.mutex);
1407 }
1408 
set_trace_opts(struct ftrace_state * state,bool * new)1409 void set_trace_opts(struct ftrace_state *state, bool *new)
1410 {
1411 	int i;
1412 	int r;
1413 
1414 	/*
1415 	 * We only set options if we earlier detected that the option exists in
1416 	 * the trace_options file and that the wanted setting is different from
1417 	 * the one we saw in save_and_disable_tracer()
1418 	 */
1419 	for (i = 0; i < OPTIDX_NR; i++)
1420 		if (state->opt_valid[i] &&
1421 		    state->opt[i] != new[i]) {
1422 			r = set_trace_opt(optstr[i], new[i]);
1423 			if (r < 0) {
1424 				warnx("Failed to set the %s option to %s",
1425 				      optstr[i], bool2str(new[i]));
1426 				cleanup_exit(EXIT_FAILURE);
1427 			}
1428 			if (verbose_ftrace()) {
1429 				mutex_lock(&print_mtx);
1430 				printf("%s in %s was set to %s\n", optstr[i],
1431 				       TR_OPTIONS, bool2str(new[i]));
1432 				mutex_unlock(&print_mtx);
1433 			}
1434 		}
1435 }
1436 
enable_tracer(void)1437 static void enable_tracer(void)
1438 {
1439 	mutex_lock(&save_state.mutex);
1440 	set_trace_opts(&save_state, use_options);
1441 
1442 	write_file(TR_THRESH, save_state.thresh, threshold, ERR_CLEANUP);
1443 	write_file(TR_CURRENT, NOP_TRACER, current_tracer, ERR_CLEANUP);
1444 
1445 	mutex_unlock(&save_state.mutex);
1446 }
1447 
tracing_loop(void)1448 static void tracing_loop(void)
1449 {
1450 	int ifd = inotify_init();
1451 	int wd;
1452 	const ssize_t bufsize = sizeof(inotify_buffer);
1453 	const ssize_t istructsize = sizeof(struct inotify_event);
1454 	char *buf = &inotify_buffer[0];
1455 	ssize_t nr_read;
1456 	char *p;
1457 	int modified;
1458 	struct inotify_event *event;
1459 	struct entry req;
1460 	char *buffer;
1461 	const size_t bufspace = PRINT_BUFFER_SIZE;
1462 	struct timespec timestamp;
1463 
1464 	print_priority();
1465 
1466 	buffer = malloc_or_die(bufspace);
1467 
1468 	if (ifd < 0)
1469 		err(EXIT_FAILURE, "inotify_init() failed!");
1470 
1471 
1472 	if (setup_ftrace) {
1473 		/*
1474 		 * We must disable the tracer before resetting the max_latency
1475 		 */
1476 		save_and_disable_tracer();
1477 		/*
1478 		 * We must reset the max_latency before the inotify_add_watch()
1479 		 * call.
1480 		 */
1481 		reset_max_latency();
1482 	}
1483 
1484 	wd = inotify_add_watch(ifd, debug_maxlat, IN_MODIFY);
1485 	if (wd < 0)
1486 		err(EXIT_FAILURE, "inotify_add_watch() failed!");
1487 
1488 	if (setup_ftrace)
1489 		enable_tracer();
1490 
1491 	signal_blocking(SIG_UNBLOCK);
1492 
1493 	while (true) {
1494 		modified = 0;
1495 		check_signals();
1496 		nr_read = read(ifd, buf, bufsize);
1497 		check_signals();
1498 		if (nr_read < 0) {
1499 			if (errno == EINTR)
1500 				continue;
1501 			warn("read() failed on inotify fd!");
1502 			cleanup_exit(EXIT_FAILURE);
1503 		}
1504 		if (nr_read == bufsize)
1505 			warnx("inotify() buffer filled, skipping events");
1506 		if (nr_read < istructsize) {
1507 			warnx("read() returned too few bytes on inotify fd");
1508 			cleanup_exit(EXIT_FAILURE);
1509 		}
1510 
1511 		for (p = buf; p < buf + nr_read;) {
1512 			event = (struct inotify_event *) p;
1513 			if ((event->mask & IN_MODIFY) != 0)
1514 				modified++;
1515 			p += istructsize + event->len;
1516 		}
1517 		while (modified > 0) {
1518 			check_signals();
1519 			mutex_lock(&printstate.mutex);
1520 			check_signals();
1521 			printstate_next_ticket(&req);
1522 			if (printstate_cnt_read() > 0) {
1523 				printstate_mark_req_completed(&req);
1524 				mutex_unlock(&printstate.mutex);
1525 				if (verbose_lostevent()) {
1526 					clock_gettime_or_die(CLOCK_MONOTONIC,
1527 							     &timestamp);
1528 					print_lostmessage(&timestamp, buffer,
1529 							  bufspace, &req,
1530 							  "inotify loop");
1531 				}
1532 				break;
1533 			}
1534 			mutex_unlock(&printstate.mutex);
1535 			if (queue_try_to_add_entry(&printqueue, &req) != 0) {
1536 				/* These prints could happen concurrently */
1537 				check_signals();
1538 				mutex_lock(&print_mtx);
1539 				check_signals();
1540 				write_or_die(fd_stdout, queue_full_warning,
1541 					     strlen(queue_full_warning));
1542 				mutex_unlock(&print_mtx);
1543 			}
1544 			modified--;
1545 		}
1546 	}
1547 }
1548 
do_printloop(void * arg)1549 static void *do_printloop(void *arg)
1550 {
1551 	const size_t bufspace = PRINT_BUFFER_SIZE;
1552 	char *buffer;
1553 	long *rseed = (long *) arg;
1554 	struct drand48_data drandbuf;
1555 	long slept = 0;
1556 	struct entry req;
1557 	int prob = 0;
1558 	struct timespec timestamp;
1559 	struct short_msg resize_msg;
1560 
1561 	print_priority();
1562 
1563 	if (srand48_r(*rseed, &drandbuf) != 0) {
1564 		warn("srand48_r() failed!\n");
1565 		cleanup_exit(EXIT_FAILURE);
1566 	}
1567 
1568 	buffer = malloc_or_die(bufspace);
1569 
1570 	while (true) {
1571 		req = queue_wait_for_entry(&printqueue);
1572 		clock_gettime_or_die(CLOCK_MONOTONIC, &timestamp);
1573 		mutex_lock(&printstate.mutex);
1574 		if (prev_req_won_race(&req)) {
1575 			printstate_mark_req_completed(&req);
1576 			mutex_unlock(&printstate.mutex);
1577 			if (verbose_lostevent())
1578 				print_lostmessage(&timestamp, buffer, bufspace,
1579 						  &req, "print loop");
1580 			continue;
1581 		}
1582 		mutex_unlock(&printstate.mutex);
1583 
1584 		/*
1585 		 * Toss a coin to decide if we want to sleep before printing
1586 		 * out the backtrace. The reason for this is that opening
1587 		 * /sys/kernel/tracing/trace will cause a blackout of
1588 		 * hundreds of ms, where no latencies will be noted by the
1589 		 * latency tracer. Thus by randomly sleeping we try to avoid
1590 		 * missing traces systematically due to this. With this option
1591 		 * we will sometimes get the first latency, some other times
1592 		 * some of the later ones, in case of closely spaced traces.
1593 		 */
1594 		if (trace_enable && use_random_sleep) {
1595 			slept = 0;
1596 			prob = table_get_probability(&req, &resize_msg);
1597 			if (!toss_coin(&drandbuf, prob))
1598 				slept = go_to_sleep(&req);
1599 			if (slept >= 0) {
1600 				/* A print is ongoing */
1601 				printstate_cnt_inc();
1602 				/*
1603 				 * We will do the printout below so we have to
1604 				 * mark it as completed while we still have the
1605 				 * mutex.
1606 				 */
1607 				mutex_lock(&printstate.mutex);
1608 				printstate_mark_req_completed(&req);
1609 				mutex_unlock(&printstate.mutex);
1610 			}
1611 		}
1612 		if (trace_enable) {
1613 			/*
1614 			 * slept < 0  means that we detected another
1615 			 * notification in go_to_sleep() above
1616 			 */
1617 			if (slept >= 0)
1618 				/*
1619 				 * N.B. printstate_cnt_dec(); will be called
1620 				 * inside print_tracefile()
1621 				 */
1622 				print_tracefile(&resize_msg, &timestamp, buffer,
1623 						bufspace, slept, &req);
1624 			else
1625 				print_skipmessage(&resize_msg, &timestamp,
1626 						  buffer, bufspace, &req, true);
1627 		} else {
1628 			print_skipmessage(&resize_msg, &timestamp, buffer,
1629 					  bufspace, &req, false);
1630 		}
1631 	}
1632 	return NULL;
1633 }
1634 
start_printthread(void)1635 static void start_printthread(void)
1636 {
1637 	unsigned int i;
1638 	long *seed;
1639 	int ufd;
1640 
1641 	ufd = open(DEV_URANDOM, O_RDONLY);
1642 	if (nr_threads > MAX_THREADS) {
1643 		warnx(
1644 "Number of requested print threads was %d, max number is %d\n",
1645 		      nr_threads, MAX_THREADS);
1646 		nr_threads = MAX_THREADS;
1647 	}
1648 	for (i = 0; i < nr_threads; i++) {
1649 		seed = malloc_or_die(sizeof(*seed));
1650 		if (ufd <  0 ||
1651 		    read(ufd, seed, sizeof(*seed)) != sizeof(*seed)) {
1652 			printf(
1653 "Warning! Using trivial random number seed, since %s not available\n",
1654 			DEV_URANDOM);
1655 			fflush(stdout);
1656 			*seed = i;
1657 		}
1658 		errno = pthread_create(&printthread[i], NULL, do_printloop,
1659 				       seed);
1660 		if (errno)
1661 			err(EXIT_FAILURE, "pthread_create()");
1662 	}
1663 	if (ufd > 0 && close(ufd) != 0)
1664 		warn("close() failed");
1665 }
1666 
show_usage(void)1667 static void show_usage(void)
1668 {
1669 	printf(
1670 "Usage: %s [OPTION]...\n\n"
1671 "Collect closely occurring latencies from %s\n"
1672 "with any of the following tracers: preemptirqsoff, preemptoff, irqsoff, "
1673 "wakeup,\nwakeup_dl, or wakeup_rt.\n\n"
1674 
1675 "The occurrence of a latency is detected by monitoring the file\n"
1676 "%s with inotify.\n\n"
1677 
1678 "The following options are supported:\n\n"
1679 
1680 "-l, --list\t\tList the latency tracers that are supported by the\n"
1681 "\t\t\tcurrently running Linux kernel. If you don't see the\n"
1682 "\t\t\ttracer that you want, you will probably need to\n"
1683 "\t\t\tchange your kernel config and build a new kernel.\n\n"
1684 
1685 "-t, --tracer TR\t\tUse the tracer TR. The default is to use the first\n"
1686 "\t\t\ttracer that is supported by the kernel in the following\n"
1687 "\t\t\torder of precedence:\n\n"
1688 "\t\t\tpreemptirqsoff\n"
1689 "\t\t\tpreemptoff\n"
1690 "\t\t\tirqsoff\n"
1691 "\t\t\twakeup\n"
1692 "\t\t\twakeup_rt\n"
1693 "\t\t\twakeup_dl\n"
1694 "\n"
1695 "\t\t\tIf TR is not on the list above, then a warning will be\n"
1696 "\t\t\tprinted.\n\n"
1697 
1698 "-F, --force\t\tProceed even if another ftrace tracer is active. Without\n"
1699 "\t\t\tthis option, the program will refuse to start tracing if\n"
1700 "\t\t\tany other tracer than the nop tracer is active.\n\n"
1701 
1702 "-s, --threshold TH\tConfigure ftrace to use a threshold of TH microseconds\n"
1703 "\t\t\tfor the tracer. The default is 0, which means that\n"
1704 "\t\t\ttracing_max_latency will be used. tracing_max_latency is\n"
1705 "\t\t\tset to 0 when the program is started and contains the\n"
1706 "\t\t\tmaximum of the latencies that have been encountered.\n\n"
1707 
1708 "-f, --function\t\tEnable the function-trace option in trace_options. With\n"
1709 "\t\t\tthis option, ftrace will trace the functions that are\n"
1710 "\t\t\texecuted during a latency, without it we only get the\n"
1711 "\t\t\tbeginning, end, and backtrace.\n\n"
1712 
1713 "-g, --graph\t\tEnable the display-graph option in trace_option. This\n"
1714 "\t\t\toption causes ftrace to show the graph of how functions\n"
1715 "\t\t\tare calling other functions.\n\n"
1716 
1717 "-c, --policy POL\tRun the program with scheduling policy POL. POL can be\n"
1718 "\t\t\tother, batch, idle, rr or fifo. The default is rr. When\n"
1719 "\t\t\tusing rr or fifo, remember that these policies may cause\n"
1720 "\t\t\tother tasks to experience latencies.\n\n"
1721 
1722 "-p, --priority PRI\tRun the program with priority PRI. The acceptable range\n"
1723 "\t\t\tof PRI depends on the scheduling policy.\n\n"
1724 
1725 "-n, --notrace\t\tIf latency is detected, do not print out the content of\n"
1726 "\t\t\tthe trace file to standard output\n\n"
1727 
1728 "-t, --threads NRTHR\tRun NRTHR threads for printing. Default is %d.\n\n"
1729 
1730 "-r, --random\t\tArbitrarily sleep a certain amount of time, default\n"
1731 "\t\t\t%ld ms, before reading the trace file. The\n"
1732 "\t\t\tprobabilities for sleep are chosen so that the\n"
1733 "\t\t\tprobability of obtaining any of a cluster of closely\n"
1734 "\t\t\toccurring latencies are equal, i.e. we will randomly\n"
1735 "\t\t\tchoose which one we collect from the trace file.\n\n"
1736 "\t\t\tThis option is probably only useful with the irqsoff,\n"
1737 "\t\t\tpreemptoff, and preemptirqsoff tracers.\n\n"
1738 
1739 "-a, --nrlat NRLAT\tFor the purpose of arbitrary delay, assume that there\n"
1740 "\t\t\tare no more than NRLAT clustered latencies. If NRLAT\n"
1741 "\t\t\tlatencies are detected during a run, this value will\n"
1742 "\t\t\tautomatically be increased to NRLAT + 1 and then to\n"
1743 "\t\t\tNRLAT + 2 and so on. The default is %d. This option\n"
1744 "\t\t\timplies -r. We need to know this number in order to\n"
1745 "\t\t\tbe able to calculate the probabilities of sleeping.\n"
1746 "\t\t\tSpecifically, the probabilities of not sleeping, i.e. to\n"
1747 "\t\t\tdo an immediate printout will be:\n\n"
1748 "\t\t\t1/NRLAT  1/(NRLAT - 1) ... 1/3  1/2  1\n\n"
1749 "\t\t\tThe probability of sleeping will be:\n\n"
1750 "\t\t\t1 - P, where P is from the series above\n\n"
1751 "\t\t\tThis descending probability will cause us to choose\n"
1752 "\t\t\tan occurrence at random. Observe that the final\n"
1753 "\t\t\tprobability is 0, it is when we reach this probability\n"
1754 "\t\t\tthat we increase NRLAT automatically. As an example,\n"
1755 "\t\t\twith the default value of 2, the probabilities will be:\n\n"
1756 "\t\t\t1/2  0\n\n"
1757 "\t\t\tThis means, when a latency is detected we will sleep\n"
1758 "\t\t\twith 50%% probability. If we ever detect another latency\n"
1759 "\t\t\tduring the sleep period, then the probability of sleep\n"
1760 "\t\t\twill be 0%% and the table will be expanded to:\n\n"
1761 "\t\t\t1/3  1/2  0\n\n"
1762 
1763 "-v, --verbose\t\tIncrease the verbosity. If this option is given once,\n"
1764 "\t\t\tthen print a message every time that the NRLAT value\n"
1765 "\t\t\tis automatically increased. It also causes a message to\n"
1766 "\t\t\tbe printed when the ftrace settings are changed. If this\n"
1767 "\t\t\toption is given at least twice, then also print a\n"
1768 "\t\t\twarning for lost events.\n\n"
1769 
1770 "-u, --time TIME\t\tArbitrarily sleep for a specified time TIME ms before\n"
1771 "\t\t\tprinting out the trace from the trace file. The default\n"
1772 "\t\t\tis %ld ms. This option implies -r.\n\n"
1773 
1774 "-x, --no-ftrace\t\tDo not configure ftrace. This assume that the user\n"
1775 "\t\t\tconfigures the ftrace files in sysfs such as\n"
1776 "\t\t\t/sys/kernel/tracing/current_tracer or equivalent.\n\n"
1777 
1778 "-i, --tracefile FILE\tUse FILE as trace file. The default is\n"
1779 "\t\t\t%s.\n"
1780 "\t\t\tThis options implies -x\n\n"
1781 
1782 "-m, --max-lat FILE\tUse FILE as tracing_max_latency file. The default is\n"
1783 "\t\t\t%s.\n"
1784 "\t\t\tThis options implies -x\n\n"
1785 ,
1786 prg_name, debug_tracefile_dflt, debug_maxlat_dflt, DEFAULT_NR_PRINTER_THREADS,
1787 SLEEP_TIME_MS_DEFAULT, DEFAULT_TABLE_SIZE, SLEEP_TIME_MS_DEFAULT,
1788 debug_tracefile_dflt, debug_maxlat_dflt);
1789 }
1790 
find_tracefiles(void)1791 static void find_tracefiles(void)
1792 {
1793 	debug_tracefile_dflt = tracefs_get_tracing_file("trace");
1794 	if (debug_tracefile_dflt == NULL) {
1795 		/* This is needed in show_usage() */
1796 		debug_tracefile_dflt = DEBUG_NOFILE;
1797 	}
1798 
1799 	debug_maxlat_dflt = tracefs_get_tracing_file("tracing_max_latency");
1800 	if (debug_maxlat_dflt == NULL) {
1801 		/* This is needed in show_usage() */
1802 		debug_maxlat_dflt = DEBUG_NOFILE;
1803 	}
1804 
1805 	debug_tracefile = debug_tracefile_dflt;
1806 	debug_maxlat = debug_maxlat_dflt;
1807 }
1808 
alldigits(const char * s)1809 bool alldigits(const char *s)
1810 {
1811 	for (; *s != '\0'; s++)
1812 		if (!isdigit(*s))
1813 			return false;
1814 	return true;
1815 }
1816 
check_alldigits(const char * optarg,const char * argname)1817 void check_alldigits(const char *optarg, const char *argname)
1818 {
1819 	if (!alldigits(optarg))
1820 		errx(EXIT_FAILURE,
1821 		     "The %s parameter expects a decimal argument\n", argname);
1822 }
1823 
scan_arguments(int argc,char * argv[])1824 static void scan_arguments(int argc, char *argv[])
1825 {
1826 	int c;
1827 	int i;
1828 	int option_idx = 0;
1829 
1830 	static struct option long_options[] = {
1831 		{ "list",       no_argument,            0, 'l' },
1832 		{ "tracer",	required_argument,	0, 't' },
1833 		{ "force",      no_argument,            0, 'F' },
1834 		{ "threshold",  required_argument,      0, 's' },
1835 		{ "function",   no_argument,            0, 'f' },
1836 		{ "graph",      no_argument,            0, 'g' },
1837 		{ "policy",	required_argument,	0, 'c' },
1838 		{ "priority",	required_argument,	0, 'p' },
1839 		{ "help",	no_argument,		0, 'h' },
1840 		{ "notrace",	no_argument,		0, 'n' },
1841 		{ "random",	no_argument,		0, 'r' },
1842 		{ "nrlat",	required_argument,	0, 'a' },
1843 		{ "threads",	required_argument,	0, 'e' },
1844 		{ "time",	required_argument,	0, 'u' },
1845 		{ "verbose",	no_argument,		0, 'v' },
1846 		{ "no-ftrace",  no_argument,            0, 'x' },
1847 		{ "tracefile",	required_argument,	0, 'i' },
1848 		{ "max-lat",	required_argument,	0, 'm' },
1849 		{ 0,		0,			0,  0  }
1850 	};
1851 	const struct policy *p;
1852 	int max, min;
1853 	int value;
1854 	bool notracer, valid;
1855 
1856 	/*
1857 	 * We must do this before parsing the arguments because show_usage()
1858 	 * needs to display these.
1859 	 */
1860 	find_tracefiles();
1861 
1862 	while (true) {
1863 		c = getopt_long(argc, argv, "lt:Fs:fgc:p:hnra:e:u:vxi:m:",
1864 				long_options, &option_idx);
1865 		if (c == -1)
1866 			break;
1867 
1868 		switch (c) {
1869 		case 'l':
1870 			show_available();
1871 			exit(0);
1872 			break;
1873 		case 't':
1874 			current_tracer = strdup(optarg);
1875 			if (!is_relevant_tracer(current_tracer)) {
1876 				warnx("%s is not a known latency tracer!\n",
1877 				      current_tracer);
1878 			}
1879 			valid = tracer_valid(current_tracer, &notracer);
1880 			if (notracer)
1881 				errx(EXIT_FAILURE, "%s", no_tracer_msg);
1882 			if (!valid)
1883 				errx(EXIT_FAILURE,
1884 "The tracer %s is not supported by your kernel!\n", current_tracer);
1885 			break;
1886 		case 'F':
1887 			force_tracer = true;
1888 			break;
1889 		case 's':
1890 			check_alldigits(optarg, "-s [--threshold]");
1891 			threshold = strdup(optarg);
1892 			break;
1893 		case 'f':
1894 			use_options[OPTIDX_FUNC_TR] = true;
1895 			break;
1896 		case 'g':
1897 			use_options[OPTIDX_DISP_GR] = true;
1898 			break;
1899 		case 'c':
1900 			p = policy_from_name(optarg);
1901 			if (p != NULL) {
1902 				sched_policy = p->policy;
1903 				sched_policy_set = true;
1904 				if (!sched_pri_set) {
1905 					sched_pri = p->default_pri;
1906 					sched_pri_set = true;
1907 				}
1908 			} else {
1909 				warnx("Unknown scheduling %s\n", optarg);
1910 				show_usage();
1911 				exit(0);
1912 			}
1913 			break;
1914 		case 'p':
1915 			check_alldigits(optarg, "-p [--priority]");
1916 			sched_pri = atoi(optarg);
1917 			sched_pri_set = true;
1918 			break;
1919 		case 'h':
1920 			show_usage();
1921 			exit(0);
1922 			break;
1923 		case 'n':
1924 			trace_enable = false;
1925 			use_random_sleep = false;
1926 			break;
1927 		case 'e':
1928 			check_alldigits(optarg, "-e [--threads]");
1929 			value = atoi(optarg);
1930 			if (value > 0)
1931 				nr_threads = value;
1932 			else {
1933 				warnx("NRTHR must be > 0\n");
1934 				show_usage();
1935 				exit(0);
1936 			}
1937 			break;
1938 		case 'u':
1939 			check_alldigits(optarg, "-u [--time]");
1940 			value = atoi(optarg);
1941 			if (value < 0) {
1942 				warnx("TIME must be >= 0\n");
1943 				show_usage();
1944 				exit(0);
1945 			}
1946 			trace_enable = true;
1947 			use_random_sleep = true;
1948 			sleep_time = value * USEC_PER_MSEC;
1949 			break;
1950 		case 'v':
1951 			verbosity++;
1952 			break;
1953 		case 'r':
1954 			trace_enable = true;
1955 			use_random_sleep = true;
1956 			break;
1957 		case 'a':
1958 			check_alldigits(optarg, "-a [--nrlat]");
1959 			value = atoi(optarg);
1960 			if (value <= 0) {
1961 				warnx("NRLAT must be > 0\n");
1962 				show_usage();
1963 				exit(0);
1964 			}
1965 			trace_enable = true;
1966 			use_random_sleep = true;
1967 			table_startsize = value;
1968 			break;
1969 		case 'x':
1970 			setup_ftrace = false;
1971 			break;
1972 		case 'i':
1973 			setup_ftrace = false;
1974 			debug_tracefile = strdup(optarg);
1975 			break;
1976 		case 'm':
1977 			setup_ftrace = false;
1978 			debug_maxlat = strdup(optarg);
1979 			break;
1980 		default:
1981 			show_usage();
1982 			exit(0);
1983 			break;
1984 		}
1985 	}
1986 
1987 	if (setup_ftrace) {
1988 		if (!current_tracer) {
1989 			current_tracer = find_default_tracer();
1990 			if (!current_tracer)
1991 				errx(EXIT_FAILURE,
1992 "No default tracer found and tracer not specified\n");
1993 		}
1994 
1995 		if (use_random_sleep && !random_makes_sense(current_tracer)) {
1996 			warnx("WARNING: The tracer is %s and random sleep has",
1997 			      current_tracer);
1998 			fprintf(stderr,
1999 "been enabled. Random sleep is intended for the following tracers:\n");
2000 			for (i = 0; random_tracers[i]; i++)
2001 				fprintf(stderr, "%s\n", random_tracers[i]);
2002 			fprintf(stderr, "\n");
2003 		}
2004 	}
2005 
2006 	if (debug_tracefile == DEBUG_NOFILE ||
2007 	    debug_maxlat == DEBUG_NOFILE)
2008 		errx(EXIT_FAILURE,
2009 "Could not find tracing directory e.g. /sys/kernel/tracing\n");
2010 
2011 	if (!sched_policy_set) {
2012 		sched_policy = SCHED_RR;
2013 		sched_policy_set = true;
2014 		if (!sched_pri_set) {
2015 			sched_pri = RT_DEFAULT_PRI;
2016 			sched_pri_set = true;
2017 		}
2018 	}
2019 
2020 	max = sched_get_priority_max(sched_policy);
2021 	min = sched_get_priority_min(sched_policy);
2022 
2023 	if (sched_pri < min) {
2024 		printf(
2025 "ATTENTION: Increasing priority to minimum, which is %d\n", min);
2026 		sched_pri = min;
2027 	}
2028 	if (sched_pri > max) {
2029 		printf(
2030 "ATTENTION: Reducing priority to maximum, which is %d\n", max);
2031 		sched_pri = max;
2032 	}
2033 }
2034 
show_params(void)2035 static void show_params(void)
2036 {
2037 	printf(
2038 "\n"
2039 "Running with scheduling policy %s and priority %d. Using %d print threads.\n",
2040 		policy_name(sched_policy), sched_pri, nr_threads);
2041 	if (trace_enable) {
2042 		if (use_random_sleep) {
2043 			printf(
2044 "%s will be printed with random delay\n"
2045 "Start size of the probability table:\t\t\t%d\n"
2046 "Print a message when the prob. table changes size:\t%s\n"
2047 "Print a warning when an event has been lost:\t\t%s\n"
2048 "Sleep time is:\t\t\t\t\t\t%ld ms\n",
2049 debug_tracefile,
2050 table_startsize,
2051 bool2str(verbose_sizechange()),
2052 bool2str(verbose_lostevent()),
2053 sleep_time / USEC_PER_MSEC);
2054 		} else {
2055 			printf("%s will be printed immediately\n",
2056 			       debug_tracefile);
2057 		}
2058 	} else {
2059 		printf("%s will not be printed\n",
2060 		       debug_tracefile);
2061 	}
2062 	if (setup_ftrace) {
2063 		printf("Tracer:\t\t\t\t\t\t\t%s\n"
2064 		       "%s option:\t\t\t\t\t%s\n"
2065 		       "%s option:\t\t\t\t\t%s\n",
2066 		       current_tracer,
2067 		       optstr[OPTIDX_FUNC_TR],
2068 		       bool2str(use_options[OPTIDX_FUNC_TR]),
2069 		       optstr[OPTIDX_DISP_GR],
2070 		       bool2str(use_options[OPTIDX_DISP_GR]));
2071 		if (!strcmp(threshold, "0"))
2072 			printf("Threshold:\t\t\t\t\t\ttracing_max_latency\n");
2073 		else
2074 			printf("Threshold:\t\t\t\t\t\t%s\n", threshold);
2075 	}
2076 	printf("\n");
2077 }
2078 
main(int argc,char * argv[])2079 int main(int argc, char *argv[])
2080 {
2081 	init_save_state();
2082 	signal_blocking(SIG_BLOCK);
2083 	setup_sig_handler();
2084 	open_stdout();
2085 
2086 	if (argc >= 1)
2087 		prg_name = argv[0];
2088 	else
2089 		prg_name = prg_unknown;
2090 
2091 	scan_arguments(argc, argv);
2092 	show_params();
2093 
2094 	init_printstate();
2095 	init_print_mtx();
2096 	if (use_random_sleep) {
2097 		init_probabilities();
2098 		if (verbose_sizechange())
2099 			printf("Initializing probability table to %d\n",
2100 			       table_startsize);
2101 		sleeptable_resize(table_startsize, false, NULL);
2102 	}
2103 	set_priority();
2104 	init_queue(&printqueue);
2105 	start_printthread();
2106 	tracing_loop();
2107 	return 0;
2108 }
2109