[ACTU] Groupement automatique des processus

Publié par cpb
Avr 01 2011

Depuis 2003, plusieurs ordonnanceurs se sont succédé dans le noyau Linux 2.6. Le dernier en date (apparu dans Linux 2.6.24) est le “CFS – Complete Fair Scheduler” autrement dit “l’ordonnanceur vraiment équitable”. Celui-ci garantit que le temps CPU disponible est réparti de manière équitable entre les différentes tâches. Ceci ne concerne naturellement que les tâches ordonnancées en temps-partagé, celles s’exécutant en temps-réel disposent de tout le temps-processeur qu’elles désirent (voir toutefois cet article…)

Pour améliorer le temps de réponse des applications interactives (notamment l’interface utilisateur graphique), ce scheduler propose un partage du temps CPU entre les groupes de processus. Supposons que nous ayons un premier groupe de dix tâches réalisant des calculs intensifs (la compilation d’un projet important comme le noyau Linux). Le temps processeur sera alors réparti en dix tranches de 10 % (en ignorant les quelques pourcents indispensables pour faire fonctionner les autres processus du système). Si nous ajoutons à présent un second groupe de trois processus de calcul, la répartition se fera ainsi :

  • 5 % pour chacun des trois processus du premier groupe qui totalise donc 50% ;
  • 16,6 % pour chacun des trois processus du second groupe, qui reçoit les 50% restants.

 

Ce mécanisme, très pratique, est malheureusement assez compliqué à mettre en œuvre, et doit être explicitement activé lors de la création des tâches à placer dans les groupes.

Dans le noyau 2.6.38 – publié récemment comme je l’avais signalé dans un précédent article – est apparu un nouvel élément de configuration nommé CONFIG_SCHED_AUTOGROUP. Celui-ci est accessible dans le menu “General Setup” de l’interface de configuration du kernel (make menuconfig, make xconfig, ou make gconfig) sous la dénomination “Automatic process group scheduling” .

Avec l’auto-groupement des tâches, l’ordonnanceur prend automatiquement en considération le terminal de contrôle du processus. Le temps CPU est réparti équitablement entre les terminaux, quelque soit le nombre de tâches sur chaque terminal.

Pour tester cette fonctionnalité, nous allons utiliser le petit programme suivant, qui lance en parallèle le nombre de processus demandé sur sa ligne de commande. Chaque processus consomme, dans une boucle active, tout le temps CPU qui lui est offert :

boucles-actives.c :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char * argv[])
{
	int nb;
	if ((argc != 2) || (sscanf(argv[1], "%d", & nb) != 1)) {
		fprintf(stderr, "usage: %s n", argv[0]);
		exit(1);
	}
	while (nb > 0) {
		if (fork() == 0)
			while (1)
				;
		nb --;
	}
	return 0;
}

Ouvrons un terminal et lançons un premier jeu de processus. Nous observons que la charge CPU monte en flèche.
Linux Sched Autogroup 1

Basculons alors sur un autre bureau virtuel et ouvrons un second terminal. Première surprise : la fluidité de l’interface graphique. Les applications de l’environnement graphique (Gnome sur ce poste) n’ont pas de terminaux de contrôle et appartiennent donc à un groupe différent de celui des processus en boucle. Le temps processeur dont elles ont besoin est donc réservé et nous n’observons plus de saccades dans la gestion de la souris par exemple comme ce pouvait être le cas précédement. Ce point a d’ailleurs été longuement commenté suite à un message enthousiaste de Linus Torvalds en novembre dernier lorsqu’il s’est aperçu que son interface graphique conservait toute sa réactivité, même durant une compilation largement parallélisée du noyau.

Ouvrons un second terminal et lançons une deuxième série de processus en boucle :

Linux Sched Autogroup 2

 

 

Puis en basculant sur un troisième terminal, observons les répartitions de temps processeur (sur cette machine, le processeur dispose de deux cœurs, aussi la somme des temps CPU est de 200%) :

