162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017, 2018, 2019, 2021 BMW Car IT GmbH 462306a36Sopenharmony_ci * Author: Viktor Rosendahl (viktor.rosendahl@bmw.de) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#define _GNU_SOURCE 862306a36Sopenharmony_ci#define _POSIX_C_SOURCE 200809L 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <ctype.h> 1162306a36Sopenharmony_ci#include <stdbool.h> 1262306a36Sopenharmony_ci#include <stdio.h> 1362306a36Sopenharmony_ci#include <stdlib.h> 1462306a36Sopenharmony_ci#include <string.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <err.h> 1762306a36Sopenharmony_ci#include <errno.h> 1862306a36Sopenharmony_ci#include <fcntl.h> 1962306a36Sopenharmony_ci#include <getopt.h> 2062306a36Sopenharmony_ci#include <sched.h> 2162306a36Sopenharmony_ci#include <linux/unistd.h> 2262306a36Sopenharmony_ci#include <signal.h> 2362306a36Sopenharmony_ci#include <sys/inotify.h> 2462306a36Sopenharmony_ci#include <unistd.h> 2562306a36Sopenharmony_ci#include <pthread.h> 2662306a36Sopenharmony_ci#include <tracefs.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const char *prg_name; 2962306a36Sopenharmony_cistatic const char *prg_unknown = "unknown program name"; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int fd_stdout; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int sched_policy; 3462306a36Sopenharmony_cistatic bool sched_policy_set; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int sched_pri; 3762306a36Sopenharmony_cistatic bool sched_pri_set; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic bool trace_enable = true; 4062306a36Sopenharmony_cistatic bool setup_ftrace = true; 4162306a36Sopenharmony_cistatic bool use_random_sleep; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define TRACE_OPTS \ 4462306a36Sopenharmony_ci C(FUNC_TR, "function-trace"), \ 4562306a36Sopenharmony_ci C(DISP_GR, "display-graph"), \ 4662306a36Sopenharmony_ci C(NR, NULL) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#undef C 4962306a36Sopenharmony_ci#define C(a, b) OPTIDX_##a 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cienum traceopt { 5262306a36Sopenharmony_ci TRACE_OPTS 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#undef C 5662306a36Sopenharmony_ci#define C(a, b) b 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic const char *const optstr[] = { 5962306a36Sopenharmony_ci TRACE_OPTS 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cienum errhandling { 6362306a36Sopenharmony_ci ERR_EXIT = 0, 6462306a36Sopenharmony_ci ERR_WARN, 6562306a36Sopenharmony_ci ERR_CLEANUP, 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic bool use_options[OPTIDX_NR]; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic char inotify_buffer[655360]; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define likely(x) __builtin_expect(!!(x), 1) 7362306a36Sopenharmony_ci#define unlikely(x) __builtin_expect(!!(x), 0) 7462306a36Sopenharmony_ci#define bool2str(x) (x ? "true":"false") 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define DEFAULT_NR_PRINTER_THREADS (3) 7762306a36Sopenharmony_cistatic unsigned int nr_threads = DEFAULT_NR_PRINTER_THREADS; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define DEFAULT_TABLE_SIZE (2) 8062306a36Sopenharmony_cistatic unsigned int table_startsize = DEFAULT_TABLE_SIZE; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int verbosity; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define verbose_sizechange() (verbosity >= 1) 8562306a36Sopenharmony_ci#define verbose_lostevent() (verbosity >= 2) 8662306a36Sopenharmony_ci#define verbose_ftrace() (verbosity >= 1) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define was_changed(ORIG, CUR) (strcmp(ORIG, CUR) != 0) 8962306a36Sopenharmony_ci#define needs_change(CUR, WANTED) (strcmp(CUR, WANTED) != 0) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const char *debug_tracefile; 9262306a36Sopenharmony_cistatic const char *debug_tracefile_dflt; 9362306a36Sopenharmony_cistatic const char *debug_maxlat; 9462306a36Sopenharmony_cistatic const char *debug_maxlat_dflt; 9562306a36Sopenharmony_cistatic const char * const DEBUG_NOFILE = "[file not found]"; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic const char * const TR_MAXLAT = "tracing_max_latency"; 9862306a36Sopenharmony_cistatic const char * const TR_THRESH = "tracing_thresh"; 9962306a36Sopenharmony_cistatic const char * const TR_CURRENT = "current_tracer"; 10062306a36Sopenharmony_cistatic const char * const TR_OPTIONS = "trace_options"; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic const char * const NOP_TRACER = "nop"; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic const char * const OPT_NO_PREFIX = "no"; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define DFLT_THRESHOLD_US "0" 10762306a36Sopenharmony_cistatic const char *threshold = DFLT_THRESHOLD_US; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define DEV_URANDOM "/dev/urandom" 11062306a36Sopenharmony_ci#define RT_DEFAULT_PRI (99) 11162306a36Sopenharmony_ci#define DEFAULT_PRI (0) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define USEC_PER_MSEC (1000L) 11462306a36Sopenharmony_ci#define NSEC_PER_USEC (1000L) 11562306a36Sopenharmony_ci#define NSEC_PER_MSEC (USEC_PER_MSEC * NSEC_PER_USEC) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define MSEC_PER_SEC (1000L) 11862306a36Sopenharmony_ci#define USEC_PER_SEC (USEC_PER_MSEC * MSEC_PER_SEC) 11962306a36Sopenharmony_ci#define NSEC_PER_SEC (NSEC_PER_MSEC * MSEC_PER_SEC) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define SLEEP_TIME_MS_DEFAULT (1000L) 12262306a36Sopenharmony_ci#define TRY_PRINTMUTEX_MS (1000) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic long sleep_time = (USEC_PER_MSEC * SLEEP_TIME_MS_DEFAULT); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic const char * const queue_full_warning = 12762306a36Sopenharmony_ci"Could not queue trace for printing. It is likely that events happen faster\n" 12862306a36Sopenharmony_ci"than what they can be printed. Probably partly because of random sleeping\n"; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic const char * const no_tracer_msg = 13162306a36Sopenharmony_ci"Could not find any tracers! Running this program as root may help!\n"; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic const char * const no_latency_tr_msg = 13462306a36Sopenharmony_ci"No latency tracers are supported by your kernel!\n"; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistruct policy { 13762306a36Sopenharmony_ci const char *name; 13862306a36Sopenharmony_ci int policy; 13962306a36Sopenharmony_ci int default_pri; 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic const struct policy policies[] = { 14362306a36Sopenharmony_ci { "other", SCHED_OTHER, DEFAULT_PRI }, 14462306a36Sopenharmony_ci { "batch", SCHED_BATCH, DEFAULT_PRI }, 14562306a36Sopenharmony_ci { "idle", SCHED_IDLE, DEFAULT_PRI }, 14662306a36Sopenharmony_ci { "rr", SCHED_RR, RT_DEFAULT_PRI }, 14762306a36Sopenharmony_ci { "fifo", SCHED_FIFO, RT_DEFAULT_PRI }, 14862306a36Sopenharmony_ci { NULL, 0, DEFAULT_PRI } 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* 15262306a36Sopenharmony_ci * The default tracer will be the first on this list that is supported by the 15362306a36Sopenharmony_ci * currently running Linux kernel. 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_cistatic const char * const relevant_tracers[] = { 15662306a36Sopenharmony_ci "preemptirqsoff", 15762306a36Sopenharmony_ci "preemptoff", 15862306a36Sopenharmony_ci "irqsoff", 15962306a36Sopenharmony_ci "wakeup", 16062306a36Sopenharmony_ci "wakeup_rt", 16162306a36Sopenharmony_ci "wakeup_dl", 16262306a36Sopenharmony_ci NULL 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* This is the list of tracers for which random sleep makes sense */ 16662306a36Sopenharmony_cistatic const char * const random_tracers[] = { 16762306a36Sopenharmony_ci "preemptirqsoff", 16862306a36Sopenharmony_ci "preemptoff", 16962306a36Sopenharmony_ci "irqsoff", 17062306a36Sopenharmony_ci NULL 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic const char *current_tracer; 17462306a36Sopenharmony_cistatic bool force_tracer; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistruct ftrace_state { 17762306a36Sopenharmony_ci char *tracer; 17862306a36Sopenharmony_ci char *thresh; 17962306a36Sopenharmony_ci bool opt[OPTIDX_NR]; 18062306a36Sopenharmony_ci bool opt_valid[OPTIDX_NR]; 18162306a36Sopenharmony_ci pthread_mutex_t mutex; 18262306a36Sopenharmony_ci}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistruct entry { 18562306a36Sopenharmony_ci int ticket; 18662306a36Sopenharmony_ci int ticket_completed_ref; 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistruct print_state { 19062306a36Sopenharmony_ci int ticket_counter; 19162306a36Sopenharmony_ci int ticket_completed; 19262306a36Sopenharmony_ci pthread_mutex_t mutex; 19362306a36Sopenharmony_ci pthread_cond_t cond; 19462306a36Sopenharmony_ci int cnt; 19562306a36Sopenharmony_ci pthread_mutex_t cnt_mutex; 19662306a36Sopenharmony_ci}; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistruct short_msg { 19962306a36Sopenharmony_ci char buf[160]; 20062306a36Sopenharmony_ci int len; 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic struct print_state printstate; 20462306a36Sopenharmony_cistatic struct ftrace_state save_state; 20562306a36Sopenharmony_civolatile sig_atomic_t signal_flag; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci#define PROB_TABLE_MAX_SIZE (1000) 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ciint probabilities[PROB_TABLE_MAX_SIZE]; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistruct sleep_table { 21262306a36Sopenharmony_ci int *table; 21362306a36Sopenharmony_ci int size; 21462306a36Sopenharmony_ci pthread_mutex_t mutex; 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic struct sleep_table sleeptable; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define QUEUE_SIZE (10) 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistruct queue { 22262306a36Sopenharmony_ci struct entry entries[QUEUE_SIZE]; 22362306a36Sopenharmony_ci int next_prod_idx; 22462306a36Sopenharmony_ci int next_cons_idx; 22562306a36Sopenharmony_ci pthread_mutex_t mutex; 22662306a36Sopenharmony_ci pthread_cond_t cond; 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define MAX_THREADS (40) 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistruct queue printqueue; 23262306a36Sopenharmony_cipthread_t printthread[MAX_THREADS]; 23362306a36Sopenharmony_cipthread_mutex_t print_mtx; 23462306a36Sopenharmony_ci#define PRINT_BUFFER_SIZE (16 * 1024 * 1024) 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void cleanup_exit(int status); 23762306a36Sopenharmony_cistatic int set_trace_opt(const char *opt, bool value); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic __always_inline void *malloc_or_die(size_t size) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci void *ptr = malloc(size); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (unlikely(ptr == NULL)) { 24462306a36Sopenharmony_ci warn("malloc() failed"); 24562306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci return ptr; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic __always_inline void *malloc_or_die_nocleanup(size_t size) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci void *ptr = malloc(size); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (unlikely(ptr == NULL)) 25562306a36Sopenharmony_ci err(0, "malloc() failed"); 25662306a36Sopenharmony_ci return ptr; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic __always_inline void write_or_die(int fd, const char *buf, size_t count) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci ssize_t r; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci do { 26462306a36Sopenharmony_ci r = write(fd, buf, count); 26562306a36Sopenharmony_ci if (unlikely(r < 0)) { 26662306a36Sopenharmony_ci if (errno == EINTR) 26762306a36Sopenharmony_ci continue; 26862306a36Sopenharmony_ci warn("write() failed"); 26962306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci count -= r; 27262306a36Sopenharmony_ci buf += r; 27362306a36Sopenharmony_ci } while (count > 0); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic __always_inline void clock_gettime_or_die(clockid_t clk_id, 27762306a36Sopenharmony_ci struct timespec *tp) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci int r = clock_gettime(clk_id, tp); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (unlikely(r != 0)) 28262306a36Sopenharmony_ci err(EXIT_FAILURE, "clock_gettime() failed"); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic __always_inline void sigemptyset_or_die(sigset_t *s) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci if (unlikely(sigemptyset(s) != 0)) { 28862306a36Sopenharmony_ci warn("sigemptyset() failed"); 28962306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic __always_inline void sigaddset_or_die(sigset_t *s, int signum) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci if (unlikely(sigaddset(s, signum) != 0)) { 29662306a36Sopenharmony_ci warn("sigemptyset() failed"); 29762306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic __always_inline void sigaction_or_die(int signum, 30262306a36Sopenharmony_ci const struct sigaction *act, 30362306a36Sopenharmony_ci struct sigaction *oldact) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci if (unlikely(sigaction(signum, act, oldact) != 0)) { 30662306a36Sopenharmony_ci warn("sigaction() failed"); 30762306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void open_stdout(void) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci if (setvbuf(stdout, NULL, _IONBF, 0) != 0) 31462306a36Sopenharmony_ci err(EXIT_FAILURE, "setvbuf() failed"); 31562306a36Sopenharmony_ci fd_stdout = fileno(stdout); 31662306a36Sopenharmony_ci if (fd_stdout < 0) 31762306a36Sopenharmony_ci err(EXIT_FAILURE, "fileno() failed"); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* 32162306a36Sopenharmony_ci * It's not worth it to call cleanup_exit() from mutex functions because 32262306a36Sopenharmony_ci * cleanup_exit() uses mutexes. 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_cistatic __always_inline void mutex_lock(pthread_mutex_t *mtx) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci errno = pthread_mutex_lock(mtx); 32762306a36Sopenharmony_ci if (unlikely(errno)) 32862306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_mutex_lock() failed"); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic __always_inline void mutex_unlock(pthread_mutex_t *mtx) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci errno = pthread_mutex_unlock(mtx); 33562306a36Sopenharmony_ci if (unlikely(errno)) 33662306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_mutex_unlock() failed"); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic __always_inline void cond_signal(pthread_cond_t *cond) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci errno = pthread_cond_signal(cond); 34262306a36Sopenharmony_ci if (unlikely(errno)) 34362306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_cond_signal() failed"); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic __always_inline void cond_wait(pthread_cond_t *restrict cond, 34762306a36Sopenharmony_ci pthread_mutex_t *restrict mutex) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci errno = pthread_cond_wait(cond, mutex); 35062306a36Sopenharmony_ci if (unlikely(errno)) 35162306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_cond_wait() failed"); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic __always_inline void cond_broadcast(pthread_cond_t *cond) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci errno = pthread_cond_broadcast(cond); 35762306a36Sopenharmony_ci if (unlikely(errno)) 35862306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_cond_broadcast() failed"); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic __always_inline void 36262306a36Sopenharmony_cimutex_init(pthread_mutex_t *mutex, 36362306a36Sopenharmony_ci const pthread_mutexattr_t *attr) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci errno = pthread_mutex_init(mutex, attr); 36662306a36Sopenharmony_ci if (errno) 36762306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_mutex_init() failed"); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic __always_inline void mutexattr_init(pthread_mutexattr_t *attr) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci errno = pthread_mutexattr_init(attr); 37362306a36Sopenharmony_ci if (errno) 37462306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_mutexattr_init() failed"); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic __always_inline void mutexattr_destroy(pthread_mutexattr_t *attr) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci errno = pthread_mutexattr_destroy(attr); 38062306a36Sopenharmony_ci if (errno) 38162306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_mutexattr_destroy() failed"); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic __always_inline void mutexattr_settype(pthread_mutexattr_t *attr, 38562306a36Sopenharmony_ci int type) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci errno = pthread_mutexattr_settype(attr, type); 38862306a36Sopenharmony_ci if (errno) 38962306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_mutexattr_settype() failed"); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic __always_inline void condattr_init(pthread_condattr_t *attr) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci errno = pthread_condattr_init(attr); 39562306a36Sopenharmony_ci if (errno) 39662306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_condattr_init() failed"); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic __always_inline void condattr_destroy(pthread_condattr_t *attr) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci errno = pthread_condattr_destroy(attr); 40262306a36Sopenharmony_ci if (errno) 40362306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_condattr_destroy() failed"); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic __always_inline void condattr_setclock(pthread_condattr_t *attr, 40762306a36Sopenharmony_ci clockid_t clock_id) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci errno = pthread_condattr_setclock(attr, clock_id); 41062306a36Sopenharmony_ci if (unlikely(errno)) 41162306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_condattr_setclock() failed"); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic __always_inline void cond_init(pthread_cond_t *cond, 41562306a36Sopenharmony_ci const pthread_condattr_t *attr) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci errno = pthread_cond_init(cond, attr); 41862306a36Sopenharmony_ci if (errno) 41962306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_cond_init() failed"); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic __always_inline int 42362306a36Sopenharmony_cicond_timedwait(pthread_cond_t *restrict cond, 42462306a36Sopenharmony_ci pthread_mutex_t *restrict mutex, 42562306a36Sopenharmony_ci const struct timespec *restrict abstime) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci errno = pthread_cond_timedwait(cond, mutex, abstime); 42862306a36Sopenharmony_ci if (errno && errno != ETIMEDOUT) 42962306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_cond_timedwait() failed"); 43062306a36Sopenharmony_ci return errno; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void init_printstate(void) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci pthread_condattr_t cattr; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci printstate.ticket_counter = 0; 43862306a36Sopenharmony_ci printstate.ticket_completed = 0; 43962306a36Sopenharmony_ci printstate.cnt = 0; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci mutex_init(&printstate.mutex, NULL); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci condattr_init(&cattr); 44462306a36Sopenharmony_ci condattr_setclock(&cattr, CLOCK_MONOTONIC); 44562306a36Sopenharmony_ci cond_init(&printstate.cond, &cattr); 44662306a36Sopenharmony_ci condattr_destroy(&cattr); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic void init_print_mtx(void) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci pthread_mutexattr_t mattr; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci mutexattr_init(&mattr); 45462306a36Sopenharmony_ci mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); 45562306a36Sopenharmony_ci mutex_init(&print_mtx, &mattr); 45662306a36Sopenharmony_ci mutexattr_destroy(&mattr); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void signal_blocking(int how) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci sigset_t s; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci sigemptyset_or_die(&s); 46562306a36Sopenharmony_ci sigaddset_or_die(&s, SIGHUP); 46662306a36Sopenharmony_ci sigaddset_or_die(&s, SIGTERM); 46762306a36Sopenharmony_ci sigaddset_or_die(&s, SIGINT); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci errno = pthread_sigmask(how, &s, NULL); 47062306a36Sopenharmony_ci if (unlikely(errno)) { 47162306a36Sopenharmony_ci warn("pthread_sigmask() failed"); 47262306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic void signal_handler(int num) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci signal_flag = num; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic void setup_sig_handler(void) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct sigaction sa; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 48662306a36Sopenharmony_ci sa.sa_handler = signal_handler; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci sigaction_or_die(SIGHUP, &sa, NULL); 48962306a36Sopenharmony_ci sigaction_or_die(SIGTERM, &sa, NULL); 49062306a36Sopenharmony_ci sigaction_or_die(SIGINT, &sa, NULL); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic void process_signal(int signal) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci char *name; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci name = strsignal(signal); 49862306a36Sopenharmony_ci if (name == NULL) 49962306a36Sopenharmony_ci printf("Received signal %d\n", signal); 50062306a36Sopenharmony_ci else 50162306a36Sopenharmony_ci printf("Received signal %d (%s)\n", signal, name); 50262306a36Sopenharmony_ci cleanup_exit(EXIT_SUCCESS); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic __always_inline void check_signals(void) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci int signal = signal_flag; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (unlikely(signal)) 51062306a36Sopenharmony_ci process_signal(signal); 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic __always_inline void get_time_in_future(struct timespec *future, 51462306a36Sopenharmony_ci long time_us) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci long nsec; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci clock_gettime_or_die(CLOCK_MONOTONIC, future); 51962306a36Sopenharmony_ci future->tv_sec += time_us / USEC_PER_SEC; 52062306a36Sopenharmony_ci nsec = future->tv_nsec + (time_us * NSEC_PER_USEC) % NSEC_PER_SEC; 52162306a36Sopenharmony_ci if (nsec >= NSEC_PER_SEC) { 52262306a36Sopenharmony_ci future->tv_nsec = nsec % NSEC_PER_SEC; 52362306a36Sopenharmony_ci future->tv_sec += 1; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic __always_inline bool time_has_passed(const struct timespec *time) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct timespec now; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci clock_gettime_or_die(CLOCK_MONOTONIC, &now); 53262306a36Sopenharmony_ci if (now.tv_sec > time->tv_sec) 53362306a36Sopenharmony_ci return true; 53462306a36Sopenharmony_ci if (now.tv_sec < time->tv_sec) 53562306a36Sopenharmony_ci return false; 53662306a36Sopenharmony_ci return (now.tv_nsec >= time->tv_nsec); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic bool mutex_trylock_limit(pthread_mutex_t *mutex, int time_ms) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci long time_us = time_ms * USEC_PER_MSEC; 54262306a36Sopenharmony_ci struct timespec limit; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci get_time_in_future(&limit, time_us); 54562306a36Sopenharmony_ci do { 54662306a36Sopenharmony_ci errno = pthread_mutex_trylock(mutex); 54762306a36Sopenharmony_ci if (errno && errno != EBUSY) 54862306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_mutex_trylock() failed"); 54962306a36Sopenharmony_ci } while (errno && !time_has_passed(&limit)); 55062306a36Sopenharmony_ci return errno == 0; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic void restore_trace_opts(const struct ftrace_state *state, 55462306a36Sopenharmony_ci const bool *cur) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci int i; 55762306a36Sopenharmony_ci int r; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci for (i = 0; i < OPTIDX_NR; i++) 56062306a36Sopenharmony_ci if (state->opt_valid[i] && state->opt[i] != cur[i]) { 56162306a36Sopenharmony_ci r = set_trace_opt(optstr[i], state->opt[i]); 56262306a36Sopenharmony_ci if (r < 0) 56362306a36Sopenharmony_ci warnx("Failed to restore the %s option to %s", 56462306a36Sopenharmony_ci optstr[i], bool2str(state->opt[i])); 56562306a36Sopenharmony_ci else if (verbose_ftrace()) 56662306a36Sopenharmony_ci printf("Restored the %s option in %s to %s\n", 56762306a36Sopenharmony_ci optstr[i], TR_OPTIONS, 56862306a36Sopenharmony_ci bool2str(state->opt[i])); 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic char *read_file(const char *file, enum errhandling h) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci int psize; 57562306a36Sopenharmony_ci char *r; 57662306a36Sopenharmony_ci static const char *emsg = "Failed to read the %s file"; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci r = tracefs_instance_file_read(NULL, file, &psize); 57962306a36Sopenharmony_ci if (!r) { 58062306a36Sopenharmony_ci if (h) { 58162306a36Sopenharmony_ci warn(emsg, file); 58262306a36Sopenharmony_ci if (h == ERR_CLEANUP) 58362306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 58462306a36Sopenharmony_ci } else 58562306a36Sopenharmony_ci errx(EXIT_FAILURE, emsg, file); 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (r && r[psize - 1] == '\n') 58962306a36Sopenharmony_ci r[psize - 1] = '\0'; 59062306a36Sopenharmony_ci return r; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic void restore_file(const char *file, char **saved, const char *cur) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci if (*saved && was_changed(*saved, cur)) { 59662306a36Sopenharmony_ci if (tracefs_instance_file_write(NULL, file, *saved) < 0) 59762306a36Sopenharmony_ci warnx("Failed to restore %s to %s!", file, *saved); 59862306a36Sopenharmony_ci else if (verbose_ftrace()) 59962306a36Sopenharmony_ci printf("Restored %s to %s\n", file, *saved); 60062306a36Sopenharmony_ci free(*saved); 60162306a36Sopenharmony_ci *saved = NULL; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void restore_ftrace(void) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci mutex_lock(&save_state.mutex); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci restore_file(TR_CURRENT, &save_state.tracer, current_tracer); 61062306a36Sopenharmony_ci restore_file(TR_THRESH, &save_state.thresh, threshold); 61162306a36Sopenharmony_ci restore_trace_opts(&save_state, use_options); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci mutex_unlock(&save_state.mutex); 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic void cleanup_exit(int status) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci char *maxlat; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (!setup_ftrace) 62162306a36Sopenharmony_ci exit(status); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * We try the print_mtx for 1 sec in order to avoid garbled 62562306a36Sopenharmony_ci * output if possible, but if it cannot be obtained we proceed anyway. 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_ci mutex_trylock_limit(&print_mtx, TRY_PRINTMUTEX_MS); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci maxlat = read_file(TR_MAXLAT, ERR_WARN); 63062306a36Sopenharmony_ci if (maxlat) { 63162306a36Sopenharmony_ci printf("The maximum detected latency was: %sus\n", maxlat); 63262306a36Sopenharmony_ci free(maxlat); 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci restore_ftrace(); 63662306a36Sopenharmony_ci /* 63762306a36Sopenharmony_ci * We do not need to unlock the print_mtx here because we will exit at 63862306a36Sopenharmony_ci * the end of this function. Unlocking print_mtx causes problems if a 63962306a36Sopenharmony_ci * print thread happens to be waiting for the mutex because we have 64062306a36Sopenharmony_ci * just changed the ftrace settings to the original and thus the 64162306a36Sopenharmony_ci * print thread would output incorrect data from ftrace. 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_ci exit(status); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic void init_save_state(void) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci pthread_mutexattr_t mattr; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci mutexattr_init(&mattr); 65162306a36Sopenharmony_ci mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); 65262306a36Sopenharmony_ci mutex_init(&save_state.mutex, &mattr); 65362306a36Sopenharmony_ci mutexattr_destroy(&mattr); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci save_state.tracer = NULL; 65662306a36Sopenharmony_ci save_state.thresh = NULL; 65762306a36Sopenharmony_ci save_state.opt_valid[OPTIDX_FUNC_TR] = false; 65862306a36Sopenharmony_ci save_state.opt_valid[OPTIDX_DISP_GR] = false; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic int printstate_next_ticket(struct entry *req) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci int r; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci r = ++(printstate.ticket_counter); 66662306a36Sopenharmony_ci req->ticket = r; 66762306a36Sopenharmony_ci req->ticket_completed_ref = printstate.ticket_completed; 66862306a36Sopenharmony_ci cond_broadcast(&printstate.cond); 66962306a36Sopenharmony_ci return r; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic __always_inline 67362306a36Sopenharmony_civoid printstate_mark_req_completed(const struct entry *req) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci if (req->ticket > printstate.ticket_completed) 67662306a36Sopenharmony_ci printstate.ticket_completed = req->ticket; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic __always_inline 68062306a36Sopenharmony_cibool printstate_has_new_req_arrived(const struct entry *req) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci return (printstate.ticket_counter != req->ticket); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic __always_inline int printstate_cnt_inc(void) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci int value; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci mutex_lock(&printstate.cnt_mutex); 69062306a36Sopenharmony_ci value = ++printstate.cnt; 69162306a36Sopenharmony_ci mutex_unlock(&printstate.cnt_mutex); 69262306a36Sopenharmony_ci return value; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic __always_inline int printstate_cnt_dec(void) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci int value; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci mutex_lock(&printstate.cnt_mutex); 70062306a36Sopenharmony_ci value = --printstate.cnt; 70162306a36Sopenharmony_ci mutex_unlock(&printstate.cnt_mutex); 70262306a36Sopenharmony_ci return value; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic __always_inline int printstate_cnt_read(void) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci int value; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci mutex_lock(&printstate.cnt_mutex); 71062306a36Sopenharmony_ci value = printstate.cnt; 71162306a36Sopenharmony_ci mutex_unlock(&printstate.cnt_mutex); 71262306a36Sopenharmony_ci return value; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic __always_inline 71662306a36Sopenharmony_cibool prev_req_won_race(const struct entry *req) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci return (printstate.ticket_completed != req->ticket_completed_ref); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void sleeptable_resize(int size, bool printout, struct short_msg *msg) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci int bytes; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (printout) { 72662306a36Sopenharmony_ci msg->len = 0; 72762306a36Sopenharmony_ci if (unlikely(size > PROB_TABLE_MAX_SIZE)) 72862306a36Sopenharmony_ci bytes = snprintf(msg->buf, sizeof(msg->buf), 72962306a36Sopenharmony_ci"Cannot increase probability table to %d (maximum size reached)\n", size); 73062306a36Sopenharmony_ci else 73162306a36Sopenharmony_ci bytes = snprintf(msg->buf, sizeof(msg->buf), 73262306a36Sopenharmony_ci"Increasing probability table to %d\n", size); 73362306a36Sopenharmony_ci if (bytes < 0) 73462306a36Sopenharmony_ci warn("snprintf() failed"); 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci msg->len = bytes; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (unlikely(size < 0)) { 74062306a36Sopenharmony_ci /* Should never happen */ 74162306a36Sopenharmony_ci warnx("Bad program state at %s:%d", __FILE__, __LINE__); 74262306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 74362306a36Sopenharmony_ci return; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci sleeptable.size = size; 74662306a36Sopenharmony_ci sleeptable.table = &probabilities[PROB_TABLE_MAX_SIZE - size]; 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic void init_probabilities(void) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci int i; 75262306a36Sopenharmony_ci int j = 1000; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci for (i = 0; i < PROB_TABLE_MAX_SIZE; i++) { 75562306a36Sopenharmony_ci probabilities[i] = 1000 / j; 75662306a36Sopenharmony_ci j--; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci mutex_init(&sleeptable.mutex, NULL); 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic int table_get_probability(const struct entry *req, 76262306a36Sopenharmony_ci struct short_msg *msg) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci int diff = req->ticket - req->ticket_completed_ref; 76562306a36Sopenharmony_ci int rval = 0; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci msg->len = 0; 76862306a36Sopenharmony_ci diff--; 76962306a36Sopenharmony_ci /* Should never happen...*/ 77062306a36Sopenharmony_ci if (unlikely(diff < 0)) { 77162306a36Sopenharmony_ci warnx("Programmer assumption error at %s:%d\n", __FILE__, 77262306a36Sopenharmony_ci __LINE__); 77362306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci mutex_lock(&sleeptable.mutex); 77662306a36Sopenharmony_ci if (diff >= (sleeptable.size - 1)) { 77762306a36Sopenharmony_ci rval = sleeptable.table[sleeptable.size - 1]; 77862306a36Sopenharmony_ci sleeptable_resize(sleeptable.size + 1, verbose_sizechange(), 77962306a36Sopenharmony_ci msg); 78062306a36Sopenharmony_ci } else { 78162306a36Sopenharmony_ci rval = sleeptable.table[diff]; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci mutex_unlock(&sleeptable.mutex); 78462306a36Sopenharmony_ci return rval; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic void init_queue(struct queue *q) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci q->next_prod_idx = 0; 79062306a36Sopenharmony_ci q->next_cons_idx = 0; 79162306a36Sopenharmony_ci mutex_init(&q->mutex, NULL); 79262306a36Sopenharmony_ci errno = pthread_cond_init(&q->cond, NULL); 79362306a36Sopenharmony_ci if (errno) 79462306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_cond_init() failed"); 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic __always_inline int queue_len(const struct queue *q) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci if (q->next_prod_idx >= q->next_cons_idx) 80062306a36Sopenharmony_ci return q->next_prod_idx - q->next_cons_idx; 80162306a36Sopenharmony_ci else 80262306a36Sopenharmony_ci return QUEUE_SIZE - q->next_cons_idx + q->next_prod_idx; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic __always_inline int queue_nr_free(const struct queue *q) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci int nr_free = QUEUE_SIZE - queue_len(q); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* 81062306a36Sopenharmony_ci * If there is only one slot left we will anyway lie and claim that the 81162306a36Sopenharmony_ci * queue is full because adding an element will make it appear empty 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci if (nr_free == 1) 81462306a36Sopenharmony_ci nr_free = 0; 81562306a36Sopenharmony_ci return nr_free; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic __always_inline void queue_idx_inc(int *idx) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci *idx = (*idx + 1) % QUEUE_SIZE; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic __always_inline void queue_push_to_back(struct queue *q, 82462306a36Sopenharmony_ci const struct entry *e) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci q->entries[q->next_prod_idx] = *e; 82762306a36Sopenharmony_ci queue_idx_inc(&q->next_prod_idx); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic __always_inline struct entry queue_pop_from_front(struct queue *q) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct entry e = q->entries[q->next_cons_idx]; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci queue_idx_inc(&q->next_cons_idx); 83562306a36Sopenharmony_ci return e; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic __always_inline void queue_cond_signal(struct queue *q) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci cond_signal(&q->cond); 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic __always_inline void queue_cond_wait(struct queue *q) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci cond_wait(&q->cond, &q->mutex); 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic __always_inline int queue_try_to_add_entry(struct queue *q, 84962306a36Sopenharmony_ci const struct entry *e) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci int r = 0; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci mutex_lock(&q->mutex); 85462306a36Sopenharmony_ci if (queue_nr_free(q) > 0) { 85562306a36Sopenharmony_ci queue_push_to_back(q, e); 85662306a36Sopenharmony_ci cond_signal(&q->cond); 85762306a36Sopenharmony_ci } else 85862306a36Sopenharmony_ci r = -1; 85962306a36Sopenharmony_ci mutex_unlock(&q->mutex); 86062306a36Sopenharmony_ci return r; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic struct entry queue_wait_for_entry(struct queue *q) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct entry e; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci mutex_lock(&q->mutex); 86862306a36Sopenharmony_ci while (true) { 86962306a36Sopenharmony_ci if (queue_len(&printqueue) > 0) { 87062306a36Sopenharmony_ci e = queue_pop_from_front(q); 87162306a36Sopenharmony_ci break; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci queue_cond_wait(q); 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci mutex_unlock(&q->mutex); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci return e; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic const struct policy *policy_from_name(const char *name) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci const struct policy *p = &policies[0]; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci while (p->name != NULL) { 88562306a36Sopenharmony_ci if (!strcmp(name, p->name)) 88662306a36Sopenharmony_ci return p; 88762306a36Sopenharmony_ci p++; 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci return NULL; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic const char *policy_name(int policy) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci const struct policy *p = &policies[0]; 89562306a36Sopenharmony_ci static const char *rval = "unknown"; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci while (p->name != NULL) { 89862306a36Sopenharmony_ci if (p->policy == policy) 89962306a36Sopenharmony_ci return p->name; 90062306a36Sopenharmony_ci p++; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci return rval; 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic bool is_relevant_tracer(const char *name) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci unsigned int i; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci for (i = 0; relevant_tracers[i]; i++) 91062306a36Sopenharmony_ci if (!strcmp(name, relevant_tracers[i])) 91162306a36Sopenharmony_ci return true; 91262306a36Sopenharmony_ci return false; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic bool random_makes_sense(const char *name) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci unsigned int i; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci for (i = 0; random_tracers[i]; i++) 92062306a36Sopenharmony_ci if (!strcmp(name, random_tracers[i])) 92162306a36Sopenharmony_ci return true; 92262306a36Sopenharmony_ci return false; 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic void show_available(void) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci char **tracers; 92862306a36Sopenharmony_ci int found = 0; 92962306a36Sopenharmony_ci int i; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci tracers = tracefs_tracers(NULL); 93262306a36Sopenharmony_ci for (i = 0; tracers && tracers[i]; i++) { 93362306a36Sopenharmony_ci if (is_relevant_tracer(tracers[i])) 93462306a36Sopenharmony_ci found++; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (!tracers) { 93862306a36Sopenharmony_ci warnx(no_tracer_msg); 93962306a36Sopenharmony_ci return; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (!found) { 94362306a36Sopenharmony_ci warnx(no_latency_tr_msg); 94462306a36Sopenharmony_ci tracefs_list_free(tracers); 94562306a36Sopenharmony_ci return; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci printf("The following latency tracers are available on your system:\n"); 94962306a36Sopenharmony_ci for (i = 0; tracers[i]; i++) { 95062306a36Sopenharmony_ci if (is_relevant_tracer(tracers[i])) 95162306a36Sopenharmony_ci printf("%s\n", tracers[i]); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci tracefs_list_free(tracers); 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic bool tracer_valid(const char *name, bool *notracer) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci char **tracers; 95962306a36Sopenharmony_ci int i; 96062306a36Sopenharmony_ci bool rval = false; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci *notracer = false; 96362306a36Sopenharmony_ci tracers = tracefs_tracers(NULL); 96462306a36Sopenharmony_ci if (!tracers) { 96562306a36Sopenharmony_ci *notracer = true; 96662306a36Sopenharmony_ci return false; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci for (i = 0; tracers[i]; i++) 96962306a36Sopenharmony_ci if (!strcmp(tracers[i], name)) { 97062306a36Sopenharmony_ci rval = true; 97162306a36Sopenharmony_ci break; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci tracefs_list_free(tracers); 97462306a36Sopenharmony_ci return rval; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic const char *find_default_tracer(void) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci int i; 98062306a36Sopenharmony_ci bool notracer; 98162306a36Sopenharmony_ci bool valid; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci for (i = 0; relevant_tracers[i]; i++) { 98462306a36Sopenharmony_ci valid = tracer_valid(relevant_tracers[i], ¬racer); 98562306a36Sopenharmony_ci if (notracer) 98662306a36Sopenharmony_ci errx(EXIT_FAILURE, no_tracer_msg); 98762306a36Sopenharmony_ci if (valid) 98862306a36Sopenharmony_ci return relevant_tracers[i]; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci return NULL; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cistatic bool toss_coin(struct drand48_data *buffer, unsigned int prob) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci long r; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (unlikely(lrand48_r(buffer, &r))) { 99862306a36Sopenharmony_ci warnx("lrand48_r() failed"); 99962306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci r = r % 1000L; 100262306a36Sopenharmony_ci if (r < prob) 100362306a36Sopenharmony_ci return true; 100462306a36Sopenharmony_ci else 100562306a36Sopenharmony_ci return false; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cistatic long go_to_sleep(const struct entry *req) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci struct timespec future; 101262306a36Sopenharmony_ci long delay = sleep_time; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci get_time_in_future(&future, delay); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci mutex_lock(&printstate.mutex); 101762306a36Sopenharmony_ci while (!printstate_has_new_req_arrived(req)) { 101862306a36Sopenharmony_ci cond_timedwait(&printstate.cond, &printstate.mutex, &future); 101962306a36Sopenharmony_ci if (time_has_passed(&future)) 102062306a36Sopenharmony_ci break; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (printstate_has_new_req_arrived(req)) 102462306a36Sopenharmony_ci delay = -1; 102562306a36Sopenharmony_ci mutex_unlock(&printstate.mutex); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci return delay; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic void set_priority(void) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci int r; 103462306a36Sopenharmony_ci pid_t pid; 103562306a36Sopenharmony_ci struct sched_param param; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci memset(¶m, 0, sizeof(param)); 103862306a36Sopenharmony_ci param.sched_priority = sched_pri; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci pid = getpid(); 104162306a36Sopenharmony_ci r = sched_setscheduler(pid, sched_policy, ¶m); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (r != 0) 104462306a36Sopenharmony_ci err(EXIT_FAILURE, "sched_setscheduler() failed"); 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cipid_t latency_collector_gettid(void) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci return (pid_t) syscall(__NR_gettid); 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic void print_priority(void) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci pid_t tid; 105562306a36Sopenharmony_ci int policy; 105662306a36Sopenharmony_ci int r; 105762306a36Sopenharmony_ci struct sched_param param; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci tid = latency_collector_gettid(); 106062306a36Sopenharmony_ci r = pthread_getschedparam(pthread_self(), &policy, ¶m); 106162306a36Sopenharmony_ci if (r != 0) { 106262306a36Sopenharmony_ci warn("pthread_getschedparam() failed"); 106362306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci mutex_lock(&print_mtx); 106662306a36Sopenharmony_ci printf("Thread %d runs with scheduling policy %s and priority %d\n", 106762306a36Sopenharmony_ci tid, policy_name(policy), param.sched_priority); 106862306a36Sopenharmony_ci mutex_unlock(&print_mtx); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cistatic __always_inline 107262306a36Sopenharmony_civoid __print_skipmessage(const struct short_msg *resize_msg, 107362306a36Sopenharmony_ci const struct timespec *timestamp, char *buffer, 107462306a36Sopenharmony_ci size_t bufspace, const struct entry *req, bool excuse, 107562306a36Sopenharmony_ci const char *str) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci ssize_t bytes = 0; 107862306a36Sopenharmony_ci char *p = &buffer[0]; 107962306a36Sopenharmony_ci long us, sec; 108062306a36Sopenharmony_ci int r; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci sec = timestamp->tv_sec; 108362306a36Sopenharmony_ci us = timestamp->tv_nsec / 1000; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (resize_msg != NULL && resize_msg->len > 0) { 108662306a36Sopenharmony_ci strncpy(p, resize_msg->buf, resize_msg->len); 108762306a36Sopenharmony_ci bytes += resize_msg->len; 108862306a36Sopenharmony_ci p += resize_msg->len; 108962306a36Sopenharmony_ci bufspace -= resize_msg->len; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (excuse) 109362306a36Sopenharmony_ci r = snprintf(p, bufspace, 109462306a36Sopenharmony_ci"%ld.%06ld Latency %d printout skipped due to %s\n", 109562306a36Sopenharmony_ci sec, us, req->ticket, str); 109662306a36Sopenharmony_ci else 109762306a36Sopenharmony_ci r = snprintf(p, bufspace, "%ld.%06ld Latency %d detected\n", 109862306a36Sopenharmony_ci sec, us, req->ticket); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (r < 0) 110162306a36Sopenharmony_ci warn("snprintf() failed"); 110262306a36Sopenharmony_ci else 110362306a36Sopenharmony_ci bytes += r; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* These prints could happen concurrently */ 110662306a36Sopenharmony_ci mutex_lock(&print_mtx); 110762306a36Sopenharmony_ci write_or_die(fd_stdout, buffer, bytes); 110862306a36Sopenharmony_ci mutex_unlock(&print_mtx); 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cistatic void print_skipmessage(const struct short_msg *resize_msg, 111262306a36Sopenharmony_ci const struct timespec *timestamp, char *buffer, 111362306a36Sopenharmony_ci size_t bufspace, const struct entry *req, 111462306a36Sopenharmony_ci bool excuse) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci __print_skipmessage(resize_msg, timestamp, buffer, bufspace, req, 111762306a36Sopenharmony_ci excuse, "random delay"); 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic void print_lostmessage(const struct timespec *timestamp, char *buffer, 112162306a36Sopenharmony_ci size_t bufspace, const struct entry *req, 112262306a36Sopenharmony_ci const char *reason) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci __print_skipmessage(NULL, timestamp, buffer, bufspace, req, true, 112562306a36Sopenharmony_ci reason); 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic void print_tracefile(const struct short_msg *resize_msg, 112962306a36Sopenharmony_ci const struct timespec *timestamp, char *buffer, 113062306a36Sopenharmony_ci size_t bufspace, long slept, 113162306a36Sopenharmony_ci const struct entry *req) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci static const int reserve = 256; 113462306a36Sopenharmony_ci char *p = &buffer[0]; 113562306a36Sopenharmony_ci ssize_t bytes = 0; 113662306a36Sopenharmony_ci ssize_t bytes_tot = 0; 113762306a36Sopenharmony_ci long us, sec; 113862306a36Sopenharmony_ci long slept_ms; 113962306a36Sopenharmony_ci int trace_fd; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* Save some space for the final string and final null char */ 114262306a36Sopenharmony_ci bufspace = bufspace - reserve - 1; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (resize_msg != NULL && resize_msg->len > 0) { 114562306a36Sopenharmony_ci bytes = resize_msg->len; 114662306a36Sopenharmony_ci strncpy(p, resize_msg->buf, bytes); 114762306a36Sopenharmony_ci bytes_tot += bytes; 114862306a36Sopenharmony_ci p += bytes; 114962306a36Sopenharmony_ci bufspace -= bytes; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci trace_fd = open(debug_tracefile, O_RDONLY); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (trace_fd < 0) { 115562306a36Sopenharmony_ci warn("open() failed on %s", debug_tracefile); 115662306a36Sopenharmony_ci return; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci sec = timestamp->tv_sec; 116062306a36Sopenharmony_ci us = timestamp->tv_nsec / 1000; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (slept != 0) { 116362306a36Sopenharmony_ci slept_ms = slept / 1000; 116462306a36Sopenharmony_ci bytes = snprintf(p, bufspace, 116562306a36Sopenharmony_ci"%ld.%06ld Latency %d randomly sleep for %ld ms before print\n", 116662306a36Sopenharmony_ci sec, us, req->ticket, slept_ms); 116762306a36Sopenharmony_ci } else { 116862306a36Sopenharmony_ci bytes = snprintf(p, bufspace, 116962306a36Sopenharmony_ci "%ld.%06ld Latency %d immediate print\n", sec, 117062306a36Sopenharmony_ci us, req->ticket); 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (bytes < 0) { 117462306a36Sopenharmony_ci warn("snprintf() failed"); 117562306a36Sopenharmony_ci return; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci p += bytes; 117862306a36Sopenharmony_ci bufspace -= bytes; 117962306a36Sopenharmony_ci bytes_tot += bytes; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci bytes = snprintf(p, bufspace, 118262306a36Sopenharmony_ci">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> BEGIN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" 118362306a36Sopenharmony_ci ); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (bytes < 0) { 118662306a36Sopenharmony_ci warn("snprintf() failed"); 118762306a36Sopenharmony_ci return; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci p += bytes; 119162306a36Sopenharmony_ci bufspace -= bytes; 119262306a36Sopenharmony_ci bytes_tot += bytes; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci do { 119562306a36Sopenharmony_ci bytes = read(trace_fd, p, bufspace); 119662306a36Sopenharmony_ci if (bytes < 0) { 119762306a36Sopenharmony_ci if (errno == EINTR) 119862306a36Sopenharmony_ci continue; 119962306a36Sopenharmony_ci warn("read() failed on %s", debug_tracefile); 120062306a36Sopenharmony_ci if (unlikely(close(trace_fd) != 0)) 120162306a36Sopenharmony_ci warn("close() failed on %s", debug_tracefile); 120262306a36Sopenharmony_ci return; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci if (bytes == 0) 120562306a36Sopenharmony_ci break; 120662306a36Sopenharmony_ci p += bytes; 120762306a36Sopenharmony_ci bufspace -= bytes; 120862306a36Sopenharmony_ci bytes_tot += bytes; 120962306a36Sopenharmony_ci } while (true); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (unlikely(close(trace_fd) != 0)) 121262306a36Sopenharmony_ci warn("close() failed on %s", debug_tracefile); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci printstate_cnt_dec(); 121562306a36Sopenharmony_ci /* Add the reserve space back to the budget for the final string */ 121662306a36Sopenharmony_ci bufspace += reserve; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci bytes = snprintf(p, bufspace, 121962306a36Sopenharmony_ci ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n"); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (bytes < 0) { 122262306a36Sopenharmony_ci warn("snprintf() failed"); 122362306a36Sopenharmony_ci return; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci bytes_tot += bytes; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci /* These prints could happen concurrently */ 122962306a36Sopenharmony_ci mutex_lock(&print_mtx); 123062306a36Sopenharmony_ci write_or_die(fd_stdout, buffer, bytes_tot); 123162306a36Sopenharmony_ci mutex_unlock(&print_mtx); 123262306a36Sopenharmony_ci} 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_cistatic char *get_no_opt(const char *opt) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci char *no_opt; 123762306a36Sopenharmony_ci int s; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci s = strlen(opt) + strlen(OPT_NO_PREFIX) + 1; 124062306a36Sopenharmony_ci /* We may be called from cleanup_exit() via set_trace_opt() */ 124162306a36Sopenharmony_ci no_opt = malloc_or_die_nocleanup(s); 124262306a36Sopenharmony_ci strcpy(no_opt, OPT_NO_PREFIX); 124362306a36Sopenharmony_ci strcat(no_opt, opt); 124462306a36Sopenharmony_ci return no_opt; 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_cistatic char *find_next_optstr(const char *allopt, const char **next) 124862306a36Sopenharmony_ci{ 124962306a36Sopenharmony_ci const char *begin; 125062306a36Sopenharmony_ci const char *end; 125162306a36Sopenharmony_ci char *r; 125262306a36Sopenharmony_ci int s = 0; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (allopt == NULL) 125562306a36Sopenharmony_ci return NULL; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci for (begin = allopt; *begin != '\0'; begin++) { 125862306a36Sopenharmony_ci if (isgraph(*begin)) 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (*begin == '\0') 126362306a36Sopenharmony_ci return NULL; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci for (end = begin; *end != '\0' && isgraph(*end); end++) 126662306a36Sopenharmony_ci s++; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci r = malloc_or_die_nocleanup(s + 1); 126962306a36Sopenharmony_ci strncpy(r, begin, s); 127062306a36Sopenharmony_ci r[s] = '\0'; 127162306a36Sopenharmony_ci *next = begin + s; 127262306a36Sopenharmony_ci return r; 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistatic bool get_trace_opt(const char *allopt, const char *opt, bool *found) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci *found = false; 127862306a36Sopenharmony_ci char *no_opt; 127962306a36Sopenharmony_ci char *str; 128062306a36Sopenharmony_ci const char *next = allopt; 128162306a36Sopenharmony_ci bool rval = false; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci no_opt = get_no_opt(opt); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci do { 128662306a36Sopenharmony_ci str = find_next_optstr(next, &next); 128762306a36Sopenharmony_ci if (str == NULL) 128862306a36Sopenharmony_ci break; 128962306a36Sopenharmony_ci if (!strcmp(str, opt)) { 129062306a36Sopenharmony_ci *found = true; 129162306a36Sopenharmony_ci rval = true; 129262306a36Sopenharmony_ci free(str); 129362306a36Sopenharmony_ci break; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci if (!strcmp(str, no_opt)) { 129662306a36Sopenharmony_ci *found = true; 129762306a36Sopenharmony_ci rval = false; 129862306a36Sopenharmony_ci free(str); 129962306a36Sopenharmony_ci break; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci free(str); 130262306a36Sopenharmony_ci } while (true); 130362306a36Sopenharmony_ci free(no_opt); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci return rval; 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic int set_trace_opt(const char *opt, bool value) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci char *str; 131162306a36Sopenharmony_ci int r; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (value) 131462306a36Sopenharmony_ci str = strdup(opt); 131562306a36Sopenharmony_ci else 131662306a36Sopenharmony_ci str = get_no_opt(opt); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci r = tracefs_instance_file_write(NULL, TR_OPTIONS, str); 131962306a36Sopenharmony_ci free(str); 132062306a36Sopenharmony_ci return r; 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_civoid save_trace_opts(struct ftrace_state *state) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci char *allopt; 132662306a36Sopenharmony_ci int psize; 132762306a36Sopenharmony_ci int i; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci allopt = tracefs_instance_file_read(NULL, TR_OPTIONS, &psize); 133062306a36Sopenharmony_ci if (!allopt) 133162306a36Sopenharmony_ci errx(EXIT_FAILURE, "Failed to read the %s file\n", TR_OPTIONS); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci for (i = 0; i < OPTIDX_NR; i++) 133462306a36Sopenharmony_ci state->opt[i] = get_trace_opt(allopt, optstr[i], 133562306a36Sopenharmony_ci &state->opt_valid[i]); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci free(allopt); 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic void write_file(const char *file, const char *cur, const char *new, 134162306a36Sopenharmony_ci enum errhandling h) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci int r; 134462306a36Sopenharmony_ci static const char *emsg = "Failed to write to the %s file!"; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci /* Do nothing if we now that the current and new value are equal */ 134762306a36Sopenharmony_ci if (cur && !needs_change(cur, new)) 134862306a36Sopenharmony_ci return; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci r = tracefs_instance_file_write(NULL, file, new); 135162306a36Sopenharmony_ci if (r < 0) { 135262306a36Sopenharmony_ci if (h) { 135362306a36Sopenharmony_ci warnx(emsg, file); 135462306a36Sopenharmony_ci if (h == ERR_CLEANUP) 135562306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 135662306a36Sopenharmony_ci } else 135762306a36Sopenharmony_ci errx(EXIT_FAILURE, emsg, file); 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci if (verbose_ftrace()) { 136062306a36Sopenharmony_ci mutex_lock(&print_mtx); 136162306a36Sopenharmony_ci printf("%s was set to %s\n", file, new); 136262306a36Sopenharmony_ci mutex_unlock(&print_mtx); 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic void reset_max_latency(void) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci write_file(TR_MAXLAT, NULL, "0", ERR_CLEANUP); 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic void save_and_disable_tracer(void) 137262306a36Sopenharmony_ci{ 137362306a36Sopenharmony_ci char *orig_th; 137462306a36Sopenharmony_ci char *tracer; 137562306a36Sopenharmony_ci bool need_nop = false; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci mutex_lock(&save_state.mutex); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci save_trace_opts(&save_state); 138062306a36Sopenharmony_ci tracer = read_file(TR_CURRENT, ERR_EXIT); 138162306a36Sopenharmony_ci orig_th = read_file(TR_THRESH, ERR_EXIT); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (needs_change(tracer, NOP_TRACER)) { 138462306a36Sopenharmony_ci mutex_lock(&print_mtx); 138562306a36Sopenharmony_ci if (force_tracer) { 138662306a36Sopenharmony_ci printf( 138762306a36Sopenharmony_ci "The %s tracer is already in use but proceeding anyway!\n", 138862306a36Sopenharmony_ci tracer); 138962306a36Sopenharmony_ci } else { 139062306a36Sopenharmony_ci printf( 139162306a36Sopenharmony_ci "The %s tracer is already in use, cowardly bailing out!\n" 139262306a36Sopenharmony_ci "This could indicate that another program or instance is tracing.\n" 139362306a36Sopenharmony_ci "Use the -F [--force] option to disregard the current tracer.\n", tracer); 139462306a36Sopenharmony_ci exit(0); 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci mutex_unlock(&print_mtx); 139762306a36Sopenharmony_ci need_nop = true; 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci save_state.tracer = tracer; 140162306a36Sopenharmony_ci save_state.thresh = orig_th; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (need_nop) 140462306a36Sopenharmony_ci write_file(TR_CURRENT, NULL, NOP_TRACER, ERR_EXIT); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci mutex_unlock(&save_state.mutex); 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_civoid set_trace_opts(struct ftrace_state *state, bool *new) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci int i; 141262306a36Sopenharmony_ci int r; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci /* 141562306a36Sopenharmony_ci * We only set options if we earlier detected that the option exists in 141662306a36Sopenharmony_ci * the trace_options file and that the wanted setting is different from 141762306a36Sopenharmony_ci * the one we saw in save_and_disable_tracer() 141862306a36Sopenharmony_ci */ 141962306a36Sopenharmony_ci for (i = 0; i < OPTIDX_NR; i++) 142062306a36Sopenharmony_ci if (state->opt_valid[i] && 142162306a36Sopenharmony_ci state->opt[i] != new[i]) { 142262306a36Sopenharmony_ci r = set_trace_opt(optstr[i], new[i]); 142362306a36Sopenharmony_ci if (r < 0) { 142462306a36Sopenharmony_ci warnx("Failed to set the %s option to %s", 142562306a36Sopenharmony_ci optstr[i], bool2str(new[i])); 142662306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci if (verbose_ftrace()) { 142962306a36Sopenharmony_ci mutex_lock(&print_mtx); 143062306a36Sopenharmony_ci printf("%s in %s was set to %s\n", optstr[i], 143162306a36Sopenharmony_ci TR_OPTIONS, bool2str(new[i])); 143262306a36Sopenharmony_ci mutex_unlock(&print_mtx); 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic void enable_tracer(void) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci mutex_lock(&save_state.mutex); 144062306a36Sopenharmony_ci set_trace_opts(&save_state, use_options); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci write_file(TR_THRESH, save_state.thresh, threshold, ERR_CLEANUP); 144362306a36Sopenharmony_ci write_file(TR_CURRENT, NOP_TRACER, current_tracer, ERR_CLEANUP); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci mutex_unlock(&save_state.mutex); 144662306a36Sopenharmony_ci} 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_cistatic void tracing_loop(void) 144962306a36Sopenharmony_ci{ 145062306a36Sopenharmony_ci int ifd = inotify_init(); 145162306a36Sopenharmony_ci int wd; 145262306a36Sopenharmony_ci const ssize_t bufsize = sizeof(inotify_buffer); 145362306a36Sopenharmony_ci const ssize_t istructsize = sizeof(struct inotify_event); 145462306a36Sopenharmony_ci char *buf = &inotify_buffer[0]; 145562306a36Sopenharmony_ci ssize_t nr_read; 145662306a36Sopenharmony_ci char *p; 145762306a36Sopenharmony_ci int modified; 145862306a36Sopenharmony_ci struct inotify_event *event; 145962306a36Sopenharmony_ci struct entry req; 146062306a36Sopenharmony_ci char *buffer; 146162306a36Sopenharmony_ci const size_t bufspace = PRINT_BUFFER_SIZE; 146262306a36Sopenharmony_ci struct timespec timestamp; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci print_priority(); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci buffer = malloc_or_die(bufspace); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci if (ifd < 0) 146962306a36Sopenharmony_ci err(EXIT_FAILURE, "inotify_init() failed!"); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (setup_ftrace) { 147362306a36Sopenharmony_ci /* 147462306a36Sopenharmony_ci * We must disable the tracer before resetting the max_latency 147562306a36Sopenharmony_ci */ 147662306a36Sopenharmony_ci save_and_disable_tracer(); 147762306a36Sopenharmony_ci /* 147862306a36Sopenharmony_ci * We must reset the max_latency before the inotify_add_watch() 147962306a36Sopenharmony_ci * call. 148062306a36Sopenharmony_ci */ 148162306a36Sopenharmony_ci reset_max_latency(); 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci wd = inotify_add_watch(ifd, debug_maxlat, IN_MODIFY); 148562306a36Sopenharmony_ci if (wd < 0) 148662306a36Sopenharmony_ci err(EXIT_FAILURE, "inotify_add_watch() failed!"); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (setup_ftrace) 148962306a36Sopenharmony_ci enable_tracer(); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci signal_blocking(SIG_UNBLOCK); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci while (true) { 149462306a36Sopenharmony_ci modified = 0; 149562306a36Sopenharmony_ci check_signals(); 149662306a36Sopenharmony_ci nr_read = read(ifd, buf, bufsize); 149762306a36Sopenharmony_ci check_signals(); 149862306a36Sopenharmony_ci if (nr_read < 0) { 149962306a36Sopenharmony_ci if (errno == EINTR) 150062306a36Sopenharmony_ci continue; 150162306a36Sopenharmony_ci warn("read() failed on inotify fd!"); 150262306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci if (nr_read == bufsize) 150562306a36Sopenharmony_ci warnx("inotify() buffer filled, skipping events"); 150662306a36Sopenharmony_ci if (nr_read < istructsize) { 150762306a36Sopenharmony_ci warnx("read() returned too few bytes on inotify fd"); 150862306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci for (p = buf; p < buf + nr_read;) { 151262306a36Sopenharmony_ci event = (struct inotify_event *) p; 151362306a36Sopenharmony_ci if ((event->mask & IN_MODIFY) != 0) 151462306a36Sopenharmony_ci modified++; 151562306a36Sopenharmony_ci p += istructsize + event->len; 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci while (modified > 0) { 151862306a36Sopenharmony_ci check_signals(); 151962306a36Sopenharmony_ci mutex_lock(&printstate.mutex); 152062306a36Sopenharmony_ci check_signals(); 152162306a36Sopenharmony_ci printstate_next_ticket(&req); 152262306a36Sopenharmony_ci if (printstate_cnt_read() > 0) { 152362306a36Sopenharmony_ci printstate_mark_req_completed(&req); 152462306a36Sopenharmony_ci mutex_unlock(&printstate.mutex); 152562306a36Sopenharmony_ci if (verbose_lostevent()) { 152662306a36Sopenharmony_ci clock_gettime_or_die(CLOCK_MONOTONIC, 152762306a36Sopenharmony_ci ×tamp); 152862306a36Sopenharmony_ci print_lostmessage(×tamp, buffer, 152962306a36Sopenharmony_ci bufspace, &req, 153062306a36Sopenharmony_ci "inotify loop"); 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci break; 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci mutex_unlock(&printstate.mutex); 153562306a36Sopenharmony_ci if (queue_try_to_add_entry(&printqueue, &req) != 0) { 153662306a36Sopenharmony_ci /* These prints could happen concurrently */ 153762306a36Sopenharmony_ci check_signals(); 153862306a36Sopenharmony_ci mutex_lock(&print_mtx); 153962306a36Sopenharmony_ci check_signals(); 154062306a36Sopenharmony_ci write_or_die(fd_stdout, queue_full_warning, 154162306a36Sopenharmony_ci strlen(queue_full_warning)); 154262306a36Sopenharmony_ci mutex_unlock(&print_mtx); 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci modified--; 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_cistatic void *do_printloop(void *arg) 155062306a36Sopenharmony_ci{ 155162306a36Sopenharmony_ci const size_t bufspace = PRINT_BUFFER_SIZE; 155262306a36Sopenharmony_ci char *buffer; 155362306a36Sopenharmony_ci long *rseed = (long *) arg; 155462306a36Sopenharmony_ci struct drand48_data drandbuf; 155562306a36Sopenharmony_ci long slept = 0; 155662306a36Sopenharmony_ci struct entry req; 155762306a36Sopenharmony_ci int prob = 0; 155862306a36Sopenharmony_ci struct timespec timestamp; 155962306a36Sopenharmony_ci struct short_msg resize_msg; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci print_priority(); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci if (srand48_r(*rseed, &drandbuf) != 0) { 156462306a36Sopenharmony_ci warn("srand48_r() failed!\n"); 156562306a36Sopenharmony_ci cleanup_exit(EXIT_FAILURE); 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci buffer = malloc_or_die(bufspace); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci while (true) { 157162306a36Sopenharmony_ci req = queue_wait_for_entry(&printqueue); 157262306a36Sopenharmony_ci clock_gettime_or_die(CLOCK_MONOTONIC, ×tamp); 157362306a36Sopenharmony_ci mutex_lock(&printstate.mutex); 157462306a36Sopenharmony_ci if (prev_req_won_race(&req)) { 157562306a36Sopenharmony_ci printstate_mark_req_completed(&req); 157662306a36Sopenharmony_ci mutex_unlock(&printstate.mutex); 157762306a36Sopenharmony_ci if (verbose_lostevent()) 157862306a36Sopenharmony_ci print_lostmessage(×tamp, buffer, bufspace, 157962306a36Sopenharmony_ci &req, "print loop"); 158062306a36Sopenharmony_ci continue; 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci mutex_unlock(&printstate.mutex); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci /* 158562306a36Sopenharmony_ci * Toss a coin to decide if we want to sleep before printing 158662306a36Sopenharmony_ci * out the backtrace. The reason for this is that opening 158762306a36Sopenharmony_ci * /sys/kernel/tracing/trace will cause a blackout of 158862306a36Sopenharmony_ci * hundreds of ms, where no latencies will be noted by the 158962306a36Sopenharmony_ci * latency tracer. Thus by randomly sleeping we try to avoid 159062306a36Sopenharmony_ci * missing traces systematically due to this. With this option 159162306a36Sopenharmony_ci * we will sometimes get the first latency, some other times 159262306a36Sopenharmony_ci * some of the later ones, in case of closely spaced traces. 159362306a36Sopenharmony_ci */ 159462306a36Sopenharmony_ci if (trace_enable && use_random_sleep) { 159562306a36Sopenharmony_ci slept = 0; 159662306a36Sopenharmony_ci prob = table_get_probability(&req, &resize_msg); 159762306a36Sopenharmony_ci if (!toss_coin(&drandbuf, prob)) 159862306a36Sopenharmony_ci slept = go_to_sleep(&req); 159962306a36Sopenharmony_ci if (slept >= 0) { 160062306a36Sopenharmony_ci /* A print is ongoing */ 160162306a36Sopenharmony_ci printstate_cnt_inc(); 160262306a36Sopenharmony_ci /* 160362306a36Sopenharmony_ci * We will do the printout below so we have to 160462306a36Sopenharmony_ci * mark it as completed while we still have the 160562306a36Sopenharmony_ci * mutex. 160662306a36Sopenharmony_ci */ 160762306a36Sopenharmony_ci mutex_lock(&printstate.mutex); 160862306a36Sopenharmony_ci printstate_mark_req_completed(&req); 160962306a36Sopenharmony_ci mutex_unlock(&printstate.mutex); 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci if (trace_enable) { 161362306a36Sopenharmony_ci /* 161462306a36Sopenharmony_ci * slept < 0 means that we detected another 161562306a36Sopenharmony_ci * notification in go_to_sleep() above 161662306a36Sopenharmony_ci */ 161762306a36Sopenharmony_ci if (slept >= 0) 161862306a36Sopenharmony_ci /* 161962306a36Sopenharmony_ci * N.B. printstate_cnt_dec(); will be called 162062306a36Sopenharmony_ci * inside print_tracefile() 162162306a36Sopenharmony_ci */ 162262306a36Sopenharmony_ci print_tracefile(&resize_msg, ×tamp, buffer, 162362306a36Sopenharmony_ci bufspace, slept, &req); 162462306a36Sopenharmony_ci else 162562306a36Sopenharmony_ci print_skipmessage(&resize_msg, ×tamp, 162662306a36Sopenharmony_ci buffer, bufspace, &req, true); 162762306a36Sopenharmony_ci } else { 162862306a36Sopenharmony_ci print_skipmessage(&resize_msg, ×tamp, buffer, 162962306a36Sopenharmony_ci bufspace, &req, false); 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci return NULL; 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cistatic void start_printthread(void) 163662306a36Sopenharmony_ci{ 163762306a36Sopenharmony_ci unsigned int i; 163862306a36Sopenharmony_ci long *seed; 163962306a36Sopenharmony_ci int ufd; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci ufd = open(DEV_URANDOM, O_RDONLY); 164262306a36Sopenharmony_ci if (nr_threads > MAX_THREADS) { 164362306a36Sopenharmony_ci warnx( 164462306a36Sopenharmony_ci"Number of requested print threads was %d, max number is %d\n", 164562306a36Sopenharmony_ci nr_threads, MAX_THREADS); 164662306a36Sopenharmony_ci nr_threads = MAX_THREADS; 164762306a36Sopenharmony_ci } 164862306a36Sopenharmony_ci for (i = 0; i < nr_threads; i++) { 164962306a36Sopenharmony_ci seed = malloc_or_die(sizeof(*seed)); 165062306a36Sopenharmony_ci if (ufd < 0 || 165162306a36Sopenharmony_ci read(ufd, seed, sizeof(*seed)) != sizeof(*seed)) { 165262306a36Sopenharmony_ci printf( 165362306a36Sopenharmony_ci"Warning! Using trivial random number seed, since %s not available\n", 165462306a36Sopenharmony_ci DEV_URANDOM); 165562306a36Sopenharmony_ci fflush(stdout); 165662306a36Sopenharmony_ci *seed = i; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci errno = pthread_create(&printthread[i], NULL, do_printloop, 165962306a36Sopenharmony_ci seed); 166062306a36Sopenharmony_ci if (errno) 166162306a36Sopenharmony_ci err(EXIT_FAILURE, "pthread_create()"); 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci if (ufd > 0 && close(ufd) != 0) 166462306a36Sopenharmony_ci warn("close() failed"); 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic void show_usage(void) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci printf( 167062306a36Sopenharmony_ci"Usage: %s [OPTION]...\n\n" 167162306a36Sopenharmony_ci"Collect closely occurring latencies from %s\n" 167262306a36Sopenharmony_ci"with any of the following tracers: preemptirqsoff, preemptoff, irqsoff, " 167362306a36Sopenharmony_ci"wakeup,\nwakeup_dl, or wakeup_rt.\n\n" 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci"The occurrence of a latency is detected by monitoring the file\n" 167662306a36Sopenharmony_ci"%s with inotify.\n\n" 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci"The following options are supported:\n\n" 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci"-l, --list\t\tList the latency tracers that are supported by the\n" 168162306a36Sopenharmony_ci"\t\t\tcurrently running Linux kernel. If you don't see the\n" 168262306a36Sopenharmony_ci"\t\t\ttracer that you want, you will probably need to\n" 168362306a36Sopenharmony_ci"\t\t\tchange your kernel config and build a new kernel.\n\n" 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci"-t, --tracer TR\t\tUse the tracer TR. The default is to use the first\n" 168662306a36Sopenharmony_ci"\t\t\ttracer that is supported by the kernel in the following\n" 168762306a36Sopenharmony_ci"\t\t\torder of precedence:\n\n" 168862306a36Sopenharmony_ci"\t\t\tpreemptirqsoff\n" 168962306a36Sopenharmony_ci"\t\t\tpreemptoff\n" 169062306a36Sopenharmony_ci"\t\t\tirqsoff\n" 169162306a36Sopenharmony_ci"\t\t\twakeup\n" 169262306a36Sopenharmony_ci"\t\t\twakeup_rt\n" 169362306a36Sopenharmony_ci"\t\t\twakeup_dl\n" 169462306a36Sopenharmony_ci"\n" 169562306a36Sopenharmony_ci"\t\t\tIf TR is not on the list above, then a warning will be\n" 169662306a36Sopenharmony_ci"\t\t\tprinted.\n\n" 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci"-F, --force\t\tProceed even if another ftrace tracer is active. Without\n" 169962306a36Sopenharmony_ci"\t\t\tthis option, the program will refuse to start tracing if\n" 170062306a36Sopenharmony_ci"\t\t\tany other tracer than the nop tracer is active.\n\n" 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci"-s, --threshold TH\tConfigure ftrace to use a threshold of TH microseconds\n" 170362306a36Sopenharmony_ci"\t\t\tfor the tracer. The default is 0, which means that\n" 170462306a36Sopenharmony_ci"\t\t\ttracing_max_latency will be used. tracing_max_latency is\n" 170562306a36Sopenharmony_ci"\t\t\tset to 0 when the program is started and contains the\n" 170662306a36Sopenharmony_ci"\t\t\tmaximum of the latencies that have been encountered.\n\n" 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci"-f, --function\t\tEnable the function-trace option in trace_options. With\n" 170962306a36Sopenharmony_ci"\t\t\tthis option, ftrace will trace the functions that are\n" 171062306a36Sopenharmony_ci"\t\t\texecuted during a latency, without it we only get the\n" 171162306a36Sopenharmony_ci"\t\t\tbeginning, end, and backtrace.\n\n" 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci"-g, --graph\t\tEnable the display-graph option in trace_option. This\n" 171462306a36Sopenharmony_ci"\t\t\toption causes ftrace to show the graph of how functions\n" 171562306a36Sopenharmony_ci"\t\t\tare calling other functions.\n\n" 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci"-c, --policy POL\tRun the program with scheduling policy POL. POL can be\n" 171862306a36Sopenharmony_ci"\t\t\tother, batch, idle, rr or fifo. The default is rr. When\n" 171962306a36Sopenharmony_ci"\t\t\tusing rr or fifo, remember that these policies may cause\n" 172062306a36Sopenharmony_ci"\t\t\tother tasks to experience latencies.\n\n" 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci"-p, --priority PRI\tRun the program with priority PRI. The acceptable range\n" 172362306a36Sopenharmony_ci"\t\t\tof PRI depends on the scheduling policy.\n\n" 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci"-n, --notrace\t\tIf latency is detected, do not print out the content of\n" 172662306a36Sopenharmony_ci"\t\t\tthe trace file to standard output\n\n" 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci"-t, --threads NRTHR\tRun NRTHR threads for printing. Default is %d.\n\n" 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci"-r, --random\t\tArbitrarily sleep a certain amount of time, default\n" 173162306a36Sopenharmony_ci"\t\t\t%ld ms, before reading the trace file. The\n" 173262306a36Sopenharmony_ci"\t\t\tprobabilities for sleep are chosen so that the\n" 173362306a36Sopenharmony_ci"\t\t\tprobability of obtaining any of a cluster of closely\n" 173462306a36Sopenharmony_ci"\t\t\toccurring latencies are equal, i.e. we will randomly\n" 173562306a36Sopenharmony_ci"\t\t\tchoose which one we collect from the trace file.\n\n" 173662306a36Sopenharmony_ci"\t\t\tThis option is probably only useful with the irqsoff,\n" 173762306a36Sopenharmony_ci"\t\t\tpreemptoff, and preemptirqsoff tracers.\n\n" 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci"-a, --nrlat NRLAT\tFor the purpose of arbitrary delay, assume that there\n" 174062306a36Sopenharmony_ci"\t\t\tare no more than NRLAT clustered latencies. If NRLAT\n" 174162306a36Sopenharmony_ci"\t\t\tlatencies are detected during a run, this value will\n" 174262306a36Sopenharmony_ci"\t\t\tautomatically be increased to NRLAT + 1 and then to\n" 174362306a36Sopenharmony_ci"\t\t\tNRLAT + 2 and so on. The default is %d. This option\n" 174462306a36Sopenharmony_ci"\t\t\timplies -r. We need to know this number in order to\n" 174562306a36Sopenharmony_ci"\t\t\tbe able to calculate the probabilities of sleeping.\n" 174662306a36Sopenharmony_ci"\t\t\tSpecifically, the probabilities of not sleeping, i.e. to\n" 174762306a36Sopenharmony_ci"\t\t\tdo an immediate printout will be:\n\n" 174862306a36Sopenharmony_ci"\t\t\t1/NRLAT 1/(NRLAT - 1) ... 1/3 1/2 1\n\n" 174962306a36Sopenharmony_ci"\t\t\tThe probability of sleeping will be:\n\n" 175062306a36Sopenharmony_ci"\t\t\t1 - P, where P is from the series above\n\n" 175162306a36Sopenharmony_ci"\t\t\tThis descending probability will cause us to choose\n" 175262306a36Sopenharmony_ci"\t\t\tan occurrence at random. Observe that the final\n" 175362306a36Sopenharmony_ci"\t\t\tprobability is 0, it is when we reach this probability\n" 175462306a36Sopenharmony_ci"\t\t\tthat we increase NRLAT automatically. As an example,\n" 175562306a36Sopenharmony_ci"\t\t\twith the default value of 2, the probabilities will be:\n\n" 175662306a36Sopenharmony_ci"\t\t\t1/2 0\n\n" 175762306a36Sopenharmony_ci"\t\t\tThis means, when a latency is detected we will sleep\n" 175862306a36Sopenharmony_ci"\t\t\twith 50%% probability. If we ever detect another latency\n" 175962306a36Sopenharmony_ci"\t\t\tduring the sleep period, then the probability of sleep\n" 176062306a36Sopenharmony_ci"\t\t\twill be 0%% and the table will be expanded to:\n\n" 176162306a36Sopenharmony_ci"\t\t\t1/3 1/2 0\n\n" 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci"-v, --verbose\t\tIncrease the verbosity. If this option is given once,\n" 176462306a36Sopenharmony_ci"\t\t\tthen print a message every time that the NRLAT value\n" 176562306a36Sopenharmony_ci"\t\t\tis automatically increased. It also causes a message to\n" 176662306a36Sopenharmony_ci"\t\t\tbe printed when the ftrace settings are changed. If this\n" 176762306a36Sopenharmony_ci"\t\t\toption is given at least twice, then also print a\n" 176862306a36Sopenharmony_ci"\t\t\twarning for lost events.\n\n" 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci"-u, --time TIME\t\tArbitrarily sleep for a specified time TIME ms before\n" 177162306a36Sopenharmony_ci"\t\t\tprinting out the trace from the trace file. The default\n" 177262306a36Sopenharmony_ci"\t\t\tis %ld ms. This option implies -r.\n\n" 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci"-x, --no-ftrace\t\tDo not configure ftrace. This assume that the user\n" 177562306a36Sopenharmony_ci"\t\t\tconfigures the ftrace files in sysfs such as\n" 177662306a36Sopenharmony_ci"\t\t\t/sys/kernel/tracing/current_tracer or equivalent.\n\n" 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci"-i, --tracefile FILE\tUse FILE as trace file. The default is\n" 177962306a36Sopenharmony_ci"\t\t\t%s.\n" 178062306a36Sopenharmony_ci"\t\t\tThis options implies -x\n\n" 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci"-m, --max-lat FILE\tUse FILE as tracing_max_latency file. The default is\n" 178362306a36Sopenharmony_ci"\t\t\t%s.\n" 178462306a36Sopenharmony_ci"\t\t\tThis options implies -x\n\n" 178562306a36Sopenharmony_ci, 178662306a36Sopenharmony_ciprg_name, debug_tracefile_dflt, debug_maxlat_dflt, DEFAULT_NR_PRINTER_THREADS, 178762306a36Sopenharmony_ciSLEEP_TIME_MS_DEFAULT, DEFAULT_TABLE_SIZE, SLEEP_TIME_MS_DEFAULT, 178862306a36Sopenharmony_cidebug_tracefile_dflt, debug_maxlat_dflt); 178962306a36Sopenharmony_ci} 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_cistatic void find_tracefiles(void) 179262306a36Sopenharmony_ci{ 179362306a36Sopenharmony_ci debug_tracefile_dflt = tracefs_get_tracing_file("trace"); 179462306a36Sopenharmony_ci if (debug_tracefile_dflt == NULL) { 179562306a36Sopenharmony_ci /* This is needed in show_usage() */ 179662306a36Sopenharmony_ci debug_tracefile_dflt = DEBUG_NOFILE; 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci debug_maxlat_dflt = tracefs_get_tracing_file("tracing_max_latency"); 180062306a36Sopenharmony_ci if (debug_maxlat_dflt == NULL) { 180162306a36Sopenharmony_ci /* This is needed in show_usage() */ 180262306a36Sopenharmony_ci debug_maxlat_dflt = DEBUG_NOFILE; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci debug_tracefile = debug_tracefile_dflt; 180662306a36Sopenharmony_ci debug_maxlat = debug_maxlat_dflt; 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_cibool alldigits(const char *s) 181062306a36Sopenharmony_ci{ 181162306a36Sopenharmony_ci for (; *s != '\0'; s++) 181262306a36Sopenharmony_ci if (!isdigit(*s)) 181362306a36Sopenharmony_ci return false; 181462306a36Sopenharmony_ci return true; 181562306a36Sopenharmony_ci} 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_civoid check_alldigits(const char *optarg, const char *argname) 181862306a36Sopenharmony_ci{ 181962306a36Sopenharmony_ci if (!alldigits(optarg)) 182062306a36Sopenharmony_ci errx(EXIT_FAILURE, 182162306a36Sopenharmony_ci "The %s parameter expects a decimal argument\n", argname); 182262306a36Sopenharmony_ci} 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_cistatic void scan_arguments(int argc, char *argv[]) 182562306a36Sopenharmony_ci{ 182662306a36Sopenharmony_ci int c; 182762306a36Sopenharmony_ci int i; 182862306a36Sopenharmony_ci int option_idx = 0; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci static struct option long_options[] = { 183162306a36Sopenharmony_ci { "list", no_argument, 0, 'l' }, 183262306a36Sopenharmony_ci { "tracer", required_argument, 0, 't' }, 183362306a36Sopenharmony_ci { "force", no_argument, 0, 'F' }, 183462306a36Sopenharmony_ci { "threshold", required_argument, 0, 's' }, 183562306a36Sopenharmony_ci { "function", no_argument, 0, 'f' }, 183662306a36Sopenharmony_ci { "graph", no_argument, 0, 'g' }, 183762306a36Sopenharmony_ci { "policy", required_argument, 0, 'c' }, 183862306a36Sopenharmony_ci { "priority", required_argument, 0, 'p' }, 183962306a36Sopenharmony_ci { "help", no_argument, 0, 'h' }, 184062306a36Sopenharmony_ci { "notrace", no_argument, 0, 'n' }, 184162306a36Sopenharmony_ci { "random", no_argument, 0, 'r' }, 184262306a36Sopenharmony_ci { "nrlat", required_argument, 0, 'a' }, 184362306a36Sopenharmony_ci { "threads", required_argument, 0, 'e' }, 184462306a36Sopenharmony_ci { "time", required_argument, 0, 'u' }, 184562306a36Sopenharmony_ci { "verbose", no_argument, 0, 'v' }, 184662306a36Sopenharmony_ci { "no-ftrace", no_argument, 0, 'x' }, 184762306a36Sopenharmony_ci { "tracefile", required_argument, 0, 'i' }, 184862306a36Sopenharmony_ci { "max-lat", required_argument, 0, 'm' }, 184962306a36Sopenharmony_ci { 0, 0, 0, 0 } 185062306a36Sopenharmony_ci }; 185162306a36Sopenharmony_ci const struct policy *p; 185262306a36Sopenharmony_ci int max, min; 185362306a36Sopenharmony_ci int value; 185462306a36Sopenharmony_ci bool notracer, valid; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci /* 185762306a36Sopenharmony_ci * We must do this before parsing the arguments because show_usage() 185862306a36Sopenharmony_ci * needs to display these. 185962306a36Sopenharmony_ci */ 186062306a36Sopenharmony_ci find_tracefiles(); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci while (true) { 186362306a36Sopenharmony_ci c = getopt_long(argc, argv, "lt:Fs:fgc:p:hnra:e:u:vxi:m:", 186462306a36Sopenharmony_ci long_options, &option_idx); 186562306a36Sopenharmony_ci if (c == -1) 186662306a36Sopenharmony_ci break; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci switch (c) { 186962306a36Sopenharmony_ci case 'l': 187062306a36Sopenharmony_ci show_available(); 187162306a36Sopenharmony_ci exit(0); 187262306a36Sopenharmony_ci break; 187362306a36Sopenharmony_ci case 't': 187462306a36Sopenharmony_ci current_tracer = strdup(optarg); 187562306a36Sopenharmony_ci if (!is_relevant_tracer(current_tracer)) { 187662306a36Sopenharmony_ci warnx("%s is not a known latency tracer!\n", 187762306a36Sopenharmony_ci current_tracer); 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci valid = tracer_valid(current_tracer, ¬racer); 188062306a36Sopenharmony_ci if (notracer) 188162306a36Sopenharmony_ci errx(EXIT_FAILURE, no_tracer_msg); 188262306a36Sopenharmony_ci if (!valid) 188362306a36Sopenharmony_ci errx(EXIT_FAILURE, 188462306a36Sopenharmony_ci"The tracer %s is not supported by your kernel!\n", current_tracer); 188562306a36Sopenharmony_ci break; 188662306a36Sopenharmony_ci case 'F': 188762306a36Sopenharmony_ci force_tracer = true; 188862306a36Sopenharmony_ci break; 188962306a36Sopenharmony_ci case 's': 189062306a36Sopenharmony_ci check_alldigits(optarg, "-s [--threshold]"); 189162306a36Sopenharmony_ci threshold = strdup(optarg); 189262306a36Sopenharmony_ci break; 189362306a36Sopenharmony_ci case 'f': 189462306a36Sopenharmony_ci use_options[OPTIDX_FUNC_TR] = true; 189562306a36Sopenharmony_ci break; 189662306a36Sopenharmony_ci case 'g': 189762306a36Sopenharmony_ci use_options[OPTIDX_DISP_GR] = true; 189862306a36Sopenharmony_ci break; 189962306a36Sopenharmony_ci case 'c': 190062306a36Sopenharmony_ci p = policy_from_name(optarg); 190162306a36Sopenharmony_ci if (p != NULL) { 190262306a36Sopenharmony_ci sched_policy = p->policy; 190362306a36Sopenharmony_ci sched_policy_set = true; 190462306a36Sopenharmony_ci if (!sched_pri_set) { 190562306a36Sopenharmony_ci sched_pri = p->default_pri; 190662306a36Sopenharmony_ci sched_pri_set = true; 190762306a36Sopenharmony_ci } 190862306a36Sopenharmony_ci } else { 190962306a36Sopenharmony_ci warnx("Unknown scheduling %s\n", optarg); 191062306a36Sopenharmony_ci show_usage(); 191162306a36Sopenharmony_ci exit(0); 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci break; 191462306a36Sopenharmony_ci case 'p': 191562306a36Sopenharmony_ci check_alldigits(optarg, "-p [--priority]"); 191662306a36Sopenharmony_ci sched_pri = atoi(optarg); 191762306a36Sopenharmony_ci sched_pri_set = true; 191862306a36Sopenharmony_ci break; 191962306a36Sopenharmony_ci case 'h': 192062306a36Sopenharmony_ci show_usage(); 192162306a36Sopenharmony_ci exit(0); 192262306a36Sopenharmony_ci break; 192362306a36Sopenharmony_ci case 'n': 192462306a36Sopenharmony_ci trace_enable = false; 192562306a36Sopenharmony_ci use_random_sleep = false; 192662306a36Sopenharmony_ci break; 192762306a36Sopenharmony_ci case 'e': 192862306a36Sopenharmony_ci check_alldigits(optarg, "-e [--threads]"); 192962306a36Sopenharmony_ci value = atoi(optarg); 193062306a36Sopenharmony_ci if (value > 0) 193162306a36Sopenharmony_ci nr_threads = value; 193262306a36Sopenharmony_ci else { 193362306a36Sopenharmony_ci warnx("NRTHR must be > 0\n"); 193462306a36Sopenharmony_ci show_usage(); 193562306a36Sopenharmony_ci exit(0); 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci break; 193862306a36Sopenharmony_ci case 'u': 193962306a36Sopenharmony_ci check_alldigits(optarg, "-u [--time]"); 194062306a36Sopenharmony_ci value = atoi(optarg); 194162306a36Sopenharmony_ci if (value < 0) { 194262306a36Sopenharmony_ci warnx("TIME must be >= 0\n"); 194362306a36Sopenharmony_ci show_usage(); 194462306a36Sopenharmony_ci exit(0); 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci trace_enable = true; 194762306a36Sopenharmony_ci use_random_sleep = true; 194862306a36Sopenharmony_ci sleep_time = value * USEC_PER_MSEC; 194962306a36Sopenharmony_ci break; 195062306a36Sopenharmony_ci case 'v': 195162306a36Sopenharmony_ci verbosity++; 195262306a36Sopenharmony_ci break; 195362306a36Sopenharmony_ci case 'r': 195462306a36Sopenharmony_ci trace_enable = true; 195562306a36Sopenharmony_ci use_random_sleep = true; 195662306a36Sopenharmony_ci break; 195762306a36Sopenharmony_ci case 'a': 195862306a36Sopenharmony_ci check_alldigits(optarg, "-a [--nrlat]"); 195962306a36Sopenharmony_ci value = atoi(optarg); 196062306a36Sopenharmony_ci if (value <= 0) { 196162306a36Sopenharmony_ci warnx("NRLAT must be > 0\n"); 196262306a36Sopenharmony_ci show_usage(); 196362306a36Sopenharmony_ci exit(0); 196462306a36Sopenharmony_ci } 196562306a36Sopenharmony_ci trace_enable = true; 196662306a36Sopenharmony_ci use_random_sleep = true; 196762306a36Sopenharmony_ci table_startsize = value; 196862306a36Sopenharmony_ci break; 196962306a36Sopenharmony_ci case 'x': 197062306a36Sopenharmony_ci setup_ftrace = false; 197162306a36Sopenharmony_ci break; 197262306a36Sopenharmony_ci case 'i': 197362306a36Sopenharmony_ci setup_ftrace = false; 197462306a36Sopenharmony_ci debug_tracefile = strdup(optarg); 197562306a36Sopenharmony_ci break; 197662306a36Sopenharmony_ci case 'm': 197762306a36Sopenharmony_ci setup_ftrace = false; 197862306a36Sopenharmony_ci debug_maxlat = strdup(optarg); 197962306a36Sopenharmony_ci break; 198062306a36Sopenharmony_ci default: 198162306a36Sopenharmony_ci show_usage(); 198262306a36Sopenharmony_ci exit(0); 198362306a36Sopenharmony_ci break; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci } 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci if (setup_ftrace) { 198862306a36Sopenharmony_ci if (!current_tracer) { 198962306a36Sopenharmony_ci current_tracer = find_default_tracer(); 199062306a36Sopenharmony_ci if (!current_tracer) 199162306a36Sopenharmony_ci errx(EXIT_FAILURE, 199262306a36Sopenharmony_ci"No default tracer found and tracer not specified\n"); 199362306a36Sopenharmony_ci } 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci if (use_random_sleep && !random_makes_sense(current_tracer)) { 199662306a36Sopenharmony_ci warnx("WARNING: The tracer is %s and random sleep has", 199762306a36Sopenharmony_ci current_tracer); 199862306a36Sopenharmony_ci fprintf(stderr, 199962306a36Sopenharmony_ci"been enabled. Random sleep is intended for the following tracers:\n"); 200062306a36Sopenharmony_ci for (i = 0; random_tracers[i]; i++) 200162306a36Sopenharmony_ci fprintf(stderr, "%s\n", random_tracers[i]); 200262306a36Sopenharmony_ci fprintf(stderr, "\n"); 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci if (debug_tracefile == DEBUG_NOFILE || 200762306a36Sopenharmony_ci debug_maxlat == DEBUG_NOFILE) 200862306a36Sopenharmony_ci errx(EXIT_FAILURE, 200962306a36Sopenharmony_ci"Could not find tracing directory e.g. /sys/kernel/tracing\n"); 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci if (!sched_policy_set) { 201262306a36Sopenharmony_ci sched_policy = SCHED_RR; 201362306a36Sopenharmony_ci sched_policy_set = true; 201462306a36Sopenharmony_ci if (!sched_pri_set) { 201562306a36Sopenharmony_ci sched_pri = RT_DEFAULT_PRI; 201662306a36Sopenharmony_ci sched_pri_set = true; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci max = sched_get_priority_max(sched_policy); 202162306a36Sopenharmony_ci min = sched_get_priority_min(sched_policy); 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci if (sched_pri < min) { 202462306a36Sopenharmony_ci printf( 202562306a36Sopenharmony_ci"ATTENTION: Increasing priority to minimum, which is %d\n", min); 202662306a36Sopenharmony_ci sched_pri = min; 202762306a36Sopenharmony_ci } 202862306a36Sopenharmony_ci if (sched_pri > max) { 202962306a36Sopenharmony_ci printf( 203062306a36Sopenharmony_ci"ATTENTION: Reducing priority to maximum, which is %d\n", max); 203162306a36Sopenharmony_ci sched_pri = max; 203262306a36Sopenharmony_ci } 203362306a36Sopenharmony_ci} 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_cistatic void show_params(void) 203662306a36Sopenharmony_ci{ 203762306a36Sopenharmony_ci printf( 203862306a36Sopenharmony_ci"\n" 203962306a36Sopenharmony_ci"Running with scheduling policy %s and priority %d. Using %d print threads.\n", 204062306a36Sopenharmony_ci policy_name(sched_policy), sched_pri, nr_threads); 204162306a36Sopenharmony_ci if (trace_enable) { 204262306a36Sopenharmony_ci if (use_random_sleep) { 204362306a36Sopenharmony_ci printf( 204462306a36Sopenharmony_ci"%s will be printed with random delay\n" 204562306a36Sopenharmony_ci"Start size of the probability table:\t\t\t%d\n" 204662306a36Sopenharmony_ci"Print a message when the prob. table changes size:\t%s\n" 204762306a36Sopenharmony_ci"Print a warning when an event has been lost:\t\t%s\n" 204862306a36Sopenharmony_ci"Sleep time is:\t\t\t\t\t\t%ld ms\n", 204962306a36Sopenharmony_cidebug_tracefile, 205062306a36Sopenharmony_citable_startsize, 205162306a36Sopenharmony_cibool2str(verbose_sizechange()), 205262306a36Sopenharmony_cibool2str(verbose_lostevent()), 205362306a36Sopenharmony_cisleep_time / USEC_PER_MSEC); 205462306a36Sopenharmony_ci } else { 205562306a36Sopenharmony_ci printf("%s will be printed immediately\n", 205662306a36Sopenharmony_ci debug_tracefile); 205762306a36Sopenharmony_ci } 205862306a36Sopenharmony_ci } else { 205962306a36Sopenharmony_ci printf("%s will not be printed\n", 206062306a36Sopenharmony_ci debug_tracefile); 206162306a36Sopenharmony_ci } 206262306a36Sopenharmony_ci if (setup_ftrace) { 206362306a36Sopenharmony_ci printf("Tracer:\t\t\t\t\t\t\t%s\n" 206462306a36Sopenharmony_ci "%s option:\t\t\t\t\t%s\n" 206562306a36Sopenharmony_ci "%s option:\t\t\t\t\t%s\n", 206662306a36Sopenharmony_ci current_tracer, 206762306a36Sopenharmony_ci optstr[OPTIDX_FUNC_TR], 206862306a36Sopenharmony_ci bool2str(use_options[OPTIDX_FUNC_TR]), 206962306a36Sopenharmony_ci optstr[OPTIDX_DISP_GR], 207062306a36Sopenharmony_ci bool2str(use_options[OPTIDX_DISP_GR])); 207162306a36Sopenharmony_ci if (!strcmp(threshold, "0")) 207262306a36Sopenharmony_ci printf("Threshold:\t\t\t\t\t\ttracing_max_latency\n"); 207362306a36Sopenharmony_ci else 207462306a36Sopenharmony_ci printf("Threshold:\t\t\t\t\t\t%s\n", threshold); 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci printf("\n"); 207762306a36Sopenharmony_ci} 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ciint main(int argc, char *argv[]) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci init_save_state(); 208262306a36Sopenharmony_ci signal_blocking(SIG_BLOCK); 208362306a36Sopenharmony_ci setup_sig_handler(); 208462306a36Sopenharmony_ci open_stdout(); 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci if (argc >= 1) 208762306a36Sopenharmony_ci prg_name = argv[0]; 208862306a36Sopenharmony_ci else 208962306a36Sopenharmony_ci prg_name = prg_unknown; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci scan_arguments(argc, argv); 209262306a36Sopenharmony_ci show_params(); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci init_printstate(); 209562306a36Sopenharmony_ci init_print_mtx(); 209662306a36Sopenharmony_ci if (use_random_sleep) { 209762306a36Sopenharmony_ci init_probabilities(); 209862306a36Sopenharmony_ci if (verbose_sizechange()) 209962306a36Sopenharmony_ci printf("Initializing probability table to %d\n", 210062306a36Sopenharmony_ci table_startsize); 210162306a36Sopenharmony_ci sleeptable_resize(table_startsize, false, NULL); 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci set_priority(); 210462306a36Sopenharmony_ci init_queue(&printqueue); 210562306a36Sopenharmony_ci start_printthread(); 210662306a36Sopenharmony_ci tracing_loop(); 210762306a36Sopenharmony_ci return 0; 210862306a36Sopenharmony_ci} 2109