~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/tracing/rtla/src/timerlat_u.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  */
 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php