Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/tracing/rtla/src/timerlat_u.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2023 Red Hat Inc, Daniel Bristot de Oliveira <[email protected]>
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
*/
32
static 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
err_msg("Error setting timerlat u default priority: %s\n", strerror(errno));
56
exit(1);
57
}
58
} else {
59
retval = __set_sched_attr(getpid(), params->sched_param);
60
if (retval) {
61
/* __set_sched_attr prints an error message, so */
62
exit(0);
63
}
64
}
65
66
if (params->cgroup_name) {
67
retval = set_pid_cgroup(gettid(), params->cgroup_name);
68
if (!retval) {
69
err_msg("Error setting timerlat u cgroup pid\n");
70
pthread_exit(&retval);
71
}
72
}
73
74
/*
75
* This is the tool's loop. If you want to use as base for your own tool...
76
* go ahead.
77
*/
78
snprintf(buffer, sizeof(buffer), "osnoise/per_cpu/cpu%d/timerlat_fd", cpu);
79
80
timerlat_fd = tracefs_instance_file_open(NULL, buffer, O_RDONLY);
81
if (timerlat_fd < 0) {
82
err_msg("Error opening %s:%s\n", buffer, strerror(errno));
83
exit(1);
84
}
85
86
debug_msg("User-space timerlat pid %d on cpu %d\n", gettid(), cpu);
87
88
/* add should continue with a signal handler */
89
while (true) {
90
retval = read(timerlat_fd, buffer, 1024);
91
if (retval < 0)
92
break;
93
}
94
95
close(timerlat_fd);
96
97
debug_msg("Leaving timerlat pid %d on cpu %d\n", gettid(), cpu);
98
exit(0);
99
}
100
101
/*
102
* timerlat_u_send_kill - send a kill signal for all processes
103
*
104
* Return the number of processes that received the kill.
105
*/
106
static int timerlat_u_send_kill(pid_t *procs, int nr_cpus)
107
{
108
int killed = 0;
109
int i, retval;
110
111
for (i = 0; i < nr_cpus; i++) {
112
if (!procs[i])
113
continue;
114
retval = kill(procs[i], SIGKILL);
115
if (!retval)
116
killed++;
117
else
118
err_msg("Error killing child process %d\n", procs[i]);
119
}
120
121
return killed;
122
}
123
124
/**
125
* timerlat_u_dispatcher - dispatch one timerlatu/ process per monitored CPU
126
*
127
* This is a thread main that will fork one new process for each monitored
128
* CPU. It will wait for:
129
*
130
* - rtla to tell to kill the child processes
131
* - some child process to die, and the cleanup all the processes
132
*
133
* whichever comes first.
134
*
135
*/
136
void *timerlat_u_dispatcher(void *data)
137
{
138
int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
139
struct timerlat_u_params *params = data;
140
char proc_name[128];
141
int procs_count = 0;
142
int retval = 1;
143
pid_t *procs;
144
int wstatus;
145
pid_t pid;
146
int i;
147
148
debug_msg("Dispatching timerlat u procs\n");
149
150
procs = calloc(nr_cpus, sizeof(pid_t));
151
if (!procs)
152
pthread_exit(&retval);
153
154
for (i = 0; i < nr_cpus; i++) {
155
if (params->set && !CPU_ISSET(i, params->set))
156
continue;
157
158
pid = fork();
159
160
/* child */
161
if (!pid) {
162
163
/*
164
* rename the process
165
*/
166
snprintf(proc_name, sizeof(proc_name), "timerlatu/%d", i);
167
pthread_setname_np(pthread_self(), proc_name);
168
prctl(PR_SET_NAME, (unsigned long)proc_name, 0, 0, 0);
169
170
timerlat_u_main(i, params);
171
/* timerlat_u_main should exit()! Anyways... */
172
pthread_exit(&retval);
173
}
174
175
/* parent */
176
if (pid == -1) {
177
timerlat_u_send_kill(procs, nr_cpus);
178
debug_msg("Failed to create child processes");
179
pthread_exit(&retval);
180
}
181
182
procs_count++;
183
procs[i] = pid;
184
}
185
186
while (params->should_run) {
187
/* check if processes died */
188
pid = waitpid(-1, &wstatus, WNOHANG);
189
if (pid != 0) {
190
for (i = 0; i < nr_cpus; i++) {
191
if (procs[i] == pid) {
192
procs[i] = 0;
193
procs_count--;
194
}
195
}
196
197
if (!procs_count)
198
break;
199
}
200
201
sleep(1);
202
}
203
204
timerlat_u_send_kill(procs, nr_cpus);
205
206
while (procs_count) {
207
pid = waitpid(-1, &wstatus, 0);
208
if (pid == -1) {
209
err_msg("Failed to monitor child processes");
210
pthread_exit(&retval);
211
}
212
for (i = 0; i < nr_cpus; i++) {
213
if (procs[i] == pid) {
214
procs[i] = 0;
215
procs_count--;
216
}
217
}
218
}
219
220
params->stopped_running = 1;
221
222
free(procs);
223
retval = 0;
224
pthread_exit(&retval);
225
226
}
227
228