Um die Leistungsfähigkeit der ersten Version unserer Linux-Implementation
auf dem Mikrokern L4 bewerten zu können, führten wir
ein frei verfügbares Benchmark-Programm
aus. Für eine genauere Analyse der Leistung der Linux-Portierung
und eine Optimierung anhand der hier beschriebenen Resultate fanden
wir jedoch bisher wenig Zeit. 5.1 Testumgebung
Wir verwendeten für unsere Tests einen Rechner mit einem Pentium-Prozessor (100 MHz), 32 MB Hauptspeicher, NE2000-Netzwerkkarte, BusLogic-SCSI-Controller und einer SCSI-Festplatte. Das Heimatverzeichnis war jeweils über NFS eingebunden.
Als Benchmarkprogramme benutzen wir das frei verfügbare Benchmark-Paket Lmbench [24].
Wir führten die Benchmarks auf der selben Maschine jeweils mehrmals
unter Linux/i386 und Linux/L4 aus und verglichen dann die Resultate. 5.2 Meßergebnisse
Lmbench ist ein Benchmark-Paket, das von Larry McVoy entwickelt wurde. Es enthält im wesentlichen ,,Microbenchmarks'', die einzelne Subsysteme des Betriebssystems testen und messen. [24]
Wir führten jeweils drei Messungen mit Linux/i386 bzw. Linux/L4 aus. Auf den folgenden beiden Seiten sind die mit bei diesen Durchläufen erzielten Meßzeiten zu finden: die nächste Seite enthält die absoluten Meßzeiten, die darauffolgende Seite setzt die gemessenen Zeiten miteinander ins Verhältnis.
Die ersten drei Zeilen jeder Tabelle zeigen unter Linux/i386 erzielten Zeiten, die letzten drei die unter Linux/L4 erzielten.
L M B E N C H 1 . 0 S U M M A R Y ------------------------------------ Processor, Processes - times in microseconds -------------------------------------------- Host OS Mhz Null Null Simple /bin/sh Mmap 2-proc 8-proc Syscall Process Process Process lat ctxsw ctxsw --------- ------------- ---- ------- ------- ------- ------- ---- ------ ------ carola Linux 2.0.0 100 3 2K 12K 73K 239 11 18 carola.1 Linux 2.0.0 100 3 2K 12K 73K 231 11 18 carola.2 Linux 2.0.0 100 3 2K 12K 72K 229 10 19 carola.3 Linux 1.3.94 105 56 16K 39K 143K 518 111 137 carola.4 Linux 1.3.94 105 48 15K 37K 131K 516 92 107 carola.5 Linux 1.3.94 100 51 14K 37K 129K 510 96 106 *Local* Communication latencies in microseconds ----------------------------------------------- Host OS Pipe UDP RPC/ TCP RPC/ UDP TCP --------- ------------- ------- ------- ------- ------- ------- carola Linux 2.0.0 49 213 499 300 669 carola.1 Linux 2.0.0 48 216 489 322 716 carola.2 Linux 2.0.0 45 213 512 315 690 carola.3 Linux 1.3.94 442 891 1480 1104 1926 carola.4 Linux 1.3.94 375 792 1341 979 1735 carola.5 Linux 1.3.94 388 775 1309 962 1734 *Local* Communication bandwidths in megabytes/second ---------------------------------------------------- Host OS Pipe TCP File Mmap Bcopy Bcopy Mem Mem reread reread (libc) (hand) read write --------- ------------- ---- ---- ------ ------ ------ ------ ---- ----- carola Linux 2.0.0 22 9 22 51 23 22 62 35 carola.1 Linux 2.0.0 22 10 22 50 23 22 62 35 carola.2 Linux 2.0.0 22 10 22 51 23 22 62 35 carola.3 Linux 1.3.94 9 8 21 21 20 21 60 35 carola.4 Linux 1.3.94 10 8 17 23 22 21 61 35 carola.5 Linux 1.3.94 10 7 17 25 22 21 61 35 Memory latencies in nanoseconds (WARNING - may not be correct, check graphs) -------------------------------------------- Host OS Mhz L1 $ L2 $ Main mem Guesses --------- ------------- --- ---- ---- -------- ------- carola Linux 2.0.0 99 10 190 316 carola.1 Linux 2.0.0 99 10 196 316 carola.2 Linux 2.0.0 99 10 223 316 carola.3 Linux 1.3.94 104 - - - Bad mhz? carola.4 Linux 1.3.94 104 - - - Bad mhz? carola.5 Linux 1.3.94 99 0 188 312
L M B E N C H 1 . 0 S U M M A R Y ------------------------------------ Comparison to best of the breed ------------------------------- (Best numbers are starred, i.e., *123) Processor, Processes - factor slower than the best -------------------------------------------------- Host OS Mhz Null Null Simple /bin/sh Mmap 2-proc 8-proc Syscall Process Process Process lat ctxsw ctxsw --------- ------------- ---- ------- ------- ------- ------- ---- ------ ------ carola Linux 2.0.0 100 *3 1.0 1.0 1.0 1.0 1.1 *18 carola.1 Linux 2.0.0 100 *3 *1.8K *12.0K 1.0 1.0 1.1 *18 carola.2 Linux 2.0.0 100 *3 1.0 1.0 *70.6K *229 *10 1.1 carola.3 Linux 1.3.94 105 19 8.7 3.2 2.0 2.3 11 7.6 carola.4 Linux 1.3.94 105 16 7.7 3.0 1.8 2.3 9.2 5.9 carola.5 Linux 1.3.94 100 17 7.4 3.0 1.8 2.2 9.6 5.9 *Local* Communication latencies - factor slower than the best ------------------------------------------------------------- Host OS Pipe UDP RPC/ TCP RPC/ UDP TCP --------- ------------- ------- ------- ------- ------- ------- carola Linux 2.0.0 1.1 *213 1.0 *300 *669 carola.1 Linux 2.0.0 1.1 1.0 *489 1.1 1.1 carola.2 Linux 2.0.0 *45 *213 1.0 1.1 1.0 carola.3 Linux 1.3.94 9.8 4.2 3.0 3.7 2.9 carola.4 Linux 1.3.94 8.3 3.7 2.7 3.3 2.6 carola.5 Linux 1.3.94 8.6 3.6 2.7 3.2 2.6 *Local* Communication bandwidths - percentage of the best --------------------------------------------------------- Host OS Pipe TCP File Mmap Bcopy Bcopy Mem Mem reread reread (libc) (hand) read write --------- ------------- ---- ---- ------ ------ ------ ------ ---- ----- carola Linux 2.0.0 *22 96% 98% 99% 99% 99% 99% 99% carola.1 Linux 2.0.0 99% *9 99% 98% 99% *21 *61 *35 carola.2 Linux 2.0.0 98% 99% *22 *51 *22 99% 99% 99% carola.3 Linux 1.3.94 38% 77% 92% 41% 86% 97% 97% 98% carola.4 Linux 1.3.94 44% 79% 77% 44% 98% 97% 98% 97% carola.5 Linux 1.3.94 44% 75% 77% 48% 98% 98% 97% 98% Memory latencies in nanoseconds - factor slower than the best (WARNING - may not be correct, check graphs) ------------------------------------------------------------- Host OS Mhz L1 $ L2 $ Main mem Guesses --------- ------------- --- ---- ---- -------- ------- carola Linux 2.0.0 99 -5.0 1.0 1.0 carola.1 Linux 2.0.0 99 -5.0 1.0 1.0 carola.2 Linux 2.0.0 99 -5.0 1.2 1.0 carola.3 Linux 1.3.94 104 - - - Bad mhz? carola.4 Linux 1.3.94 104 - - - Bad mhz? carola.5 Linux 1.3.94 99 ??? *188 1.0
5.3 Interpretation der Meßergebnisse
Auf den ersten Blick fällt auf, daß unter der Linux-Emulation auf L4 gegenüber Linux/i386 die Durchsätze auf 44-99% sinken und die Latenzzeiten auf das 1,8-19-fache steigen. In Absolutwerten heißt das etwa, daß Systemrufe ca. 50 s länger dauern oder daß Pipes nur 10 MB/s Durchsatz erreichen statt 22 MB/s (um die beiden extremsten Beispiele herauszugreifen).
Diese Ergebnisse mögen etwas entmutigend erscheinen; wir glauben jedoch, daß diese Werte für eine erste, unoptimierte Version durchaus innerhalb der zu erwartenden Grenzen liegen. Es soll auch nicht übersehen werden, daß wichtige Meßergebnisse wie TCP- und Dateisystem-Durchsatz im brauchbaren Bereich liegen, was den subjektiven Eindruck bestätigt, daß Linux/L4 im praktischen Betrieb nicht spürbar langsamer ist als Linux/i386.
Im folgenden gehen wir auf einzelne Meßergebnisse ein und stellen Vermutungen an, wie sie zustande kamen. Leider hatten wir aus Zeitgründen noch keine Möglichkeit, diese Hypothesen zu überprüfen; dies muß jedoch im Anschluß an diese Arbeit geschehen.
Neben den stets auftretenden Extra-Kosten für das Abfangen der Ausnahme auf Nutzerseite sind überflüssige L4-Systemaufrufe eine mögliche Senke für die zusätzlich benötigte Zeit. Jean Wolter fand heraus, daß bei jedem Systemruf bestenfalls mindestens 8 Systemrufe l4_myself() stattfinden (Erfragen der Thread-ID des ausführenden Threads) [25]. Setzt man die Dauer für einen L4-Systemruf bei etwa 1,5 s an [22], so tragen allein diese 8 Systemrufe für 12 s der Systemaufrufzeit bei.
Die l4_myself()-Systemrufe lassen sich leicht einsparen - man kann die Thread-IDs der Threads auf ihrem privaten Stack ablegen und eine Inline-Funktion schreiben, die mit Hilfe des aktuellen Stack-Pointers die Thread-ID ermittelt.
Ein Problem beim Einblenden von Speicher in eine Applikation ist, daß momentan für jede mmap()-Operation die Kern-Task zweimal betreten werden muß: Einmal für den eigentlichen Systemruf, der die Seitentabellen entsprechend manipuliert, und ein zweites Mal, wenn der erste Seitenfehler in der manipulierten Region eintritt. Die Ursache ist, daß die Manipulation der Seitentabellen unter L4 nicht automatisch die Seiten in die Nutzer-Task einblendet.
Dies würde auch teilweise das schlechtere Abschneiden beim ,,Mmap reread''-Benchmark (Einblenden bereits im Haupspeicher zwischengespeicherter Seiten) und bei der Prozeßerzeugung erklären.
Eine mögliche Abhilfe wäre hier, bei Systemrufen, die Seiten in den Speicher einblenden, beim Senden der Systemruf-Antwort stets die eingeblendeten Seiten als Flexpages mitzusenden.