Utilice la función sched_setaffinity en C
-
Utilice la función
sched_setaffinity
para limitar la ejecución del proceso a determinadas CPU (s) -
Utilice la macro
CPU_SET
para indicar los núcleos de la CPU a los que enlazar el proceso
Este artículo explicará varios métodos de cómo utilizar la función sched_setaffinity
en C.
Utilice la función sched_setaffinity
para limitar la ejecución del proceso a determinadas CPU (s)
Hoy en día, el hardware de múltiples núcleos es omnipresente y los sistemas operativos necesitan administrar múltiples procesos que se ejecutan simultáneamente en estos núcleos. La parte del sistema operativo que se ocupa de administrar la ejecución de procesos / subprocesos se denomina programador. Un programador intenta distribuir de manera eficiente todos los procesos / subprocesos existentes en los núcleos disponibles y asignar los intervalos de tiempo en consecuencia. La programación es uno de los problemas de diseño más difíciles en los sistemas operativos, ya que es la principal garantía de rendimiento para el sistema dado. No hay una interfaz C estándar para interactuar con el programador, pero ciertos sistemas operativos proporcionan llamadas al sistema para modificar varios parámetros de programación de procesos.
sched_setaffinity
es parte de la biblioteca GNU C, y se basa principalmente en funciones específicas de Linux. La función establece la denominada máscara de afinidad de CPU, que indica el conjunto de núcleos de CPU en los que el proceso puede ejecutarse. sched_setaffinity
toma el valor PID como primer argumento y sizeof(cpu_set_t)
como el segundo. El tercer argumento es de tipo cpu_set_t
y es una estructura opaca que necesita ser manipulada usando las macros predefinidas del encabezado <sched.h>
. Sin embargo, tenga en cuenta que la macro _GNU_SOURCE
debe definirse para que estas funciones y macros estén disponibles. En el siguiente ejemplo, implementamos un programa que toma tres números enteros del usuario como argumentos de la línea de comandos y los almacena para representar los números de CPU del proceso padre / hijo y varias iteraciones de bucle, respectivamente. Luego, la macro CPU_ZERO
se usa para borrar la variable cpu_set_t
, y se llama a fork
para generar un proceso hijo.
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[]) {
cpu_set_t set;
int parentCPU, childCPU, wstatus;
long nloops;
if (argc != 4) {
fprintf(stderr, "Usage: %s parent-cpu child-cpu num-loops\n", argv[0]);
exit(EXIT_FAILURE);
}
parentCPU = strtol(argv[1], NULL, 0);
childCPU = strtol(argv[2], NULL, 0);
nloops = strtol(argv[3], NULL, 0);
CPU_ZERO(&set);
switch (fork()) {
case -1:
errExit("fork");
case 0:
CPU_SET(childCPU, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
errExit("sched_setaffinity");
for (int j = 0; j < nloops; j++) getpid();
exit(EXIT_SUCCESS);
default:
CPU_SET(parentCPU, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
errExit("sched_setaffinity");
for (int j = 0; j < nloops; j++) getpid();
wait(NULL);
exit(EXIT_SUCCESS);
}
}
Utilice la macro CPU_SET
para indicar los núcleos de la CPU a los que enlazar el proceso
La función sched_setaffinity
se llama por proceso o hilo; por lo tanto, una vez que regresa el fork
, podemos especificar las diferentes máscaras de CPU para los procesos padre e hijo. La macro CPU_SET
se utiliza para modificar la estructura cpu_set_t
previamente puesta a cero y, en consecuencia, pasarla a la llamada sched_setaffinity
. Tenga en cuenta que cada proceso ejecuta un bucle en el que llaman a getpid
para ocupar los recursos de la CPU y facilitar la demostración del ejemplo. El proceso padre espera al hijo con la llamada wait
en el ejemplo anterior y usando waitpid
en el siguiente. Si desea observar el comportamiento demostrado, puede observar los procesos del sistema utilizando la utilidad de línea de comandos htop
, ampliamente disponible en sistemas Linux.
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
int main(int argc, char *argv[]) {
cpu_set_t set;
int parentCPU, childCPU, wstatus;
long nloops;
if (argc != 4) {
fprintf(stderr, "Usage: %s parent-cpu child-cpu num-loops\n", argv[0]);
exit(EXIT_FAILURE);
}
parentCPU = strtol(argv[1], NULL, 0);
childCPU = strtol(argv[2], NULL, 0);
nloops = strtol(argv[3], NULL, 0);
CPU_ZERO(&set);
pid_t c_pid = fork();
if (c_pid == -1) errExit("fork");
switch (c_pid) {
case -1:
errExit("fork");
case 0:
CPU_SET(childCPU, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
errExit("sched_setaffinity");
for (int j = 0; j < nloops; j++) getpid();
exit(EXIT_SUCCESS);
default:
CPU_SET(parentCPU, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
errExit("sched_setaffinity");
for (int j = 0; j < nloops; j++) getpid();
if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1)
errExit("waitpid");
exit(EXIT_SUCCESS);
}
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook