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