3 points par GN⁺ 2023-08-26 | 1 commentaires | Partager sur WhatsApp
  • Faire démarrer le noyau FreeBSD 14 dans Firecracker VMM, une microVM centrée sur Linux pour AWS Lambda, a mis en évidence les hypothèses implicites et les goulets d’étranglement du chemin d’initialisation de l’OS dans un environnement de virtualisation minimal
  • Le premier démarrage a été bloqué par des différences de format d’ELF Note en mode de boot PVH, par des hypercalls spécifiques à Xen et par des différences de disposition mémoire dans Firecracker ; le problème a été résolu en modifiant le code PVH de FreeBSD
  • Comme Firecracker ne fournit pas d’ACPI, le chemin pour obtenir les informations CPU et interruptions a changé ; une option MPTABLE_LINUX_BUG_COMPAT a été ajoutée pour s’aligner sur le bug de traitement MPTable de Linux
  • Lors de la connexion de la console série et des périphériques Virtio, des contraintes sont apparues autour du fonctionnement de l’UART, de l’analyse de la ligne de commande du noyau et des E/S disque non alignées ; FreeBSD a appliqué hw.broken_txfifo, un contournement de vidage FIFO et un traitement bounce basé sur busdma
  • Avec des correctifs non encore intégrés, le noyau FreeBSD démarre en moins de 20 ms dans une VM à 1 CPU et 128 Mo de RAM ; les tâches restantes portent sur l’intégration du support PVH, la séparation du code Xen, une configuration de noyau plus petite et l’étude d’un portage de Firecracker vers FreeBSD

Pourquoi essayer d’exécuter FreeBSD sur Firecracker

  • Firecracker est un VMM qui crée et gère des microVM à faible surcharge sur Linux KVM pour des environnements d’exécution serverless comme AWS Lambda
  • Le travail de portage vers FreeBSD a commencé en juin 2022
  • La motivation était de mettre en évidence simultanément les limites de FreeBSD et de Firecracker
    • En poursuivant le travail d’amélioration du temps de démarrage de FreeBSD, l’objectif était de voir jusqu’où il pouvait aller sur un hyperviseur minimal
    • Porter FreeBSD sur une nouvelle plateforme révèle des bugs à la fois dans FreeBSD et dans la plateforme concernée
    • AWS Lambda ne prend actuellement en charge que Linux ; indépendamment d’une éventuelle adoption de Lambda, le support de Firecracker par FreeBSD est une condition préalable nécessaire
    • Firecracker est en lui-même une plateforme intéressante, et il fallait vérifier son fonctionnement réel

Les premiers obstacles avant l’exécution du noyau

  • Firecracker a été conçu à l’origine pour exécuter des noyaux Linux, mais un correctif ajouté en 2020 apportait la prise en charge du mode de boot PVH en plus de linuxboot
  • FreeBSD prenant déjà en charge le démarrage PVH sur Xen, la même voie a été tentée sur Firecracker
  • Le premier problème était que Firecracker, après avoir chargé le noyau FreeBSD en mémoire, ne trouvait pas le point d’entrée du noyau
    • Le protocole de boot PVH stocke cette valeur dans une ELF Note
    • Il existe des ELF Note PT_NOTE et SHT_NOTE, et FreeBSD ne fournissait pas le format que Firecracker recherchait
    • Une petite modification du script de l’éditeur de liens du noyau FreeBSD a permis à Firecracker de lancer l’exécution du noyau FreeBSD
  • L’exécution du noyau s’est de nouveau arrêtée environ 1 microseconde plus tard

