Ayant réfléchi à tout ce qui pouvait être responsable de la lenteur de démarrage du noyau, Arjan en a déduit quelques observations, puis une solution. En juillet celui-ci a révélé un petit projet nommé Fastboot.
Pour expliquer ce qu'est fastboot : ce pourquoi il est né et ce qu'il propose, il faut d'abord faire un petit état des lieux de ce qui se déroule en interne au démarrage du noyau. L'initialisation du noyau
Commençons par le commencement.
Le noyau Linux est compilé au format ELF, qui est un format standard d'exécutables largement utilisé dans le monde des Unix. Dans un exécutable ELF, le compilateur (GCC) ainsi que l'éditeur de liens (linker Ld) utilisent beaucoup les sections pour stocker des informations utiles, telles que les fonctions appelées dans les bibliothèques externes, les informations de débuggage, etc.
Un programme destiné à être compilé au format Elf peut même créer ses propres sections pour y stocker du code ou des données spécifiques et destinées à être regroupées. Par exemple, il est tout à fait possible de regrouper le code d'un ensemble de fonctions dans une section spécifique, puis d'extraire l'adresse de cette section pour parcourir toutes les fonctions qui y sont contenues.
Ce genre d'astuce est très utilisée dans le noyau Linux, et notamment pour résoudre un problème d'envergure : la plupart des composants du noyau ont besoin d'exécuter une fonction pour s'initialiser au démarrage. Par exemple les pilotes ont besoin de signaler au noyau qu'ils attachent telles fonctions à tel périphérique matériel, ils ont besoin de signaler qu'ils écoutent sur les fichiers de périphériques (répertoire /dev), ou même d'initialiser un périphérique, voire d'allouer de la mémoire pour la suite.
En bref, chaque composant du noyau, ou presque, a besoin d'exécuter une fonction d'initialisation au démarrage du système. S'il fallait regrouper un appel à toutes ces fonctions dans un fichier source et les appeler les unes après les autres, ce serait un enfer à maintenir et franchement peu élégant.
Ainsi le noyau Linux crée une section nommée .init.text pour ranger toutes les fonctions d'initialisation dedans. Lorsqu'un pilote décide de soumettre une fonction qui s'exécutera au démarrage, il a juste à faire précéder le nom de sa fonction par l'annotation __init, ce qui rangera le code de la fonction dans la section .init.text. Ensuite, il faudra que ce pilote appelle la macro device_initcall pour ranger l'adresse de sa fonction dans une autre section appelée .initcallxx.init
Cela ne sert pas à grand chose d'expliquer ce que signifie le xx ici, mais il est remplacé dynamiquement pour définir plusieurs niveaux d'initialisation, par exemple le cœur du noyau peut avoir besoin de s'initialiser avant le système de fichiers, etc.
Exemple :
int __init ma_fonction(void);
device_initcall(ma_fonction);
À la compilation, GCC va regrouper toutes ces fonctions dans la section .init.text et leurs adresses dans la section .initcallxx.init
Le noyau, quant à lui, aura pris soin de baliser la section .initcallxx.init avec deux pointeurs :
- __initcall_start, le début de la section .initcallxx.init ;
- __initcall_end, la fin de cette section.
Au démarrage, lorsque le noyau veut exécuter toutes ces fonctions, il procède en utilisant une boucle :
for (call = __initcall_start; call < __initcall_end; call++)
call();
C'est un schéma grossier de ce qui se passe réellement, mais en réalité les choses ne sont pas beaucoup plus compliquées : tous les pointeurs de fonctions contenus dans la section .initcallxx.init vont s'exécuter.
À la fin de cette séquence, la mémoire utilisée pour stocker le code de ces fonctions sera libérée (la section .init.text).
Le problème qui se pose
Comme vous avez pu le voir, ces fonctions sont exécutées les unes après les autres. Ce sont les résultats de ces fonctions qui sont affichés sur votre écran au démarrage. Il peut y en avoir plusieurs centaines qui s'exécutent, certaines sont plus longues que d'autres.
Ce qui peut chagriner ici, c'est que les appels de ces fonctions sont sérialisés, ou encore synchrones. Si le mot peut faire peur, en réalité il traduit un concept simple : la prochaine fonction ne s'exécutera pas tant que la fonction en cours d'exécution n'est pas terminée.
Cela peut faire tiquer si l'on recense les ressources disponibles à ce stade du démarrage :
- Les machines récentes ont plusieurs processeurs, alors qu'ici, un seul processeur est utilisé à la fois puisque ces fonctions ne vont pas s'exécuter de manière simultanée. Et d'ailleurs les fonctionnalités SMP (multiprocesseur) sont activées à ce stade du démarrage. Mais il semble qu'on n'en profite pas vraiment ;
- Les fonctions d'initialisation risquent de faire des entrées-sorties, des allocations mémoires, en gros il y a des moments où ces fonctions vont "dormir", en attente de réponse de la part d'un périphérique, ou d'autres ressources du système. C'est dommage, on pourrait profiter de ce temps libre pour exécuter d'autres fonctions d'initialisation ;
- À ce stade du démarrage, l'ordonnanceur de tâches est déjà initialisé. On peut donc créer des threads et profiter du fait que nous avons plusieurs processeurs pour créer des tâches qui s'exécuteront tout à fait en parallèle. Et quand bien même nous n'avons qu'un seul processeur, on peut profiter de la préemption : lorsqu'une fonction d'initialisation bloque (dort) en attente de ressources, une autre peut profiter du processeur pendant ce temps là.
Juillet 2008, premier jet, premier Fastboot
En juillet dernier, Arjan Van de Ven a posté une première solution découpée en trois patchs :
- http://lkml.org/lkml/2008/7/18/488
- http://lkml.org/lkml/2008/7/18/489
- http://lkml.org/lkml/2008/7/18/490
- http://lkml.org/lkml/2008/7/18/491
Cette solution créait un nouveau niveau d'initialisation appelé asynchronous initcall, ce qui signifie fonction d'initialisation asynchrone. Il était donc possible, par le biais de ces patchs, de définir des fonctions d'initialisation qui pouvaient s'exécuter en parallèle à d'autres fonctions d'initialisation. Ou pour faire simple : plusieurs fonctions d'initialisation pouvaient maintenant s'exécuter en même temps, permettant ainsi de profiter des ressources rendues disponibles par la préemption et le multi-processeur.
Par défaut, les fonctions __init continuaient de s'exécuter de manière synchrone, les unes après les autres. Mais les développeurs aventureux et désireux d'optimiser le démarrage du noyau pouvaient tester leur fonction d'initialisation de manière asynchrone.
Ce travail était implémenté en utilisant le système des workqueues. C'est-à-dire un thread s'exécutant dans le noyau dans lequel réside une file d'attente de tâches à exécuter. Les workqueues sont une solution légère : elles ne nécessitent pas de création de multiples threads, on a juste un seul thread qui possède une liste de fonctions à exécuter.
Un nouveau thread de type workqueue était donc créé, et lorsqu'une fonction d'initialisation asynchrone était trouvée, elle était ajoutée en queue de liste du workqueue.
Ce qui implique une chose : ce workqueue n'exécutant qu'une seule tâche à la fois, seules deux fonctions d'initialisation pouvaient s'exécuter en parallèle: la partie synchrone, donc les fonctions __init habituelles, et une fonction exécutée par le workqueue.
Qu'est-il arrivé à cette solution? Il semble que Linus n'ait pas trop apprécié l'approche. L'idée de l'exécution asynchrone ne semblait pas mauvaise, mais il préférait quelque chose de plus granulé. Somme toute, ramener la partie asynchrone du démarrage à des choses plus fines plutôt que sur tout une fonction d'initialisation.
Arjan est donc revenu en ce 4 janvier 2009 avec une nouvelle approche.
Janvier 2009, un fastboot 2, plus granulé
Le 4 janvier 2009, Arjan revient avec une nouvelle approche. L'idée des initcalls complètement asynchrones a été abandonnée au profit d'une API permettant à quiconque de décider quelles parties de ses fonctions d'initialisation seront asynchrones.
- http://lkml.org/lkml/2009/1/4/159
- http://lkml.org/lkml/2009/1/4/155
- http://lkml.org/lkml/2009/1/4/156
- http://lkml.org/lkml/2009/1/4/157
- http://lkml.org/lkml/2009/1/4/158
Il ne s'agit plus maintenant de rendre toute une fonction d'initialisation asynchrone, mais de décider quelle(s) partie(s) d'une fonction d'initialisation devra s'exécuter de manière asynchrone.
Il suffit d'appeler la fonction
void async_schedule(async_func_ptr *ptr, void *data)
ptr étant la fonction à exécuter et data, les données à lui passer en paramètre.
C'est une idée beaucoup plus souple, laissant plus de contrôle au développeur et permettant ainsi d'éviter des conditions de concurrence, d'incohérences d'états au niveau du système. Exemple : que se passerait-il si le pilote de votre disque n'avait pas fini de s'initialiser pendant le montage de votre système de fichier ?
Pour éviter ce genre de situation, cette nouvelle API fournit de nouveaux outils de synchronisation. Lorsqu'une fonction asynchrone est créée, celle-ci reçoit un "cookie", permettant ainsi de l'identifier par rapport aux autres. Si cette fonction décide à un moment ou à un autre d'attendre que toutes les fonctions asynchrones qui ont été lancées avant elle se terminent, il lui suffit de lancer la fonction
void async_synchronize_cookie(async_cookie_t cookie)
en passant son propre cookie. C'est donc un outil de synchronisation entre fonctions asynchrones.
Par exemple si A et B sont des fonctions asynchrones qui font l'état des lieux de certains périphériques. Et si C a été lancée après A et B, et qu'à un moment C a besoin de la liste de tous les périphériques recensés par A et B, alors il lui suffit d'appeler async_synchronize_cookie pour être sûre que A et B ont bien fini leur travail et ont tout trouvé.
Un autre outil de synchronisation a été prévu pour que les fonctions d'initialisation synchrones puissent attendre que toutes les fonctions asynchrones soient terminées.
Pour reprendre l'exemple de tout à l'heure, lorsque la fonction d'initialisation qui va monter la partition racine (/) va s'exécuter, elle voudra être sûre que l'initialisation des périphériques de stockage est terminée, sans quoi elle n'aurait pas de système de fichier à lire. Si ces périphériques sont encore en cours d'initialisation à cause de fonctions asynchrones, alors il suffira d'appeler
void async_synchronize_full(void)
pour attendre leur terminaison.
Si async_synchronize_cookie permet une synchronisation entre fonctions asynchrones, async_synchronize_full permet de synchroniser entre fonctions synchrones et asynchrones.
Voilà, mal de crâne mis à part, il semble que l'idée soit en bonne voie. Si des commentaires critiques sont évoqués dans la révision de ces patchs, pour l'instant ils semblent seulement concerner de petits détails et non pas l'idée principale, ce qui est plutôt bon signe et augure une bonne voie quant à l'inclusion de ces patchs dans la branche principale du noyau, avec beaucoup de chance pour la fenêtre d'inclusion (merge-window) en cours du 2.6.29, avec un peu moins de chance pour 2.6.30.
Dans tous les cas, il y a de fortes chances qu'on retrouve les évolutions du développement de fastboot dans la branche -tip maintenue par Ingo Molnar.
Voici de quoi dépend la rapidité de démarrage de vos futures distributions Linux.
Aller plus loin
- Fastboot, première version (45 clics)
- Fastboot, seconde version (104 clics)
# Importance
Posté par Pascal Terjan (site web personnel) . Évalué à 10.
Ces optimisations servent à gagner quelques secondes dans le cas ou tu n'as pas d'initrd (ou initramfs...), elles ne se voient pas sinon.
Elles lui ont sans doute permis de passer de 7 ou 8s à 5s, mais la plupart des distros sont à au moins 20 ou 25s, et beaucoup sont plutot à 40s.
Il y a beaucoup de choses qui influencent plus sur une distribution générique, les divers services en particulier, ou le temps passé dans l'initrd.
Il y a donc je pense beaucoup de choses plus visibles pour améliorer le temps de boot.
Je peux citer par exemple l'ajout du cache à modprobe qui fait passer le coldboot udev de 11s à 7s sur mon laptop (mais arjan n'a pas ce problème il a fait une "distrib" specifique à sa machine).
[^] # Re: Importance
Posté par liberforce (site web personnel) . Évalué à 6.
[^] # Re: Importance
Posté par blubliblo . Évalué à 6.
[^] # Re: Importance
Posté par nazcafan . Évalué à 1.
http://en.wikipedia.org/wiki/Upstart
http://en.wikipedia.org/wiki/Upstart
[^] # Re: Importance
Posté par ZeGrunt . Évalué à 1.
[^] # Re: Importance
Posté par blubliblo . Évalué à 1.
[^] # Re: Importance
Posté par Temsa (site web personnel) . Évalué à 2.
[^] # Re: Importance
Posté par liberforce (site web personnel) . Évalué à 9.
http://mces.blogspot.com/2008/10/improving-login-time-part-1(...)
http://mces.blogspot.com/2008/11/improving-login-time-part-2(...)
http://mces.blogspot.com/2008/12/improving-login-time-part-3(...)
La rapidité de démarrage des distributions se joue sur tous les fronts...
[^] # Re: Importance
Posté par nazcafan . Évalué à 1.
Je vais pas cracher dans la soupe, ceci dit, tomboy est diablement pratique ! Cette saloperie me manque beaucoup au travail ...
[^] # Re: Importance
Posté par Loic Dreux . Évalué à 0.
[^] # Re: Importance
Posté par patrick_g (site web personnel) . Évalué à 4.
http://library.gnome.org/users/stickynotes_applet/2.25/stick(...)
C'est quoi les fonctions fabuleudement géniales qui rendent Tomboy incontournable pour toi ?
[^] # Re: Importance
Posté par ccomb (site web personnel) . Évalué à 2.
Avant j'utilisais sticky notes et je me retrouvais avec des post-its faisant toute la hauteur de l'écran. En passant à tomboy, j'ai pu tout séparer dans plusieurs notes, tout réduire et commencer une gestion à la GTD, avec une note pour chaque bucket. Après, moi aussi je préférerais avoir un tomboy sans mono...
[^] # Re: Importance
Posté par TImaniac (site web personnel) . Évalué à -1.
Le temps de chargement du runtime Mono est ridicule, tu t'en apercevra jamais.
Après une appli Mono peut être plus lente (à démarrer mais pas seulement) qu'une appli C++ évidemment, mais c'est pas lié au temps de démarrage du runtime Mono.
[^] # Re: Importance
Posté par reno . Évalué à 3.
Tu devrais éviter l'abus de 'virtuel': l'implémentation elle est bien réelle..
Puisque tu affirme que le ralentissement est négligeable, c'est que j'imagine que tu as des chiffre qui mesurent ce ralentissement?
Pourrais-tu nous les donner?
[^] # Re: Importance
Posté par TImaniac (site web personnel) . Évalué à 1.
Hello, world !
real 0m0.140s
user 0m0.015s
sys 0m0.000s
C'est évidemment le temps d'exécution total, t'en déduis ce que tu veux sur le temps de "chargement".
[^] # Re: Importance
Posté par HoloAddict (site web personnel) . Évalué à 2.
Je ne connais pas bien mono, mais par exemple pour java, le premier démarrage a froid de la machine virtuelle est non-négligeable (lecture DD, mis en place dans la ram). Sun veut d'ailleurs l'améliorer.
Après peut-être que Mono est mieux foutu de se côté là, mais franchement je pense que ton exemple à été pris "à chaud", avec un mono déjà démarré.
Après, j'ai la flemme d'installer mono juste pour un test hello word.
[^] # Re: Importance
Posté par TImaniac (site web personnel) . Évalué à 2.
C'est pas la machine virtuelle qui démarre, c'est l'environnement d'exécution qui démarre.
Après peut-être que Mono est mieux foutu de se côté là, mais franchement je pense que ton exemple à été pris "à chaud", avec un mono déjà démarré.
je pensais que ca se voyait, je démarrer mono dans ce test, il n'était pas démarré avant donc.
Mono n'est pas un process qui tourne en tache de fond et qui attend d'exécuter des programmes. C'est pas une VM, c'est un environnement d'exécution qui est démarré à la demande pour exécuter tel ou tel programme, de la même manière que t'appelle perl ou python pour exécuter ton script.
Bref, comme tu peux le constater, le temps de démarrage de l'environnement d'exécution pour un pauvre hello world, c'est peanuts.
Pour Java, y'a des raisons historiques qui font que la première exécution d'une application est plus "lente", mais c'est pas pour autant qu'il y a un process qui tourne en tâche de fond sur ta machine en attente d'une application Java !
[^] # Re: Importance
Posté par HoloAddict (site web personnel) . Évalué à 2.
Par exemple avec un programme java (plus lent car pas un hello word hein...) :
> time java -jar wiihamster.jar
real 0m5.235s
user 0m0.524s
sys 0m0.084s
> time java -jar wiihamster.jar
real 0m2.042s
user 0m0.536s
sys 0m0.052s
Grande différence. La première fois je n'avais encore jamais lancé java sur cette machine. La deuxième fois si.
Et pourtant, pas de process 'java' en tache de fond.
N'as tu jamais démarré mono (pour une raison X ou Y) sur ta machine avant de faire ce test (et sans utiliser preload hein...) ? Si non, ce sont les résultats de mono a froid, et je m'excuse donc de ma suspicion : Mono est léger au démarrage.
Après, un "environnement d'exécution", pour moi ça veut tout et rien dire. Le vrai process qui se lancera sera "mono" (soit au final la machine virtuelle) qui se démerdera pour lire tous les fichiers et foutre tout ton "environnement d'éxécution" en RAM.
[^] # Re: Importance
Posté par TImaniac (site web personnel) . Évalué à 1.
Oué mais la différence, c'est pas le temps de démarrage de la jvm, c'est juste que lors de la première exécution, la jvm a trouvé des optimisations judicieuses qui ont été "enregistrées" et utilisées lors du 2ème démarrage.
Ca vient du mode de fonctionnement de java qui fonctionne initialement comme un interpreteur puis compile les méthodes qui sont souvent utilisées.
Mono marche pas pareil. le bytecode exécuté est conçu dès le départ pour être compilé et exécuté en code natif (contrairement au bytecode java initialement prévu pour être interprété). Cela dit on retrouve un problème similaire : au début de l'exécution du programme, il faut compiler le code avant de l'exécuter, et ca prend plus de temps qu'après. Mais ca n'a rien à voir avec le temps de chargement du runtime en mémoire en soit. Ce problème peut être contourner en "précompilant" l'application en code natif sur la machine cible, l'application démarrera alors plus vite (même au démarrage de ta machine). Imagine si j'avais utilisé cette possibilité pour mon hello world ;)
N'as tu jamais démarré mono (pour une raison X ou Y) sur ta machine avant de faire ce test (et sans utiliser preload hein...) ?
C'est pas la question. Que j'ai exécuté mono avant n'y change rien. Idem pour java : avoir exécuté java avant ne change rien.
Ce qui change en java, c'est quand t'as déjà exécuté le même programme avant. Bref, rien à voir avec le temps de démarrage de la jvm en soit. C'est uniquement lié au contexte de ton programme.
Après, un "environnement d'exécution", pour moi ça veut tout et rien dire.
Ben c'est pourtant ca le terme exacte. C'est un runtime, mono, qui s'exécute dans un process, et qui s'arrange pour exécuter ton bytecode, tout comme ton process python exécute ton script, etc.
qui se démerdera pour lire tous les fichiers et foutre tout ton "environnement d'éxécution" en RAM.
Oué bah oué, tu sais, même C++ a un "runtime", php aussi, python aussi, à part le C...
Dès que le langage de programmation se base sur la présence de services (garbage collector, type check, introspection, etc.), il faut un runtime capable de charger ces services additionnels.
Le vrai process qui se lancera sera "mono"
Tu peux compiler ton programme pour qu'il inclu le runtime, et tu le verras pas, et ton programme n'aura à aucun moment le nom "mono".
[^] # Re: Importance
Posté par HoloAddict (site web personnel) . Évalué à 1.
Malheureusement je ne retrouve plus le lien.
Tout ça pour dire que, __dans le cas de Java__, le démarrage de la JVM en elle-même est conséquent (a cause de la grosse taille de la librairie standard). J'ai juste fais le même parallèle avec Mono (car il possède également une grosse librairie), sans vraiment pouvoir le prouver, n'ayant pas testé.
Après, je veux bien croire que le second lancement de l'appli est plus rapide (optimisations déjà faites), mais n'empêche que c'est également le cas pour la JVM elle-même, et je pense que c'est surtout ça qui a fait diminuer de moitié le lancement de mon prog.
Entre nous, si .net/mono arrive a faire en sorte que le lancement de la machine virtuelle et le chargement des libs ne se sentent pas sur le démarrage de l'appli, chapeau bas, je n'arrive pas à imaginer comment ils ont fait. J'espère cependant que c'est le cas, car je trouve personnellement Java un poil trop lourd (surtout Swing en fait).
[^] # Re: Importance
Posté par TImaniac (site web personnel) . Évalué à 2.
Ce qu'il faut retenir, c'est que mon exemple t'as clairement montré que le temps de chargement du runtime est négligeable (j'ai refait le test après avoir redémarrer ma machine), et c'est bien le principal.
[^] # Re: Importance
Posté par HoloAddict (site web personnel) . Évalué à 1.
Ok, voila la réponse que j'attendais, il semblerait donc en effet que Mono soit plus efficace que Java sur ce point là, à savoir le temps de démarrage.
[^] # Re: Importance
Posté par TImaniac (site web personnel) . Évalué à 2.
[^] # Re: Importance
Posté par HoloAddict (site web personnel) . Évalué à 1.
A retester dès que j'ai un peu de temps, mais j'ai pas l'impression que ça se soit beaucoup amélioré.
[^] # Re: Importance
Posté par Stibb . Évalué à 1.
Mais néanmoins, que ce soit pour mono ou pour java, il y a bien une machine virtuelle qui tourne derriere, donc un processus dédié, donc si celui ci est déjà charger, le prochain démarage du programme java/.net sera plus rapide.
[^] # Re: Importance
Posté par bluelambda . Évalué à 5.
C'est à dire?
Ca m'intéresse, as-tu un article, une URL sur le sujet?
[^] # Re: Importance
Posté par Pascal Terjan (site web personnel) . Évalué à 9.
[^] # Re: Importance
Posté par fweisbec . Évalué à 7.
Même au niveau noyau, il y a bien d'autres enjeux pour raccourcir le temps de démarrage. D'ailleurs la discussion sur la dernière mouture de fastboot a soulevé de nouvelles questions sur le délai d'attente concernant les tests d'interruptions, la manière de dresser la liste des périphériques etc...
[^] # Re: Importance
Posté par Violet_73 . Évalué à 7.
En effet le temps de boot du kernel est très restrictif dans l'utilisation de Linux sur des systèmes embarqués, comme les téléphones. 7s de démarrage au minimum c'est intolérable. Sur un processeur ARM le temps de boot du kernel est proche de 3s au mieux, avec le minimum de drivers, et cachant le chargement des modules lors de l'initialisation des services, enfin en utilisant tous les trucs possibles et imaginables pour améliorer ce temps.
Par contre il y a toujours des drivers au sein du kernel qui peuvent démarrer ensembles, écrans (le 's' a son importance), audio...
Merci pour l'article. Il est très bien.
[^] # Re: Importance
Posté par gpe . Évalué à 3.
La vache! Comment faites-vous? Sur mon fixe je suis à plus de 200s ...
[^] # Re: Importance
Posté par LupusMic (site web personnel, Mastodon) . Évalué à 4.
[^] # Re: Importance
Posté par Metzgermeister . Évalué à 2.
Haha, on est pas vendredi, mais troller ça réchauffe pendant la nuit :(
[^] # Re: Importance
Posté par Gauthier (Mastodon) . Évalué à -3.
[^] # Re: Importance
Posté par thedude . Évalué à 7.
On peut se poser la question de la pertinence de la vitesse du boot quand la vraie solution serait d'avoir un suspend to ram/disk efficace et de rebooter une fois par mois pour les updates de secu.
Un suspend to ram, ca reduit *drastiquement* le temps de chargement (a vue de nez sur macos, 1s, peut etre 2, windows est pas mal a la traine derriere, linux on est content quand le kernel se vautre pas a la sortie de la veille), pas besoin de demarrer le window/desktop manager, on retrouve ses fenetres commes elles l'etaient etc.
Et le suspend to disk dans le cas de laptop qui va rester comme ca longtemps, histoire de pas atomiser la pauvre batterie.
Bref, resoudre le probleme du boot trop long reviendrait peut etre a avoir un suspend qui fonctionne bien et qui ne casse pas toutes les 2 versions de kernel.
[^] # Re: Importance
Posté par Metzgermeister . Évalué à 3.
[^] # Re: Importance
Posté par claudex . Évalué à 1.
Heu non, Vista détecte et utilise bien les 8 Go, c'est une version 64 bits.
Faudrait savoir: XP démarre en 30 secondes mais Vista détecte bien les 8Go de RAM ne veut pas dire que XP détecte bien les 8Go de RAM.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: Importance
Posté par Metzgermeister . Évalué à 1.
[^] # Re: Importance
Posté par TImaniac (site web personnel) . Évalué à 1.
[^] # Re: Importance
Posté par claudex . Évalué à -3.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
[^] # Re: Importance
Posté par TImaniac (site web personnel) . Évalué à -1.
[^] # Re: Importance
Posté par claudex . Évalué à -1.
« Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche
# Chapeau
Posté par vpinon . Évalué à 10.
Je trouve étonnant que la parallélisation des initialisations ne soit pas apparue plus tôt, ça ne semble pas une idée si farfelue pourtant...
Et combien de temps avant qu'un nombre significatif de pilotes soit mis à jour avec l'API ? Et quand on utilise du vieux matos avec des pilotes qui n'évoluent plus trop ?
[^] # Re: Chapeau
Posté par fweisbec . Évalué à 7.
En réalité il ya déjà eu des tentatives de ce genre par le passé.
Je cite un message d'Ingo Molnar:
http://lkml.org/lkml/2008/7/20/24
Pour traduire un passage:
"bonne idée - et j'aime bien la manière d'amener ça petit à petit.
La plupart des tentatives précédentes de faire du démarrage parallèle avaient pour défaut de vouloir trop en faire d'un coup"
Il faut voir aussi que se pose un lourd problème de synchronisation.
Lancer des fonctions asynchrones, c'est bien mais il y a toujours des étapes précises à suivre, il faut lister les périphériques avant de leur attribuer un numéro d'inode, il faut lister les disques de stockage avant de se lancer sur le montage de systèmes de fichiers etc....
D'ou ce soucis de devoir "synchroniser" les appels asynchrones. Et ce n'est pas une tâche aisée car il faut être sûr d'avoir bien deréssé la liste de chacune des dépendances.
Et combien de temps avant qu'un nombre significatif de pilotes soit mis à jour avec l'API ? Et quand on utilise du vieux matos avec des pilotes qui n'évoluent plus trop ?
A mon avis ça va prendre du temps. Je pense même que seules certaines parties significatives, celles qui seront reconnues pour consommer beaucoup de temps d'execution, seront éventuellement adaptées en asynchrone, si tant est que fastboot trace bien son chemin.
[^] # Re: Chapeau
Posté par Hugues (site web personnel) . Évalué à 1.
+1. Claire et pédagogique, du beau boulot, j'ai même cru que ça venait de patrick_g :-))
Je trouve étonnant que la parallélisation des initialisations ne soit pas apparue plus tôt, ça ne semble pas une idée si farfelue pourtant...
Bof, je crois que c'est à cause de tous ces kikoololeurs qui ont gardé l'habitude d'éteindre leurs péssés tous les soirs, forcément le matin faut rebooter.
Tout ça pour éviter la prière à Saint Uptime, bande de mécréants !!!
[^] # Re: Chapeau
Posté par Mimoza . Évalué à 3.
[^] # Re: Chapeau
Posté par Aris Adamantiadis (site web personnel) . Évalué à 7.
[^] # Re: Chapeau
Posté par Olivier Jeannet . Évalué à 1.
# Fort intéressant...
Posté par windu.2b . Évalué à 9.
Un article comme ça, ça fait toujours plaisir à lire :-)
Du "patrick_g" dans le texte !
Par contre, quelques détails m'échappent, quand je lis ceci :
"Par exemple si A et B sont des fonctions asynchrones qui font l'état des lieux de certains périphériques. Et si C a été lancée après A et B, et qu'à un moment C a besoin de la liste de tous les périphériques recensés par A et B, alors il lui suffit d'appeler async_synchronize_cookie pour être sûre que A et B ont bien fini leur travail et ont tout trouvé."
Comment C indique-t-il qu'il n'attend que A et B, et pas autre chose ? En passant les cookies de A et B à la fonction "async_synchronize_cookie" ? Mais comment les connait-il dans ce cas ?
Ou alors est-ce simplement le fait d'avoir été lancé après A et B qui sous-entend qu'il attend ces derniers ? Dans ce cas, Z risque de devoir attendre des fonctions inutilement...
[^] # Re: Fort intéressant...
Posté par fweisbec . Évalué à 2.
En fait, en interne ces cookies ne représentent qu'un compteur interne.
A aura le cookie 0, B aura le cookie 1 et C aura 2.
Lorsque c appèle async_synchronize_cookie, il passe en paramètre son propre cookie, c'est à dire 2.
Puis async_synchronize_cookie va dormir tant que toutes les fonctions asynchrones ayant un cookie plus petit que 2 ne sont pas terminées.
Cette histoire de cookie-compteur permet de s'assurer du bon ordre au niveau de la synchronisation.
[^] # Re: Fort intéressant...
Posté par windu.2b . Évalué à 3.
Mais du coup, le 2° cas (celui où Z devra attendre inutilement d'autres fonctions lancées avant lui) que je soulève risque de se présenter assez souvent...
[^] # Re: Fort intéressant...
Posté par fweisbec . Évalué à 1.
Si C se synchronise, donc que C attends A et B, et que Z se synchronise un peu en même temps, donc qu'il attends A, B, et C, ça ne pose aucun soucis.
Hmm, par exemple tu imagines quoi comme problème qui pourrait arriver?
[^] # Re: Fort intéressant...
Posté par Victor . Évalué à 4.
[^] # Re: Fort intéressant...
Posté par windu.2b . Évalué à 3.
[^] # Re: Fort intéressant...
Posté par fweisbec . Évalué à 2.
En ce cas, il faut lancer Z avant C...
[^] # Re: Fort intéressant...
Posté par phoenix (site web personnel) . Évalué à 2.
[^] # Re: Fort intéressant...
Posté par fweisbec . Évalué à 6.
Le __init est un raccourci pour dire que le code de la fonction appartient à la section .init.text, permettant ainsi de libérer cette mémoire après l'appel de ces fonctions qui ne seront plus utilisées.
Là où se joue l'ordre d'appel c'est à la définition du device_initcall(fonction).
Voici un extrait de include/linux/init.h
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
/*
* Early initcalls run before initializing SMP.
*
* Only for built-in code, not modules.
*/
#define early_initcall(fn) __define_initcall("early",fn,early)
/*
* A "pure" initcall has no dependencies on anything else, and purely
* initializes variables that couldn't be statically initialized.
*
* This only exists for built-in code, not for modules.
*/
#define pure_initcall(fn) __define_initcall("0",fn,0)
#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
Le level définit l'ordre d'appel. Plus il est petit, plus l'appel se fait au début.
On commence par les early_initcall (avant que le multiprocesseur soit activé).
Ensuite viennent les fonctions du coeur du noyau, puis les éléments relatifs à l'architecture, puis les sous-systèmes, puis le système de fichier, etc....
Ce qui donnera une section .initcall0.init pour les pure_initcall, .initcall1.init pour le coeur du noyau etc....
Et voilà, les pointeurs de fonctions seront regroupés par sections et rangés dans le bon ordre :-)
# Intéressant
Posté par bluelambda . Évalué à 6.
# Et les scripts de démarrage?
Posté par zakMcKraken . Évalué à 5.
A ma connaissance, tous les scripts de /init.d démarrent séquentiellement. En les parallélisant on gagnerait un temps non négligeable. Le problème est de mettre en place un mécanisme pour savoir quels sont les scripts qui ont besoin d'autres scripts afin que ceux ci démarre en premier. Bref, la problématique est la même que pour le noyau. Il me semble qu'une distribution avait déjà tenté un truc du genre...
[^] # Re: Et les scripts de démarrage?
Posté par Migrec (site web personnel) . Évalué à 3.
http://lists.debian.org/debian-devel/2008/05/msg01119.html
Pour ma part, depuis que la mise en veille fonctionne, je n'utilise plus que ça : mon système est opérationnel en 1 à 2 secondes maxi !
[^] # Re: Et les scripts de démarrage?
Posté par NicolBolas . Évalué à 3.
- upstart (ubuntu)
- initng (debian/ubuntu/fedora/gentoo)
sont les plus connus et déjà utilisables.
Après il y a des approches plus prometteuses, mais qui demandent plus de boulot, comme launchd, déjà à l'œuvre dans Mac OS
[^] # Re: Et les scripts de démarrage?
Posté par VINDICATORs . Évalué à 1.
[^] # Re: Et les scripts de démarrage?
Posté par FantastIX . Évalué à 1.
J'ajoute aussi OpenRC et baselayout-2* sous Gentoo, une voie plus «officielle» que initng. La combinaison permet parfois de diviser par deux le temps de démarrage des services (ce fut le cas pour moi). De plus, en mode parallèle, on gagne encore du temps. Toujours en phase de test mais c'est très prometteur.
Le truc ici est de simplifier les scripts de démarrage et de les affarnchir de leur dépendance à bash, beaucoup plus lourd que nécessaire. En diminuant fortement aussi le nombre de «sub-shells», on réduit de manière draconienne le temps de démarrage.
Par exemple, il est possible de passer de 50 à 25 secondes -- juste après avoir sélectionné le système d'exploitation dans Grub et l'affichage du login à la console; sans X donc. En mode parallèle, avec X, Slim et XFCE4, sur ma machine, il me faut environ une minute pour avoir la main sur le bureau. X et XFCE prennent environ 40 secondes, c'est énorme.
Il y a certainement moyen d'optimiser X/XFCE mais bon, ce n'est pas ce qui m'intéresse pour le moment.
[^] # Re: Et les scripts de démarrage?
Posté par liberforce (site web personnel) . Évalué à 5.
[^] # Re: Et les scripts de démarrage?
Posté par windu.2b . Évalué à 2.
Donc cette valeur peut toujours servir à gérer les dépendances entre scripts (tant que les scripts 10... n'ont pas fini, impossible de lancer les scripts 20...) ?
[^] # Re: Et les scripts de démarrage?
Posté par Pascal Terjan (site web personnel) . Évalué à 7.
http://refspecs.freestandards.org/LSB_2.1.0/LSB-generic/LSB-(...)
Ils sont utilisés depuis pas mal d'années (c'est depuis 2005 ou 2006 je crois) par prcsys sur Mandriva pour paralleliser le boot. C'est un tout petit programme en C qui calcule l'arbre de dépendances au démarrage et gere ensuite le lancement des scripts.
http://wiki.mandriva.com/en/Development/Howto/Pinit
[^] # Re: Et les scripts de démarrage?
Posté par Frédéric Massot (site web personnel) . Évalué à 1.
http://packages.debian.org/lenny/insserv
[^] # Re: Et les scripts de démarrage?
Posté par Pierre Jarillon (site web personnel) . Évalué à 4.
### BEGIN INIT INFO
# Provides: ntpd
# Required-Start: $network
# Should-Start: $named
# Required-Stop: $network
# Should-Stop: $named
# Default-Start: 2 3 4 5
# Short-Description: Synchronizes system time using the Network Time Protocol (NTP)
# Description: The Network Time Protocol (NTP) is used to synchronize a computer's time
# with another reference time source.
### END INIT INFO
Cette partie comprend également toutes les informations utiles à drakxservices qui permet à un débutant de gérer les services de sa machine.
Ainsi, le script est toujours compatible system V.
On pourra se reporter à http://linuxfr.org//2006/08/29/21258.html
[^] # Re: Et les scripts de démarrage?
Posté par thedidouille . Évalué à 4.
# Il ne reste plus qu'à...
Posté par Spack . Évalué à 0.
Sinon, cela semble être la continuité de la chose, le nombre de processeurs/cœurs augmente, il faut donc adapter les programmes pour les utiliser correctement...
[^] # Re: Il ne reste plus qu'à...
Posté par reno . Évalué à 3.
[^] # Re: Il ne reste plus qu'à...
Posté par Dup (site web personnel) . Évalué à 2.
Sinon jolie news et effectivement j'ai cru lire du patrick_g jusqu'à ce que je regarde l'auteur de cette dépêche.
Du bon boulot vivement la prochaine :)
[^] # Re: Il ne reste plus qu'à...
Posté par fweisbec . Évalué à 8.
Ben merci pour ces compliments.
Je pense que j'en referai d'autres alors :-)
J'ai déjà une petite idée pour la prochaine dépêche :-)
[^] # Re: Il ne reste plus qu'à...
Posté par herodiade . Évalué à 2.
> augmente, il faut donc adapter les programmes pour les utiliser correctement...
Si le principal point de contention est la CPU...
J'ai l'impression (mais sans avoir fait de mesures, hein;) que le goulot d'étranglement, lors du chargement de l'espace utilisateur (et plus particulièrement des gros DE), sont plutôt les I/O, pour le moment.
Entendez-vous vos disques crépiter, au lancement de gnome ? Voyez-vous votre page cache si dodu, lorsque vous pouvez enfin lancer un "cat /proc/meminfo" au démarrage ?
Le lancement de ces services nécessite l'ouverture et la lecture d'une myriade de petits fichiers répartis un peu partout sur le système de fichier. Dans l'état, la parallélisation fera gagner en temps CPU, mais la contention des accès disques n'en sera pas améliorée ; elle sera plutôt empirée (en rendant les accès encore plus aléatoires / moins séquentiels).
Pour rappel, un bon disque SCSI ou SAS est capable d'environ 200 IOPS : c'est peu. C'est encore une ressource précieuse, partagée entre les tout les logiciels qui doivent se lancer, et pour laquelle il nous reste une belle marge d'amélioration. A moins qu'on ne saute cette phase, en misant sur la généralisation du SSD ?
[^] # Re: Il ne reste plus qu'à...
Posté par herodiade . Évalué à 5.
Connaissez-vous seekwatcher ? C'est un outil basé sur blktrace permettant de mesurer et visualiser finement les accès disques coûteux sur une période de temps (en mettant en vis à vis le débit, les déplacements de têtes par seconde, les offsets sur le disque). Développé par Chris Mason (de btrfs) à Oracle :
http://oss.oracle.com/~mason/seekwatcher/
Ca donne des choses comme ça, beaucoup plus lisibles que la sortie brute de blktrace ! :
http://oss.oracle.com/~mason/seekwatcher/ext3_vs_btrfs_vs_xf(...)
http://oss.oracle.com/~mason/seekwatcher/ext3-compilebench.m(...)
[^] # Re: Il ne reste plus qu'à...
Posté par fweisbec . Évalué à 2.
du tracing dans Linux on arrive à de belles choses. C'est qu'il devient de plus en plus introspectif le noyal... :-)
[^] # Re: Il ne reste plus qu'à...
Posté par fred . Évalué à 2.
[^] # Re: Il ne reste plus qu'à...
Posté par BAud (site web personnel) . Évalué à 2.
http://cookerspot.tuxfamily.org/wikka.php?wakka=Blog20080821(...)
cela permet de voir avant / après :
http://download.tuxfamily.org/cooker/images/bootchart/nc6400(...)
(et disponible en svgz aussi dans http://download.tuxfamily.org/cooker/images/bootchart/ tout simplement).
En revanche, pas de rapprochement "simple" entre les I/O et le processus qui les génére (quand il y a beaucoup de processus en parallèle) ou alors il faudrait revoir la présentation.
[^] # Re: Il ne reste plus qu'à...
Posté par Aris Adamantiadis (site web personnel) . Évalué à 2.
Manque de temps, manque de skills (j'ai pas encore très bien compris quelles étaient les tables à interroger)
[^] # Re: Il ne reste plus qu'à...
Posté par Thomas Lété . Évalué à 3.
Logiquement c'est une option qui est activable via le BIOS.
Il y a un driver dans Linux qui permet de gérer cette technique, c'est peut-être intéressant d'y jeter un coup d'oeil :)
Perso j'aimerais bien un logiciel tel que preload qui permet en théorie de charger en mémoire les fichiers les plus souvent utilisés. Le soucis c'est que je n'ai jamais vu aucune différence de rapidité après l'installation de preload ^^
[^] # Re: Il ne reste plus qu'à...
Posté par Mildred (site web personnel) . Évalué à 2.
Et sur Mac OS (qui est plus rapide), c'est de l'ordre de 200.
Je me demande si il ne serait pas possible de réduire drastiquement le temps de démarrage si on arrêtait d'utiliser des scripts shell, mais par exemple des langages de scripts légers, et utiliser des bibliothèques.
Par exemple au lieu de lancer l'exécutable modprobe (par exemple) juste utiliser une fonction dans une bibliothèque qui ferait la même chose.
# bsd ??
Posté par Mehdi Saada . Évalué à 1.
Le script d'initialisation, l'asynchronisation au niveau du noyau ?
Merci
[^] # Re: bsd ??
Posté par Patrick Lamaizière (site web personnel) . Évalué à 2.
Le problème de fastboot me semble quand même la complexité de gérer et de maintenir les dépendances ? Si c'est juste pour gagner une seconde ?
Il faut aussi que le noyau soit finement locké, pas très utile de lancer 50 fonctions en concurrence pour le même lock.
Il m'a semblé voir passer une tentative pour lancer les scripts d'init en parallèle sous FreeBSD mais de mémoire ça n'avait pas soulevé l'enthousiasme des foules.
Ça me semble faisable, les scripts sont ordonnés un peu à la manière de pinit de Mandrake (c'est le 'RCng' pompé chez NetBSD) par un outil rcorder(8)
Par exemple /etc/rc.d/nfsd
#!/bin/sh
# PROVIDE: nfsd
# REQUIRE: mountd
# KEYWORD: nojail
OpenBSD utilise le "vieux" style de script rc.
les pixels au peuple !
[^] # Re: bsd ??
Posté par Sachiel . Évalué à 2.
>et de maintenir les dépendances ? Si c'est juste pour gagner une >seconde ?
J'avoue ne pas vraiment comprendre cette remarque... Aujourd'hui déjà les scripts ne peuvent pas se lancer dans n'importe quel ordre, donc il existe déjà un système de dépendance. Il est probablement implicite, avec des numéros pour déterminer l'ordre ou quelque chose du genre, ce qui me parait encore plus compliqué à maintenir. Si quelqu'un pouvait m'éclairer sur comment c'est implémenté actuellement d'ailleurs, je prend...
# Sujet Intéressant!
Posté par Pime . Évalué à 1.
Sous Debian, je parallèllise avec startpar.
J'ai atteint 9,5 secondes pour booter
Réseau USB kde3.3 + 6 consoles textes, LVM, mais pas sur
partitions système.
Il est vrai que j'ai dégraissé plusieurs services non primordiaux,
en privilégiant le chargement à la demande.
D'après mon analyse
J'ai détecté 3 problèmes :
1 init : passage du niveau S au niveau N : temps mort.
En effet , à ce stade, il relance le script rc qui va boucler
sur le nouveau runlevel, mais la règle est que tous les
scripts du runlevel S doivent être terminés.
2 sourcing : tous les scripts ou presque sourcent des fichiers
et ce sont souvent les même = (redondances + IO inutiles)
3 execution du noyau : j'ai 4 à 6 seconde mortes sans activité.
Plus le noyau est récent et plus c'est long.
Ma meilleure performance est avec un noyau 2.6.8
Je travaille toujours avec des noyaux recompilés SANS l'initrd.
Je n'utilise pas udev, mais je vais peut-être quand-même y revenir
car le gain de temps n' est pas si convainquant que cela.
Si quelqu'un pouvait me dire comment raccourcir l'execution du noyau?
Merci.
[^] # Heu ben en fait ce sujet y répond
Posté par Pime . Évalué à 1.
Merci pour le TOPO!
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.