1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 4 */ 5 #define _GNU_SOURCE 6 #include <sys/types.h> 7 #include <sys/stat.h> 8 #include <pthread.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <unistd.h> 12 #include <errno.h> 13 #include <fcntl.h> 14 #include <stdio.h> 15 #include <sched.h> 16 17 #include "timerlat.h" 18 19 #define DEFAULT_TIMERLAT_PERIOD 1000 /* 1ms */ 20 21 /* 22 * timerlat_apply_config - apply common configs to the initialized tool 23 */ 24 int 25 timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) 26 { 27 int retval, i; 28 29 if (!params->sleep_time) 30 params->sleep_time = 1; 31 32 retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all"); 33 if (retval) { 34 err_msg("Failed to apply CPUs config\n"); 35 goto out_err; 36 } 37 38 if (!params->cpus) { 39 for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) 40 CPU_SET(i, ¶ms->monitored_cpus); 41 } 42 43 retval = osnoise_set_stop_us(tool->context, params->stop_us); 44 if (retval) { 45 err_msg("Failed to set stop us\n"); 46 goto out_err; 47 } 48 49 retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); 50 if (retval) { 51 err_msg("Failed to set stop total us\n"); 52 goto out_err; 53 } 54 55 56 retval = osnoise_set_timerlat_period_us(tool->context, 57 params->timerlat_period_us ? 58 params->timerlat_period_us : 59 DEFAULT_TIMERLAT_PERIOD); 60 if (retval) { 61 err_msg("Failed to set timerlat period\n"); 62 goto out_err; 63 } 64 65 66 retval = osnoise_set_print_stack(tool->context, params->print_stack); 67 if (retval) { 68 err_msg("Failed to set print stack\n"); 69 goto out_err; 70 } 71 72 if (params->hk_cpus) { 73 retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), 74 ¶ms->hk_cpu_set); 75 if (retval == -1) { 76 err_msg("Failed to set rtla to the house keeping CPUs\n"); 77 goto out_err; 78 } 79 } else if (params->cpus) { 80 /* 81 * Even if the user do not set a house-keeping CPU, try to 82 * move rtla to a CPU set different to the one where the user 83 * set the workload to run. 84 * 85 * No need to check results as this is an automatic attempt. 86 */ 87 auto_house_keeping(¶ms->monitored_cpus); 88 } 89 90 /* 91 * If the user did not specify a type of thread, try user-threads first. 92 * Fall back to kernel threads otherwise. 93 */ 94 if (!params->kernel_workload && !params->user_data) { 95 retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd"); 96 if (retval) { 97 debug_msg("User-space interface detected, setting user-threads\n"); 98 params->user_workload = 1; 99 params->user_data = 1; 100 } else { 101 debug_msg("User-space interface not detected, setting kernel-threads\n"); 102 params->kernel_workload = 1; 103 } 104 } 105 106 /* 107 * Set workload according to type of thread if the kernel supports it. 108 * On kernels without support, user threads will have already failed 109 * on missing timerlat_fd, and kernel threads do not need it. 110 */ 111 retval = osnoise_set_workload(tool->context, params->kernel_workload); 112 if (retval < -1) { 113 err_msg("Failed to set OSNOISE_WORKLOAD option\n"); 114 goto out_err; 115 } 116 117 return 0; 118 119 out_err: 120 return -1; 121 } 122 123 static void timerlat_usage(int err) 124 { 125 int i; 126 127 static const char * const msg[] = { 128 "", 129 "timerlat version " VERSION, 130 "", 131 " usage: [rtla] timerlat [MODE] ...", 132 "", 133 " modes:", 134 " top - prints the summary from timerlat tracer", 135 " hist - prints a histogram of timer latencies", 136 "", 137 "if no MODE is given, the top mode is called, passing the arguments", 138 NULL, 139 }; 140 141 for (i = 0; msg[i]; i++) 142 fprintf(stderr, "%s\n", msg[i]); 143 exit(err); 144 } 145 146 int timerlat_main(int argc, char *argv[]) 147 { 148 if (argc == 0) 149 goto usage; 150 151 /* 152 * if timerlat was called without any argument, run the 153 * default cmdline. 154 */ 155 if (argc == 1) { 156 timerlat_top_main(argc, argv); 157 exit(0); 158 } 159 160 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) { 161 timerlat_usage(0); 162 } else if (strncmp(argv[1], "-", 1) == 0) { 163 /* the user skipped the tool, call the default one */ 164 timerlat_top_main(argc, argv); 165 exit(0); 166 } else if (strcmp(argv[1], "top") == 0) { 167 timerlat_top_main(argc-1, &argv[1]); 168 exit(0); 169 } else if (strcmp(argv[1], "hist") == 0) { 170 timerlat_hist_main(argc-1, &argv[1]); 171 exit(0); 172 } 173 174 usage: 175 timerlat_usage(1); 176 exit(1); 177 } 178