Débogage initial et suppression de la dépendance à Xen

  • Quand le noyau plante avant l’initialisation du débogueur noyau et de la console série, les capacités de débogage de FreeBSD sont d’une aide très limitée
  • Les seules informations fournies par le processus Firecracker étaient que l’invité FreeBSD avait provoqué une triple fault
  • Une « kernel bisection » a été réalisée en insérant des instructions hlt au milieu du code de démarrage du noyau afin de localiser le point de crash
    • Si l’exécution atteignait hlt, Firecracker continuait de tourner mais l’utilisation CPU côté hôte tombait à 0 %
    • Si Firecracker s’arrêtait, on pouvait en déduire que le crash s’était produit avant ce point
  • La première cause trouvée était un hypercall Xen
    • Le point d’entrée PVH de FreeBSD était en réalité du code destiné à démarrer sur Xen, avec l’hypothèse qu’il s’exécutait dans Xen
    • Le KVM utilisé par Firecracker ne fournit pas d’hypercalls Xen, donc leur appel faisait planter la VM
    • Au départ, les hypercalls Xen ont été commentés, puis modifiés ensuite pour n’être appelés qu’après vérification de la signature Xen dans CPUID
  • La récupération de la carte mémoire physique était une fonction essentielle assurée jusque-là par un hypercall Xen
    • À partir de la version 1 de PVH, le pointeur vers la carte mémoire est transmis via la page start_info
    • FreeBSD a été modifié pour utiliser la carte mémoire PVH version 1 à la place de l’hypercall Xen
  • Les différences de disposition mémoire entre Firecracker et Xen ont aussi posé problème
    • Xen charge d’abord le noyau puis place la page start_info à la fin
    • Firecracker place la page start_info à une adresse basse fixe puis charge ensuite le noyau
    • Le code PVH de FreeBSD supposait que l’espace juste après start_info pouvait servir de scratch space, ce qui écrasait la pile noyau initiale sur Firecracker
    • Le problème a été résolu en allouant l’espace de travail après toutes les zones mémoire initialisées par l’hyperviseur

Absence d’ACPI et compatibilité MPTable

  • Sur x86, FreeBSD obtient généralement les informations sur les disques, les cartes réseau, les CPU et les contrôleurs d’interruptions via ACPI
  • Firecracker, par choix de minimalisme, ne fournit pas ACPI
  • FreeBSD peut à la place utiliser les structures MPTable de l’ancienne Intel MultiProcessor Specification
    • Elles ne sont pas incluses par défaut dans la configuration de noyau GENERIC
    • Dans une configuration de noyau allégée pour Firecracker, il a été possible d’ajouter device mptable
  • La MPTable fournie par Firecracker n’était pas strictement conforme au standard, mais à ce que Linux accepte
    • Linux comportait un bug dans sa manière de trouver et d’analyser la MPTable
    • Firecracker ayant été conçu pour démarrer Linux, il fournit une disposition non standard que Linux prend en charge
    • FreeBSD, avec son implémentation indépendante conforme au standard, ne trouvait pas la MPTable mal placée et, même en la trouvant, ne pouvait pas analyser une MPTable invalide
  • Une option de noyau options MPTABLE_LINUX_BUG_COMPAT a été ajoutée à FreeBSD
    • Elle sert lorsqu’une compatibilité bug pour bug avec le traitement Linux de la MPTable est nécessaire
    • Grâce à cette option, le démarrage de FreeBSD sur Firecracker a pu aller plus loin

