Utilisez la fonction sched_setaffinity en C

Jinku Hu 12 octobre 2023
  1. Utilisez la fonction sched_setaffinity pour limiter l’exécution du processus à certaines CPU
  2. Utilisez la macro CPU_SET pour indiquer les cœurs de processeur auxquels lier le processus
Utilisez la fonction sched_setaffinity en C

Cet article explique plusieurs méthodes d’utilisation de la fonction sched_setaffinity en C.

Utilisez la fonction sched_setaffinity pour limiter l’exécution du processus à certaines CPU

De nos jours, le matériel multicœur est omniprésent et les systèmes d’exploitation doivent gérer plusieurs processus s’exécutant simultanément sur ces cœurs. La partie du système d’exploitation qui traite de la gestion de l’exécution du processus / des threads est appelée un planificateur. Un planificateur essaie de distribuer efficacement tous les processus / threads existants sur les cœurs disponibles et d’allouer les tranches de temps en conséquence. La planification est l’un des problèmes de conception les plus difficiles dans les systèmes d’exploitation, car c’est la principale garantie de performance pour le système donné. Il n’y a pas d’interface C standard pour interagir avec le planificateur, mais certains systèmes d’exploitation fournissent des appels système pour modifier plusieurs paramètres de planification de processus.

sched_setaffinity fait partie de la bibliothèque GNU C, et il est principalement basé sur des fonctionnalités spécifiques à Linux. La fonction définit ce que l’on appelle le masque d’affinité du processeur, qui indique l’ensemble de cœurs de processeur sur lesquels le processus peut s’exécuter. sched_setaffinity prend la valeur PID comme premier argument et sizeof(cpu_set_t)comme second. Le troisième argument est de type cpu_set_t et c’est une structure opaque qui doit être manipulée en utilisant les macros prédéfinies de l’en-tête <sched.h>. Notez cependant que la macro _GNU_SOURCE doit être définie pour rendre ces fonctions et macros disponibles. Dans l’exemple suivant, nous implémentons un programme qui prend trois entiers de l’utilisateur comme arguments de ligne de commande et les stocke pour représenter respectivement les numéros de CPU du processus parent / enfant et plusieurs itérations de boucle. Ensuite, la macro CPU_ZERO est utilisée pour effacer la variable cpu_set_t, et fork est appelée pour engendrer un processus enfant.

#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);
  }
}

Utilisez la macro CPU_SET pour indiquer les cœurs de processeur auxquels lier le processus

La fonction sched_setaffinity est appelée par processus ou par thread; ainsi, une fois le fork retourné, nous pouvons spécifier les différents masques CPU pour les processus parent et enfant. La macro CPU_SET est utilisée pour modifier la structure cpu_set_t précédemment remise à zéro et la passer par conséquent à l’appel sched_setaffinity. Notez que chaque processus exécute une boucle dans laquelle ils appellent getpid pour utiliser les ressources du processeur et faciliter la démonstration de l’exemple. Le processus parent attend l’enfant avec l’appel wait dans l’exemple précédent et en utilisant waitpid dans le suivant. Si vous voulez observer le comportement démontré, vous pouvez observer les processus système en utilisant l’utilitaire de ligne de commande htop, largement disponible sur les systèmes 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);
  }
}
Auteur: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Article connexe - C Process