it-swarm.com.de

Warum enthält der Linux-Kernel mehr als 15 Millionen Codezeilen?

Was ist der Inhalt dieser monolithischen Codebasis?

Ich verstehe die Unterstützung, Sicherheit und Virtualisierung der Prozessorarchitektur, kann mir aber nicht vorstellen, dass dies mehr als 600.000 Zeilen sind.

Was sind die historischen und aktuellen Gründe, warum Treiber in der Kernel-Codebasis enthalten sind?

Enthalten diese mehr als 15 Millionen Leitungen jeden einzelnen Treiber für jede Hardware? Wenn ja, stellt sich dann die Frage, warum Treiber in den Kernel eingebettet sind und keine separaten Pakete, die automatisch erkannt und von Hardware-IDs installiert werden.

Ist die Größe der Codebasis ein Problem für Geräte mit Speicher- oder Speicherbeschränkung?

Es scheint, als würde es die Kernelgröße für Geräte mit eingeschränktem Speicherplatz aufblähen ARM Geräte, wenn alles eingebettet wäre. Werden viele Zeilen vom Präprozessor ausgesondert? Nennen Sie mich verrückt, aber ich kann mir keine vorstellen Maschine, die so viel Logik benötigt, um das auszuführen, was ich verstehe, sind die Rollen eines Kernels.

Gibt es Hinweise darauf, dass die Größe in mehr als 50 Jahren ein Problem sein wird, da sie scheinbar ständig wächst?

Das Einbeziehen von Treibern bedeutet, dass es mit der Herstellung der Hardware wächst.