Prise en charge de la console série et des périphériques Virtio

  • L’un des rares périphériques émulés fournis par Firecracker est le port série
    • Dans une configuration typique, l’entrée et la sortie standard du processus Firecracker deviennent l’entrée et la sortie du port série de la VM
  • Le noyau FreeBSD a démarré avec le disque racine intégré dans l’image noyau, et il a été possible de lire la sortie console du noyau
  • Lors du passage au démarrage de l’espace utilisateur, la sortie console s’est arrêtée au bout de 16 caractères
    • Le symptôme rappelait un ancien bug UART de QEMU
    • Aucune interruption n’arrivait lorsque la FIFO d’émission de l’UART était vide, si bien que FreeBSD ne pouvait plus écrire après 16 octets
    • Le problème a été résolu en compilant dans les variables d’environnement noyau le contournement existant hw.broken_txfifo="1"
  • L’entrée console ne fonctionnait pas non plus
    • Firecracker estimait que la FIFO de réception de l’UART émulé était pleine et ne lisait donc pas la console
    • Lors de l’initialisation de l’UART, FreeBSD remplissait la FIFO de réception avec des valeurs parasites pour mesurer sa taille, puis la vidait via le FIFO Control Register
    • Firecracker n’implémentait pas le FIFO Control Register, donc la FIFO restait pleine en permanence
    • FreeBSD a été modifié pour lire et jeter les caractères un par un afin de vider la FIFO si LSR_RXRDY restait présent après la tentative de vidage
  • Pour utiliser le disque et le réseau, il fallait des périphériques Virtio block/network
    • Firecracker les expose comme des périphériques mmio
    • La configuration de noyau FreeBSD pour Firecracker a reçu device virtio_mmio
  • FreeBSD s’attendait à l’origine à découvrir les périphériques mmio via FDT, mais Firecracker transmet des directives comme virtio_mmio.device=4K@0x1001e000:5 dans la ligne de commande du noyau
    • FreeBSD a ajouté du code pour analyser ces directives et créer des nœuds de périphériques virtio_mmio
    • Une fois ces nœuds créés, le processus habituel de détection des périphériques de FreeBSD détermine le type de périphérique Virtio et attache le pilote approprié
  • Avec plusieurs périphériques Virtio, un problème d’analyse de la ligne de commande du noyau est apparu
    • Firecracker transmet plusieurs paires key=value à la manière de Linux
    • FreeBSD analyse la ligne de commande du noyau comme des variables d’environnement, donc si deux virtio_mmio.device= portent le même nom, un seul est conservé
    • Le code d’analyse initial de l’environnement noyau a été modifié pour préserver les variables en doublon avec un suffixe numéroté, comme virtio_mmio.device= et virtio_mmio.device_1=
  • Après un arrêt anormal, si fsck s’exécutait au démarrage suivant, cela provoquait une panique noyau
    • fsck est l’un des rares cas dans FreeBSD à générer des E/S disque non alignées sur les pages
    • L’implémentation Virtio de Firecracker n’accepte qu’un seul tampon de données et ne prend pas en charge l’approche Virtio classique consistant à découper un tampon franchissant une frontière de page en plusieurs segments
    • Le pilote Virtio block de FreeBSD a été modifié pour utiliser busdma, et les requêtes non alignées ont été adaptées à la contrainte de Firecracker via un traitement bounce passant par un tampon temporaire

Les optimisations de démarrage mises au jour par Firecracker

  • Une fois FreeBSD capable de fonctionner sur Firecracker, les points à améliorer pour réduire le temps de démarrage et l’usage mémoire sont devenus très visibles
  • Dans une VM avec 128 Mo de RAM, près de la moitié de la mémoire système était à l’état wired, et les processus se terminaient fréquemment
    • L’enquête a montré que busdma réservait 32 Mo pour les bounce pages
    • Avec les limitations de Firecracker, chaque E/S disque n’avait besoin au maximum que d’une seule bounce page de 4 Kio
    • Un correctif limitant la réservation de bounce pages pour les périphériques ne prenant en charge qu’un petit nombre de segments d’E/S a réduit l’usage mémoire à 512 Kio
  • L’optimisation du générateur de nombres aléatoires du noyau a réduit le temps de démarrage
    • Dans une VM, l’entropie issue des périphériques matériels peut être peu efficace
    • x86 utilise RDRAND comme source d’entropie de secours, mais avec peu d’entropie par requête et une seule requête toutes les 100 ms
    • En demandant suffisamment d’entropie pour amorcer complètement le générateur Fortuna, 2,3 s ont été gagnées
  • Le traitement du Host ID a aussi été accéléré
    • En général, le chargeur de démarrage définit smbios.system.uuid à partir des informations BIOS ou UEFI
    • Firecracker n’ayant pas de chargeur de démarrage, aucun identifiant n’était fourni
    • Le comportement a été modifié pour attendre 2 secondes avec avertissement si le matériel fournit un identifiant erroné, mais poursuivre silencieusement et rapidement s’il n’y a pas d’identifiant du tout
  • La condition d’attente de la DAD IPv6 a été resserrée
    • FreeBSD attendait la Duplicate Address Detection dès qu’IPv6 était activé sur une interface réseau
    • IPv6 était toujours activé sur l’interface loopback
    • En attendant la DAD uniquement lorsqu’une interface autre que loopback possède IPv6, 2 s ont été gagnées
  • Les attentes fixes au redémarrage et à l’arrêt ont été supprimées
    • Au redémarrage, l’attente d’1 seconde après le message Rebooting... pour laisser le temps au printf de finir et d’être lu a été remplacée par la sysctl kern.reboot_wait_time, dont la valeur par défaut est 0
    • Lors de l’arrêt ou du redémarrage, l’attente supplémentaire d’1 seconde après que le BSP a reçu le signal d’arrêt des autres CPU a également été supprimée
  • TSLOG a été utilisé pour analyser un flame chart du démarrage
    • L’environnement minimal de Firecracker produisait peu de bruit, ce qui facilitait l’identification des goulets d’étranglement restants
    • L’exécution de la VM était si rapide qu’il était souvent possible de compiler un nouveau noyau, l’exécuter et générer un flame chart en moins de 30 secondes
  • L’analyse avec TSLOG a permis de réduire plusieurs goulets d’étranglement de l’ordre de la milliseconde
    • Réduire la boucle de calibration de lapic_init de 100000 à 1000 itérations a fait gagner 10 ms
    • Modifier ns8250_drain, qui appelait DELAY pour chaque caractère, afin de ne retarder qu’en cas de besoin après vérification de LSR_RXRDY, a fait gagner 27 ms
    • Faire en sorte que Firecracker implémente la feuille CPUID indiquant la fréquence du TSC et de l’horloge APIC locale a fait gagner 20 ms
    • Remplacer la valeur fixe de kern.nswbuf à 256 par 32 * mp_ncpus a fait gagner 5 ms dans une VM à 1 CPU
    • Remplacer le bubblesort de mi_startup par un quicksort permettrait de gagner 2 ms, mais ce n’était pas encore intégré au 22 août 2023
    • Remplacer l’initialisation immédiate par vm_mem des structures vm_page pour toute la mémoire physique par une initialisation paresseuse permettrait de gagner 2 ms, mais ce n’était pas encore intégré à la même date
    • Ajouter MAP_POPULATE au mmap de la mémoire invitée de Firecracker réduirait le coût, côté Linux, de création des structures de page lors du premier accès et ferait gagner 2 ms, mais ce n’était pas encore intégré à la même date

