xref: /linux-6.15/tools/tracing/rtla/src/timerlat.c (revision 0122938a)
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, &params->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 					   &params->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(&params->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