Dernière mise à jour : 15/06/2009

Une solution consiste à trouver d'autres distributions basées sur Debian qui proposeraient ce noyau, et d'utiliser leur noyau. La page Debian sur LinuxMAO nous suggère les distributions Pure:Dyne et 64studio. La limitation principale de cette solution est que le noyau proposé n'est pas (pas encore ?) dans la même version que celui de Debian Lenny, ce qui peut poser problème si vous avez besoin de pilotes externes au noyau comme par exemple pour les cartes graphiques ATI et nVidia. L'autre inconvénient est que, pour mettre à jour le noyau au fur et à mesure que les correctifs sont publiés, soit vous suivez régulièrement la distribution dont vient le noyau, soit vous faites des astuces de pinning[1] qui permettent de déclarer des dépôts non officiels en n'autorisant l'installation que de certains paquets par exemple.

Si aucune de ces solutions ne vous convient, ou si vous ne faites pas confiance au noyau de distributions marginales[2], il ne vous reste plus qu'une alternative : recompiler votre noyau après lui avoir appliqué le patch temps réel[3]. Contrairement à ce qu'on peut imaginer quand on découvre Linux, recompiler son noyau n'est pas du tout une opération hasardeuse et elle se réalise de nos jours en très peu de commandes. L'inconvénient de la méthode est principalement qu'il faudra recompiler votre noyau à chaque mise à jour du code source… Côté ressources, il faudra aussi dans les 1 Go de disque mais seulement 100 à 200 Mo de RAM libre pour ne pas ralentir la compilation.

Remarque : le temps réel n'est jamais activé par défaut dans un Linux standard pour des raisons de sécurité. Cette fonctionnalité permet en effet à une application de prendre le pas sur toutes les autres, ce qui pourrait être très ennuyeux dans le cas d'un logiciel malveillant…

Donner la priorité temps réel

C'est le plus facile ! Il suffit d'éditer le fichier /etc/security/limits.conf :

$ sudo nano /etc/security/limits.conf

Ce fichier permet de fixer des limites de ressources aux utilisateurs ou aux groupes d'utilisateurs. Si vous êtes intéressés par cette fonctionnalité, n'hésitez pas à consulter sa documentation en ligne en langue anglaise (man limits.conf). Pour ce qui nous concerne, nous allons ajouter les lignes suivantes à la fin du fichier :

@audio - rtprio 99
@audio - nice -10

Ces paramètres permettent d'augmenter la priorité associées aux applications de MAO pour les utilisateurs du groupe audio. Si vous ne savez pas si vous en faites partie, essayez la commande suivante :

$ groups
<userid> adm dialout sudo audio dip video plugdev games powerdev netdev fuse lpadmin

Si vous n'en faites pas partie, essayez la commande suivante :

$ sudo usermod -a -G audio $(whoami)

La commande usermod permet de modifier les attributs d'un utilisateur, l'option -a indique qu'on souhaite ajouter des groupes supplémentaires spécifiés avec l'option -G. Enfin la commande whoami retourne votre identifiant.

Remarque : cette modification permet déjà de faire tourner quelques applications musicales correctement mais dès qu'on en demande un peu trop, le son décroche et on a ce qu'on appelle des xruns (perte de synchronisation). En particulier si vous souhaitez enregistrer ou rejouer de multiples sources sonores, il vous faudra une bonne synchronisation et une faible latence[4], de l'ordre de 10ms, et là seul un noyau temps réel peut vous le procurer.

Patcher le noyau

La page How to make a real-time Linux kernel, the Debian way[5] nous donne un résumé de ce qu'il faut faire, certes pas tout-à-fait exact pour la version officielle Debian Lenny fraîchement parue pour la Saint Valentin, mais qui a le mérite de montrer que ce n'est pas si horrible à faire ! Si vous voulez une version complète avec tous les problèmes qui auraient pu vous arriver depuis un an, il faut plutôt consulter le long fil de discussion Realtime kernel build quickie + bootsplash (or not) sur les forums Debian. Nous nous en servirons pour recompiler le pilote nVidia plus tard…

Tout d'abord il faut récupérer le patch qui va bien pour votre noyau, ce qui nécessite de connaître sa version. Si vous ne savez pas quelle est sa version (de tête, 2.6.26 ?) :

$ uname -r
2.6.26-1-amd64

Gagné ! On se rend alors sur la page de kernel.org afin de récupérer le patch et surtout sa signature qui permettra de vérifier son authenticité. À ce sujet, tout est expliqué dans la page The Linux Kernel Archives OpenPGP Signature[6]. Récupérons d'abord la clef de signature :

$ gpg --keyserver wwwkeys.pgp.net --recv-keys 0x517D0F0E

Récupérons ensuite les fichiers qui nous intéressent :

$ wget http://www.kernel.org/pub/linux/kernel/projects/rt/patch-2.6.26.8-rt16.bz2
$ wget http://www.kernel.org/pub/linux/kernel/projects/rt/patch-2.6.26.8-rt16.bz2.sign

Vérifions maintenant que le patch n'a pas été altéré, volontairement ou non :

$ gpg --verify patch-2.6.26.8-rt16.bz2.sign patch-2.6.26.8-rt16.bz2
gpg: Signature faite le mar 10 fév 2009 02:57:37 CET avec la clé DSA ID 517D0F0E
gpg: Bonne signature de « Linux Kernel Archives Verification Key <ftpadmin@kernel.org> »
gpg: ATTENTION: Cette clé n'est pas certifiée avec une signature de confiance !
gpg:            Rien ne dit que la signature appartient à son propriétaire.
Empreinte de clé principale: C75D C40A 11D7 AF88 9981  ED5B C86B A06A 517D 0F0E

Tout va bien, nous pouvons désormais décompresser le patch :

$ bunzip2 patch-2.6.26.8-rt16.bz2

Ceci créera un fichier patch-2.6.26.8-rt16 dans le répertoire courant; vous aurez besoin du chemin complet de ce fichier plus tard alors regardez bien où vous êtes avec pwd ! Reste maintenant à récupérer les sources du noyau pour pouvoir le recompiler ainsi que de quoi l'empaqueter sans effort :

$ sudo apt-get install linux-source-2.6.26 kernel-package ncurses-dev zlib1g-dev
$ cd /usr/src/
$ sudo tar xjf linux-source-2.6.26.tar.bz2

La première commande installe entre autres le paquet contenant les sources, cependant celui-ci les fournit dans une archive compressée. Il faut donc aller dans le répertoire de cette archive (/usr/src) et extraire les sources de l'archive (les deux commandes suivantes). On peut enfin appliquer le patch :

$ cd linux-source-2.6.26/
$ sudo patch -p1 < /chemin/vers/le/fichier/patch-2.6.26.8-rt16

Remarque importante : si vous utilisez le dépôt des mises à jour de sécurité Debian, il est possible qu'une mise à jour récente fasse échouer la compilation du noyau par la suite. Si tel est le cas, certainement que vous avez dans votre fichier /etc/apt/sources.list la ligne suivante non commentée :

deb http://security.debian.org/ lenny/updates main contrib non-free