État actuel et travail restant

  • FreeBSD démarre sur Firecracker et fonctionne très rapidement
  • Avec les correctifs non intégrés côté FreeBSD et Firecracker, le noyau FreeBSD peut démarrer en moins de 20 ms dans une VM à 1 CPU et 128 Mo de RAM
  • Le travail restant se concentre sur la mise au propre du support PVH et sur la réduction de la configuration du noyau
    • Les correctifs mentionnés ci-dessus doivent être intégrés
    • La prise en charge du mode de boot PVH doit être fusionnée dans la branche principale de Firecracker
    • Le code de démarrage PVH est mêlé au support Xen et doit en être séparé
    • Le noyau FreeBSD arm64 ne peut actuellement pas être compilé sans support PCI ou ACPI ; supprimer ces dépendances incorrectes permettrait de produire un noyau FreeBSD/Firecracker plus petit
    • La vérification de la nécessité d’une réservation mémoire pour les GPU Intel prend 25 µs ; une configuration de noyau plus petite pourrait donc encore réduire le temps de démarrage de quelques microsecondes
  • À plus long terme, il pourrait aussi être envisagé de porter Firecracker pour qu’il s’exécute sur FreeBSD
    • Firecracker a été écrit en supposant l’usage de Linux KVM
    • Il ne semble pas y avoir de raison fondamentale empêchant de l’adapter pour utiliser la partie noyau de l’hyperviseur bhyve de FreeBSD
  • Pour expérimenter, on peut compiler le noyau FreeBSD 14.0 pour amd64 avec la configuration de noyau FIRECRACKER, et utiliser la branche feature/pvh du projet Firecracker
    • Si cette branche n’existe plus, cela signifie que le code a été fusionné dans l’arbre principal de Firecracker