[~ # ~] edit [~ # ~] : Für diejenigen, die denken, dass dies die Natur von Kerneln ist, wurde mir nach einigen Recherchen klar, dass dies nicht immer der Fall ist . Ein Kernel muss nicht so groß sein, da Carnegie Mellons Mikrokernel Mach als Beispiel "normalerweise unter 10.000 Codezeilen" aufgeführt wurde.

111
Jonathan

Treiber werden im Kernel verwaltet. Wenn eine Kerneländerung ein globales Suchen und Ersetzen (oder Suchen und Ändern) für alle Benutzer einer Funktion erfordert, wird dies von der Person durchgeführt, die die Änderung vornimmt. Es ist ein sehr schöner Vorteil, wenn Ihr Treiber von Personen aktualisiert wird, die API-Änderungen vornehmen, anstatt dies selbst tun zu müssen, wenn er nicht auf einem neueren Kernel kompiliert wird.

Die Alternative (was bei Treibern der Fall ist, die außerhalb des Baums gewartet werden) besteht darin, dass der Patch von seinen Betreuern erneut synchronisiert werden muss, um mit den Änderungen Schritt zu halten.

Eine schnelle Suche ergab sich eine Debatte über In-Tree vs. Out-of-Tree Treiberentwicklung.

Die Art und Weise, wie Linux gewartet wird, besteht hauptsächlich darin, alles im Mainline-Repo zu belassen. Das Erstellen kleiner abgespeckter Kernel wird durch Konfigurationsoptionen zur Steuerung von #ifdef Unterstützt. Sie können also absolut winzige, abgespeckte Kernel erstellen, die nur einen winzigen Teil des Codes im gesamten Repo kompilieren.

Die weit verbreitete Verwendung von Linux in eingebetteten Systemen hat zu einer besseren Unterstützung für das Auslassen von Dingen geführt als Linux Jahre zuvor, als der Kernel-Quellbaum kleiner war. Ein Super-Minimal-4.0-Kernel ist wahrscheinlich kleiner als ein Super-Minimal-2.4.0-Kernel.

46
Peter Cordes

Laut cloc gegen 3.13 läuft Linux etwa 12 Millionen Codezeilen.

  • 7 Millionen LOC in Fahrern /
  • 2 Millionen LOC in Arch /
  • nur 139 Tausend LOC im Kernel /

lsmod | wc auf meinem Debian-Laptop werden 158 Module angezeigt, die zur Laufzeit geladen werden. Das dynamische Laden von Modulen ist daher eine häufig verwendete Methode zur Unterstützung von Hardware.

Das robuste Konfigurationssystem (z. B. make menuconfig) wird verwendet, um auszuwählen, welcher Code kompiliert werden soll (und mehr zu Ihrem Punkt, welcher Code nicht kompiliert werden soll). Eingebettete Systeme definieren ihre eigenen .config Datei mit nur der Hardware-Unterstützung, die ihnen wichtig ist (einschließlich der Unterstützung der im Kernel integrierten Hardware oder als ladbare Module).

79
user4443

Für alle Neugierigen gibt es hier die Aufschlüsselung der Zeilenanzahl für den GitHub-Spiegel:

=============================================
    Item           Lines             %
=============================================
  ./usr                 845        0.0042
  ./init              5,739        0.0283
  ./samples           8,758        0.0432
  ./ipc               8,926        0.0440
  ./virt             10,701        0.0527
  ./block            37,845        0.1865
  ./security         74,844        0.3688
  ./crypto           90,327        0.4451
  ./scripts          91,474        0.4507
  ./lib             109,466        0.5394
  ./mm              110,035        0.5422
  ./firmware        129,084        0.6361
  ./tools           232,123        1.1438
  ./kernel          246,369        1.2140
  ./Documentation   569,944        2.8085
  ./include         715,349        3.5250
  ./sound           886,892        4.3703
  ./net             899,167        4.4307
  ./fs            1,179,220        5.8107
  ./Arch          3,398,176       16.7449
  ./drivers      11,488,536       56.6110
=============================================

drivers trägt zu einem Los der Zeilenanzahl bei.

68
user3276552

Die Antworten scheinen bisher "Ja, es gibt viel Code" zu sein und niemand geht die Frage mit der logischsten Antwort an: 15M +? SO WAS? Womit haben 15 Millionen Zeilen Quellcode zu tun Was macht das so unvorstellbar?

Linux macht eindeutig viel. Viel mehr als alles andere ... Aber einige Ihrer Punkte zeigen, dass Sie nicht respektieren, was passiert, wenn es gebaut und verwendet wird.

  • Nicht alles ist kompiliert. Mit dem Kernel-Build-System können Sie schnell Konfigurationen definieren, die Quellcodesätze auswählen. Einige sind experimentell, andere alt, andere werden nicht für jedes System benötigt. Schauen Sie sich /boot/config-$(uname -r) (unter Ubuntu) in make menuconfig An und Sie werden sehen, wie viel ausgeschlossen ist.

    Und das ist eine Desktop-Distribution mit variablem Ziel. Die Konfiguration für ein eingebettetes System würde nur die Dinge einbeziehen, die es benötigt.

  • Nicht alles ist integriert. In meiner Konfiguration sind die meisten Kernel-Funktionen als Module erstellt:

    grep -c '=m' /boot/config-`uname -r`  # 4078
    grep -c '=y' /boot/config-`uname -r`  # 1944
    

    Um klar zu sein, diese könnten alle eingebaut sein ... So wie sie ausgedruckt und zu einem riesigen Papiersandwich verarbeitet werden könnten. Es wäre einfach nicht sinnvoll, wenn Sie nicht einen benutzerdefinierten Build für einen diskreten Hardware-Job ausführen würden (in diesem Fall hätten Sie die Anzahl dieser Elemente bereits begrenzt).

  • Module werden dynamisch geladen. Selbst wenn einem System Tausende von Modulen zur Verfügung stehen, können Sie mit dem System genau die Dinge laden, die Sie benötigen. Vergleichen Sie die Ausgaben von:

    find /lib/modules/$(uname -r)/ -iname '*.ko' | wc -l  # 4291
    lsmod | wc -l                                         # 99
    

    Es wird fast nichts geladen.

  • Mikrokerne sind nicht dasselbe. Nur 10 Sekunden beim Betrachten des führenden Bildes zum Wikipedia-Seite du verknüpft würde hervorheben, dass sie ganz anders gestaltet sind.

    Linux-Treiber werden internalisiert (meistens als dynamisch geladene Module), nicht im Benutzerbereich, und die Dateisysteme sind ähnlich intern. Warum ist das schlimmer als die Verwendung externer Treiber? Warum ist Mikro besser für das allgemeine Rechnen geeignet?


In den Kommentaren wird erneut hervorgehoben, dass Sie es nicht erhalten. Wenn Sie Linux auf diskreter Hardware (z. B. Luft- und Raumfahrt, TiVo, Tablet usw.) bereitstellen möchten , konfigurieren Sie es so, dass nur die Treiber erstellt werden, die Sie benötigen . Sie können dasselbe auf Ihrem Desktop mit make localmodconfig Tun. Am Ende erhalten Sie einen winzigen Kernel-Build ohne Flexibilität.

Für Distributionen wie Ubuntu ist ein einzelnes 40-MB-Kernel-Paket akzeptabel. Nein, schrubben Sie das, es ist tatsächlich vorzuziehen für das massive Archivierungs- und Download-Szenario, bei dem mehr als 4000 schwebende Module als Pakete beibehalten werden. Es benötigt weniger Speicherplatz für sie, ist beim Kompilieren einfacher zu verpacken, einfacher zu speichern und besser für ihre Benutzer (die ein System haben, das einfach funktioniert).

Die Zukunft scheint auch kein Thema zu sein. Die Geschwindigkeit der CPU-Geschwindigkeit, der Festplatten-Dichte/Preisgestaltung und der Bandbreitenverbesserungen scheint viel schneller zu sein als das Wachstum des Kernels. Ein 200-MB-Kernel-Paket in 10 Jahren wäre nicht das Ende der Welt.

Es ist auch keine Einbahnstraße. Code wird rausgeschmissen, wenn er nicht gepflegt wird.

44
Oli

(Linux tinyconfig compiled sources line counttinyconfig Bubble Graph svg (Geige)

Shell-Skript Um den JSON aus dem Kernel-Build zu erstellen, verwenden Sie http://bl.ocks.org/mbostock/4063269


Bearbeiten : Es stellte sich heraus, dass unifdef einige Einschränkungen aufweist (-I Wird ignoriert und -include Nicht unterstützt Letzteres wird verwendet, um den generierten Konfigurationsheader einzuschließen.) An dieser Stelle ändert sich mit cat nicht viel:

274692 total # (was 274686)

skript und Prozedur aktualisiert.


Neben Treibern, Arch usw. wird je nach gewählter Konfiguration viel bedingter Code kompiliert oder nicht, Code nicht unbedingt in dynamisch geladenen Modulen, sondern im Kern integriert.

Also, heruntergeladen Linux-4.1.6-Quellen , wählte die tinyconfig, es aktiviert keine Module und ich weiß ehrlich gesagt nicht, was es aktiviert oder was ein Benutzer kann zur Laufzeit sowieso damit umgehen, den Kernel konfigurieren:

# tinyconfig      - Configure the tiniest possible kernel
make tinyconfig

baute den Kernel

time make V=1 # (should be fast)
#1049168 ./vmlinux (I'm using x86-32 on other Arch the size may be different)

der Kernel-Erstellungsprozess hinterlässt versteckte Dateien mit dem Namen *.cmd. Die Befehlszeile wird auch zum Erstellen von .o - Dateien verwendet, um diese Dateien zu verarbeiten und Ziel- und Abhängigkeiten zu extrahieren. Kopieren Sie script.sh unten und verwenden Sie sie mit find:

find -name "*.cmd" -exec sh script.sh "{}" \;

dadurch wird eine Kopie für jede Abhängigkeit des Ziels .o mit dem Namen .o.c erstellt.

. c Code

find -name "*.o.c" | grep -v "/scripts/" | xargs wc -l | sort -n
...
   8285 ./kernel/sched/fair.o.c
   8381 ./kernel/sched/core.o.c
   9083 ./kernel/events/core.o.c
 274692 total

. h Header (bereinigt)

make headers_install INSTALL_HDR_PATH=/tmp/test-hdr
find /tmp/test-hdr/ -name "*.h" | xargs wc -l
...
  1401 /tmp/test-hdr/include/linux/ethtool.h
  2195 /tmp/test-hdr/include/linux/videodev2.h
  4588 /tmp/test-hdr/include/linux/nl80211.h
112445 total
19
Alex

Die Kompromisse zwischen monolithischen Kernen wurden von Anfang an öffentlich zwischen Tananbaum und Torvalds diskutiert. Wenn Sie nicht für alles in den Benutzerbereich wechseln müssen, kann die Schnittstelle zum Kernel einfacher sein. Wenn der Kernel monolithisch ist, kann er intern optimiert (und chaotischer!) Werden.

Wir haben Module schon seit einiger Zeit als Kompromiss. Und es geht weiter mit Dingen wie DPDK (mehr Netzwerkfunktionen aus dem Kernel entfernen). Je mehr Kerne hinzugefügt werden, desto wichtiger ist es, ein Sperren zu vermeiden. Dadurch werden mehr Dinge in den Benutzerbereich verschoben und der Kernel wird verkleinert.

Beachten Sie, dass monolithische Kernel nicht die einzige Lösung sind. Bei einigen Architekturen ist die Kernel/Userspace-Grenze nicht teurer als jeder andere Funktionsaufruf, wodurch Mikrokerne attraktiv werden.

9
Rob