Il vous faudra alors commenter cette ligne (caractère dièze « # ») puis ré-installer la version standard des sources du noyau. Pour cela vous pouvez ouvrir Synaptic, rechercher le paquet linux-source-2.6.26 puis demander d'installer la version précédente grâce à l'option Forcer la version (Ctrl+E). Une fenêtre apparaîtra avec une liste déroulante contenant les versions possibles pour ce paquet.

Configurer le noyau

Le noyau se configure par l'intermédiaire d'un fichier texte caché .config qui se trouve à la racine du répertoire des sources. Par défaut il n'existe pas, une bonne méthode pour le créer consiste donc à recopier celui qui a été utilisé pour votre noyau actuel :

$ sudo cp /boot/config-$(uname -r) .config

Nous allons alors exécuter une première commande qui va vérifier que le fichier de configuration du noyau convient pour celui que l'on veut compiler et nous poser des questions lorsque certaines informations manquent :

$ sudo make oldconfig

Sachez que j'ai répondu non à toutes les questions et que la seule à laquelle il faut vraiment être attentif est « Preemption Mode ». C'est là qu'il faut répondre « 4. Complete Preemption (Real-Time) (PREEMPT_RT) » pour avoir un noyau temps réel. À titre indicatif voici toutes les questions indiscrètes qui m'ont été posées (pas de réponse = réponse par défaut, celle en majuscule) :

Enable concurrent radix tree operations (EXPERIMENTAL) (RADIX_TREE_CONCURRENT) [Y/n] (NEW) n
Activate tracepoints (TRACEPOINTS) [Y/n/?] (NEW) n
Preemption Mode
> 1. No Forced Preemption (Server) (PREEMPT_NONE)
  2. Voluntary Kernel Preemption (Desktop) (PREEMPT_VOLUNTARY)
  3. Preemptible Kernel (Low-Latency Desktop) (PREEMPT_DESKTOP) (NEW)
  4. Complete Preemption (Real-Time) (PREEMPT_RT) (NEW)
choice[1-4]: 4
Preemptible RCU (PREEMPT_RCU) [Y/?] (NEW) y
  Enable priority boosting of RCU read-side critical sections (PREEMPT_RCU_BOOST) [Y/n/?] (NEW) n
  Enable tracing for RCU - currently stats in debugfs (RCU_TRACE) [Y/n/?] (NEW) n
Access to physical memory via /dev/rmem (RMEM) [M/n/y/?] (NEW) n
RTSJ-specific hack to reserve memory (ALLOC_RTSJ_MEM) [M/n/y/?] (NEW) n
Debug preemptible kernel (DEBUG_PREEMPT) [Y/n/?] (NEW) n
RT Mutex integrity checker (RTMUTEX_CHECK) [Y/n/?] (NEW) n
torture tests for Priority Inheritance RW locks (RWLOCK_TORTURE_TEST) [N/m/?] (NEW)  
Kernel Function Tracer (FTRACE) [N/y/?] (NEW) 
Interrupts-off Latency Tracer (IRQSOFF_TRACER) [N/y/?] (NEW) 
Preemption-off Latency Tracer (PREEMPT_TRACER) [N/y/?] (NEW) 
Sysprof Tracer (SYSPROF_TRACER) [N/y/?] (NEW) 
Scheduling Latency Tracer (SCHED_TRACER) [N/y/?] (NEW) 
trace kernel events (EVENT_TRACER) [N/y/?] (NEW) 
Trace process context switches (CONTEXT_SWITCH_TRACER) [N/y/?] (NEW) 
Trace max stack (STACK_TRACER) [N/y/?] (NEW) 
Wakeup latency histogram (WAKEUP_LATENCY_HIST) [N/y/?] (NEW) 
Keep a record of preempt disabled spots (PREEMPT_TRACE) [N/y/?] (NEW) 
    KVM trace support (KVM_TRACE) [N/y/?] (NEW) 
Perform a startup test on ftrace (FTRACE_STARTUP_TEST) [N/y/?] (NEW)

Maintenant il y a encore un paramètre à régler, c'est le « Timer frequency » qui doit être réglé sur 1000 Hz au lieu de 250. Pour ce faire, on peut utiliser la commande suivante qui affiche une sorte de menu déroulant dans la console (hé oui !) :

$ sudo make menuconfig

Le paramètre recherché se trouve dans la rubrique « Processor type and features ».

Compiler le noyau

Tout est prêt pour la compilation, à ceci près qu'il vaut mieux changer un peu le nom du noyau afin qu'on ne le confonde pas avec le noyau normal. Pour cela il faut éditer le fichier Makefile :

$ sudo nano Makefile

Au début du fichier on changera la variable suivante :

EXTRAVERSION = .8-rt16

Ici j'ai mis la même fin que le nom du fichier du patch, mais on aurait pu se contenter d'un simple -rt comme « real-time ». Ce que vous mettrez ici vous permettra d'identifier votre noyau temps réel au redémarrage du système. Et maintenant compilons :

$ sudo time make-kpkg --initrd -rev mz1 kernel_image
3463.02user 678.30system 1:19:35elapsed 86%CPU (0avgtext+0avgdata 0maxresident)k
1209232inputs+1445128outputs (1069major+87035568minor)pagefaults 0swaps

La commande time sert juste à chronométrer l'opération de compilation lancée par make-kpkg. Cette dernière commande ne se contente pas de compiler mais crée aussi un paquet Debian prêt à l'emploi qui aura le gros avantage d'être référencé ensuite dans votre gestionnaire de logiciels. C'est là l'intérêt principal de la méthode Debian. L'option -rev permet de spécifier un numéro de version du paquet, ici j'ai bêtement recopié ce que j'ai trouvé dans les articles et discussions anglophones, mais vous pouvez mettre ce que vous voulez, pourquoi pas un classique toto1 ! L'idée est d'incrémenter le numéro lorsque vous compilerez de nouvelles versions, après des mises à jour du noyau par exemple.

NB: vous aurez certainement remarqué que la compilation sur mon AMD64 de mi-2005 a duré… 1h20, alors patience !

Si vous comptez recompiler ensuite des pilotes externes au noyau, c'est une bonne idée de demander aussi à make-kpkg le paquet des entêtes du noyau. Dans ce cas c'est cette commande à peine plus longue qu'il faudra utiliser à la place :

$ sudo time make-kpkg --initrd -rev mz1 kernel_image kernel_headers

Il n'y a plus qu'à installer les paquets fraîchement créés dans le répertoire parent :

$ sudo dpkg -i ../linux-*.deb

Éventuellement, si vous vous en sentez les compétences et surtout le besoin, vous pouvez faire un peu de ménage dans le fichier /boot/grub/menu.lst qui permet de démarrer votre système. Au prochain démarrage vous aurez deux choix supplémentaires, démarrage graphique et mode dépannage, avec le noyau que vous venez de compiler et identifiés par le nom de ce noyau.

Tests

Il n'y a plus qu'à redémarrer la machine en choisissant le bon noyau. Une fois dans votre session, vous pourrez tester par exemple la résistance aux xruns. Commençons par lancer le serveur de son de référence pour la MAO, qui permet aux applications musicales de rester synchronisées entre elles, jack :

$ jackd -R -d alsa -d hw:1 -r 44100 -p 128 -n 2

C'est l'option -R qui demande un fonctionnement temps réel pour le serveur de son, -r donne bien sûr la fréquence d'échantillonnage (44.1kHz), alors que -p indique la taille des paquets de son à utiliser (en octets) et -n le nombre de ces paquets. Ces trois derniers chiffres permettent de calculer la latence :

latence = taille × nombre / fréquence

Dans le cas précédent, on a donc une latence très honorable de 5,8 ms. Remarque : vous pouvez aussi utiliser Qjackctl pour régler les paramètres de jack de manière graphique. Enfin les deux autres paramètres qui n'ont pas été explicités sont les -d redondants. Le premier indique quel pilote utiliser pour accéder à la carte son (alsa est normalement le bon choix) puis le numéro de la carte son à utiliser hw:1. La numérotation commence à 0. Si comme moi vous avez un chipset sonore intégré à la carte mère et une carte son supplémentaire de qualité MAO, vous obtiendrez la liste des cartes de cette manière :

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: CK8S [NVidia CK8S], device 0: Intel ICH [NVidia CK8S]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: CK8S [NVidia CK8S], device 2: Intel ICH - IEC958 [NVidia CK8S - IEC958]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: EWX2496 [TerraTec EWX24/96], device 0: ICE1712 multi [ICE1712 multi]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Ici c'est la EWX24/96 que l'on souhaite utiliser. En guise de test de résistance aux xruns, activez Compiz par exemple et lancez les effets 3D les plus sophistiqués pour voir si jack se plaint de xruns (une petite rotation de bureau avec effet cylindre ou sphère activé ?). À cette latence, je n'en ai pas avec le noyau temps réel alors que j'en ai avec le noyau standard : CQFD !

Vous pouvez désormais lancer les applications MAO qui vous paraissent intéressantes et les connecter entre elles à l'aide de Qjackctl, connecter le clavier MIDI, les sorties audio, etc. Il ne reste plus qu'un mot à ajouter : bienvenue dans la MAO sous Linux !

Compiler des pilotes, cas du nVidia

Tout d'abord il nous faut les sources du pilote nVidia ainsi que l'outil standard de Debian pour compiler les pilotes : module-assistant. Rappelons qu'un pilote est un module du noyau Linux, d'où le nom de l'outil. L'installation est aussi simple que d'habitude :

$ sudo apt-get install module-assistant nvidia-kernel-source

Veuillez faire attention aussi à mettre à jour les entêtes du noyau RT précédemment compilé si une version précédente est déjà installée (paquet linux-headers-2.6.26). Dans le cas contraire le pilote recompilé ne fonctionnerait pas pour le nouveau noyau. Ensuite il suffit normalement de lancer la compilation du pilote :

$ cd /usr/src/
$ sudo m-a -t -k linux-source-2.6.26/ -l linux-image-2.6.26.8-rt16 a-b nvidia

NB: m-a est le petit nom du module-assistant. Ici vous ferez bien attention à adapter le nom du répertoire des sources du noyau (linux-source-2.6.26) et le nom du noyau que vous venez de créer (linux-image-2.6.26.8-rt16). Et si ce n'est pas le pilote nVidia qui vous intéresse, changez le dernier paramètre de la ligne !

Malheureusement dans le cas nVidia, la compilation échoue avec un message qui nous dit qu'il faut consulter un fichier pour savoir ce qui s'est passé :

# BUILD FAILED!
# See /var/cache/modass/nvidia-kernel-source.buildlog.2.6.26.8-rt16.1235946032 for details.
# La construction a échoué. Appuyez sur Entrée pour continuer...

Après lecture rapide il s'avère que le problème vient d'un certain __SEMAPHORE_INITIALIZER, problème que l'on retrouve rapporté et surtout résolu dans le long fil de discussion du forum Debian cité en début de billet. Il faut faire quelques petits ajustements dans le code du pilote nVidia avec ces deux commandes :

$ sudo sed -i '/__SEMAPHORE_INITIALIZER/ s/__SEMAPHORE_INITIALIZER/__COMPAT_SEMAPHORE_INITIALIZER/' /usr/src/modules/nvidia-kernel/nv-linux.h
$ sudo sed -i '/struct semaphore/ s/struct semaphore/struct compat_semaphore/' /usr/src/modules/nvidia-kernel/nv-linux.h

On peut alors recompiler le pilote mais avec les sources modifiés, ce qui consiste à ajouter l'option -O :

$ sudo m-a -t -k linux-source-2.6.26/ -l linux-image-2.6.26.8-rt16 a-b -O nvidia

Il n'y a plus qu'à installer le module :

$ sudo dpkg -i nvidia-kernel-*.deb

Désormais vous pouvez à la fois exploiter toutes les capacités de votre carte graphique et jouir d'un noyau temps réel, seul garant de performances à la hauteur pour la MAO. Pourquoi pas des effets 3D du bureau en pleine séance d'enregistrement multipiste ? ;-)

Notes

[1] voir la fin de la page APT HOWTO Chapitre 3 - Gestion des paquets pour les explications détaillées sur le pinning

[2] le noyau est quand même un élément clef dans la sécurité d'un système…

[3] un patch est une modification d'un logiciel d'habitude destinée à corriger un mauvais fonctionnement, mais ici il sert à ajouter une fonctionnalité manquante

[4] en gros c'est le délai entre l'arrivée du son dans la carte son et l'arrivée des données dans les applications à l'enregistrement, l'inverse dans le sens du départ pour la restitution

[5] Comment fabriquer un noyau Linux temps réel, la méthode Debian

[6] La signature OpenPGP des archives du noyau Linux