1a828cd18SDaniel Bristot de Oliveira // SPDX-License-Identifier: GPL-2.0
2a828cd18SDaniel Bristot de Oliveira /*
3a828cd18SDaniel Bristot de Oliveira * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <[email protected]>
4a828cd18SDaniel Bristot de Oliveira */
520d6b075STomas Glozar #define _GNU_SOURCE
6a828cd18SDaniel Bristot de Oliveira #include <sys/types.h>
7a828cd18SDaniel Bristot de Oliveira #include <sys/stat.h>
8a828cd18SDaniel Bristot de Oliveira #include <pthread.h>
9a828cd18SDaniel Bristot de Oliveira #include <stdlib.h>
10a828cd18SDaniel Bristot de Oliveira #include <string.h>
11a828cd18SDaniel Bristot de Oliveira #include <unistd.h>
12a828cd18SDaniel Bristot de Oliveira #include <errno.h>
13a828cd18SDaniel Bristot de Oliveira #include <fcntl.h>
14a828cd18SDaniel Bristot de Oliveira #include <stdio.h>
1520d6b075STomas Glozar #include <sched.h>
16a828cd18SDaniel Bristot de Oliveira
17a828cd18SDaniel Bristot de Oliveira #include "timerlat.h"
18a828cd18SDaniel Bristot de Oliveira
19*0122938aSTomas Glozar #define DEFAULT_TIMERLAT_PERIOD 1000 /* 1ms */
20*0122938aSTomas Glozar
2120d6b075STomas Glozar /*
2220d6b075STomas Glozar * timerlat_apply_config - apply common configs to the initialized tool
2320d6b075STomas Glozar */
2420d6b075STomas Glozar int
timerlat_apply_config(struct osnoise_tool * tool,struct timerlat_params * params)2520d6b075STomas Glozar timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
2620d6b075STomas Glozar {
2720d6b075STomas Glozar int retval, i;
2820d6b075STomas Glozar
2920d6b075STomas Glozar if (!params->sleep_time)
3020d6b075STomas Glozar params->sleep_time = 1;
3120d6b075STomas Glozar
32*0122938aSTomas Glozar retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all");
3320d6b075STomas Glozar if (retval) {
3420d6b075STomas Glozar err_msg("Failed to apply CPUs config\n");
3520d6b075STomas Glozar goto out_err;
3620d6b075STomas Glozar }
37*0122938aSTomas Glozar
38*0122938aSTomas Glozar if (!params->cpus) {
3920d6b075STomas Glozar for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++)
4020d6b075STomas Glozar CPU_SET(i, ¶ms->monitored_cpus);
4120d6b075STomas Glozar }
4220d6b075STomas Glozar
4320d6b075STomas Glozar retval = osnoise_set_stop_us(tool->context, params->stop_us);
4420d6b075STomas Glozar if (retval) {
4520d6b075STomas Glozar err_msg("Failed to set stop us\n");
4620d6b075STomas Glozar goto out_err;
4720d6b075STomas Glozar }
4820d6b075STomas Glozar
4920d6b075STomas Glozar retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us);
5020d6b075STomas Glozar if (retval) {
5120d6b075STomas Glozar err_msg("Failed to set stop total us\n");
5220d6b075STomas Glozar goto out_err;
5320d6b075STomas Glozar }
5420d6b075STomas Glozar
5520d6b075STomas Glozar
56*0122938aSTomas Glozar retval = osnoise_set_timerlat_period_us(tool->context,
57*0122938aSTomas Glozar params->timerlat_period_us ?
58*0122938aSTomas Glozar params->timerlat_period_us :
59*0122938aSTomas Glozar DEFAULT_TIMERLAT_PERIOD);
6020d6b075STomas Glozar if (retval) {
6120d6b075STomas Glozar err_msg("Failed to set timerlat period\n");
6220d6b075STomas Glozar goto out_err;
6320d6b075STomas Glozar }
6420d6b075STomas Glozar
6520d6b075STomas Glozar
6620d6b075STomas Glozar retval = osnoise_set_print_stack(tool->context, params->print_stack);
6720d6b075STomas Glozar if (retval) {
6820d6b075STomas Glozar err_msg("Failed to set print stack\n");
6920d6b075STomas Glozar goto out_err;
7020d6b075STomas Glozar }
7120d6b075STomas Glozar
7220d6b075STomas Glozar if (params->hk_cpus) {
7320d6b075STomas Glozar retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set),
7420d6b075STomas Glozar ¶ms->hk_cpu_set);
7520d6b075STomas Glozar if (retval == -1) {
7620d6b075STomas Glozar err_msg("Failed to set rtla to the house keeping CPUs\n");
7720d6b075STomas Glozar goto out_err;
7820d6b075STomas Glozar }
7920d6b075STomas Glozar } else if (params->cpus) {
8020d6b075STomas Glozar /*
8120d6b075STomas Glozar * Even if the user do not set a house-keeping CPU, try to
8220d6b075STomas Glozar * move rtla to a CPU set different to the one where the user
8320d6b075STomas Glozar * set the workload to run.
8420d6b075STomas Glozar *
8520d6b075STomas Glozar * No need to check results as this is an automatic attempt.
8620d6b075STomas Glozar */
8720d6b075STomas Glozar auto_house_keeping(¶ms->monitored_cpus);
8820d6b075STomas Glozar }
8920d6b075STomas Glozar
9020d6b075STomas Glozar /*
9120d6b075STomas Glozar * If the user did not specify a type of thread, try user-threads first.
9220d6b075STomas Glozar * Fall back to kernel threads otherwise.
9320d6b075STomas Glozar */
9420d6b075STomas Glozar if (!params->kernel_workload && !params->user_data) {
9520d6b075STomas Glozar retval = tracefs_file_exists(NULL, "osnoise/per_cpu/cpu0/timerlat_fd");
9620d6b075STomas Glozar if (retval) {
9720d6b075STomas Glozar debug_msg("User-space interface detected, setting user-threads\n");
9820d6b075STomas Glozar params->user_workload = 1;
9920d6b075STomas Glozar params->user_data = 1;
10020d6b075STomas Glozar } else {
10120d6b075STomas Glozar debug_msg("User-space interface not detected, setting kernel-threads\n");
10220d6b075STomas Glozar params->kernel_workload = 1;
10320d6b075STomas Glozar }
10420d6b075STomas Glozar }
10520d6b075STomas Glozar
10620d6b075STomas Glozar /*
10720d6b075STomas Glozar * Set workload according to type of thread if the kernel supports it.
10820d6b075STomas Glozar * On kernels without support, user threads will have already failed
10920d6b075STomas Glozar * on missing timerlat_fd, and kernel threads do not need it.
11020d6b075STomas Glozar */
11120d6b075STomas Glozar retval = osnoise_set_workload(tool->context, params->kernel_workload);
11220d6b075STomas Glozar if (retval < -1) {
11320d6b075STomas Glozar err_msg("Failed to set OSNOISE_WORKLOAD option\n");
11420d6b075STomas Glozar goto out_err;
11520d6b075STomas Glozar }
11620d6b075STomas Glozar
11720d6b075STomas Glozar return 0;
11820d6b075STomas Glozar
11920d6b075STomas Glozar out_err:
12020d6b075STomas Glozar return -1;
12120d6b075STomas Glozar }
12220d6b075STomas Glozar
timerlat_usage(int err)1234c687437SJohn Kacur static void timerlat_usage(int err)
124a828cd18SDaniel Bristot de Oliveira {
125a828cd18SDaniel Bristot de Oliveira int i;
126a828cd18SDaniel Bristot de Oliveira
127a828cd18SDaniel Bristot de Oliveira static const char * const msg[] = {
128a828cd18SDaniel Bristot de Oliveira "",
129a828cd18SDaniel Bristot de Oliveira "timerlat version " VERSION,
130a828cd18SDaniel Bristot de Oliveira "",
131a828cd18SDaniel Bristot de Oliveira " usage: [rtla] timerlat [MODE] ...",
132a828cd18SDaniel Bristot de Oliveira "",
133a828cd18SDaniel Bristot de Oliveira " modes:",
134a828cd18SDaniel Bristot de Oliveira " top - prints the summary from timerlat tracer",
1351eeb6328SDaniel Bristot de Oliveira " hist - prints a histogram of timer latencies",
136a828cd18SDaniel Bristot de Oliveira "",
137a828cd18SDaniel Bristot de Oliveira "if no MODE is given, the top mode is called, passing the arguments",
138a828cd18SDaniel Bristot de Oliveira NULL,
139a828cd18SDaniel Bristot de Oliveira };
140a828cd18SDaniel Bristot de Oliveira
141a828cd18SDaniel Bristot de Oliveira for (i = 0; msg[i]; i++)
142a828cd18SDaniel Bristot de Oliveira fprintf(stderr, "%s\n", msg[i]);
1434c687437SJohn Kacur exit(err);
144a828cd18SDaniel Bristot de Oliveira }
145a828cd18SDaniel Bristot de Oliveira
timerlat_main(int argc,char * argv[])146a828cd18SDaniel Bristot de Oliveira int timerlat_main(int argc, char *argv[])
147a828cd18SDaniel Bristot de Oliveira {
148a828cd18SDaniel Bristot de Oliveira if (argc == 0)
149a828cd18SDaniel Bristot de Oliveira goto usage;
150a828cd18SDaniel Bristot de Oliveira
151a828cd18SDaniel Bristot de Oliveira /*
152a828cd18SDaniel Bristot de Oliveira * if timerlat was called without any argument, run the
153a828cd18SDaniel Bristot de Oliveira * default cmdline.
154a828cd18SDaniel Bristot de Oliveira */
155a828cd18SDaniel Bristot de Oliveira if (argc == 1) {
156a828cd18SDaniel Bristot de Oliveira timerlat_top_main(argc, argv);
157a828cd18SDaniel Bristot de Oliveira exit(0);
158a828cd18SDaniel Bristot de Oliveira }
159a828cd18SDaniel Bristot de Oliveira
160a828cd18SDaniel Bristot de Oliveira if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
1614c687437SJohn Kacur timerlat_usage(0);
162a828cd18SDaniel Bristot de Oliveira } else if (strncmp(argv[1], "-", 1) == 0) {
163a828cd18SDaniel Bristot de Oliveira /* the user skipped the tool, call the default one */
164a828cd18SDaniel Bristot de Oliveira timerlat_top_main(argc, argv);
165a828cd18SDaniel Bristot de Oliveira exit(0);
166a828cd18SDaniel Bristot de Oliveira } else if (strcmp(argv[1], "top") == 0) {
167a828cd18SDaniel Bristot de Oliveira timerlat_top_main(argc-1, &argv[1]);
168a828cd18SDaniel Bristot de Oliveira exit(0);
1691eeb6328SDaniel Bristot de Oliveira } else if (strcmp(argv[1], "hist") == 0) {
1701eeb6328SDaniel Bristot de Oliveira timerlat_hist_main(argc-1, &argv[1]);
1711eeb6328SDaniel Bristot de Oliveira exit(0);
172a828cd18SDaniel Bristot de Oliveira }
173a828cd18SDaniel Bristot de Oliveira
174a828cd18SDaniel Bristot de Oliveira usage:
1754c687437SJohn Kacur timerlat_usage(1);
176a828cd18SDaniel Bristot de Oliveira exit(1);
177a828cd18SDaniel Bristot de Oliveira }
178