Stärken des x86 nutzen - aber wie?
-
Zum Teil übertrieben, zum Teil ist es wirklich so, dass wenn man diese Datentypen benutzt und auch noch die Ausrichtung der Variablen im Speicher beeinflusst (mit __attribute__((packed) z.B.), kann die arme 32 Bit CPU nicht anders, als weitere Zyklen einfügen. In PrettyOS kann man sich z.B. die gdt.o mit objdump anschauen:
00000054 <_gdt_install>: 54: 83 ec 10 sub $0x10,%esp 57: 66 c7 05 00 00 00 00 movw $0x2f,0x0 5e: 2f 00 60: c7 05 02 00 00 00 00 movl $0x0,0x2 67: 00 00 00 6a: 66 c7 05 02 00 00 00 movw $0x0,0x2 71: 00 00 73: c6 05 04 00 00 00 00 movb $0x0,0x4 7a: c6 05 07 00 00 00 00 movb $0x0,0x7 81: 66 c7 05 00 00 00 00 movw $0x0,0x0 88: 00 00 8a: c6 05 06 00 00 00 00 movb $0x0,0x6 91: c6 05 05 00 00 00 00 movb $0x0,0x5 98: 66 c7 05 0a 00 00 00 movw $0x0,0xa 9f: 00 00 a1: c6 05 0c 00 00 00 00 movb $0x0,0xc a8: c6 05 0f 00 00 00 00 movb $0x0,0xf af: 66 c7 05 08 00 00 00 movw $0xffff,0x8 ...
Instruktionen mit Prefix 66h (Zeilen 3, 7, 11 usw.) kann man sich als Stolpersteine vorstellen, so was wie "Du, 32 Bit CPU, zieht mal die Handbremse an und mach mal erstmal Kleinkram mit diesem 16 Bit Dings da"
Bezüglich bool bin ich der Meinung, dass es auf der Kernel-Ebene nichts zu suchen hat. bool ist ein abstraktes Ding, wo Informatiker gesagt haben, es sei false oder true. Reale CPU kennt kein false und kein true. CPUs können bei sich nur ein gewisses Zero Flag setzen, was soviel bedeutet wie, Null oder oder ungleich Null. Mehr kann die reale CPU nicht. Deswegen ist es strategisch besser im Code etwas mit Null oder ungleich Null zu vergleichen...
-
Gibt es Messungen, wo die böse 66 zeigt, daß sie langsam macht?
-
Man kann es hier nachlesen: http://www.agner.org/optimize/ pdf Dokumente in "2. Optimizing subroutines in assembly..." und "3. The microarchitecture of Intel..."
Eigene Messungen habe ich keine gemacht...
-
Ja, klar, wir machen alle Felder in der GDT 32 Bits breit. Super Idee.
Spaß beiseite. Ich gehe mal davon aus, dass du meinst, man sollte jeden Eintrag in zwei uint32_t-Einträge aufsplitten. Das wäre natürlich möglich, würde das Verständnis des Codes aber erstens extrem erschweren und zweitens nicht wirklich viel mehr Performance bringen, da die GDT nunmal nur einmal initialisiert wird und einmal ein paar Zyklen gewonnen bringt nicht viel.
-
Dennoch interessanter Punkt, am Beispiel GDT aber nicht nutzbringend verwertbar.
-
Ist ja eigentlisch Schade zu sehen das der gcc es nicht schafft das befüllen der Structs zu optimieren. Immerhin werden schon die Funktionsaufrufe und damit verbundene Berechnungen wegoptimiert und durch Konstanten ersetzt. Da sollte es doch nicht mehr so schwer sein zwei 16 Bit Konstanten zusammenzusetzen und mit einer 32 Bit operation in den Speicher zu schreiben.
Ich habe das auch mal Testweise mit -O3 und ohne packed ausprobiert, da kommt exakt der gleiche Maschinencode bei raus.
Aber noch was zum eigentlichen Thema:
Eine Idee wäre APIC Unterstützung. Das würde auch die Grundlage für Multiprozessor/Multicore Unterstützung legen. Für den Anfang könnte man weitere evtl. vorhandene CPUs/Kerne dann erstmal im Leerlauf lassen um sich nicht grundlegende Probleme zu verkomplizieren. Hatte ich im IRC ja auch schon kurz erwähnt als wir das grob in der Vorlesung behandelt hatten. Die CPU Unterstützung soll wohl schon seit dem Pentium Pro vorhanden sein und kann über cpuid abgefragt werden. Der I/O APIC Teil, der im Chipsatz liegt, soll auf Boards für Einzelprozessorsysteme allerdings erst ab 2000 Standard geworden sein und war vorher nur im höheren Preissegment vorhanden.Ein recht neues Thema wäre Hardwarevirtualisierung. Ich wüsste nicht wie man das Sinnvoll für ein OS (abgesehen von einem Exokernel) nutzen könnte. Außerdem braucht man dafür recht aktuelle Hardware und Emulatoren dürften damit auch noch nicht viel anfangen können.
Ansonsten fällt mir grad nur noch MMX/SSE ein, was aber nur wenig mit dem Betriebsystem zu tun hat. Man braucht eigentlich nur dafür sorgen das die Register beim Prozesswechsel mit gesichert werden. Alles andere ist Sache der Usermode Programme.
-
Tobiking2 schrieb:
Ist ja eigentlisch Schade zu sehen das der gcc es nicht schafft das befüllen der Structs zu optimieren. Immerhin werden schon die Funktionsaufrufe und damit verbundene Berechnungen wegoptimiert und durch Konstanten ersetzt. Da sollte es doch nicht mehr so schwer sein zwei 16 Bit Konstanten zusammenzusetzen und mit einer 32 Bit operation in den Speicher zu schreiben.
gcc ist Open Source, niemand hindert Dich daran, die Sache zu verbessern
-
Tobiking2 schrieb:
Ein recht neues Thema wäre Hardwarevirtualisierung. Ich wüsste nicht wie man das Sinnvoll für ein OS (abgesehen von einem Exokernel) nutzen könnte. Außerdem braucht man dafür recht aktuelle Hardware und Emulatoren dürften damit auch noch nicht viel anfangen können.
Also zumindest qemu kann SVM. Auf AMD-Maschinen kann man es auch mit KVM nutzen (also "verschachtelte" Virtualisierung machen).
-
Nur zur Erläuterung der verwendeten Abkürzungen:
SVM = Secure Virtual Machine http://de.wikipedia.org/wiki/Secure_Virtual_Machine
KVM = Kernel-based Virtual Machine http://de.wikipedia.org/wiki/Kernel-based_Virtual_Machine http://www.linux-kvm.org/page/Main_Page
-
abc.w schrieb:
In PrettyOS kann man sich z.B. die gdt.o mit objdump anschauen:
...
Tobiking2 schrieb:
Ist ja eigentlisch Schade zu sehen das der gcc es nicht schafft das befüllen der Structs zu optimieren.
@beide --> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22141 wenn es euch wirklich ein anliegen ist ...
-
Was 8/16 Bit angeht, bzw. die fast_xx_t Typen, gab es auf der Boost Liste mal ne Diskussion. Ergebnis war wenn ich mich richtig erinnere, dass auf aktuellen x86 CPUs es mittlerweile total wurscht ist, ob man nun 16 Bit oder gleich 32 liest. Bzw. oft sogar besser die kleineren Typen zu verwenden, wenn man damit Platz sparen kann.
-
hustbaer schrieb:
Ergebnis war wenn ich mich richtig erinnere, dass auf aktuellen x86 CPUs es mittlerweile total wurscht ist, ob man nun 16 Bit oder gleich 32 liest. Bzw. oft sogar besser die kleineren Typen zu verwenden, wenn man damit Platz sparen kann.
Das könnte stimmen. Habe neulich aus Neugier eine kleine Testapplikation mit GRUB gebootet, um die Takte fürs 16 und 32 Bit Lesen zu messen. Die Testapplikation war recht primitiv, weil kein Windows und kein Linux, sondern eben "standalone". Die Interrupts wurden gesperrt und in denen Testfunktionen wurde 1 Million mal von einer Adresse gelesen.
Hier das Ergebnis auf meinem Schmierzettel:
1 Mio. mal ein 16 Bit Wort lesen:
1000406
1000472
1000428
1000461
10004061 Mio. mal ein 32 bit Wort lesen:
1000406
1000549
1000461
1000395
1000395Zum Auslesen des Time stamp counters mit drum und dran kostet konstant 407 Takte. D.h. diese 407 Takte muss man noch von jeder der obigen Zahlen abziehen.
Also, für mich sieht es so aus, dass es keinen Unterschied ausmacht.
Ich schäme mich auch ein wenig dafür, was ich oben mit "Handbremse" und so was geschrieben habe.
Das ist ärgerlich. Sobald man selbst anfängt, den Dingen auf den Grund zu gehen, stellt man unerwartet Dinge fest, die nichts mit dem gemeinsam haben, was man irgendwo gelesen hatte o.ä. Auf nichts ist Verlass...
Das Gerüst der Testapplikation habe ich noch, ist übrigens C++ und ein Überbleibsel von meinem Traum, einen C++ Kernel zu schreiben
-
Wie man aber sieht, dauert es genauso lange, ein Word zu lesen wie ein DWord. Das heißt, man kann auch immer gleich DWords lesen.
(Man könnte auch sagen, es dauert genauso lange, zwei Millionen Bytes als Words zu lesen wie vier Millionen Bytes als DWords zu lesen)
Deshalb sollte man offensichtlich immer aufeinanderfolgende Wordzugriffe zu DWordzugriffen zusammenfassen (deinen Ergebnissen nach).