File Index
Files and directories
Sign in
FILE

timerlat_u.c

File preview with syntax highlighting.

linux-6.19.14/tools/tracing/rtla/src/timerlat_u.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2023 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
  4 */
  5
  6#define _GNU_SOURCE
  7#include <sched.h>
  8#include <fcntl.h>
  9#include <stdlib.h>
 10#include <unistd.h>
 11#include <stdio.h>
 12#include <errno.h>
 13#include <string.h>
 14#include <tracefs.h>
 15#include <pthread.h>
 16#include <sys/wait.h>
 17#include <sys/prctl.h>
 18
 19#include "utils.h"
 20#include "timerlat_u.h"
 21
 22/*
 23 * This is the user-space main for the tool timerlatu/ threads.
 24 *
 25 * It is as simple as this:
 26 *  - set affinity
 27 *  - set priority
 28 *  - open tracer fd
 29 *  - spin
 30 *  - close
 31 */
 32static int timerlat_u_main(int cpu, struct timerlat_u_params *params)
 33{
 34	struct sched_param sp = { .sched_priority = 95 };
 35	char buffer[1024];
 36	int timerlat_fd;
 37	cpu_set_t set;
 38	int retval;
 39
 40	/*
 41	 * This all is only setting up the tool.
 42	 */
 43	CPU_ZERO(&set);
 44	CPU_SET(cpu, &set);
 45
 46	retval = sched_setaffinity(gettid(), sizeof(set), &set);
 47	if (retval == -1) {
 48		debug_msg("Error setting user thread affinity %d, is the CPU online?\n", cpu);
 49		exit(1);
 50	}
 51
 52	if (!params->sched_param) {
 53		retval = sched_setscheduler(0, SCHED_FIFO, &sp);
 54		if (retval < 0)
 55			fatal("Error setting timerlat u default priority: %s", strerror(errno));
 56	} else {
 57		retval = __set_sched_attr(getpid(), params->sched_param);
 58		if (retval) {
 59			/* __set_sched_attr prints an error message, so */
 60			exit(0);
 61		}
 62	}
 63
 64	if (params->cgroup_name) {
 65		retval = set_pid_cgroup(gettid(), params->cgroup_name);
 66		if (!retval) {
 67			err_msg("Error setting timerlat u cgroup pid\n");
 68			pthread_exit(&retval);
 69		}
 70	}
 71
 72	/*
 73	 * This is the tool's loop. If you want to use as base for your own tool...
 74	 * go ahead.
 75	 */
 76	snprintf(buffer, sizeof(buffer), "osnoise/per_cpu/cpu%d/timerlat_fd", cpu);
 77
 78	timerlat_fd = tracefs_instance_file_open(NULL, buffer, O_RDONLY);
 79	if (timerlat_fd < 0)
 80		fatal("Error opening %s:%s", buffer, strerror(errno));
 81
 82	debug_msg("User-space timerlat pid %d on cpu %d\n", gettid(), cpu);
 83
 84	/* add should continue with a signal handler */
 85	while (true) {
 86		retval = read(timerlat_fd, buffer, 1024);
 87		if (retval < 0)
 88			break;
 89	}
 90
 91	close(timerlat_fd);
 92
 93	debug_msg("Leaving timerlat pid %d on cpu %d\n", gettid(), cpu);
 94	exit(0);
 95}
 96
 97/*
 98 * timerlat_u_send_kill - send a kill signal for all processes
 99 *
100 * Return the number of processes that received the kill.
101 */
102static int timerlat_u_send_kill(pid_t *procs, int nr_cpus)
103{
104	int killed = 0;
105	int i, retval;
106
107	for (i = 0; i < nr_cpus; i++) {
108		if (!procs[i])
109			continue;
110		retval = kill(procs[i], SIGKILL);
111		if (!retval)
112			killed++;
113		else
114			err_msg("Error killing child process %d\n", procs[i]);
115	}
116
117	return killed;
118}
119
120/**
121 * timerlat_u_dispatcher - dispatch one timerlatu/ process per monitored CPU
122 *
123 * This is a thread main that will fork one new process for each monitored
124 * CPU. It will wait for:
125 *
126 *  - rtla to tell to kill the child processes
127 *  - some child process to die, and the cleanup all the processes
128 *
129 * whichever comes first.
130 *
131 */
132void *timerlat_u_dispatcher(void *data)
133{
134	int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
135	struct timerlat_u_params *params = data;
136	char proc_name[128];
137	int procs_count = 0;
138	int retval = 1;
139	pid_t *procs;
140	int wstatus;
141	pid_t pid;
142	int i;
143
144	debug_msg("Dispatching timerlat u procs\n");
145
146	procs = calloc(nr_cpus, sizeof(pid_t));
147	if (!procs)
148		pthread_exit(&retval);
149
150	for (i = 0; i < nr_cpus; i++) {
151		if (params->set && !CPU_ISSET(i, params->set))
152			continue;
153
154		pid = fork();
155
156		/* child */
157		if (!pid) {
158
159			/*
160			 * rename the process
161			 */
162			snprintf(proc_name, sizeof(proc_name), "timerlatu/%d", i);
163			pthread_setname_np(pthread_self(), proc_name);
164			prctl(PR_SET_NAME, (unsigned long)proc_name, 0, 0, 0);
165
166			timerlat_u_main(i, params);
167			/* timerlat_u_main should exit()! Anyways... */
168			pthread_exit(&retval);
169		}
170
171		/* parent */
172		if (pid == -1) {
173			timerlat_u_send_kill(procs, nr_cpus);
174			debug_msg("Failed to create child processes");
175			pthread_exit(&retval);
176		}
177
178		procs_count++;
179		procs[i] = pid;
180	}
181
182	while (params->should_run) {
183		/* check if processes died */
184		pid = waitpid(-1, &wstatus, WNOHANG);
185		if (pid != 0) {
186			for (i = 0; i < nr_cpus; i++) {
187				if (procs[i] == pid) {
188					procs[i] = 0;
189					procs_count--;
190				}
191			}
192
193			if (!procs_count)
194				break;
195		}
196
197		sleep(1);
198	}
199
200	timerlat_u_send_kill(procs, nr_cpus);
201
202	while (procs_count) {
203		pid = waitpid(-1, &wstatus, 0);
204		if (pid == -1) {
205			err_msg("Failed to monitor child processes");
206			pthread_exit(&retval);
207		}
208		for (i = 0; i < nr_cpus; i++) {
209			if (procs[i] == pid) {
210				procs[i] = 0;
211				procs_count--;
212			}
213		}
214	}
215
216	params->stopped_running = 1;
217
218	free(procs);
219	retval = 0;
220	pthread_exit(&retval);
221
222}
~/ Read-only file preview.