$ ps axu
USER     PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root       1  0.0  0.0   2876  1332 ?        Ss   Mar29   0:01 /sbin/init
root       2  0.0  0.0      0     0 ?        S    Mar29   0:00 [kthreadd]
[...]
cpb     7413 10.1  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7414 10.3  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7415 10.0  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7416 10.3  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7417 10.3  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7418 10.3  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7419 10.3  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7420 10.1  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7421 10.1  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7422 10.1  0.0   1864    48 pts/0    R    08:24   0:07 ./boucles-actives 10
cpb     7425 23.4  0.0   1864    48 pts/1    R    08:24   0:15 ./boucles-actives 4
cpb     7426 24.0  0.0   1864    48 pts/1    R    08:24   0:16 ./boucles-actives 4
cpb     7427 23.7  0.0   1864    48 pts/1    R    08:24   0:16 ./boucles-actives 4
cpb     7428 23.4  0.0   1864    48 pts/1    R    08:24   0:15 ./boucles-actives 4
cpb     7456  0.0  0.0   4764   988 pts/2    R+   08:25   0:00 ps axu
$

Nous voyons bien que les dix processus issus de la commande ‘boucles-actives 10” disposent chacun de 10 % du temps CPU, tandis que ceux lancés par la commande “boucles-actives 4” profitent d’environ 25 % chacun. Pour voir les groupes de processus, nous pouvons utiliser la commande suivante :

$ ps ax -O pgrp
  PID  PGRP S TTY          TIME COMMAND
    1     1 S ?        00:00:01 /sbin/init
    2     0 S ?        00:00:00 [kthreadd]
[...]
 7413  7412 R pts/0    00:00:15 ./boucles-actives 10
 7414  7412 R pts/0    00:00:14 ./boucles-actives 10
 7415  7412 R pts/0    00:00:14 ./boucles-actives 10
 7416  7412 R pts/0    00:00:14 ./boucles-actives 10
 7417  7412 R pts/0    00:00:14 ./boucles-actives 10
 7418  7412 R pts/0    00:00:14 ./boucles-actives 10
 7419  7412 R pts/0    00:00:14 ./boucles-actives 10
 7420  7412 R pts/0    00:00:14 ./boucles-actives 10
 7421  7412 R pts/0    00:00:14 ./boucles-actives 10
 7422  7412 R pts/0    00:00:14 ./boucles-actives 10
 7425  7424 R pts/1    00:00:32 ./boucles-actives 4
 7426  7424 R pts/1    00:00:34 ./boucles-actives 4
 7427  7424 R pts/1    00:00:33 ./boucles-actives 4
 7428  7424 R pts/1    00:00:34 ./boucles-actives 4
 7477  7477 R pts/2    00:00:00 ps ax -O pgrp
$

Le numéro de groupe est indiqué en seconde colonne, le groupe 7412 contient les dix processus ayant chacun 10 % du temps CPU et le groupe 7424 est constitué des quatre processus avec 25 % de temps CPU chacun. La nouveauté du noyau 2.6.38 est d’organiser automatiquement ces groupes en se basant sur le terminal de contrôle (pts/0 dans un cas et pts/1 dans l’autre).

En conclusion, je ne peux que saluer cette nouveauté du noyau 2.6.38. Elle est particulièrement utile pour conserver une bonne réactivité à un système sur lequel de nombreuses tâches de calcul s’exécutent. L’emploi du terminal de contrôle des processus limite toutefois la portée de cette innovation, car la plupart des utilisateurs de Linux exécutent des applications purement graphiques (navigateurs, players vidéo, etc.) dans des environnements (Gnome, Kde, Xfce…) où la notion de terminal est absente. Ces processus sont présentés avec un point d’interrogation dans la colonne TTY de ps. Les principaux bénéficiaires seront plutôt les utilisateurs qui lancent régulièrement des tâches consommatrices de CPU (compilation, traitement vidéo, calculs…) depuis des terminaux shell.

URL de trackback pour cette page