Use a função sched_setaffinity em C
-
Use a função
sched_setaffinity
para limitar a execução do processo a certas CPU (s) -
Use a macro
CPU_SET
para indicar os núcleos da CPU para vincular o processo a
Este artigo irá explicar vários métodos de como usar a função sched_setaffinity
em C.
Use a função sched_setaffinity
para limitar a execução do processo a certas CPU (s)
Hoje em dia, o hardware multinúcleo é onipresente e os sistemas operacionais precisam gerenciar vários processos executados simultaneamente nesses núcleos. A parte do sistema operacional que lida com o gerenciamento da execução do processo / threads é chamada de planejador. Um planejador tenta distribuir com eficiência todos os processos / threads existentes entre os núcleos disponíveis e alocar as fatias de tempo de acordo. O escalonamento é um dos problemas de design mais difíceis em sistemas operacionais, pois é a principal garantia de desempenho de um determinado sistema. Não há interface C padrão para interagir com o agendador, mas certos sistemas operacionais fornecem chamadas de sistema para modificar vários parâmetros de agendamento de processo.
sched_setaffinity
é parte da biblioteca GNU C e é principalmente baseado em funcionalidades específicas do Linux. A função define a chamada máscara de afinidade da CPU, que indica o conjunto de núcleos da CPU nos quais o processo pode ser executado. sched_setaffinity
leva o valor PID como o primeiro argumento e sizeof(cpu_set_t)
como o segundo. O terceiro argumento é do tipo cpu_set_t
e é uma estrutura opaca que precisa ser manipulada usando as macros predefinidas do cabeçalho <sched.h>
. Observe, porém, que a macro _GNU_SOURCE
deve ser definida para tornar essas funções e macros disponíveis. No exemplo a seguir, implementamos um programa que pega três inteiros do usuário como argumentos de linha de comando e os armazena para representar os números da CPU do processo pai / filho e várias iterações de loop, respectivamente. Então, a macro CPU_ZERO
é usada para limpar a variável cpu_set_t
, e fork
é chamado para gerar um processo filho.
#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);
}
}
Use a macro CPU_SET
para indicar os núcleos da CPU para vincular o processo a
a função sched_setaffinity
é chamada por processo ou thread; portanto, quando o fork
retorna, podemos especificar as diferentes máscaras de CPU para os processos pai e filho. A macro CPU_SET
é usada para modificar a estrutura cpu_set_t
previamente zerada e, conseqüentemente, passá-la para a chamada sched_setaffinity
. Observe que cada processo executa um loop no qual chama getpid
para ocupar recursos da CPU e tornar mais fácil demonstrar o exemplo. O processo pai espera pelo filho com a chamada wait
no exemplo anterior e usando waitpid
no próximo. Se você quiser observar o comportamento demonstrado, pode observar os processos do sistema usando o utilitário de linha de comando htop
, amplamente disponível em 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