1 commentaires

 
GN⁺ 2023-08-26
Avis de Hacker News
  • Je ne savais pas vraiment que les VM Firecracker n’étaient pas une simple technologie de conteneurs Linux, mais des machines virtuelles complètes.
    Au premier abord, cela peut sembler inefficace, mais quand on regarde des cas d’usage réels comme fly.io, il est étonnant de voir à quel point les micro-VM peuvent être à la fois très petites et suffisamment puissantes.

    • Pour en savoir plus, vous pouvez consulter notre article NSDI'20 (https://www.usenix.org/conference/nsdi20/presentation/agache), qui explique pourquoi nous avons choisi cette voie, ainsi que le code source/la documentation de Firecracker (https://github.com/firecracker-microvm/firecracker).
      Grâce à KVM et à une prise en charge matérielle minimale (pas de PCI, pas d’ACPI, etc.), le code source de Firecracker reste assez simple et relativement lisible même pour des non-spécialistes.
    • Un fournisseur cloud de niveau entreprise comme AWS ne permettrait certainement pas de placer ensemble, dans une même VM, des conteneurs de clients différents sur ECS ou Lambda.
      C’est précisément la raison d’être de Firecracker.
    • Firecracker n’est pas une machine « complète », car beaucoup de choses inutiles pour Lambda et, par coïncidence, pour le cas d’usage de fly.io, ont été retirées.
      ACPI, cité dans l’article, en est un exemple. Cela dit, il virtualise bien le matériel plutôt que le noyau, et son initialisation est tellement rapide que la plupart des utilisateurs ne remarqueraient probablement pas la différence en remplaçant un containerd classique par firecracker-containerd.
    • KVM est impressionnant.
      Outre Firecracker, plusieurs micro-VM comme crosvm, cloud-hypervisor ou Dragonball de Kata sont actuellement développées au-dessus de KVM.
    • Je suis surpris qu’il ne soit pas devenu standard de créer un micro-noyau qui émule un espace utilisateur Linux, ou un espace utilisateur *NIX, adapté au sous-ensemble de matériel virtuel fourni par Firecracker et QEMU.
      Je n’ai pas l’impression qu’implémenter une nouvelle cible pour les langages de programmation soit si difficile ; en créant une cible pseudo-OS du type WASI/WASM et en envoyant des PR aux langages pris en charge, on pourrait probablement supprimer la majeure partie de l’overhead. La partie la plus difficile serait sans doute d’émuler l’espace utilisateur Linux avec suffisamment de précision, mais comme sa surface est très large, la voie d’une cible pseudo-OS semble finalement la meilleure.
  • Quand les correctifs de Colin arriveront dans FreeBSD et Firecracker, le temps de démarrage complet du noyau passera sous les 20 ms.
    Nous vivons vraiment une époque difficile à croire.

    • Je me demande comment cela se compare à Linux sur Firecracker.
      Une recherche rapide donne quelques chiffres, mais ils datent de plusieurs années, et il n’est pas clair que la méthode de mesure du temps de démarrage, ni même la définition de « temps de démarrage », soient les mêmes, donc je ne sais pas si la comparaison est valable.
  • C’est la récente présentation BSDCan de Colin, publiée il y a quelques jours.
    https://youtu.be/MT3cdeuRTzs?si=l6baNriUjcvy0ZOE

    • Pour référence, c’est quasiment le même contenu.
      Après la présentation BSDCan, le FreeBSD Journal lui a demandé : « C’était une bonne présentation, pourriez-vous la transformer en article ? », puis, après la parution de l’article dans le FreeBSD Journal, ;login: a demandé s’il pouvait le republier.
  • qemu dispose d’une machine microvm inspirée de firecracker.
    https://qemu.readthedocs.io/en/latest/system/i386/microvm.ht...

    • Je me demande combien de ces contournements sont nécessaires avec QEMU.
      Bien sûr, certains sont des corrections de bugs FreeBSD, donc ils restent indispensables.
  • Il est intéressant de voir qu’une bonne partie de cette attente d’une seconde s’avère en fait inutile.
    Je me demande combien d’administrateurs système ont réellement pris une mesure pertinente quand le système s’est arrêté à cause d’un UUID machine incorrect.

    • Il y a probablement une proportion assez importante d’administrateurs système ayant rencontré cette attente d’une seconde qui ont fait quelque chose.
      En revanche, le cas « afficher à l’utilisateur un message indiquant qu’on va redémarrer, attendre une seconde pour qu’il puisse lire la console, puis redémarrer » est un peu différent.
  • Sans vouloir paraître condescendant, je me demande à quels cas d’usage correspondent des choses comme les instances Firecracker.
    J’utilise FreeBSD partout, des serveurs en colocation à mon PC personnel, et je suis davantage un vieil administrateur Unix qu’un développeur. Je préfère le bare metal, mais j’accueille favorablement les technologies d’avenir qui contribuent au système d’exploitation. Cela dit, même si j’entends des mots à la mode comme Lambda ou Firecracker, je ne vois pas très bien à quoi ils servent concrètement. Je comprends Docker et les conteneurs, et je comprends à peine k8s, mais je ne vois pas pourquoi il faudrait lancer une VM puis la supprimer aussitôt, alors qu’on peut simplement lancer une VM et l’utiliser quand on en a besoin. Est-ce uniquement une question d’expérience cloud ou de réduction des coûts ?

    • Une instance d’application est créée dans le cadre du cycle de vie requête/réponse.
      Ainsi, n’importe quel nœud du plan de calcul peut traiter le trafic de n’importe quelle application. Une application peut grossir dynamiquement pour consommer les ressources de calcul disponibles du plan en fonction de l’évolution des schémas de trafic, et ne consomme pas de ressources lorsqu’elle ne traite pas de trafic. Augmenter la capacité du plan de calcul revient à mettre davantage de nœuds en ligne. À part gérer beaucoup de déploiements à grande échelle, je ne vois pas vraiment d’autre cas d’usage ; dans un environnement qui n’est pas à « l’échelle », c’est une technologie qui restera cachée sous la frontière du fournisseur.
    • Le principal cas d’usage, ce sont les API utilisées occasionnellement.
      Si vous exploitez un service dont l’API n’est pas appelée souvent, mais qui doit répondre rapidement quand elle l’est, Lambda ou une approche similaire convient bien. En pratique, une bonne partie des API pour applications mobiles entrent dans cette catégorie, et on n’a pas envie de garder une machine inactive 99 % du temps simplement pour répondre à ces appels d’API.
    • « Il suffit de lancer une VM et de l’utiliser quand on en a besoin. Elle est toujours allumée et toujours prête » signifie aussi qu’elle est toujours facturée.
    • Presque toutes les entreprises peuvent bénéficier du scaling, car leur trafic n’est pas constant 24 heures sur 24.
      La plupart ne le font pas parce que l’effort dépasse les économies, mais le potentiel existe. Des choses comme Lambda et Firecracker rendent cela beaucoup plus facile.
  • Il est dommage qu’AWS comme macOS sur ARM ne prennent pas en charge la virtualisation imbriquée.
    Si c’était le cas, développer et déployer des technologies basées sur Firecracker serait beaucoup plus facile.

    • À ma connaissance, on peut faire de la virtualisation sur les instances .metal.
      En fait, la virtualisation est possible sur n’importe quel type d’instance, mais je crois que seules les instances .metal permettent d’utiliser l’accélération matérielle.
    • À noter que l’instance a1.metal d’AWS est assez petite, ce qui la rend raisonnable en coût pour travailler sur des technologies de virtualisation.
  • Firecracker est impressionnant, mais il y a beaucoup de cas particuliers qui mériteraient d’être documentés.
    Un grand merci à Colin Percival d’avoir partagé cela. J’aime particulièrement la phrase « après avoir cueilli tous les fruits à portée de main » : pour Colin, cela désigne les correctifs bus_dma personnalisés. Désormais, tout le monde peut profiter gratuitement de « le noyau FreeBSD démarre en moins de 20 ms avec 1 CPU et 128 Mo de RAM ». Si vous êtes habitué au DevOps avec des clusters k8s ou beaucoup de Docker, c’est vraiment étonnant.

  • J’ai un peu essayé Firecracker : le temps de démarrage est bien conforme aux promesses, mais l’expérience d’utilisation est assez rude.
    Par exemple, après avoir réussi à démarrer et crié victoire, j’ai été refroidi en découvrant qu’il fallait encore suivre un long tutoriel pour mettre en place le réseau.

    • Il y a clairement de la place pour ajouter beaucoup de valeur avec des outils d’automatisation.
      Ce serait vraiment bien de télécharger et lancer un binaire unique qui démarre à la fois une interface web et une API, permette une configuration rapide et télécharge automatiquement ce dont on a besoin.
  • « Un noyau FreeBSD peut démarrer en moins de 20 ms dans une machine virtuelle avec 1 CPU et 128 Mo de RAM »
    Mon Dieu, comment obtenir la même chose sur du vrai matériel, sans VM ? ;)

    • Même sur du vrai matériel, le démarrage du noyau est largement assez rapide, généralement sous la seconde.
      Ce qui est lent, c’est tout le reste. Par exemple, sur ma machine : Startup finished in 14.552s (firmware) + 2.885s (loader) + 741ms (kernel) + 23.116s (initrd) + 11.191s (userspace) = 52.488s.