Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: erik.vikinger am 22. April 2010, 20:53
-
Hallo,
ich möchte hier mal ein Konzept für periodische Events vorstellen. Dieses habe ich selber schon mal implementiert und war damit recht zufrieden. Falls jemand bessere Vorschläge oder Fragen hat dann sind die hier natürlich gern gesehen.
Für periodisch auszulösende Events benötigt man natürlich einen passenden Timer der genau und monoton läuft. Da der klassische PIT nur mit einer festgelegten Frequenz IRQs generieren kann ohne von der CPU ständig neu konfiguriert zu werden fällt dieser als alleinige Basis aus. Man kann diesen aber auf z.B. 1kHz programmieren und den eigentlichen Zähler und die zugehörigen Comparators in SW implementieren, man verliert damit nicht an Langzeitgenauigkeit sondern bekommt nur einen höheren Jitter und eine kleinere zeitliche Auflösung (z.B. der HPET arbeitet normalerweise mit einigen MHz).
Der Einfachheit halber bleibe ich erst mal bei der PIT-Variante:
Man programmiert ihn eben auf 1kHz und lässt sich so jede ms einen IRQ generieren. Im IRQ-Handler zählt man einen simplen Counter nach oben, dafür sollte man gleich einen 64Bit-Wert nehmen um nicht zu schnell mit Überläufen hantieren zu müssen (welche ein ordentlicher Programmierer natürlich trotzdem berücksichtigt, auch wenn ein 64Bit-Zähler bei 1kHz erst in etwa 600 Millionen Jahren überläuft und der verantwortliche Programmierer bis da hin bestimmt was besseres macht), und schaut nach ob irgendwas gemacht werden muss also ob der aktuelle Zählerwert dem nächsten Event-Zeitpunkt entspricht.
Den Zählerwert verarbeitet man im OS-Kernel am besten so wie er ist als allgemeine absolute Zeitbasis. Wenn nun ein Programm einen periodischen Event beantragt, ich gehe jetzt mal von 64 Hz aus, dann schaut der SYSCALL-Handler nach dem aktuellem Zählerstand und vermerkt diesen als Zeit-Basis, als nächstes wird die nächste absolute Event-Zeit des ersten Events errechnet, in diesem Fall also von X+15.625s, was gerundet dann X+16ms ergibt. Beim Zählerwert X+16 generiert dann der IRQ-Handler einen Event (beim HPET wäre das dann erst ein IRQ, das zählen und vergleichen wird dort in Hardware erledigt) und errechnet vorher noch den nächsten absoluten Zählerwert für den nächsten Event welcher bei X+31.25ms liegt und zu X+32ms gerundet wird. Das Spiel geht dann immer so weiter und man bekommt einen periodischen Event welcher mit exakt 64Hz aber bis zu 1ms Jitter getriggert wird.
Das es wirklich exakt 64 Hz (mit einer durchschnittlichen Periodenlänge von exakt 15.625ms) sind ergibt sich aus folgender Liste:
- 1. Event: X+15.625ms wird zu X+16ms : also Periode gegenüber letztem Event : 16ms (okay, das zählt nicht weil es bei der Erstellung keinen Event gab)
- 2. Event: X+31.25ms wird zu X+32ms : also Periode gegenüber letztem Event : 16ms
- 3. Event: X+46.875ms wird zu X+47ms : also Periode gegenüber letztem Event : 15ms
- 4. Event: X+62.5ms wird zu X+63ms : also Periode gegenüber letztem Event : 16ms
- 5. Event: X+78.175ms wird zu X+79ms : also Periode gegenüber letztem Event : 16ms
- 6. Event: X+93.75ms wird zu X+94ms : also Periode gegenüber letztem Event : 15ms
- 7. Event: X+109.375ms wird zu X+110ms : also Periode gegenüber letztem Event : 16ms
- 8. Event: X+125.0ms wird zu X+125ms : also Periode gegenüber letztem Event : 15ms
- 9. Event: X+140.625ms wird zu X+141ms : also Periode gegenüber letztem Event : 16ms
Wie bestimmt schon aufgefallen ist hat hier jeder 8te Event eine glatte errechnete Zeit, das ist ein guter Zeitpunt um X im Event-Descriptor (die Datenstruktur im OS welche diesen periodischen Event beschreibt) auf X+125 zu setzen damit man auf lange Sicht kein Überlaufproblem mit dem rechnen bekommt. Beim erstellen von Events sollte der OS-Kernel also die gewünschte Frequenz so hinrechnen das eine vertretbare Häufigkeit von solchen Übereinstimmungen entsteht. Also genau 30 Hz geht so nicht, aber ganz sicher werden 29.99999******Hz oder 30.00000******Hz was gutes ergeben. Damit muss die Applikation auf einem Computer der nur mit endlicher Genauigkeit rechnen kann eben leben. Wie man diesen Wert intern darstellt bleibt den Fähigkeiten des OS-Programmierers überlassen, ich würde vorschlagen als Periodenlänge mit zusätzlichen 32 Nachkommabits (damit ergibt sich automatisch eine glatte Übereinstimmung nach gut 4 Milliarden Events), das hat den Vorteil das man nicht mit Gleitkommazahlen hantieren muss (der Grund dieses Vorteils sollte offensichtlich sein).
Die errechneten absoluten Event-Zeitpunkte trägt man in eine geordnete Liste ein welche dann vom IRQ-Handler für die Vergleiche benutzt wird. Damit lassen sich auch beliebig viele solcher periodischen Events (mit unabhängigen Frequenzen) verwalten und auch die einmaligen Events kann man dort problemlos eintragen. Damit das einsortieren möglichst schnell geht habe ich dafür einen Baum benutzt, das Element unten rechts war der nächste Timer der abläuft. Die absoluten Zeiten muss man natürlich in Relation zum aktuellen Timer-Zählerwert als quasi Vorzeichenbehaftet betrachten. Hinter der ganzen Mathematick stecken an einigen Stellen ein paar Tricks aber da ist nichts wovor ein geübter Programmierer Angst haben muss.
Wenn man dazu den HPET verwendet, was auf jeden Fall zu empfehlen ist, dann bekommt man nicht ständig IRQs sondern nur dann wenn wieder ein Event dran ist, dazu trägt der IRQ-Handler immer die nächste Event-Zeit in das/die Comparator-Register des HPET ein. Hier muss man beachten das man beim Eintragen prüfen sollte ob der gewünschte Zeitpunkt für den Counter noch in der Zukunft liegt und nicht zwischenzeitlich schon überzählt wurde (der Comparator im HPET prüft nur auf Gleichheit, in SW kann man das etwas besser lösen), sonst wartet man bis der Counter im HPET ein mal komplett umgelaufen ist (was bei einem 64Bit Counter selbst mit extrem hoher Frequenz sehr lange dauern kann). Der HPET-IRQ-Handler muss also möglicherweise mehrere Event auslösen (wenn deren Zeitpunkte dicht bei einander liegen).
So, ich hoffe ich hab nichts wichtiges vergessen.
Falls jemand Fragen hat dann nur zu.
Grüße
Erik
-
Um es mal kurz zu machen, ich bin eher für einen One-Shot-Timer.
Der Linux-Kernel hatte mal den Timer (unter anderem zuständig für den Scheduler) auf 1000Hz=1ms gestellt und die sind ganz schnell wieder zurück gerudert. Einmal wegen des höheren Stromverbrauchs. Denn der Timer läuft auch, wenn der PC eigentlich gar nichts zu tun hat.
Dann kommt noch der ganze Overhead für einen IRQ, alle 1ms!!!, dazu. Das ist nicht gerade wenig.
Zumal man nicht alle Probleme mit so einem Timer erschlagen kann. Was ist mit den Events die weniger als 1ms (was ich als CPU so ziemlich lange finde) "warten" wollen?
Ich habe das in meinem OS, wie gesagt, über den One-Shot Modus gelöst. Hat den Vorteil, das wenn der Computer nichts macht, auch kein Timer einen IRQ feuert (es sei denn es ist ein Event was ausgelöst werden will). Desweiteren hat der laufende Thread so effektiv mehr Zeit. Selbst wenn man jetzt nicht den PIT auch noch für den Scheduler nutzt, sondern den APIC, dann wird der Thread alle 1ms unterbrochen. Wenn man dann auch noch den APIC periodisch nutzt und sagen wir mal der feuert alle 10ms und der Thread darf 60ms laufen, dann wird er nochmals zusätzlich alle 10ms unterbrochen.
Ich behaupte mal das dieser Overhead größer ist, als die Zeit dir benötigt wird um den Timer im One-Shot-Modus zu betreiben. Ich weiß das gerade der PIT sehr sehr sehr langsam ist, aber selbst das sollte sich mit der Zeit rechnen.
Der HPET ist natürlich eine sehr feine Sache, aber halt nicht auf allen PCs verfügbar. Gut, wer anfängt ein OS zu programmieren, der sollte vielleicht auf "Altlasten" wie den PIT verzichten, aber das wift sogar Athlon XP Systeme mit raus (ich hatte selbst so eins, wo der APIC deaktiviert war). Ich programmiere aber halt auch für alte System, wo es nur den PIT gibt. Meine Lösung muss das also auch beinhalten. Wenn ich dann auch mal die Möglichkeit habe den HPET zu testen (habe nur einen PC wo der ist, auf meinem Laptop bin ich mir nicht sicher), aber wenn ich mich recht entsinne, braucht man dafür ACPI (nicht nur das parsen statischer Tabellen, sondern ausführen von deren Sprache) und das sollte für fast alle Hobby-OSs wegfallen.
Also um es zusammen zu fassen, meine Argumente dagegen wären der Overhead, Events < 1ms sind nicht möglich und der HPET ist dann doch etwas zu neu und (hier lasse ich mich gerne korregieren, dann kann ich nämlich auch endlich anfangen diesen zu programmieren) man braucht eine laufende (Interpreter) ACPI Umgebung.
-
Hallo,
der One-Shot-Modus hat die beschriebenen Vorteile und ist im Linux-Kernel inzwischen auch Standard ("tickless system"). Das war aber sehr lange nicht so und der Overhead für einen simplen IRQ ist auf einem langsamen System nicht so schlimm, wie man vermutet. Vor allem, wenn die Echtzeituhr des Systems nicht besonders viel taugt - besonders langsame Systeme leiden unter schlechten RTCs - hat man mit einem 100 Hz-PIC wenigstens eine konstante, streng monotone Zeitquelle.
Mit der SMP-Unterstützung fiel die IRQ-Last dann doch auf, besonders auf sehr großen Systemen, wo dann die Jiffies unabhängig von den Ticks eingeführt wurden (Kernel 2.6) - und erst später wurde tickless eingeführt. Linux <=2.4 nutzt 100 Hz-Ticks (x86), Alpha z.B. schon immer 1024 Hz.
Soweit ich weiß, nutzt Windows ebenfalls einen periodisch aufgerufenen IRQ (für GetTickCount und darauf beruhende).
Tickless (One-Shot) ist besser, aber regelmäßig ist einfacher und - sofern der Overhead möglichst reduziert wird - nicht wirklich langsamer.
Gruß,
Svenska
-
Hallo,
das der PIT einen enormen Overhead + Energieverbrauch erzeugt ist natürlich richtig und ein echter Nachteil dieser Variante, den hab ich damals auch nicht benutzt. Ich wollte nur die prinzipielle Funktionsweise dieses Konzepts erklären. Der HPET ist definitiv die bessere Methode und erlaubt auch eine deutlich feinere zeitliche Auflösung. Der PIT hat früher mal die 18,??Hz generiert aber für deutlich höhere Frequenzen ist das PIT-Konzept wirklich nicht geeignet.
Im Wiki-Artikel über den HPET ist ein Link auf die Spec enthalten. Da drin ist erklärt wie man den HPET in den ACPI-Tabellen findet, zum betreiben benötigt man kein ACPI.
Kontext-Switches sollte man über die enthaltenden Timer in den Local-APICs machen, so wird genau die CPU unterbrochen bei welcher auch wirklich die Zeitscheibe abgelaufen ist. Ich gehe mal von SMP als zukünftigen Normalfall aus.
Mal abgesehen vom PIT, ist den mein Konzept Eurer Meinung nach gut?
Grüße
Erik
-
...hat man mit einem 100 Hz-PIC wenigstens eine konstante, streng monotone Zeitquelle.
Bitte PIT, da ansonsten Verwirrung gestiftet wird ;)
Tickless (One-Shot) ist besser, aber regelmäßig ist einfacher und - sofern der Overhead möglichst reduziert wird - nicht wirklich langsamer.
Naja, ob ein regelmäßiger Timer einfacher ist bezweifle ich jetzt mal. Denn das war ja ein wichtiger Grund den nicht zu nehmen. Ich meine du hast nur den PIT (oder meinet wegen noch den APIC) und um das System nicht alzu sehr zu belasten hast du ne Frequenz von 100Hz. Wie willst du ne Zeit von 35ms warten (oder 16.666...ms für 60Hz, was man dann doch öfters braucht)? Den PIT mit einer Frequenz von 1000hz zu betreiben ist bestimmt nicht sonderlich toll. Da wird der Thread ja 59mal (bei einer Laufzeit von 60ms) sinnlos unterbrochen und das dann obwohl nicht mal ein Event wartet.
Mein größtes Problem ist es halt eine Art Counter auf allen Systemen (PIT und APIC) zu bekommen. Sicher die Methode mit den Events (erik weiß wovon ich spreche) ist da besser, aber selbst da gibt es bei unschönen Zahlen doch arge Probleme. Zumal in dem Fall noch das umdenken beim Programmieren dazu kommt, aber dafür lebt ja der Programmierer ;)
@erik
Du warst mit deiner Antwort schneller als ich ;)
Mal abgesehen vom PIT, ist den mein Konzept Eurer Meinung nach gut?
Wenn du nur den HPET nimmst, dann ist das System gut und sollte doch etwa der One-Shot Methode gleichen, aber wenn du keinen HPET hast, find ich den periodischen Timer wie gesagt eher ungünstig.
Kontext-Switches sollte man über die enthaltenden Timer in den Local-APICs machen, so wird genau die CPU unterbrochen bei welcher auch wirklich die Zeitscheibe abgelaufen ist. Ich gehe mal von SMP als zukünftigen Normalfall aus.
Tja und ich will nunmal mein OS auch auf (oder besser vorallem darauf) alten System laufen lassen. Auch wenn die CPU nen APIC hat, ist dieser meistens deaktiviert und ich kann ihn nicht nutzen, bin also auf den PIT beschränkt und da das sogar noch für P3 Systeme zutreffen kann (welche von der Leistung her, dem ATOM entsprechen sollten, wenn nicht sogar schneller) find ich das Thema noch halbwegs aktuell.
Dann kommen noch die ganzen embedded Systems dazu, welche meist auf älterer schwächerer Hardware aufbauen (mehr brauchen die auch einfach nicht) und du hast wieder nur den doofen PIT.
Im Wiki-Artikel über den HPET ist ein Link auf die Spec enthalten. Da drin ist erklärt wie man den HPET in den ACPI-Tabellen findet, zum betreiben benötigt man kein ACPI.
Das klingt doch sehr toll! Ich habe das Dokument zum HPET zwar schon, aber beim schnellen überfliegen konnte ich nichts finden, in welchen Tabellen das drin stehen soll, aber ich werds mir noch mal angucken!
Um nochmal auf deine periodischen Events zurück zu kommen. Ich würde diese trotzdem auf Basis eines One-Shot-Timers umsetzen. Also wenn es abgelaufen ist, den Event auslösen und wieder an die richtige Position in der Queue, aber der Timer sollte nur ausgelöst werden, wenn auch wirklich ein Event ausgelöst werden soll. Denn wie gesagt, gerade bei nem PC der gerade nichts macht (und das macht er bekanntlich am meisten ;) ) wäre mir der Overhead eines periodischen Timers einfach zu groß!
Edit::
@erik
Ich bin inzwischen echt am Überlegen, ob ich mein Konzeot mit dem Counter (um ganz geringe Zeiten zu "überbrücken") zugunsten eines periodischen Events zu ersetzen. Nur weiß ich halt nicht wie ich die eigentlich Events umsetzen soll. Ich meine wenn ich ne einfache Schleife mache, die mir mit Hilfe eines Counters sagen wir 2µs wartet, wie soll ich das dann mit nem Event machen. Ich finde es halt umständlich auf irgendein Event zu warten (weil ich halt nicht weiß, wie ich es umsetzen soll).
-
Hallo,
Der PIT im One-Shot-Modus ist aber keine streng monotone Zeitquelle, also für präzises Timing definitiv unbrauchbar. Ab einer bestimmten Anforderung an Präzision geht es erst mit den HPET, dafür wurde er ja schließlich eingeführt.
Das er in vielen nicht ganz so frischen PCs nicht vorhanden ist ist mal wieder ein Grund dafür warum ich x86 Scheiße finde, so wichtige Dinge erst dann zu implementieren wenn es nicht mehr anders geht ist einfach zu typisch für diese Plattform. Deshalb will ich ja unbedingt was eigenes/besseres. Wenn man sich auf x86 festlegt muss man eben unangenehme Kompromisse eingehen, Mitleid gibt es dafür von mir auf jeden Fall nicht. :-D
Grüße
Erik
-
Der PIT im One-Shot-Modus ist aber keine streng monotone Zeitquelle, also für präzises Timing definitiv unbrauchbar. Ab einer bestimmten Anforderung an Präzision geht es erst mit den HPET, dafür wurde er ja schließlich eingeführt.
Das er in vielen nicht ganz so frischen PCs nicht vorhanden ist ist mal wieder ein Grund dafür warum ich x86 Scheiße finde, so wichtige Dinge erst dann zu implementieren wenn es nicht mehr anders geht ist einfach zu typisch für diese Plattform. Deshalb will ich ja unbedingt was eigenes/besseres. Wenn man sich auf x86 festlegt muss man eben unangenehme Kompromisse eingehen, Mitleid gibt es dafür von mir auf jeden Fall nicht. grin
Ich verlang ja auch gar kein Mitleid, aber Hilfe beim Leben mit solchen Sachen ;)
Außerdem wo bleibt der Spaß, wenn man nicht solche "netten" Probleme hätte.
Ich finde mit dem APIC kann man schon ziemlich genau timen (ich habe den Overhead zum setzen eines neuen Zählwerts des APIC Timers noch nicht getestet, aber der dürfte ziemlich gering sein).
Ich habe mir schon über legt die Zeit die fürs Lesen/Schreiben beim PIT draufgeht, einfach mit drauf zu rechnen (1. kenn ich diese Zeit genau und 2. ist mein Counter dann auch ziemlich genau!).
-
Tickless (One-Shot) ist besser, aber regelmäßig ist einfacher und - sofern der Overhead möglichst reduziert wird - nicht wirklich langsamer.
Naja, ob ein regelmäßiger Timer einfacher ist bezweifle ich jetzt mal. Denn das war ja ein wichtiger Grund den nicht zu nehmen. Ich meine du hast nur den PIT (oder meinet wegen noch den APIC) und um das System nicht alzu sehr zu belasten hast du ne Frequenz von 100Hz. Wie willst du ne Zeit von 35ms warten (oder 16.666...ms für 60Hz, was man dann doch öfters braucht)? Den PIT mit einer Frequenz von 1000hz zu betreiben ist bestimmt nicht sonderlich toll. Da wird der Thread ja 59mal (bei einer Laufzeit von 60ms) sinnlos unterbrochen und das dann obwohl nicht mal ein Event wartet.
Da hast du Recht, aber dafür ist der PIT ja auch garnicht da... :-) Es gibt viele Ereignisse, die länger benötigen (sei es die halbsekünde Anzeige der CPU-Auslastung), und das Teil ist dann immernoch genauer als manche RTC. Kann man eigentlich One-Shot und kontinuierlichen Modus kombinieren? Dann könntest du kürzere Intervalle besser realisieren.
Ich halte eine Event-Warteschlange für die regelmäßigen, nicht Echtzeit bedürfenden Ereignisse für sinnvoll und einfach, außerdem ist der (PIT-)Overhead konstant. Im One-Shot-Modus ist der abhängig von der Anzahl der Events.
Der Linux-PIT war z.B. auch für 250 Hz oder 300 Hz konfigurierbar, um Videobearbeitung auf NTSC oder PAL damit besser zu ermöglichen. So ähnlich kann man das ja auch gestalten, um den Jitter etwas zu verringern.
Gruß,
Svenska
-
Da hast du Recht, aber dafür ist der PIT ja auch garnicht da...
Dem halte ich wieder entgegen, was machst du wenn du nur den PIT hast? Die RTC kannst du knicken, ich weiß nicht mal ob die nen One-Shot-Modus hätte und ansonsten kann die auch nur 2er-Potenzen an Frequenzen.
Da fällt mir doch glatt ein Bsp ein, wo ich dran gescheitert bin mit einem periodischem Timer.
Ein Thread gibt ab und zwar irgendwo zw. 2 PIT Interrupts. Wie wollt ihr da sichern das der neue Thread auch wirklich seine Zeit verbraten darf, die ihm zusteht? Wie wollt ihr dann ausrechnen wie lange der Thread gelaufen ist (was ein generelles Problem ist und erstmal rein gar nichts mit dem periodischem Timer zu tun hat) oder wie lange er im Kernel oder im Userspace war?
Eine Lösung wäre jetzt, da wo man nur den PIT hat, sollte man den TSC nutzen können (obwohl ich mir da auf Laptop CPUs nicht sicher bin, wenn die sich runter takten wird ja die TSC Frequenz geändert) und wenn ihr nen APIC habt, reicht der dafür vollkommen aus.
Ich überlege schon die ganze Zeit wie ich die Zeit. die durch das Lesen/Schreiben des PITs entsteht, in meine Zeit Berechnungen mit einbeziehen kann. Das einzigste was dann noch nen Jitter verursacht ist die Zeit die mein Scheduler verbrät, wenn er nen neuen Thread aussucht.
-
Ein Thread gibt ab und zwar irgendwo zw. 2 PIT Interrupts. Wie wollt ihr da sichern das der neue Thread auch wirklich seine Zeit verbraten darf, die ihm zusteht? Wie wollt ihr dann ausrechnen wie lange der Thread gelaufen ist (was ein generelles Problem ist und erstmal rein gar nichts mit dem periodischem Timer zu tun hat) oder wie lange er im Kernel oder im Userspace war?
Das sind die Kosten einer Abstraktion. Man muss nicht die perfekten Algorithmen schreiben, sondern nur ausreichend dokumentierte.
-
Wenn deine Zeitbasis nur gebrauchbare 100ms hat, dann kannst du damit nur in Sonderfällen genauer arbeiten. Ergo kommst du mit dem PIT nicht viel weiter.
Du kannst für genauere Ereignisse den One-Shot-Modus zusätzlich benutzen (gibt ja mehrere getrennte Timer).
Der Thread, der seine Zeitscheibe abgibt, ist ja beim nächsten PIT-Interrupt nicht mehr da. Also hat er seine Zeitscheibe abgegeben, nichts leichter als das. Wie lange er sie genutzt hat, kriegst du so allerdings auch nicht raus. Mit einer schlechten Zeitbasis wird das nichts, da brauchst du eine andere Basis.
Was den TSC angeht, kannst du den durchaus verwenden. Da du als Betriebssystem selbst die Herrschaft über die Taktfrequenz hast, kannst du die natürlich auch berücksichtigen (und sei es, indem du bei niedrigerem Takt auf die TSC-Werte einen Faktor draufmultiplizierst).
-
Was den TSC angeht, kannst du den durchaus verwenden. Da du als Betriebssystem selbst die Herrschaft über die Taktfrequenz hast, kannst du die natürlich auch berücksichtigen (und sei es, indem du bei niedrigerem Takt auf die TSC-Werte einen Faktor draufmultiplizierst).
Ist dem so? Ich war immer der Meinung, zumindest auf Intel CPUs, dass das ganz automatisch passiert.
Ich vermute mal das wird im SMM gemacht und da komme ich als OS ja nicht rein.
Wenn es nicht automatisch passiert, wieso braucht man dann bei AMD nen Treiber für die dynamische Taktung und bei Intel nicht? (Ich frage weil ich es nicht weiß)
Du kannst für genauere Ereignisse den One-Shot-Modus zusätzlich benutzen (gibt ja mehrere getrennte Timer).
Nicht wirklich. Einer ist für den Speaker da und der andere ware mal in Benutzung (DRAM Refresh glaub ich).
Naja, sobald man den APIC nutzen kann, hat man die ganzen Probleme nicht mehr, aber ich will halt auch mit dem PIT ein halbwegs vernünftiges Ergebnis bekommen.
Wenn du mir jetzt allerdings ne Quelle (also ne technische Doku) geben kannst, wo drin steht das solange ich nichts machen, die CPU sich auch nicht runtertaktet. Dann kann ich ganz einfach den TSC als Counter nehmen (auch beim APIC).
Mein großes Problem ist halt, das die meisten Programme (z.b. Spiele) so geschrieben sind, das sie sich den Wert eines Counters (high precision counter) holen, dann ihre Aufgabe erledigen, wieder den Wert des Counters holen und anhand der Differenz wissen wie lange sie noch warten müssen. Das ganze wäre auch nicht so schwierig, wenn die TSCs konstant wären und auf SMP System nicht von einander "weglaufen" würden. So muss ich den PIT als Zeitbasis nehmen (da er die einzige Konstante in einem SMP System ist, auf die du dich verlassen kannst und die einen Counter hat). So bekomme ich immerhin ne Counter mit ner Präzision die halbwegs in Ordnung ist.
Ich bin aber gerne offen für andere Vorschläge, wie man nen konstanten hoch präzisen Counter auf nem SMP System (ohne HPET!!!) umsetzen kann.
-
Also mein Linux-Notebook mit Intel T5500 (Core2, 1.66 GHz) nutzt für das Heruntertakten den Treiber "acpi-cpufreq". Außerdem kann ich ja die maximale Frequenz auch festpinnen, das ist schon eine Betriebssystemfunktion. Hardware/SMM-Modi wurden auf CPUs genutzt, die ein Heruntertakten eigentlich nicht unterstützen (z.B. 486er oder Pentiums); aber auch damit kann man leben.
Außerdem erkennt die CPU ja nicht selbstständig, ob das Betriebssystem im Leerlauf ist (MS-DOS!) oder ob die niedrige Frequenz nicht Absicht ist (Akkulaufzeit!).
Bei AMD brauchtest du einen CPU-spezifischen Treiber, bei Intel geht das schon länger über die ACPI-Schnittstelle. Wenn du also dort nichts einträgst, dürfte die CPU auch nicht heruntertakten. Ausnahme: Überhitzung. Da schaltet die Hardware (bzw. das BIOS) den Takt selbst runter.
Du kannst ja den TSC regelmäßig mit dem PIT (z.B. mit 10 Hz) abgleichen, dann merkst du recht schnell, wenn der TSC aus dem Ruder läuft. Das scheint bei einigen Prozessoren so zu sein und in dem Fall verlierst du halt die Präzision. So wie du es beschreibst, gibt es keine Universallösung.
Gruß,
Svenska
-
So wie du es beschreibst, gibt es keine Universallösung.
Das ist das "schöne" an der x86 Architektur ;)
Das einzigste ist, ich kenn mich. Wenn ich jetzt davon ausgehe, das sich die Frequenz des TSC nicht ändert und dann mal in 2 oder noch mehr Jahren ACPI und das Runtertakten unterstütze. Dann kann ich wieder stundenland nach dem Fehler suchen, warum mit einmal alles aus dem Ruder läuft, da ich ja vergessen habe, das ich angenomme habe, das der TSC konstant ist ;)
Mich würde jetzt mal interessieren, wie das z.B. Sound und Video Apps machen, das Sound und Video synchron bleiben. Ich meine das funktioniert ja auch auf allen PCs und bei Spielen scheint es ja auch zu klappen.
-
Hallo,
Das ist das "schöne" an der x86 Architektur ;)
Wenn Du x86 so "schön" findest dann verstehe ich ehrlich nicht warum Du so jammerst! :-D
Der TSC ist nur dann verlässlich konstant wenn man alle entsprechenden BIOS-Optionen ausschaltet ansonsten kann es passieren dass das BIOS z.B. bei bestimmten Power-Management-Erfordernissen die CPU-Frequenz regelt. Diese Automatismen sind aber nicht allzu viele (das war eher zu APM-Zeiten) und heutzutage ist es eigentlich Aufgabe des OS das ganze aktiv zu managen. Genaueres sollte die ACPI-Spec verraten, die kann man frei downloaden. Auf PCs mit ordentlichem ACPI sollte auch ein HPET vorhanden sein.
Es gibt ein paar CPUs bei welchen der TSC "holprig" läuft aber das trifft nur die untersten Bits und auf lange Sicht läuft auch dort der TSC genau mit der richtigen Frequenz, er eignet sich dort nur leider nicht für ganze kurze Timings (um z.B. den Taktbedarf einer kurzen Befehlsfolge zu messen).
Ich habe mich damals auch auf den TSC gestützt und war von seiner Genauigkeit recht beeindruckt, nachdem ich die exakte Frequenz per PIT gemessen hatte. Der große Nachteil des TSC ist das er keine Interrupts generieren kann und daher in einem preemptiven Multitasking nicht nutzbar ist.
Mich würde jetzt mal interessieren, wie das z.B. Sound und Video Apps machen, das Sound und Video synchron bleiben. Ich meine das funktioniert ja auch auf allen PCs und bei Spielen scheint es ja auch zu klappen.
Die nutzen den Takt der Sound-Karte, diese "verbraucht" die Audiodaten ja mit einer bestimmten Datenrate (den aktuellen Lese-Pointer bekommt man wimre über das Sound-API vom OS welches diese Info vom Treiber holt) und genau darauf synchronisieren sich solche Programme meistens.
Wenn es nicht automatisch passiert, wieso braucht man dann bei AMD nen Treiber für die dynamische Taktung und bei Intel nicht? (Ich frage weil ich es nicht weiß)
Ich denke weil M$ besser mit Intel zusammenarbeitet als mit AMD und daher mehr Treiber für Intel schon mit drin sind als für AMD. Immerhin war MS so freundlich für Intel eine neue Plattform zu unterstützen ohne das damals absehbar war ob der Itanium wirklich ein Erfolg wird (wobei die Schwierigkeit wohl nicht nur in der CPU sondern auch in der Plattform lag: kein BIOS, kein PIC und auch viele andere der lieben alten Schrulligkeiten der PC-Plattform waren einfach weg), heute wissen wir dass das vergebliche Liebesmüh vom Microsoft war (aber zumindest von der Unterstützung für EFI und GUID-Partitionen werden wir wohl alle profitieren). Die Unterstützung für die AMD-Variante hat MS gezwungenermaßen aufgrund der drohenden/bedrohlichen viralen Marktmacht eines anderen bestimmten OS (an dessen Quell-Code die AMD Leute auch ohne Bürokratie und NDAs mitwirken durften) in Windows eingebaut um auf den Servern und großen Workstations nicht völlig abgehängt zu werden.
Du kannst für genauere Ereignisse den One-Shot-Modus zusätzlich benutzen (gibt ja mehrere getrennte Timer).
Nicht wirklich. Einer ist für den Speaker da und der andere ware mal in Benutzung (DRAM Refresh glaub ich).
Beides wird wimre heutzutage nicht mehr benötigt, oder willst Du die Soundausgabe in Deinem OS per Speaker machen? (für Windows 3.x gabs es damals einen entsprechenden Treiber der gar nicht mal so schlecht geklungen hat aber auf damaligen 486 mit ~50MHz ziemlich CPU-intensiv war)
Naja, sobald man den APIC nutzen kann, hat man die ganzen Probleme nicht mehr,
Du schreibst immer von APIC, erkläre doch mal genauer was Du damit meinst. Es gibt da einen oder mehrere I/O-APICs mit denen man nichts timen kann und dann hat jeder CPU-Thread (bei Hyper-Threading) seinen eigenen Local-APIC welcher zwar einen Timer anthält der aber wimre nur der lokalen CPU Interrupts schicken kann. Den Timer im Local-APIC würde ich nur für die Zeitscheiben benutzten, dafür wurde er auch gebaut. Für Timing-Events die nicht einer bestimmten CPU zuzuordnen sind, dazu gehören periodische Events und auch alle anderen User-Mode-Timings, gibt es den HPET.
aber ich will halt auch mit dem PIT ein halbwegs vernünftiges Ergebnis bekommen.
Das ist leider zum Scheitern verurteilt, es sei denn Du definierst "halbwegs vernünftiges Ergebnis" auf recht kreative Art.
Ich bin aber gerne offen für andere Vorschläge, wie man nen konstanten hoch präzisen Counter auf nem SMP System (ohne HPET!!!) umsetzen kann.
Ich nehme an Du kannst Dir selber denken wie ich darauf antworten würde. ;)
Du kannst für genauere Ereignisse den One-Shot-Modus zusätzlich benutzen.
Mit dem One-Shot-Modus kann man aber nicht genau timen! Was machst Du wenn der nächste Event für in 200 ms geplant ist und dann eine andere Applikation einen in 50ms will? Die Restzeit auslesen und neu rechnen? Klar das geht aber da bekommst Du mit der Zeit immer mehr Fehler rein weil dieser Vorgang eben etwas aber nicht deterministische Zeit braucht. Zum genauen Timen braucht man eine exakt kontinuierliche und streng monotone Zeitbasis (und das geht nur in Hardware ohne das da Software dazwischen fummelt) und die gibt es im PIT-One-Shot-Modus eben nicht.
Ein Thread gibt ab und zwar irgendwo zw. 2 PIT Interrupts. Wie wollt ihr da sichern das der neue Thread auch wirklich seine Zeit verbraten darf, die ihm zusteht? Wie wollt ihr dann ausrechnen wie lange der Thread gelaufen ist (was ein generelles Problem ist und erstmal rein gar nichts mit dem periodischem Timer zu tun hat) oder wie lange er im Kernel oder im Userspace war?
Für die Verwaltung der Zeitscheibe benutzt man am besten den Timer im Local-APIC, so hat man für jeden gerade laufenden Thread eine eigene und unabhängige Instanz. Wenn der Thread vorzeitig abbricht dann ließ man eben die Restzeit aus, so will ich das auf meiner Plattform auch machen. Zum unterscheiden zwischen Kernel-Mode und User-Mode kann man beim Eintritt und Austritt zum/vom Kernel-Mode immer den Timer-Wert auslesen und die so gemessenen/errechneten Zeiten dem entsprechenden Interrupt zuordnen und vom Zeitscheibenverbrauch des User-Mode-Threads abziehen (außer bei SYSCALLs natürlich, die ordnet man zwar dem Thread zu aber als Kernel-Mode-Zeit).
Grüße
Erik
-
Es gibt ein paar CPUs bei welchen der TSC "holprig" läuft aber das trifft nur die untersten Bits und auf lange Sicht läuft auch dort der TSC genau mit der richtigen Frequenz, er eignet sich dort nur leider nicht für ganze kurze Timings (um z.B. den Taktbedarf einer kurzen Befehlsfolge zu messen).
Problem ist halt das der TSC mit der Frequenz der CPU zusammen hängt und wenn die sich ändert (wo ich halt davon ausgegangen bin, dass das auf Laptops z.B. automatisch geht) dann ändern sich auch die Rate mit der der TSC aktualisiert wird. Ganz schlecht zum Timen.
Die nutzen den Takt der Sound-Karte, diese "verbraucht" die Audiodaten ja mit einer bestimmten Datenrate (den aktuellen Lese-Pointer bekommt man wimre über das Sound-API vom OS welches diese Info vom Treiber holt) und genau darauf synchronisieren sich solche Programme meistens.
Das hört sich doch gut an, klingt jedenfalls so, als wenn ich mir darüber so schnell keinen Kopf machen brauche. Aber was ist mit "Videos" die ohne Sound laufen bzw wo keine Soundkarte vorhanden ist. Gibt es da ne Art Backup-Methode oder laufen die dann aus dem Ruder?
Du schreibst immer von APIC, erkläre doch mal genauer was Du damit meinst. Es gibt da einen oder mehrere I/O-APICs mit denen man nichts timen kann und dann hat jeder CPU-Thread (bei Hyper-Threading) seinen eigenen Local-APIC welcher zwar einen Timer anthält der aber wimre nur der lokalen CPU Interrupts schicken kann. Den Timer im Local-APIC würde ich nur für die Zeitscheiben benutzten, dafür wurde er auch gebaut. Für Timing-Events die nicht einer bestimmten CPU zuzuordnen sind, dazu gehören periodische Events und auch alle anderen User-Mode-Timings, gibt es den HPET.
Ich meinte halt immer den Local-APIC-Timer (ich dachte das wäre klar, wenn wir von Timern reden ;) ).
Bei mir läuft das im Moment auf SMP Systemen so. Ein Thread sagt er will so und so lange schlafen. Daraufhin kommt er in the Sleep-Queue der CPU auf der er gerade Läuft (ist ne Delta-Queue).
Also gehen wir mal davon aus die Sleep-Queue ist leer. Der Scheduler wird das 1. Mal aufgerufen, wählt nen Thread aus, der darf 60ms laufen, also wird der APIC-Timer auf 60ms gestellt, ich setze dann ne Variable "timerStart" auf 60ms. Wenn der Scheduler das nächste Mal aufgerufen wird, dann liest er als erstes den aktuellen Wert des APIC-Counters aus (bzw. bekommt er ne "Restzeit" zurück) welche von der Variable "timerStart" abgezogen wird, so habe ich die genaue Zeit die der Thread gelaufen ist. Diese ziehe ich von der Zeit vom aktuellen Thread ab und diese ziehe ich vom 1. Thread in der Sleep-Queue ab (wenn denn einer vorhanden ist). Gleichzeitig wird ne Variable "sleepNext" auf die Zeit gesetzt, wenn der nächste Thread aufgeweckt werden soll.
Der Scheduler guckt jetzt ob der aktuelle Thread seine Zeit verbraucht hat oder abgeben will oder ob ein Thread mit höherer Prio bereit ist. Ist irgendetwas davon der Fall wird der Thread in die Run-Queue gepackt und ein neuer Thread wird rausgesucht (aus der Ready-Queue).
Jetzt wird geguckt, was näher (zeitlich gesehen) ist, die Zeit bis zum nächsten Thread der aufgeweckt werden soll oder die Zeit bis der neue Thread seine Zeit aufgebraucht hat.
Diese Zeit wird dann dem APIC-Timer übergeben und der neue Thread darf laufen.
Der "Fehler" in diesem System ist die Zeit zwischen dem Eintritt in den Scheduler und dem Abgeben an den neuen Thread. Dieser "Jitter" summiert sich leider mit der Zeit ziemlich tolle auf. Im Moment braucht mein Scheduler im Worst-Case so ca. 1500ns auf nem K6-3 400MHz (hatte ich mal ausgemesen).
Ich nehme an Du kannst Dir selber denken wie ich darauf antworten würde. Wink
Ja, wäre nur nicht sonderlich hilfreich ;)
Auf nem SMP System (was auch DualCores mit einschließt) habe ich nunmal außer dem PIT nichts brauchbares (für ne absolute Zeitquelle, denn die APIC-Timer sind leider dafür nicht zu gebrauchen) :(
Zum unterscheiden zwischen Kernel-Mode und User-Mode kann man beim Eintritt und Austritt zum/vom Kernel-Mode immer den Timer-Wert auslesen und die so gemessenen/errechneten Zeiten dem entsprechenden Interrupt zuordnen und vom Zeitscheibenverbrauch des User-Mode-Threads abziehen (außer bei SYSCALLs natürlich, die ordnet man zwar dem Thread zu aber als Kernel-Mode-Zeit).
Würde ich auch so machen. Im Moment weiß ich aber noch nicht wofür ich das gebrauchen könnte, zumal da wieder das nette Problem kommt. Mein OS läuft auch auf PIT-only Systemen und das Auslesen alleine kostet schon Zeit (3*832ns).
Linux macht das zwar auch so, aber naja. Ich hatte mir den Source mal angeguckt und die haben ja auch Code für PIT-only Systeme und die machen das da genau wie ich (und ich habe noch gelernt, das man den PIT nicht ständig neu initialisieren muss wenn man nen neuen Wert reinschreibt und zwischen durch nur ausliest).
-
Beides wird wimre heutzutage nicht mehr benötigt, oder willst Du die Soundausgabe in Deinem OS per Speaker machen? (für Windows 3.x gabs es damals einen entsprechenden Treiber der gar nicht mal so schlecht geklungen hat aber auf damaligen 486 mit ~50MHz ziemlich CPU-intensiv war)
Naja, er hat die IRQs abgeschaltet und hat daher das gesamte System komplett angehalten... und er lief unter Windows 95 auch noch ganz prima. ;)
Du kannst für genauere Ereignisse den One-Shot-Modus zusätzlich benutzen.
Mit dem One-Shot-Modus kann man aber nicht genau timen! Was machst Du wenn der nächste Event für in 200 ms geplant ist und dann eine andere Applikation einen in 50ms will?
Naja, wenn du eine gewisse Echtzeitanforderung hast, dann musst du in der Lage sein, auch mal genauere Ereignisse einplanen zu können. Das 200ms-Event ist übrigens nicht geeignet als Beispiel, weil der PIT ja alle 100ms deine Zeitbasis erzeugt. ;-)
Dass der TSC mit der Frequenz schwankt, ist bekannt. Bekannte Fehler sind ungefährlich. Du könntest also einerseits den PIT für eine sehr langsame, aber genaue Zeitquelle nutzen (vllt. 1-10 Hz) und damit den TSC regelmäßig kalibrieren. Wenn du später irgendwann dein ACPI soweit hast, dass du den CPU-Takt regeln kannst, dann kennst du den aktuellen CPU-Takt und kannst damit die TSC-Schwankung ebenfalls rausrechnen. Ich sehe darin kein Problem, nur etwas Aufwand. Alternativ bleibst du beim PIT stehen, nimmst den als Zeitbasis und lebst mit den Designschwächen.
Gruß,
Svenska
-
Nur mal dazwischen geschoben, die kleinste Freqeunz die der PIT kann sind 18,2Hz und das sind 54,5ms (Pi mal Daumen ;) ).
Ich überlege schon, den PIT für´s "Grobe" zu nehmen und wenn dann die Zeit zum Warten kleiner 54,5ms ist, dann wird der Thread halt in die Sleep-Queue der CPU gepackt auf dem der PIT IRQ Handler gerade läuft. Damit sollte dann auch der Jitter der Entsteht egal sein. Was haltet ihr von der Variante?
Das einzige Problem damit wäre dann das Reinpacken eines Threads in die PIT-Sleep-Queue. Denn ich müsste den Thread zw. 2 PIT-IRQs reinpacken und dazu müsste ich diesen auslesen, was wiederum nen Jitter von 3*832ns erzeugt und das jedes Mal wenn ich nen Thread reinpacke.
-
Hallo,
Ich überlege schon, den PIT für´s "Grobe" zu nehmen und wenn dann die Zeit zum Warten kleiner 54,5ms ist, dann wird der Thread halt in die Sleep-Queue der CPU gepackt auf dem der PIT IRQ Handler gerade läuft. Damit sollte dann auch der Jitter der Entsteht egal sein. Was haltet ihr von der Variante?
Das einzige Problem damit wäre dann das Reinpacken eines Threads in die PIT-Sleep-Queue. Denn ich müsste den Thread zw. 2 PIT-IRQs reinpacken und dazu müsste ich diesen auslesen, was wiederum nen Jitter von 3*832ns erzeugt und das jedes Mal wenn ich nen Thread reinpacke.
Hä? Was willst Du da genau machen? Also ich würde nicht bestimme OS-Kernel-Aufgaben auf bestimmte CPUs festpinnen. Das würde ich auch nicht mit IRQs machen, ein IRQ wird am besten auf der CPU verarbeitet auf welcher gerade der User-Mode-Code mit der niedrigsten Priorität läuft. Auf den PIT würde ich gar nicht zugreifen (außer zur Initialisierung natürlich), das ist einfach ungeschickt langsam. Ich würde mir von diesem einfach einen periodischen IRQ generieren lassen um damit in Software eine streng monotone und präzise Uhr zu generieren, nur die zeitliche Auflösung wäre eben bescheiden. Die PIT-IRQ-Frequenz den Erfordernissen anzupassen halte ich für eine gute Idee auch wenn damit die Langzeitgenauigkeit zerstört wird (die Umkonfiguration benötigt eben etwas Zeit), aber wenn das nur selten passiert ist es IMHO Okay. Die Last eines IRQ, der eigentlich nur einen Zähler inkrementieren muss und diesen dann mit einem Wert vergleicht (mit der nächsten relevanten absoluten Event-Zeit, nur bei Gleichheit muss muss auch tatsächlich ein Event generiert werden), würde ich als recht gering ansehen. Wenn man mit dem PIT eine hohe Langzeitgenauigkeit haben will, z.B. ein 24Hz-Event in genau 5 Stunden genau 432000 mal ausgelöst werden soll, dann ist dieser PIT-Modus der einzigst mögliche. Das damit die Stromrechnung nicht gerade geschont wird ist mir klar, dagegen gibt es ja den HPET.
Naja, wenn du eine gewisse Echtzeitanforderung hast, dann musst du in der Lage sein, auch mal genauere Ereignisse einplanen zu können.
Wie genau Du Events auslösen kannst hängt eben von der verwendeten Zeitbasis ab. Wenn man per PIT eine Software-Uhr mit 1ms Auflösung generiert dann ist eben 1ms das kleinste was geht, wenn man den HPET nutzt und der mit 10MHz läuft dann bekommt am eine zeitliche Auflösung von 100ns. Um mal irgendwo 30ns abzuwarten ist beides nicht geeignet aber die im Ursprungspost genannten 64Hz-Events kann man mit beiden gleich gut und sehr präzise realisieren, beim HPET ist nur der Jitter deutlich kleiner und auch die CPU-Belastung geringer und man kann die CPU schlafen lassen wenn keine Events anstehen.
Das 200ms-Event ist übrigens nicht geeignet als Beispiel, weil der PIT ja alle 100ms deine Zeitbasis erzeugt.
In meinem Ursprungsport hatte ich doch eine Zeitbasis von 1ms per PIT erzeugt, gröber als 10ms würde ich auf keinen Fall akzeptieren.
Alternativ bleibst du beim PIT stehen, nimmst den als Zeitbasis und lebst mit den Designschwächen.
Als Alternative würde ich den PIT nicht betrachten, aller höchstens, und nur mit viel Bauchweh, als Notlösung.
Es gibt ein paar CPUs bei welchen der TSC "holprig" läuft aber das trifft nur die untersten Bits und auf lange Sicht läuft auch dort der TSC genau mit der richtigen Frequenz, er eignet sich dort nur leider nicht für ganze kurze Timings (um z.B. den Taktbedarf einer kurzen Befehlsfolge zu messen).
Problem ist halt das der TSC mit der Frequenz der CPU zusammen hängt und wenn die sich ändert (wo ich halt davon ausgegangen bin, dass das auf Laptops z.B. automatisch geht) dann ändern sich auch die Rate mit der der TSC aktualisiert wird. Ganz schlecht zum Timen.
Ja, der TSC hängt von der CPU-Frequenz ab und wenn die CPU in einen der tieferen Schlafmodi wechselt dann hält der sogar an. Den TSC kann man nur unter klar kontrollierten Bedingungen einsetzen und die kannst Du auf beliebigen PCs, auf denen Dein OS ja laufen soll, leider nicht garantieren. In Emulatoren u.ä. dürfte der TSC auch nur von begrenzter Brauchbarkeit sein. Hier würde eine klare und verbindliche Plattform-Spezifikation, in der all solche Dinge klar geregelt sind, was nützen. Das hat Intel ja beim Itanium versucht aber zum Massen-Erfolg ist die CPU einfach ungeeignet.
Aber was ist mit "Videos" die ohne Sound laufen bzw wo keine Soundkarte vorhanden ist. Gibt es da ne Art Backup-Methode oder laufen die dann aus dem Ruder?
Das Backup sind die Timing-Methoden des OS, eben periodische Events. Das es damit etwas holpriger wird dürfte bei einem Stummfilm nicht auffallen, ich denke ein paar wenige ms Jitter spielen da keine Rolle. Das Auge reagiert ja auch auf Frame-Dropps nicht so empfindlich wie das Ohr auf einen kurzen Aussetzer. Du kannst ja mal in Deinem präferierten Video-Player einen Film 10% schneller oder langsamer laufen lassen, ich denke das fällt nur bei sehr genauer Beobachtung in speziellen Szenen auf. Wenn man dagegen den Ton um 10% schneller oder langsamer abspielt, also ohne Algorithmen welche die Tonhöhe konstant halten sondern nur durch verändern der Samplerate, dann wird man das schon deutlich hören.
Ich meinte halt immer den Local-APIC-Timer (ich dachte das wäre klar, wenn wir von Timern reden ;) ).
Das habe ich mir auch so gedacht, ich wollte das nur konkretisieren damit wir nicht irgendwo an einander vorbei schreiben.
Bei mir läuft das im Moment auf SMP Systemen so. Ein Thread sagt er will so und so lange schlafen. Daraufhin kommt er in the Sleep-Queue der CPU auf der er gerade Läuft ....
Ich denke ich verstehe ungefähr was Du meinst aber der Fehler ist IMHO das Du überhaupt die aktuelle Rest-Zeit zum rechnen nimmst. Zwischen dem Moment wo Du diese Restzeit ausliest und dann das Rechenergebnis in den Timer schreibst (egal bei welchen Timer) vergeht Zeit und die akkumuliert sich als Fehler auf und versaut Dir die Langzeitstabilität. Du musst immer mit absoluten Zeiten rechnen. Wenn Dein Programm zum Zeitpunkt 510638ms den ersten Event bekommen hat und der nächste Event 60ms später kommen soll dann muss das eben zum Zeitpunkt 510698ms passieren und darf nicht von der verbrauchten Zeit o.ä. abhängen. Den HPET kann man auch nicht einfach so mal auf einen neuen Zählerwert setzen sondern man kann nur einen neuen absoluten Vergleichswert hinein laden an dem der nächste IRQ generiert wird, genau das habe ich in meinem Ursprungspost beim PIT in Software nach gebaut.
Auf nem SMP System (was auch DualCores mit einschließt) habe ich nunmal außer dem PIT nichts brauchbares (für ne absolute Zeitquelle, denn die APIC-Timer sind leider dafür nicht zu gebrauchen) :(
Also wenn Dual-Core (nicht Dual-Sockel) vorhanden ist dann sollte auch ein HPET anwesend sein. Auf älteren PCs kannst Du ja den PIT im Periodic-Modus nutzen, dort dürften die CPUs auch nicht so interessante Tiefschlaf-Modi kennen so das dort kein so großes Problem entsteht.
Grüße
Erik
-
Hä? Was willst Du da genau machen? Also ich würde nicht bestimme OS-Kernel-Aufgaben auf bestimmte CPUs festpinnen. Das würde ich auch nicht mit IRQs machen, ein IRQ wird am besten auf der CPU verarbeitet auf welcher gerade der User-Mode-Code mit der niedrigsten Priorität läuft.
Also bei meinem System wird der IRQ Handler immer auf der CPU mit der niedrigsten Prio ausgeführt (Ausnahme sind CPUs im Idle-Zustand).
Ich hab mir das so vorgestellt. Du hast halt den PIT im periodischen Modus mit den magischen 18,2Hz = 55,4ms.
Ein Thread läuft auf CPU0 und möchte für 200ms schlafen, dann ruft er halt sleep(200000000) auf (die Zahl ist so groß, weil ich ns als Basis nehme, da rechnet sich einiges leichter ohne die FPU verwenden zu müssen) und die holt sich den aktuellen Wert des internen PIT Counters (weil ich den vorher von der zu wartenden Zeit abziehen muss) und packe den Thread in die Delta-Queue des PIT-Handlers.
Jedes Mal wenn der PIT den IRQ-Handler aufruft, zieht er 55,4ms von dem 1. Thread in der Delta-Queue ab und wenn die Zeit die da rauskommt kleiner als 55,4ms ist, wird der (und alle Threads für die dies auch noch gilt) in die Sleep Queue der CPU gepackt auf welcher der IRQ-Handler gerade ausgeführt wird.
Ich hätte dann also eine "globale" Sleep-Queue die nur vom PIT bearbeitet wird und auf jeder CPU noch mal eine Sleep-Queue die von der jeweiligen CPU bearbeitet wird.
In der PIT Queue sind alle Threads welche länger als 55,4ms warten wollen und in den CPU Queues sind alle Threads welche weniger als 55,4ms warten wollen.
Damit sollte ich den Jitter klein halten bzw. (mal vom worst-case abgesehen) sollte der sich zumindestens nicht aufaddieren.
Als Alternative würde ich den PIT nicht betrachten, aller höchstens, und nur mit viel Bauchweh, als Notlösung.
Genau das ist er auch (aber war er das nicht von Anfang an ;) ).
Du musst immer mit absoluten Zeiten rechnen. Wenn Dein Programm zum Zeitpunkt 510638ms den ersten Event bekommen hat und der nächste Event 60ms später kommen soll dann muss das eben zum Zeitpunkt 510698ms passieren und darf nicht von der verbrauchten Zeit o.ä. abhängen. Den HPET kann man auch nicht einfach so mal auf einen neuen Zählerwert setzen sondern man kann nur einen neuen absoluten Vergleichswert hinein laden an dem der nächste IRQ generiert wird, genau das habe ich in meinem Ursprungspost beim PIT in Software nach gebaut.
Wenn ich dich richtig verstanden habe, dann meinst du das ich Probleme mit periodischen Events bekommen würde.
Das Problem was ich im Moment mit Events habe ist, ich habe noch gar keine Events auf meinem System ;) Ich rede die ganze Zeit nur von Threads die schlafen gelegt werden. Das andere was ich noch meine ist ne Performance Counter um sagen zu können wieviel Zeit vergangen ist.
Aber, deine Idee mit den Events (um z.B. ein Spiel auf 60FPS zu "eichen") find ich gut, ich weiß halt nur nicht wie ich die umsetzen würde/sollte.
Jetzt so spontan würd ich einfach ne Message an einen vorgegebenen Port senden und der Inhalt wäre halt ne Art ID die sagt, Event ausgelöst.
So dass ich einfach Events in anstatt Threads in eine Queue packe (anstatt der Sleep-Queue im PIT und auf den CPUs) und dann so alles löse.
Die periodischen Events würde ich dann so lösen, das du ne Startzeit (die Zeit bei der der Event eingetragen wurde) nimmst und die Eventzeit draufrechnest und den Event wieder in die PIT-Queue packst und nen "neuen" Event erzeugst mit der Restzeit (kleiner als 55,4ms) und diesen in die CPU Queue packst.
Ich hoffe ich war einigermaßen verständlich, klingt alles ein wenig wirr ich weiß.
Ich würde spontan sagen, das ich ne Semaphore für die Events nutzen könnte (zumindest für das Sleep-Event). Es wird halt ein neues Event erstellt, das einmal feuern soll und in 200ms soll das ganze passieren, der Thread versucht darauf hin die Semaphore zu bekommen (was ja nicht klappt und der wird auf blockierend/wartend gesetzt). Wenn das Event dann feuert, gibt es die Semaphore frei (was den Thread praktisch aufweckt) und "zerstört" sich selbst. Dann hätte ich die Sleep-Funktion über Events gelöst und müsste mir nur noch nen Kopf machen, wie ich das mit anderen Events mache.
Obwohl es gar nicht schlecht wäre das immer über Semaphoren zu machen. Um nochmal das Bsp mit dem Game zu bringen, wenn das Event alle 16ms die Semaphore freigibt und der Thread mal länger brauchen sollte, dann bekommt er die Semaphore ja sofort und kann gleich den nächsten Frame berechnen.
Wenn ich dann noch die Linux Idee von den Futexen nutze, dann kann ich das ganze noch halbwegs effizient im User-Space machen.
Was haltet ihr von der Idee (meine Event Idee und die Sache mit dem PIT)?
Also wenn Dual-Core (nicht Dual-Sockel) vorhanden ist dann sollte auch ein HPET anwesend sein. Auf älteren PCs kannst Du ja den PIT im Periodic-Modus nutzen, dort dürften die CPUs auch nicht so interessante Tiefschlaf-Modi kennen so das dort kein so großes Problem entsteht.
Ich habe hier einige Motherboards mit mehreren CPUs (Slot1, Sockel370, Sockel5/7, SockelA) die keinen HPET haben und die möchte ich ja auch unterstützen!
Du weißt nicht zufällig ab wann ungefähr der HPET auf neuen Boards vertreten war?
Ich hab von dem Ding das erste Mal zu Core2 Zeiten gehört.
-
Hallo,
Ich hab mir das so vorgestellt. Du hast halt den PIT im periodischen Modus mit den magischen 18,2Hz = 55,4ms.
Das ist meiner persönlichen Meinung nach etwas zu grob, weniger als 100Hz würde ich nicht nehmen.
Ein Thread läuft auf CPU0 und möchte für 200ms schlafen, dann ruft er halt sleep(200000000) auf und die holt sich den aktuellen Wert des internen PIT Counters (weil ich den vorher von der zu wartenden Zeit abziehen muss) und packe den Thread in die Delta-Queue des PIT-Handlers.
Du möchtest quasi den Zählerwert vom PIT als Nachkommastellen für Deinen 18,2Hz-Software-Zähler nutzen? Interessante Idee aber ich glaube nicht das das viel nutzt genauer als auf ca. 55ms bekommst Du damit trotzdem keinen IRQ. Ich würde lieber zu einer höheren IRQ-Frequenz raten.
Jedes Mal wenn der PIT den IRQ-Handler aufruft, zieht er 55,4ms von dem 1. Thread in der Delta-Queue ab und wenn die Zeit die da rauskommt kleiner als 55,4ms ist, wird der (und alle Threads für die dies auch noch gilt) in die Sleep Queue der CPU gepackt auf welcher der IRQ-Handler gerade ausgeführt wird.
Wenn Du viele Threads am schlafen hast dann wird das schnell zu einem Problem. Ich würde lieber die absolute Zeit des Aufweckens errechnen (dafür muss man natürlich den Zeit-Counter lesen, was beim HPET ein HW-Zugriff ist) und diesen in eine sortierte Liste eintragen. Der IRQ-Handler für den periodischen PIT-IRQ inkrementiert seinen SW-Zahler und vergleicht dann diesen absoluten Ist-Zeit-Wert mit dem absoluten Soll-Zeit-Wert im vordersten Listeneintrag. Bei Gleichheit wird eine entsprechende Aktion ausgelöst. Das kann das simple Aufwecken eines Threads sein (der einfach nur ein sleep() gemacht hat) aber auch das verschicken einer Message/Signals an einen Prozess oder das setzen eines Event-Object auf das möglicherweise gerade jemand wartet der dann sofort geweckt werden muss.
Wenn ich dich richtig verstanden habe, dann meinst du das ich Probleme mit periodischen Events bekommen würde.
Ja. Solange Du den PIT nicht frei laufen lässt sondern immer mal dran "rumdrehst" bekommst Du Fehler die sich aufakkumulieren.
Das Problem was ich im Moment mit Events habe ist, ich habe noch gar keine Events auf meinem System ;) Ich rede die ganze Zeit nur von Threads die schlafen gelegt werden.
Und wo ist Dein Problem? Wenn ein Event (oder was auch immer) nicht mehrfach sondern nur einmalig auftreten soll dann wird es eben nicht erneut in die geordnete Event-Liste eingetragen. Wo ist das Problem?
Das andere was ich noch meine ist ne Performance Counter um sagen zu können wieviel Zeit vergangen ist.
Wenn Du diese "Performance Counter" nur zu "Statistischen Zwecken", z.B. zur Anzeige in einem Taskmanager, nutzen möchtest dann solltest Du Dir da erstmal keine zu großen Sorgen machen. User-Code sollte sich von so etwas nie abhängig machen.
Ich würde spontan sagen, das ich ne Semaphore für die Events nutzen könnte (zumindest für das Sleep-Event)....
Also das klingt für mich nicht sonderlich klug da noch einen zusätzlichen Mechanismus dazwischen zu setzen. Leg den Thread, der sleep() aufgerufen hat, direkt schlafen und wecke ihn in der Event-Abhängigen Funktion, welche der PIT-IRQ-Handler beim erreichen des entsprechenden Zeitpunkts aufruft, einfach wieder auf.
Obwohl es gar nicht schlecht wäre das immer über Semaphoren zu machen. Um nochmal das Bsp mit dem Game zu bringen, wenn das Event alle 16ms die Semaphore freigibt und der Thread mal länger brauchen sollte, dann bekommt er die Semaphore ja sofort und kann gleich den nächsten Frame berechnen.
Für Spiele oder Multimediaprogramme würde ich ein Event-Object benutzen:
t_handle event_object = CreateEventPeriodic(50ms); //Event-Objekt erstellen das vom System alle 50ms gesetzt wird
/// ....
while(...)
{
WaitForEvent(event_object); //wartet bis das Event-Object gesetzt ist und tut es dann zurücksetzen, falls es bereits gesetzt ist weil die letzte Aktion den Zeitrahmen etwas gesprengt hat dann kommt ohne warten zurück
tuWasPeriodisches(); //hier wird z.B. das nächste Bild berechnet
}
Ich habe hier einige Motherboards mit mehreren CPUs (Slot1, Sockel370, Sockel5/7, SockelA) die keinen HPET haben und die möchte ich ja auch unterstützen!
Bist Du sicher das Du Boards mit Slot1 oder Sockel5/7 und mehreren CPUs hast? ;)
Du weißt nicht zufällig ab wann ungefähr der HPET auf neuen Boards vertreten war? Ich hab von dem Ding das erste Mal zu Core2 Zeiten gehört.
Nein, genau weiß ich das nicht aber es sollte schon einige Jahre her sein.
Als Alternative würde ich den PIT nicht betrachten, aller höchstens, und nur mit viel Bauchweh, als Notlösung.
Genau das ist er auch (aber war er das nicht von Anfang an ;) ).
So wie fast alles bei der x86-Plattform! Hoch lebe die heilige Kuh der Kompatibilität!
Grüße
Erik
-
Wenn Du viele Threads am schlafen hast dann wird das schnell zu einem Problem. Ich würde lieber die absolute Zeit des Aufweckens errechnen (dafür muss man natürlich den Zeit-Counter lesen, was beim HPET ein HW-Zugriff ist) und diesen in eine sortierte Liste eintragen. Der IRQ-Handler für den periodischen PIT-IRQ inkrementiert seinen SW-Zahler und vergleicht dann diesen absoluten Ist-Zeit-Wert mit dem absoluten Soll-Zeit-Wert im vordersten Listeneintrag. Bei Gleichheit wird eine entsprechende Aktion ausgelöst. Das kann das simple Aufwecken eines Threads sein (der einfach nur ein sleep() gemacht hat) aber auch das verschicken einer Message/Signals an einen Prozess oder das setzen eines Event-Object auf das möglicherweise gerade jemand wartet der dann sofort geweckt werden muss.
Irgendwie habe ich das Gefühl das wir aneinander vorbei reden ;)
Wo ist jetzt der Unterschied ob du die Threads aufweckst, wenn ihre Zeit abgelaufen ist oder du sie in eine neue Queue packst?
Genauso verstehe ich nicht wo der Unterschied ist ob ich ne Zahl hab und den Thread aufwecke wenn diese Zahl bei "0" ist oder ob zwei Zahlen habe und den Thread aufwecke wenn beide gleich sind?!
Auch sollte ich vielleicht näher erläutern was ich mit einer Delta-Queue meine, denn das ist ne sortierte Liste!
Also in einer Delta-Queue stehen nicht die Absoluten Werte, sondern immer der Abstand zum Vorgänger, so dass nur im 1. Element der Liste der Absolute Wert steht.
Du möchtest quasi den Zählerwert vom PIT als Nachkommastellen für Deinen 18,2Hz-Software-Zähler nutzen? Interessante Idee aber ich glaube nicht das das viel nutzt genauer als auf ca. 55ms bekommst Du damit trotzdem keinen IRQ. Ich würde lieber zu einer höheren IRQ-Frequenz raten.
Auch hier kann ich dir nicht folgen :(
Also folgender Pseudo-Code:
void sleep(uint64t time) {
//Pointer auf aktuellen Thread holen
struct thread_t *thread= threadGetCurrThread();
//die Zeit die geschlafen werden soll + die schon seit dem letzten Tick vergangen ist speichern
thread->sleepTime= time + (timerGetCountNSecsPerTick() - timerGetCurrCountNSecs());
//Thread in the Sleep-Queue des Timers packen
timerAddThread(thread)
}
Und der Code des Timer (z.B. der PIT) würde ungefähr so aussehen:
void timerIRQhandler() {
if(sleepQueue) {
//Pointer auf das 1. Element der Queue
struct thread_t *t= sleepQueue;
//Zeit für einen Tick vom 1. Element abziehen
thread->sleepTime-= timerGetCountNSecsPerTick();
//gegebenenfalls Threads aufwecken
while(t->sleepTime <= timerGetCountNSecsPerTick()) {
//1. Element der Queue entfernen
sleepQueue= queueRemoveHead(sleepQueue);
//1. Element der Queue in die CPU Sleep-Queue packen, da müsste dann auch die Zeit die der Timer der aktuellen CPU schon verbraten haben, nochmal drauf gerechnet werden, so wie oben
schedAddThreadSleep(t);
//Pointer aktualisieren
t= sleepQueue;
}
}
}
Und in meinem Scheduler dann ungefähr sowas:
void schedHandler() {
if(thisCPU->sleepQueue) {
struct thread_t *t= thisCPU->sleepQueue;
//Zeit (dauer der gerade abgelaufenen Zeitscheibe) abziehen
t->sleepTime-= thisCPU->lastTimeSlice;
while(t->sleepTime <= NE_KONSTANTE_WO_ES_SICH_NICHT_MEHR_LOHNT_DAS_DER_THREAD_NOCHMAL_SCHLAEFT) {
thisCPU->sleepQueue= queueRemoveHead(thisCPU->sleepQueue);
schedAddThreadReady(t);
t= thisCPU->SleepQueue;
}
}
}
So ich hoffe ich konnte mich jetzt genauer und besser Ausdrücken ;)
Bist Du sicher das Du Boards mit Slot1 oder Sockel5/7 und mehreren CPUs hast?
Damals aus reiner Sammelleidenschaft und heute zum Testen meines OSs :D Damit ich mich ja auch mit den "schönsten" Seiten der x86 Architektur rumquählen darf ;)
Ja. Solange Du den PIT nicht frei laufen lässt sondern immer mal dran "rumdrehst" bekommst Du Fehler die sich aufakkumulieren.
Naja, das lässt sich nicht wirklich vermeiden, wenn man eh so ne "alte" Krücke hat die nur den PIT und nicht mal den APIC unterstützt ;)
Aber mal was anderes irgendwo habe ich mal gelesen das man, auch wenn der Local-APIC deaktiviert ist, einige Sachen benutzen kann?! Muss ich direkt nochmal nach gucken ob ich dazu nochmal was finde.
Für Spiele oder Multimediaprogramme würde ich ein Event-Object benutzen:
Der Punkt ist, meine Semaphore/Futex Idee wäre aber schneller ;) Weil du nur noch ein "lock sub dword[event],1" machst und wenn das Event gefeuert hat, dann kannst du gleich weiter machen (weil der neue Wert größer 0 ist) und wenn nicht, dann rufst du den Kernel auf und legst dich in der Semaphore "schlafen" und das Event weckt dich dann mit dem Semaphore-Code wieder auf. Also mir gefällt diese Idee :D Aber ich wenn du mir sagst warum dir diese Idee nicht so gefällt kann ich die Nachteile vielleicht auch erkennen. Dazu haben wir den Thread ja!
Wenn Du diese "Performance Counter" nur zu "Statistischen Zwecken", z.B. zur Anzeige in einem Taskmanager, nutzen möchtest dann solltest Du Dir da erstmal keine zu großen Sorgen machen. User-Code sollte sich von so etwas nie abhängig machen.
Ich hab halt mal nen Bsp. für ne innere Schleife bei nem Game unter Windows gesehen und da haben die es so gemacht. Also mit QeueryPerformanceCounter. Da bin ich dann ganz frech davon ausgegangen das man das unter anderen Systemen ähnlich löst. Wenn ich mich recht entsinne, sollst du unter Linux sowas mit der "Zeit" machen, die geben die, glaub ich in ms oder noch genauer an und da sollst du die beiden Werte dann vergleichen, halt was ähnliches nur nicht so genau.
-
Hallo,
Irgendwie habe ich das Gefühl das wir aneinander vorbei reden ;)
Ja, diesen Eindruck habe ich auch. :(
Wo ist jetzt der Unterschied ob du die Threads aufweckst, wenn ihre Zeit abgelaufen ist oder du sie in eine neue Queue packst?
Da ist kein wirklicher Unterschied, vermute ich mal, das ist ein Implementierungsdetail Deines Schedulers was für allen anderen Code in Deinem Kernel völlig egal ist (zumindest sein sollte wenn Du guten modularen Code schreibst).
Genauso verstehe ich nicht wo der Unterschied ist ob ich ne Zahl hab und den Thread aufwecke wenn diese Zahl bei "0" ist oder ob zwei Zahlen habe und den Thread aufwecke wenn beide gleich sind?!
In Deinem Beispiel modifizierst Du immer die Werte in der Queue, das dauert länger als ein Vergleich. Den Time-Counter wirst Du auf jeden Fall zählen müssen damit Du die Systemlaufzeit u.ä. hast. Das alles fällt natürlich weg wenn der HPET da ist.
Ich habe irgendwie den Eindruck das Deine Variante recht kompliziert ist aber vielleicht erblicke ich einfach nur nicht die simple Einfachheit. ;)
In meiner Vorstellung müsste der PIT-IRQ-Handler ungefähr so aussehen:
void IRQ_PIT(void)
{
time_counter++; // Software-Uhr zählen
// oder falls man mit einer anderen Zeitbasis arbeitest, wovon ich abrate, dann eben: time_counter += PIT_IRQ_PERIPODE;
while(true)
{
T_TimerQueueObject* const obj = TimerQueueGetFirst(); // hole das Objekt welches als nächstes abläuft, nur ne Referenz nicht aus der Queue entfernen
if (obj->time == time_counter) // prüfe ob das nächste Object nun dran ist, auf Gleichheit zu prüfen reicht wenn 'time_counter' nur inkrementiert wird
{
switch(obj->action)
{
case THREAD_RESUME: // Thread aufwecken, z.B. nach einem sleep()
ShedulerThreadResume(obj->thread);
break;
case SET_EVENT: // Event einmalig generieren
EventSet(obj->event);
break;
case SET_EVENT_PERIODIC: // Event periodisch generieren
EventSet(obj->event);
obj->time = ????; // neue absolute Zeit ausrechnen (z.B. wie in meinem Ursprungspost)
TimerQueueAdd(obj); // Object wieder in die Timer-Queue einfügen, eventuell auch ein neues Object generieren weil das aktuelle ja gleich gelöscht wird
break;
case KONTEXT_SWITCH: // den aktuellen Thread gegen einen anderen austauschen (kann hier entfallen wenn zum Kontext-Switch der Local-APIC verwendet wird)
obj->time += SchedulerThreadSwitch(); // Sheduler wechselt in einen anderen Thread (wie und in welchen Thread ist hier egal) und gibt die Länge der neuen Zeitscheibe in Timer-Ticks zurück
TimerQueueAdd(obj); // Object wieder in die Timer-Queue einfügen, eventuell auch ein neues Object generieren weil das aktuelle ja gleich gelöscht wird
break;
default: // sonst Fehler!
KernelError("unbekannte Timer-Aktion");
}
TimerQueueKillFirst(); // vorderstes Timer-Queue-Object entfernen, wurde gerade abgearbeitet
}
else // noch nicht dran : IRQ ist fertig
{ return; }
// Schleife so lange wiederholen bis alle Objekte, deren Zeit gekommen ist, aus der Queue abgearbeitet wurden!
}
}
Der IRQ-Handler für den HPET sieht sehr ähnlich aus (so will ich das auf meiner Plattform auch machen):
void IRQ_HPET(void)
{
while(true)
{
T_TimerQueueObject* const obj = TimerQueueGetFirst(); // hole das Objekt welches als nächstes abläuft, nur ne Referenz nicht aus der Queue entfernen
const uint64 time_counter = HPET->counter; // aktuellen Time-Counter aus den HPET auslesen (richtiger HW-Lese-Zugriff in MMIO)
if (obj->time <= time_counter) // prüfe ob das nächste Object nun dran ist, VORSICHT: das '<=' muss natürlich auch bei einem Überlauf noch funktionieren
{
/* Hier ist der selbe Code wie beim PIT-IRQ-Handler,
nur 'case KONTEXT_SWITCH' geht nicht (wenn HPET vorhanden ist dann sollten auch Local-APICs da sein),
sicher kann man das in _eine_ extra Funktion auslagern oder man merged beide IRQ-Handler mit ein paar #ifdef...#else...#endif */
}
else // noch nicht dran : IRQ ist fertig
{
HPET->cmp_value = obj->time; // absolute Zeit für das nächste Object in den HPET-Comparator schreiben, damit nächster IRQ zur rechten Zeit kommt
if (obj->time > HPET->counter) // prüfen ob das Object nicht doch schon dran ist, dann wäre der IRQ eventuell verloren/verpasst und das darf nicht sein
{ return; } // nächstes Object ist noch nicht dran also IRQ fertig
// nächstes Object ist doch schon dran also Schleife doch noch mal durchlaufen
}
// Schleife so lange wiederholen bis alle Objekte, deren Zeit gekommen ist, aus der Queue abgearbeitet wurden!
}
}
Wenn Du so in dieser Art vorgehst kannst Du alles andere in Deinem Kernel gleich lassen nur die unterschiedlichen Zeitbasen (100Hz bis 1000Hz beim PIT oder >=10MHz beim HPET) musst Du berücksichtigen, deshalb empfehle ich im Kernel nie von einer konkreten Zeitbasis auszugehen stattdessen sollte TICKS_PER_SECOND was sinnvolles liefern. Im User-Mode gilt das erst recht. Im Kernel gibt es eigentlich nichts was von konkreten Zeitspannen abhängig ist, außer die Zeitscheiben natürlich.
Also in einer Delta-Queue stehen nicht die Absoluten Werte, sondern immer der Abstand zum Vorgänger, so dass nur im 1. Element der Liste der Absolute Wert steht.
Das klingt nach viel rechnen. Wie soll man denn da effizient was einfügen (also nicht ans Ende anhängen)? Da muss man doch vor jedem Vergleich erst mal nen Absolutwert berechnen denn man dann mit dem neuen einzufügenden Absolutwert vergleichen kann und vor allem linear durch wandern. Falls ich Dich falsch verstanden hab dann erkläre mir das mal Bitte genauer. Spätestens wenn Du mit dem HPET arbeitest benötigst Du auf jeden Fall die absoluten Zeit-Werte, denn den HPET-Counter kann man nicht (so einfach) beeinflussen. Das ist der Vorteil meiner PIT-Variante, die ist bis auf ein paar winzige Unterschiede im IRQ-Handler mit der HPET-Variante exakt identisch. Die PIT-Variante emuliert quasi den HPET, nur mit gröberer Zeiteinteilung. Nur noch GetTicks() ist unterschiedlich, läuft aber in beiden Varianten auf einen simplen Speicherlesezugriff hinaus der wohl nur recht wenig kosten sollte.
Du möchtest quasi den Zählerwert vom PIT als Nachkommastellen für Deinen 18,2Hz-Software-Zähler nutzen? Interessante Idee aber ich glaube nicht das das viel nutzt genauer als auf ca. 55ms bekommst Du damit trotzdem keinen IRQ. Ich würde lieber zu einer höheren IRQ-Frequenz raten.
Auch hier kann ich dir nicht folgen :(
Ich will damit sagen das Du mit dem häufigen Auslesen des PIT-Zählers trotzdem keine genaueren IRQs bekommst, Du also trotzdem auf dem 55ms-Raster hängen bleibst.
Also folgender Pseudo-Code:.........
So ich hoffe ich konnte mich jetzt genauer und besser Ausdrücken ;)
Das macht irgendwie einen komplizierten Eindruck. Vielleicht täuscht mich das, aber wenn der Scheduler das Timer-Management berücksichtigen muss dann finde ich persönlich das irgendwie ungeschickt. Außerdem scheinst Du Dich auf verschiedene HW-Timer zu verlassen, die werden 100%-tig auseinander driften, das gibt sicher viel Freude.
Ja. Solange Du den PIT nicht frei laufen lässt sondern immer mal dran "rumdrehst" bekommst Du Fehler die sich aufakkumulieren.
Naja, das lässt sich nicht wirklich vermeiden, wenn man eh so ne "alte" Krücke hat die nur den PIT und nicht mal den APIC unterstützt ;)
Doch das geht. Genau in diese Richtung geht ja das PIT-Konzept in meinem Ursprungspost, dort wird der PIT nur zur Initialisierung angefasst und danach geht alles nur noch in Software (im PIT-IRQ-Handler, siehe oben).
Der Punkt ist, meine Semaphore/Futex Idee wäre aber schneller ;) Weil du nur noch ein "lock sub dword[event],1" machst und wenn das Event gefeuert hat, dann kannst du gleich weiter machen (weil der neue Wert größer 0 ist) und wenn nicht, dann rufst du den Kernel auf und legst dich in der Semaphore "schlafen" und das Event weckt dich dann mit dem Semaphore-Code wieder auf.
Ich persönlich bin der Meinung das eine zusätzliche Ebene (schlafen legen und aufwecken musst Du den Thread ja trotzdem) auch zusätzliche Zeit kostet.
Ich hab halt mal nen Bsp. für ne innere Schleife bei nem Game unter Windows gesehen und da haben die es so gemacht. Also mit QeueryPerformanceCounter. Da bin ich dann ganz frech davon ausgegangen das man das unter anderen Systemen ähnlich löst. Wenn ich mich recht entsinne, sollst du unter Linux sowas mit der "Zeit" machen, die geben die, glaub ich in ms oder noch genauer an und da sollst du die beiden Werte dann vergleichen, halt was ähnliches nur nicht so genau.
Klingt nach aktivem warten, sowas sollte man nur für wirklich kurze Zeiten machen, und das mit dem ausrechnen der sleep-Zeit ist IMHO genauso ungeschickt (was macht man da mit negativen Ergebnissen).
Bist Du sicher das Du Boards mit Slot1 oder Sockel5/7 und mehreren CPUs hast?
Damals aus reiner Sammelleidenschaft und heute zum Testen meines OSs :D Damit ich mich ja auch mit den "schönsten" Seiten der x86 Architektur rumquählen darf ;)
Wo hast Du denn z.B. das Board mit mehreren Sockel 5 her? Im normalen Handel gab es das bestimmt nicht. Laut http://de.wikipedia.org/wiki/Sockel_5 ist in den Sockel 5 CPUs immer ein Local-APIC drin, bei allen neueren CPUs sowieso.
Aber wenn Du so auf "rumquählen" stehst dann kann ich Dir versichern das Deine Wahl für x86 genau richtig war und sicher noch für lange Zeit bleiben wird. ;)
Grüße
Erik
-
In Deinem Beispiel modifizierst Du immer die Werte in der Queue, das dauert länger als ein Vergleich. Den Time-Counter wirst Du auf jeden Fall zählen müssen damit Du die Systemlaufzeit u.ä. hast. Das alles fällt natürlich weg wenn der HPET da ist.
Ich wusste zwar auch nicht immer was mit einer Delta-Queue anzufangen, aber so wie ich dein Wissen einschätze, habe ich eigentlich gedacht das du das Prinzip kennst.
Also bei deiner Methode, musst du doch auch den Thread in eine sortierte Queue reinpacken. Also musst du auch dort linear, ein Element nach dem Anderen durchgehen.
Ich geb dir mal folgenden Pseudo-Code:
void queueAddDelta(struct thread_t *t) {
struct thread_t *ptr= deltaQueue;
while(ptr->next) {
if(ptr->sleepTime >= t->sleepTime) {
ptr->sleepTime-= t->sleepTime;
t->next= ptr;
t->prev= ptr->prev;
ptr->prev= t;
if(t->prev) {
t->prev->next= t;
} else {
sleepQueue= t;
}
return;
} else {
t->sleepTime-= ptr->sleepTime;
}
ptr= ptr->next;
}
ptr->next= t;
t->prev= ptr;
t->next= 0;
}
Ich hoffe dieser Code (ist erstmal fehlerfrei ;) ) und du verstehst jetzt mein Prinzip. Ich muss immer nur vom Head einer Queue einen Wert abziehen, ist also genauso effizient wie dein Vergleich. Denn ob ich einen Vergleich mache (was intern auch nur ne Subtraktion ist) oder ob ich etwas abziehen und bei den Flags dann auf 0 prüfe (was unter C leider nicht möglich ist, glaub ich jedenfalls) ist im Endeffekt das selbe!
Im Endeffekt sind unsere Systeme sich schon ähnlich nur das ich den PIT so langsam wie möglich laufen lassen möchte (bzw. ihn sogar ganz deaktivieren, wenn er nicht gebraucht wird). Wenn ich dein Konzept mit den Events nutze, dann würde ich sogar von meinem PerformanceCounter weggehen, aber eigentlich müsste das OS so eine Funktion bereitstellen und dafür war ja auch mal der TSC gedacht, bevor Intel erst hinterher festgestellt hat, das es dumm ist wenn sich die Aktualisierungsrate mit der Frequenz ändert ;)
Das klingt nach viel rechnen. Wie soll man denn da effizient was einfügen (also nicht ans Ende anhängen)? Da muss man doch vor jedem Vergleich erst mal nen Absolutwert berechnen denn man dann mit dem neuen einzufügenden Absolutwert vergleichen kann und vor allem linear durch wandern. Falls ich Dich falsch verstanden hab dann erkläre mir das mal Bitte genauer. Spätestens wenn Du mit dem HPET arbeitest benötigst Du auf jeden Fall die absoluten Zeit-Werte, denn den HPET-Counter kann man nicht (so einfach) beeinflussen. Das ist der Vorteil meiner PIT-Variante, die ist bis auf ein paar winzige Unterschiede im IRQ-Handler mit der HPET-Variante exakt identisch. Die PIT-Variante emuliert quasi den HPET, nur mit gröberer Zeiteinteilung. Nur noch GetTicks() ist unterschiedlich, läuft aber in beiden Varianten auf einen simplen Speicherlesezugriff hinaus der wohl nur recht wenig kosten sollte.
Die Delta-Queue habe ich ja oben schon erläutert. Was ich noch nicht ganz verstehe ist, das du sachen bemängelst die bei deinem System doch genauso sind. Du hättest nur den Vorteil, das du mit absoluten Werten ne andere Struktur als ne Liste (z.B. nen RB-Tree) nehmen könntest, aber auch du musst sortiert eintragen (was in einer Liste nun mal linear ist) oder du müsstest bei jedem IRQ Aufruf die komplette Liste durch gehen, was alles andere als optimal ist.
Was das Beeinflussen des HPET-Counters betrifft. Wenn ich das alles richtig Verstanden habe, dann gibt man nun nen Comperator (einen Wert, in dem Fall nen absoluten) an und der HPET feuert dann nen IRQ wenn der Counter diesen Wert erreicht hat.
Ich würde das wieder über ne Delta-Queue lösen, einfach auf den alten Wert der schon drin steht den neuen Wert vom 1. Element der Delta-Queue drauf addieren und fertig. Ganz simpel :D
Ich will damit sagen das Du mit dem häufigen Auslesen des PIT-Zählers trotzdem keine genaueren IRQs bekommst, Du also trotzdem auf dem 55ms-Raster hängen bleibst.
Dann hast du leider mein Konzept immernoch nicht verstanden :(
Ich lese den Counter aus um zu wissen wieviel Zeit seit dem letzten PIT IRQ schon wieder vergangen ist, damit ich diese auf die Zeit, die der Thread schlafen will drauf rechnen kann. Denn der IRQ Handler vom PIT zieht immer 55,4ms ab, egal wann der Thread schlafen gelegt wurde. So sichere ich das der Thread mind. genauso lange schläft wie er das vor hat.
Um zu sichern, das ein Thread auch genauer als das 55ms Raster schlafen kann, habe ich ja eine per CPU Sleep-Queue die für alles <55ms zuständig ist und da ich da wieder mit ner Delta-Queue arbeite, ist auch mein Jitter nicht so schlimm. Denn der kann sich ja nicht immer wieder aufsummieren (jedenfalls nicht was die Sleep-Queue betrifft).
Das macht irgendwie einen komplizierten Eindruck. Vielleicht täuscht mich das, aber wenn der Scheduler das Timer-Management berücksichtigen muss dann finde ich persönlich das irgendwie ungeschickt. Außerdem scheinst Du Dich auf verschiedene HW-Timer zu verlassen, die werden 100%-tig auseinander driften, das gibt sicher viel Freude.
Wie gesagt, da der Scheduler-Timer nur für alles <55ms zuständig ist, kann eigentlich nicht viel passieren. Gerade da ein Thread mit normaler Prio bei mir 30ms als Zeitscheibe bekommt, wird der Scheduler im average-case 2mal aufgerufen und der Jitter ist dort selbst mit PIT "gerade" mal (3*832ns für lesen beim reinpacken des Threads + 5*832ns pro Scheduleraufruf= 13*832ns=) 10816ns= 10,8µs, was ich für verdammt gut für so ne alte Krücke halte ;) Wenn du jetzt noch den APIC-Timer für den Scheduler nimmst, dann wird es noch genauer!
Das einzige Problem was ich haben werde, sind halt PCs die nur nen PIT haben, da summiert sich dann der Jitter auf, obwohl ich gerade ganz spontan mit dem Gedanken spiele in dem Fall die RTC dafür zu mißbrauchen ;) Also das ich die RTC für´s Grobe nutze und den PIT für´s "feine", dann summiert sich mein Jitter auch nicht auf. Muss ich mal sehen ob ich das irgendwie vernünftig über mein Interface umsetzen kann.
Ich persönlich bin der Meinung das eine zusätzliche Ebene (schlafen legen und aufwecken musst Du den Thread ja trotzdem) auch zusätzliche Zeit kostet.
Ja, aber nur wenn das Event noch nicht ausgelöst wurde. Was willst du denn dann machen oder besser gesagt, wie willst du dann warten. Du musst doch den Thread auch schlafen legen (ich hätte vielleicht sagen sollen, das er so lange wartet bis er aufgeweckt wird und nicht eine bestimmte Zeit schläft).
Klingt nach aktivem warten, sowas sollte man nur für wirklich kurze Zeiten machen, und das mit dem ausrechnen der sleep-Zeit ist IMHO genauso ungeschickt (was macht man da mit negativen Ergebnissen).
Ich hab von Spieleprogrammierung keine Ahnung, obwohl mich ne 3D-Engine auch reizen würde :D
Ist halt das einzige was ich kenne wo dieser PerformanceCounter verwendet wurde, aber da du mich ja inzwischen von deinem Event-System überzeugt hast, kann ich das ja erstmal vergessen ;)
Wo hast Du denn z.B. das Board mit mehreren Sockel 5 her? Im normalen Handel gab es das bestimmt nicht. Laut http://de.wikipedia.org/wiki/Sockel_5 ist in den Sockel 5 CPUs immer ein Local-APIC drin, bei allen neueren CPUs sowieso.
Da muss ich dich dann mal ganz frech nach deinem Alter fragen und wie lange du dich schon mit der OS Programmierung auf x86 beschäftigst ;)
Denn den APIC haben die alle drin, der wird aber immer deaktiviert, Ausnahmen sind halt Dual-Sockel-Boards. Selbst bei nem Athlon XP wurde das noch meistens gemacht. Das war ein Grund warum ich mir mal nen neues Board geholt habe, weil EPOX damals gesagt hat, es bringt nur Probleme und deswegen lassen sie den APIC deaktiviert.
Aber das beste war die Begründung, der IO-APIC macht nur Probleme, da frag ich mich dann wieso der APIC nicht genutzt werden kann ohne das ein IO-APIC da ist!?
Wenn du willst mache ich dir nen Foto von dem einen Sockel5 Board was ich hier habe? Bei dem hast du sogar recht, das muss irgendeins aus nem Server sein. Denn ich habe bis heute kein Netzteil dafür :( und weiß erst seit dem Wochenende dass das mal nen kleiner Standard war (nen erweiterter AT).
Ein anderes ist noch bei meinen Eltern zu Hause (da ist mein großes Lager ;) ). Das verwendet sogar die defaul Konfiguration der MPS. Sockel 7 habe ich dann auch nochmal 2 und 1 Sockel 8 Board habe ich doch total unterschlagen ;) (alles natürlich Dual-Sockel).
Aber wenn Du so auf "rumquählen" stehst dann kann ich Dir versichern das Deine Wahl für x86 genau richtig war und sicher noch für lange Zeit bleiben wird. Wink
Darauf würde ich dir mit nem anderen Hobby von mir antworten. Andere sehen Triathlon auch nur als Quählerei an, ich sehe sowas was Herausforderung und wenn man es geschafft hat, dann kann man auch Stolz auch sich sein. Was soll ich mir denn leichte Ziele setzen?! Dann reicht es ja das neueste Spiel durch zu zocken, aber das macht nicht halb so viel Spaß, man lernt nicht so viel dabei (von der Erfahrung mal ganz abgesehen) und es gibt verdammt viele die aus auch schaffen.
Um es mal so zu sagen, OS Programmierung ist doch ne Extreme Sportart unter den Programmierern ;)
-
Hallo,
Ich wusste zwar auch nicht immer was mit einer Delta-Queue anzufangen, aber so wie ich dein Wissen einschätze, habe ich eigentlich gedacht das du das Prinzip kennst.
Also bei deiner Methode, musst du doch auch den Thread in eine sortierte Queue reinpacken. Also musst du auch dort linear, ein Element nach dem Anderen durchgehen.
Ich denke schon das ich das Prinzip der Delta-Queue verstanden hab, aber ich bin der Meinung das die für diesen Zweck eher ungeeignet ist.
Wenn Du auf dem vordersten Element rumrechnest dann kommt auch immer ein Speicherschreibzugriff zusätzlich, gegenüber einem Vergleich, dazu. Zum prüfen, im IRQ-Handler, ob das vorderste Element nun dran ist müssen wir beide auch nur das vorderste Element anfassen (Du lesen und schreiben, ich nur lesen), das komplette durchgehen der Liste ist dafür nicht erforderlich (siehe meinen IRQ-Handler-Code). Zum beliebigen Einfügen eines neuen Elements musst Du Deine Delta-Queue in jedem Fall linear von vorne an durchlaufen bis die richtige Stelle gefunden ist, ich dagegen kann diese Liste als Baum realisieren und kann daher sehr viel schneller Einfügen. Das Entfernen des vordersten Elementes, also das Element unten links in meinem Baum, ist nur minimal komplizierter als bei Deiner Delta-Queue.
Ich weiß wovon ich schreibe, ich habe diese Baum-Variante schon mal implementiert (vor knapp 9 Jahren), in purem x86-32Bit-Assembler, mit absoluten 64Bit-Zeitwerten. Das war für ne Industrie-Maschine mit vielen Pneumatik-Zylindern, Motoren und haufenweise anderem Zeugs. Für jede Bewegung wurde ein TimeOut-Timer gestartet so das dort oft über 100 Timer (mit Laufzeiten von etwa 200ms bis etwa 3s, aber auch ein paar Timern im Stundenbereich) gleichzeitig aktiv waren. Da die meisten der Timer wieder gelöscht wurden bevor sie abgelaufen sind, da die Bewegungen ja normalerweise rechtzeitig fertig waren (anders wäre es ein Fehler gewesen), und dann wieder neue Timer gestartet wurden war das einfügen von Timern ein essenziell wichtiger Vorgang. Die gelöschten Timer wurden nicht aus dem Baum entfernt, das erschien mir zu kompliziert, (entfernt habe ich solche Timer nur wenn sie nur ein Kind haben) sondern einfach deaktiviert und wenn sie dann abgelaufen sind (dann haben die garantiert maximal nur ein Kind) einfach ohne weitere Aktion gelöscht. Zu dem Timing-System gibt es noch einen Message-Handler und einen Event-Handler welche beide auf dem Timing-System aufsetzen (für TimeOuts usw.). Auch ein kooperativer Thread-Scheduler war mit dabei, der wiederum vom Timing-System benutzt wurde. Mit diesem System bin ich auf einem K6-500MHz auf knapp 600'000 Thread-Wechsel pro Sekunde gekommen, die ungefähr 20 Threads haben auch was sinnvolles getan.
Ich geb dir mal folgenden Pseudo-Code:.......
Ich hoffe dieser Code (ist erstmal fehlerfrei ;) ) und du verstehst jetzt mein Prinzip.
Ähm, nein, leider überhaupt gar nicht. :(
Deinen Code hab ich ehrlich gesagt gar nicht verstanden, Bitte poste ihn noch mal mit reichlich und aussagekräftigen Kommentaren dabei. Was mich stört ist das Du da das einzufügende Element ständig modifizierst und auch das Queue-Element vor (wirklich davor? oder habe ich mich da verschaut? ) welches das neue kommt wird auch modifiziert. In meiner Variante wird nur die richtige Stelle gesucht (nur Vergleiche keine Modifikationen) und dann eingefügt (simple Pointer-Magie, so wie bei Dir), egal ob lineare sortierte Liste oder sortierter Baum, schon allein deshalb (keine zusätzlichen/verteilten Schreibzugriffe) sollte meine Variante schneller sein.
Ich muss immer nur vom Head einer Queue einen Wert abziehen,
Du meinst im IRQ-Handler?
ist also genauso effizient wie dein Vergleich. Denn ob ich einen Vergleich mache (was intern auch nur ne Subtraktion ist) oder ob ich etwas abziehen und bei den Flags dann auf 0 prüfe (was unter C leider nicht möglich ist, glaub ich jedenfalls) ist im Endeffekt das selbe!
Beim richtigen rechnen kommt eben noch der Speicherschreibzugriff dazu. Da Du einzelne Werte (viel kleiner als eine Cache-Line), quer über den RAM verteilt, modifizierst könnte das schon recht gut bremsen. Auf den Cache kannst Du dabei jedenfalls nicht zählen, der dürfte IMHO eher bremsen weil er versucht komplette Cache-Lines zu lesen und die modifizierten Cache-Lines dann wieder komplett schreiben will (oder sie im Cache liegen bleiben und dort wertvollen Platz kosten).
Im Endeffekt sind unsere Systeme sich schon ähnlich
Ja, nur das ich mit absoluten Werten arbeiten will und diese IMHO weniger (Rechen-)Arbeit machen.
nur das ich den PIT so langsam wie möglich laufen lassen möchte (bzw. ihn sogar ganz deaktivieren, wenn er nicht gebraucht wird).
Wenn Du den PIT abschalten möchtest musst Du das in GetTicks() berücksichtigen oder soll dann in Deinem OS die Zeit stehen bleiben? Wenn es Dir aufs Energiesparen ankommt würde ich eher dazu raten die PIT-Frequenz zu reduzieren, alle 100ms die CPU für ein paar Mikrosekunden aufzuwecken dürfte nur wenig Energie kosten. Wenn Du deutlich besseres Power-Management willst (was eh erst auf recht modernen CPUs und Boards geht) dann solltest Du auch den HPET voraussetzen (der braucht zum laufen fast gar nichts an Energie).
aber eigentlich müsste das OS so eine Funktion bereitstellen und dafür war ja auch mal der TSC gedacht, bevor Intel erst hinterher festgestellt hat, das es dumm ist wenn sich die Aktualisierungsrate mit der Frequenz ändert ;)
Das der TSC von der CPU-Core-Frequenz abhängig ist finde ich gar nicht so schlecht, das macht ihn mit den anderen Performance-Monitoring-Counters (z.B. Anzahl der abgearbeiteten Befehle, nur Integer-Befehle, nur FPU-Befehle, Cache-Hits usw.) vergleichbar. Der TSC ist nur zum Messen von kleinen Zeiträumen gedacht, für präzise Langzeitmessungen gibt es ja den HPET oder die RTC.
Was ich noch nicht ganz verstehe ist, das du sachen bemängelst die bei deinem System doch genauso sind.
Ich habe bemängelt das bei der Delta-Queue mehr zu rechnen ist und das Du nicht effizient neue Elemente einfügen kannst. Das sind beides Dinge die mit absoluten Zeit-Werten nicht auftreten und das Einfügen lässt sich noch zusätzlich durch die Benutzung eines Baumes deutlich beschleunigen.
Du hättest nur den Vorteil, das du mit absoluten Werten ne andere Struktur als ne Liste (z.B. nen RB-Tree) nehmen könntest, aber auch du musst sortiert eintragen (was in einer Liste nun mal linear ist)
Absolute Zeitwerte haben den Vorteil das man diese immer beliebig miteinander Vergleichen kann (also jeden mit jeden) wogegen bei relativen Zeit-Werten immer der Bezugspunkt mit eingerechnet werden muss. Wegen der beliebigen Vergleichbarkeit der absoluten Zeitwerte muss man bei der linearen sortierten Liste auch nicht zwingenst jedes Element anfassen, da könnte man eventuell in großen Sprüngen über die Liste gehen bis man in der Nähe des gewünschten Ziels ist und dann immer feiner suchen (dazu bräuchte man natürlich einen effizienten wahlfreien Zugriff auf die Liste). Zumindest stehen mit den absoluten Zeitwerten ein menge Möglichkeiten offen, es gibt bestimmt noch was besseres als nen einfacher Baum, wogegen bei den relativen Zeitwerten der erforderliche Bezugspunkt einiges ziemlich kompliziert macht.
oder du müsstest bei jedem IRQ Aufruf die komplette Liste durch gehen, was alles andere als optimal ist.
Zumindest da sind wir uns offensichtlich einig.
Was das Beeinflussen des HPET-Counters betrifft. Wenn ich das alles richtig Verstanden habe, dann gibt man nun nen Comperator (einen Wert, in dem Fall nen absoluten) an und der HPET feuert dann nen IRQ wenn der Counter diesen Wert erreicht hat.
Exakt. Der HPET feuert nur bei Gleichheit, weshalb man mit Zeitwerten die gleich dran sind etwas aufpassen muss (aber das sollte der HPET-IRQ-Handler aus meinem letzten Post theoretisch hinbekommen).
Ich würde das wieder über ne Delta-Queue lösen, einfach auf den alten Wert der schon drin steht den neuen Wert vom 1. Element der Delta-Queue drauf addieren und fertig. Ganz simpel :D
Ganz simpel finde ich das nicht. Zum draufaddieren musst Du vorher lesen und das wird in einem Non-Cachable-Bereich eher langsam sein. Wenn Du zum Schluss eh absolute Werte brauchst, warum dann so viel Mühe um immer mit relativen Werten zu arbeiten?
Ich will damit sagen das Du mit dem häufigen Auslesen des PIT-Zählers trotzdem keine genaueren IRQs bekommst, Du also trotzdem auf dem 55ms-Raster hängen bleibst.
Dann hast du leider mein Konzept immernoch nicht verstanden :(
Ganz offensichtlich. :(
Ich lese den Counter aus um zu wissen wieviel Zeit seit dem letzten PIT IRQ schon wieder vergangen ist, damit ich diese auf die Zeit, die der Thread schlafen will drauf rechnen kann. Denn der IRQ Handler vom PIT zieht immer 55,4ms ab, egal wann der Thread schlafen gelegt wurde. So sichere ich das der Thread mind. genauso lange schläft wie er das vor hat.
Um zu sichern, das ein Thread auch genauer als das 55ms Raster schlafen kann, habe ich ja eine per CPU Sleep-Queue die für alles <55ms zuständig ist und da ich da wieder mit ner Delta-Queue arbeite, ist auch mein Jitter nicht so schlimm. Denn der kann sich ja nicht immer wieder aufsummieren (jedenfalls nicht was die Sleep-Queue betrifft).
Das sieht in meinen Augen irgendwie extrem Aufwendig aus. Ich verstehe nicht welchen Vorteil Du Dir von diesem Aufwand erhoffst. Das ganze kann man doch eigentlich ganz einfach und simpel Lösen.
Wie gesagt, da der Scheduler-Timer nur für alles <55ms zuständig ist,
Also ich finde es ungeschickt wenn der Scheduler was mit Timing zu tun hat. Ich persönlich bin der Meinung das der Schuler nur für die Verwaltung der Threads (und deren Zustände wie lauffähig, blockiert, schlafend usw.) und für den Kontext-Switch zuständig ist. Ein ordentlicher Scheduler, der mehrere CPUs fair + schnell über die Threads verteilt und dafür effiziente + leistungsfähige Management-Funktionen bietet, ist ansich schon kompliziert genug, da muss man nicht auch noch fremde Aufgaben mit rein packen.
Gerade da ein Thread mit normaler Prio bei mir 30ms als Zeitscheibe bekommt, wird der Scheduler im average-case 2mal aufgerufen
Auf einem normalen System dürfte kaum eine Zeitscheibe aufgebraucht werden, üblicherweise läuft ein Thread ziemlich schnell auf eine blockierende Anfrage (aus Datei lesen, ins Netzwerk senden oder auf User-Eingabe warten). Nur Threads die wirklich was zu rechnen haben werden ihre Zeitscheiben aufbrauchen. Die Länge der Zeitscheiben zu optimieren bringt IMHO nicht viel, da ist ein effizienter Kontext-Switch schon nützlicher.
und der Jitter ist dort selbst mit PIT "gerade" mal (3*832ns für lesen beim reinpacken des Threads + 5*832ns pro Scheduleraufruf= 13*832ns=) 10816ns= 10,8µs, was ich für verdammt gut für so ne alte Krücke halte ;) Wenn du jetzt noch den APIC-Timer für den Scheduler nimmst, dann wird es noch genauer!
Von was für einen Jitter schreibst Du da eigentlich? Die exakte Länge der Zeitscheiben ist eher unkritisch, 10% hin oder her dürften da gar nichts machen. Viel wichtiger ist das wenn ein Thread mit ner hohen Priorität zum Zeitpunkt X wieder aufgeweckt werden soll dass das auch möglichst zum rechten Zeitpunkt passiert und dieser Thread dann auch einen anderen Thread mit niedrigerer Priorität verdrängen kann.
Das einzige Problem was ich haben werde, sind halt PCs die nur nen PIT haben, da summiert sich dann der Jitter auf,
Nur wenn Du den PIT nicht frei laufen lässt. In der PIT-Variante meines Ursprungsposts wird auch nichts aufakkumuliert.
obwohl ich gerade ganz spontan mit dem Gedanken spiele in dem Fall die RTC dafür zu mißbrauchen ;) Also das ich die RTC für's Grobe nutze und den PIT für's "feine", dann summiert sich mein Jitter auch nicht auf. Muss ich mal sehen ob ich das irgendwie vernünftig über mein Interface umsetzen kann.
Mehrere unabhängige Timer (die RTC ist ja auch ein Timer) zu benutzen halte ich für keine gute Idee. Du wirst ne Menge Aufwand treiben müssen um das auch bei sehr langer Laufzeit (über Monate oder gar Jahre, oder baust Du ein OS mit konstruktiv begrenzter Laufzeit? ) synchron zu halten.
Genau deshalb stelle ich mir die Frage: Warum Kompliziert wenn es doch auch so einfach geht? Was erhoffst Du Dir davon? Wo genau siehst Du den Vorteil?
Relative Zeitwerte, mehrere unabhängige Timer und verwische Zuständigkeiten in den SW-Modulen. Klar das kann man alles realisieren aber wenn Du diesen Aufwand treiben möchtest dann erwartest Du doch auch was, ich sehe das nur eben nicht, das müsstest Du mir erklären.
Ich persönlich bin der Meinung das eine zusätzliche Ebene (schlafen legen und aufwecken musst Du den Thread ja trotzdem) auch zusätzliche Zeit kostet.
Ja, aber nur wenn das Event noch nicht ausgelöst wurde. Was willst du denn dann machen oder besser gesagt, wie willst du dann warten.
Wenn der Event noch nicht ausgelöst wurde (was sich ja einfach feststellen lässt) dann wird die aktuelle Thread-ID im Event-Object als wartend vermerkt und der Thread einfach schlafen gelegt. Wenn das Event dann irgendwann ausgelöst wird dann muss der Thread wieder geweckt werden und wenn kein Thread wartet dann eben nicht. Nur auf einem SMP-System muss man da etwas mit der Atomizität dieser Aktionen aufpassen.
(ich hätte vielleicht sagen sollen, das er so lange wartet bis er aufgeweckt wird und nicht eine bestimmte Zeit schläft)
Ja, davon bin ich ausgegangen. Wobei man als zusätzliches Feature ja noch ein optionales TimeOut einbauen kann. Meine damalige Implementierung kann das.
Da muss ich dich dann mal ganz frech nach deinem Alter fragen und wie lange du dich schon mit der OS Programmierung auf x86 beschäftigst ;)
Das findest Du in meinem Forums-Profil (http://forum.lowlevel.eu/index.php?action=profile;u=7880) und meiner Wiki-Benutzer-Seite (http://www.lowlevel.eu/wiki/Benutzer:Erik.vikinger). Wieso fragst Du das, weil ich wissen möchte wo Du so exotische Boards her hast?
Denn den APIC haben die alle drin, der wird aber immer deaktiviert,
Das wusste ich nicht das die APICs vom BIOS per Default deaktiviert werden.
Meine Erfahrung mit solchen Boards habe ich mit 4x PentiumPro 200MHz 1MB-L2-Cache unter Windows NT gemacht und ich kann Dir sagen das Windows NT verdammt schlecht skaliert hat. Das Board und die CPUs hatten zwar alle APICs aber Windows NT konnte damit nicht allzu viel anfangen. Der IO-APIC war wimre komplett deaktiviert und die Local-APICs wurden von Windows NT nur mit dem absolut notwendigsten (für SMP) benutzt.
Wenn du willst mache ich dir nen Foto von dem einen Sockel5 Board was ich hier habe?
Ja, gerne. Was haste denn für Prozies drauf? Falls Du das Board nicht in Betrieb bekommst würde ich mich dafür interessieren.
Um es mal so zu sagen, OS Programmierung ist doch ne Extreme Sportart unter den Programmierern ;)
Full ACK!
Aber man kann den Triathlon bei normalem Wetter (leicht Bewölkt, kein Regen und kein Wind) in normaler Umgebung (Flachland) durchziehen oder, wenn man masochistisch veranlagt ist, bei extremsten Wetter (>100 l Regen pro m² und h mit Windstärke 8 ) und in unpassenster Umgebung (Gebirge). ;)
SCNR :D
Grüße
Erik
-
Wenn Du auf dem vordersten Element rumrechnest dann kommt auch immer ein Speicherschreibzugriff zusätzlich, gegenüber einem Vergleich, dazu. Zum prüfen, im IRQ-Handler, ob das vorderste Element nun dran ist müssen wir beide auch nur das vorderste Element anfassen (Du lesen und schreiben, ich nur lesen), das komplette durchgehen der Liste ist dafür nicht erforderlich (siehe meinen IRQ-Handler-Code). Zum beliebigen Einfügen eines neuen Elements musst Du Deine Delta-Queue in jedem Fall linear von vorne an durchlaufen bis die richtige Stelle gefunden ist, ich dagegen kann diese Liste als Baum realisieren und kann daher sehr viel schneller Einfügen. Das Entfernen des vordersten Elementes, also das Element unten links in meinem Baum, ist nur minimal komplizierter als bei Deiner Delta-Queue.
Also ich wüde wahrscheinlich sogar ne Delta-Queue in einen Baum packen können ;)
Was das Entfernen betrifft, ist meine Queue klar schneller, besonders wenn der Baum immer voller wird. Denn du versaust dir da den Cache, durch die "vielen" (ein paar reichen ja) Speicherzugriffe und die "längere" (sollte eigentlich unwesentlich sein) addiert sich ja auch, wenn du doch mal einige Elemente Entfernen musst. Rein theoretisch betrachtet ist die Queue in dem Fall O(1) und der Baum O(log n).
... Mit diesem System bin ich auf einem K6-500MHz auf knapp 600'000 Thread-Wechsel pro Sekunde gekommen, die ungefähr 20 Threads haben auch was sinnvolles getan.
Die Zahl erschein mir irgendwie arg hoch. Denn das macht gerade mal 833 Takte pro Thread und so ein Thread-Wechsel kostet ja doch einiges an Zeit und Performance (oder liefen die alle in einem Adressraum?).
Deinen Code hab ich ehrlich gesagt gar nicht verstanden, Bitte poste ihn noch mal mit reichlich und aussagekräftigen Kommentaren dabei. Was mich stört ist das Du da das einzufügende Element ständig modifizierst und auch das Queue-Element vor (wirklich davor? oder habe ich mich da verschaut? ) welches das neue kommt wird auch modifiziert. In meiner Variante wird nur die richtige Stelle gesucht (nur Vergleiche keine Modifikationen) und dann eingefügt (simple Pointer-Magie, so wie bei Dir), egal ob lineare sortierte Liste oder sortierter Baum, schon allein deshalb (keine zusätzlichen/verteilten Schreibzugriffe) sollte meine Variante schneller sein.
Der "Witz" bei einer Delta-Queue ist doch, das du nur die Abstände zwischen den Elementen speicherst und nicht die direkten (absoluten) Werte. Ich weiß gar nicht mehr in welchem Zusammenhang ich das damals gelernt habe, aber kann schon sein, das es was fürs Zeitmanagement war.
Was du ja schon richtig erkannt hast, ist das deine Lösung nur ein (oder mehrere) Pointer ändern und meiner bis zu 2 Werte und ein paar Pointer, den einen Wert dafür ständig (im worst-case).
Um deine eine Frage zu beantworten, du musst den Abstand zwischen dem einzufügendem Element und dem Element danach ändern, den der Abstand zw. den beiden ist ja anders.
void queueAddDelta(struct thread_t *t) {
//head der queue
struct thread_t *ptr= deltaQueue;
//so lange durch gehen, bis kein element mehr kommt oder wir unsere position gefunden haben
while(ptr->next) {
//wenn der abstand bis zum nächsten element größer ist, als unser abstand zum vorherigen element, dann haben wir unsere position (das schließt gleich den fall ein, das wir der neue head werden)
if(ptr->sleepTime >= t->sleepTime) {
//abstand zum nachfolger aktualisieren
ptr->sleepTime-= t->sleepTime;
//ptr wird unser nachfolger
t->next= ptr;
//unser vorgänger ist der vorgänger von ptr
t->prev= ptr->prev;
//ptr´s vorgänger werden wir
ptr->prev= t;
//wir müssen noch den fall betrachten das wir der neue head sind oder halt mitten drin
if(t->prev) {
t->prev->next= t;
} else {
sleepQueue= t;
}
//fertsch, wir können endlich raus hier ;)
return;
} else {
//falls wir unsere position noch nicht gefunden haben, dann müssen wir zumindest unsere zeit (den abstand sozusagen) aktualisieren
t->sleepTime-= ptr->sleepTime;
}
//ab zum nächsten eintrag in der liste
ptr= ptr->next;
}
//dummerweise sind wir das letzte (element ;) )
ptr->next= t;
t->prev= ptr;
t->next= 0;
}
Du meinst im IRQ-Handler?
Jap.
Beim richtigen rechnen kommt eben noch der Speicherschreibzugriff dazu. Da Du einzelne Werte (viel kleiner als eine Cache-Line), quer über den RAM verteilt, modifizierst könnte das schon recht gut bremsen. Auf den Cache kannst Du dabei jedenfalls nicht zählen, der dürfte IMHO eher bremsen weil er versucht komplette Cache-Lines zu lesen und die modifizierten Cache-Lines dann wieder komplett schreiben will (oder sie im Cache liegen bleiben und dort wertvollen Platz kosten).
Wie oben schon geschrieben, solltest du doch durch die "vielen" Zugriffe (bei einem Baum z.b.) auch den Cache trashen, oder? Aber ansonsten hast du recht.
Wenn Du den PIT abschalten möchtest musst Du das in GetTicks() berücksichtigen oder soll dann in Deinem OS die Zeit stehen bleiben? Wenn es Dir aufs Energiesparen ankommt würde ich eher dazu raten die PIT-Frequenz zu reduzieren, alle 100ms die CPU für ein paar Mikrosekunden aufzuwecken dürfte nur wenig Energie kosten. Wenn Du deutlich besseres Power-Management willst (was eh erst auf recht modernen CPUs und Boards geht) dann solltest Du auch den HPET voraussetzen (der braucht zum laufen fast gar nichts an Energie).
Naja, wozu brauche ich denn die Zeit noch, außer um solche Events auszuführen? Denn für die Uhr wollte ich eigentlich (also mache ich schon) die RTC nehmen, die wird einfach jede Sekunde einmal aktualisiert. Aber gerade fällt mir ein, das einige Dateisysteme die Zeit bis auf die ms genau wollen, oder?
Der TSC ist nur zum Messen von kleinen Zeiträumen gedacht, für präzise Langzeitmessungen gibt es ja den HPET oder die RTC.
Naja, die RTC ist nicht wirklich gut für sowas geeignet (meine bescheidene Meinung) und du immer mit deinem HPET ;) Ich weiß auch das ein Auto besser ist um nach Hause zu fahren (und meistens weniger stressig), aber ich kann mir einfach keins leisten, also fahre ich Zug und mache das beste daraus ;)
Ganz simpel finde ich das nicht. Zum draufaddieren musst Du vorher lesen und das wird in einem Non-Cachable-Bereich eher langsam sein. Wenn Du zum Schluss eh absolute Werte brauchst, warum dann so viel Mühe um immer mit relativen Werten zu arbeiten?
Macht der Gewohneit? Ich weiß es nicht, aber was ich weiß ist, das ich ein riesen Problem habe, auf SMP Systemen (ohne den netten HPET ;) ) ne halbwegs akkurate globale Zeit zu bekommen. Wenn ich das in den Griff bekommen würde, dann kann ich auch absolute Werte nutzen.
So aber finde ich ist es einfacher, zu sagen, so jetzt soll der Thread mal so und so lange schlafen und nicht er soll bis dann schlafen!
Das sieht in meinen Augen irgendwie extrem Aufwendig aus. Ich verstehe nicht welchen Vorteil Du Dir von diesem Aufwand erhoffst. Das ganze kann man doch eigentlich ganz einfach und simpel Lösen.
Ich dachte mir halt, wenn du schon so ein schönes Thema wie die OS Programmierung machst, dann mach es auch richtig und mit richtig meine ich in dem Fall, das ich die höchste Präzision aus den gegebenen Mitteln heraus hole (ohne dabei ander Dinge negativ zu beeinflussen, wie z.B. durch ne PIT Frequenz von 1000Hz).
So weit für SMP Systeme. Für ein CPU Systeme hab ich mich halt vollkommen auf den One-Shot-Modus eingeschossen. Ich find die Idee halt toll und sehe auch die Vorteile, nur leider ist der PIT da anderer Meinung ;) So langsam spiele ich mit dem Gedanken auf PIT only Systemen doch wieder nen periodischen Modus zu nutzen, aber damit nehme ich mir einen Vorteil und das wäre die Präzision von Events. Ich müsste halt abwiegen was schlimmer ist.
Also ich finde es ungeschickt wenn der Scheduler was mit Timing zu tun hat. Ich persönlich bin der Meinung das der Schuler nur für die Verwaltung der Threads (und deren Zustände wie lauffähig, blockiert, schlafend usw.) und für den Kontext-Switch zuständig ist. Ein ordentlicher Scheduler, der mehrere CPUs fair + schnell über die Threads verteilt und dafür effiziente + leistungsfähige Management-Funktionen bietet, ist ansich schon kompliziert genug, da muss man nicht auch noch fremde Aufgaben mit rein packen.
Naja, so wie ich das sehe hat er schon was mit Timing zu tun, denn er kümmert sich doch ohnehin darum wie lange ein Thread laufen darf! Da kann er dann auch noch Events mit einbeziehen, so dass der Thread dann halt ein wenig früher unterbrochen wird. Wirklich komplizierter wird er meiner Meinung nach deswegen nicht.
Das ist übrigenz auch ein wunderbarer Fall für relative Zeiten. Denn wenn du möglichst Präzise (was mit dem APIC auf SMP Systemen ja möglich ist) Events auslösen willst, kannst du dich nicht auf die globale Zeit verlosen, da zu ungenau und da jede CPU ihre eigene "Zeit" hat, musst du halt mir relativen Zeiten arbeiten. Um es mal so zu sagen, kann ich einfach dein Konzeot mit meinem vermischen.
Ich nutze für den PIT die globale Zeit und wecke den Thread nicht auf wenn er gleich der globalen Zeit ist, sondern ich packe ihn in die Sleep-Queue der CPU wenn er kleiner der globalen Zeit+ein Tick ist. Dann kann ich auch andere Datenstrukturen nutzen und habe auch nur noch Vergleiche.
In den Sleep-Queues der CPUs nutze ich dann wieder die Relative Zeit.
Genau deshalb stelle ich mir die Frage: Warum Kompliziert wenn es doch auch so einfach geht? Was erhoffst Du Dir davon? Wo genau siehst Du den Vorteil?
Relative Zeitwerte, mehrere unabhängige Timer und verwische Zuständigkeiten in den SW-Modulen. Klar das kann man alles realisieren aber wenn Du diesen Aufwand treiben möchtest dann erwartest Du doch auch was, ich sehe das nur eben nicht, das müsstest Du mir erklären.
Hatte ich ja oben schon beantwortet. Nur noch mal ganz kurz, höchst mögliche Präzision auf alten (wie neuen) Systemen. Wofür, ich habe keine Ahnung ;)
Sag mir doch mal was das höchste an Präzision ist, was man in einem OS wahrscheinlich brauchen wird. Denn ich versuche ja schon mit meinem System bis auf ns runter zu gehen (beim PIT eher µs).
... Wieso fragst Du das, weil ich wissen möchte wo Du so exotische Boards her hast?
Auch, aber weil du das mit den APICs nicht wusstest.
Meine Erfahrung mit solchen Boards habe ich mit 4x PentiumPro 200MHz 1MB-L2-Cache unter Windows NT gemacht und ich kann Dir sagen das Windows NT verdammt schlecht skaliert hat. Das Board und die CPUs hatten zwar alle APICs aber Windows NT konnte damit nicht allzu viel anfangen. Der IO-APIC war wimre komplett deaktiviert und die Local-APICs wurden von Windows NT nur mit dem absolut notwendigsten (für SMP) benutzt.
Also so richtig kann ich es nicht glauben das der IO-APIC deaktiviert war. Denn das hieße ja, dass alle IRQs immer auf die selbe CPU geleitet wurden (man kann den PIC durchaus auf SMP Systemen nutzen, aber eher sehr unvorteilhaft)! Die APICs sind ja auch für SMP zwingend erforderlich!
Das mit den deaktivierten APICs ärgert mich bis heute, ich meine Athlon XP Systeme sehe ich schon als halbwegs modern an! Und wer kauft sich schon nur ein neues Board damit er sein eigenes kleines OS darauf testen kann ;)
Ja, gerne. Was haste denn für Prozies drauf? Falls Du das Board nicht in Betrieb bekommst würde ich mich dafür interessieren.
Im Moment sind da gar keine drauf. Mir mangelt es an dem richtigen Netzteil, weil wie gesagt eine Art erweiterter AT Standard (P8 und P9 Stecker wie normal, aber zusätzlich noch nen P10 Stecker). Das Board wurde augenscheinlich auch von irgendeinem Vorbesitzer modifiziert (ich glaube um Sockel 7 CPUs laufen zu lassen, aber da irre ich mich wahrscheinlich). Wenn ich es schaffe, dann mache ich mal ein Bild.
Aber man kann den Triathlon bei normalem Wetter (leicht Bewölkt, kein Regen und kein Wind) in normaler Umgebung (Flachland) durchziehen oder, wenn man masochistisch veranlagt ist, bei extremsten Wetter (>100 l Regen pro m² und h mit Windstärke 8 ) und in unpassenster Umgebung (Gebirge). Wink
SCNR
Wer sich gerne quählt ;) Du bist da mit deiner eigenen CPU (bzw. System) ja auch nicht weit entfernt von ;)
-
Hallo,
Also ich wüde wahrscheinlich sogar ne Delta-Queue in einen Baum packen können
Sicher? Das kann ich mir momentan kaum vorstellen. Außerdem bleibt der Overhead das Du die relativen Zeiten immer mitrechnen musst, also zusätzliche Schreibzugriffe erzeugst.
Was das Entfernen betrifft, ist meine Queue klar schneller, besonders wenn der Baum immer voller wird.
Wieso? Ich muss Doch meinen Timer nicht suchen (und wenn wir beide suchen müssten dann wäre der Baum wieder im Vorteil). Ich muss zwar einen Pointer mehr prüfen (um zu wissen welches der beiden Kinder noch da ist, was bei einem abgelaufenen Timer eigentlich klar ist da es keine Kinder mit früherem Ablaufzeitpunkt geben kann) als in einer bidirektional verketteten Liste aber das war es auch schon.
Denn du versaust dir da den Cache, durch die "vielen" (ein paar reichen ja) Speicherzugriffe und die "längere" (sollte eigentlich unwesentlich sein) addiert sich ja auch, wenn du doch mal einige Elemente Entfernen musst. Rein theoretisch betrachtet ist die Queue in dem Fall O(1) und der Baum O(log n).
Zum entfernen muss ich maximal 2 Pointer aktualisieren. Vom zu entfernenden Element der entsprechende Kind-Pointer des Eltern-Elements und von dem maximal einem Kind-Element den Eltern-Pointer (ich hoffe ich drücke mich verständlich aus). Für den Fall dass das zu löschende Element die Wurzel ist dann muss natürlich der spezielle Wurzel-Pointer auch aktualisiert werden. Baum-Elemente die noch 2 Kinder haben lösche ich nicht sofort sondern markiere diese nur als inaktiv. Solche toten Timer fliegen automatisch raus wenn sie als nächstes dran wären. Das kostet zwar etwas Speicher aber der ist nun so knapp auch wieder nicht.
Die Zahl erschein mir irgendwie arg hoch. Denn das macht gerade mal 833 Takte pro Thread und so ein Thread-Wechsel kostet ja doch einiges an Zeit und Performance (oder liefen die alle in einem Adressraum?).
Sorry, hab ich vergessen zu erwähnen. Das waren alles Threads eines Steuerungsprogramms, die liefen alle im selben Adressraum. Der Kontext-Switch selber hat etwas mehr als 200 Takte gedauert, war ein Round-Robin-Scheduler mit 8 verschiedenen Prioritäten (wovon nur 7 ausgeführt werden, die unterste war die Sleep-Priorität).
Der "Witz" bei einer Delta-Queue ist doch, das du nur die Abstände zwischen den Elementen speicherst und nicht die direkten (absoluten) Werte.
Ich bezeichne das nicht als "Witz" sondern als "unnötigen Zusatzaufwand". Ich verstehe immer noch nicht warum Du das machst.
Was du ja schon richtig erkannt hast, ist das deine Lösung nur ein (oder mehrere) Pointer ändern und meiner bis zu 2 Werte und ein paar Pointer, den einen Wert dafür ständig (im worst-case).
Ganz recht. Du erkennst den Unterschied?
Um deine eine Frage zu beantworten,....
Ich glaube ich hab das (und Deinen Queue-Add-Code) jetzt einigermaßen verstanden. Ich kann nur eben keinen Vorteil erkennen. Der Code zum einfügen eines Elementes in einen Baum ist sicher nicht umfangreicher oder komplexer, aber gerade bei vielen Elementen auf jeden Fall schneller: O(log n) < O(n/2).
solltest du doch durch die "vielen" Zugriffe (bei einem Baum z.b.) auch den Cache trashen, oder?
Wieso? Zum einfügen eines neuen Elements braucht man bei einem Baum ja weniger Zugriffe als in einer linearen Liste, deswegen nimmt man doch den Baum. Das Element das als nächstes Abläuft muss ich nicht suchen sondern ich hab immer einen extra Pointer da drauf. Das Entfernen eines beliebigen Elementes hab ich ja schon beschrieben. Bei einer linearen sortierten Liste ist das einfügen deutlich aufwändiger (lange Suche), das vorderste Element ist auch direkt über einen Pointer ansprechbar und das Entfernen ist minimal schneller als beim Baum. Aus meiner Sicht ein ganz klarer Sieg für den Baum, deswegen hab ich mich damals dafür entschieden (trotz dessen das ich den in Assembler implementieren musste). Es gibt bestimmt auch noch was besseres als nen Baum.
das einige Dateisysteme die Zeit bis auf die ms genau wollen, oder?
NTFS macht 100ns Schritte, in ext4 ist da wimre auch was ziemlich genaues drin. Auch in diesem Fall wäre der HPET ein Vorteil aber zu Not lässt Du die unteren Bits einfach auf 0. Welcher User merkt schon den Unterschied? Das klassische FAT kann nur in 2s Schritten und das hat auch immer gereicht.
aber was ich weiß ist, das ich ein riesen Problem habe, auf SMP Systemen (ohne den netten HPET ;) ) ne halbwegs akkurate globale Zeit zu bekommen. Wenn ich das in den Griff bekommen würde, dann kann ich auch absolute Werte nutzen.
Das stimmt. Ich schreibe es nur ungerne (Du bist bestimmt schon genervt) aber ließ Dir noch mal die PIT-Variante in meinem Ursprungsport durch. Die Löst dieses Problem perfekt (egal wie viele CPUs). Das mit der hohen IRQ-Frequenz sehe ich nicht als so ernstes Problem, machen viele andere OSe ja auch so, jede Sache hat eben ihren Preis. Der einzigste echte Nachteil ist das damit die CPU nicht richtig tief schlafen kann um Energie zu sparen.
So aber finde ich ist es einfacher, zu sagen, so jetzt soll der Thread mal so und so lange schlafen und nicht er soll bis dann schlafen!
Bei der zweiten Variante musst Du in der Sleep-Funktion einmalig eine Addition ausführen, bei der ersten Variante musst Du ständig die relativen Zeiten passend hinrechnen um vernünftig Vergleichen zu können. Zusätzlich bekommst Du bei periodischen Events, mit den absoluten Zeitwerten, eine perfekte Langzeitgenauigkeit.
Ich find die Idee halt toll und sehe auch die Vorteile
Also ich sehe da keine Vorteile. Vielleicht erklärst Du mir diese mal.
Bei den absoluten Zeitwerten sehe ich noch einen Vorteil: Wenn ein IRQ kommt und dieser als Message in ein User-Mode-Prozess geleitet wird dann soll in der Message der Zeitpunt des IRQs vermerkt sein (quasi als Zeitstempel) damit der User-Mode-IRQ-Handler schauen kann wie lange die Latenz war, es könnte ja sein das ein anderer Thread mit einer höheren Priorität lief und daher der IRQ-Handler-Thread warten musste.
denn er kümmert sich doch ohnehin darum wie lange ein Thread laufen darf!
Er muss die Länge der Zeitscheiben vorgeben, aber deren Einhaltung zu kontrollieren fällt IMHO nicht in seinen Zuständigkeitsbereich. Außerdem werden Zeitscheiben wirklich nur selten aufgebraucht.
Wenn Du die Local-APICs hast dann sind diese für die Zeitscheiben zuständig ansonsten musst Du das leider mit ins normale Timing nehmen. Für andere Dinge würde ich die Local-APICs nicht nehmen. In meinen CPUs will ich was ähnliches vorsehen das dann auch mit relativen Zeiten arbeitet, einen simplen Down-Counter in welchen einfach die Zeitscheibenlänge eingetragen wird und der dann bei 0 (falls er überhaupt bis da hin kommt) einen extra Kontext-Switch-IRQ auslöst (und das zählen aufhört).
Wirklich komplizierter wird er meiner Meinung nach deswegen nicht.
Darum geht es mir gar nicht primär, sondern um die Modularität des Quell-Codes. Wenn Du das Timing über mehrere Module verteilst wirst Du Dich irgendwann später mal ziemlich ärgern darüber. Stell Dir vor Du tauscht mal den Scheduler gegen einen anderen aus, dann gibt es Teile des Timing-Systems mehrmals (in jedem Scheduler). Wartbarer Code ist IMHO was anderes.
... und da jede CPU ihre eigene "Zeit" hat ...
Wenn bei Dir jede CPU ne eigene Zeit hat dann machst Du IMHO was falsch. Bei mir wird es nur eine Zeit geben, die eine reicht mir einfach.
höchst mögliche Präzision auf alten (wie neuen) Systemen. Wofür, ich habe keine Ahnung ;)
Genau: Wofür? Ich glaube nicht das normale Programme was genaueres als ein paar Mikrosekunden brauchen. Fürs meiste dürften auch Millisekunden völlig reichen. Programme die wirklich was genaueres brauchen (dazu gehören bestimmt keine Multimediaprogramme o.ä.) machen das sicherlich über ne extra Library welche Du dann auf Dein OS portieren musst, da braucht diese Library bestimmt eh ein paar spezielle SYSCALLs oder die Library bekommt einen eigenen Timing-Treiber mit HW-Zugriff.
Also so richtig kann ich es nicht glauben das der IO-APIC deaktiviert war.
Ich bin mir nicht sicher ob der IO-APIC vom BIOS deaktiviert wurde aber Windows NT hat den auf jeden Fall nicht benutzt. Selbst in Windows 2000 war die IO-APIC-Unterstützung noch ziemlich rudimentär.
Die APICs sind ja auch für SMP zwingend erforderlich!
Ja, gerade so das absolut nötigste hat Windows NT unterstützt. Die SMP-Unterstützung war damals auf der Alpha-Plattform deutlich besser als auf x86.
und du immer mit deinem HPET ;)
Fühlst du Dich genervt? Sorry, aber ich bin es gewohnt mit ordentlichem Werkzeug zu arbeiten. ;)
Ich dachte mir halt, wenn du schon so ein schönes Thema wie die OS Programmierung machst, dann mach es auch richtig
Full ACK!
Darf ich Dich daran erinnern das es noch viele andere Plattformen gibt außer x86? Die meisten dürften deutlich besser sein als x86.
Das mit den deaktivierten APICs ärgert mich bis heute, ich meine Athlon XP Systeme sehe ich schon als halbwegs modern an! Und wer kauft sich schon nur ein neues Board damit er sein eigenes kleines OS darauf testen kann ;)
Darf ich Dich nochmal daran erinnern das es noch viele andere Plattformen gibt außer x86?
Wer sich gerne quählt ;) Du bist da mit deiner eigenen CPU (bzw. System) ja auch nicht weit entfernt von ;)
Also ich quäle mich wirklich nicht gerne. Und weil ich mich auch nicht gerne mit idiotischer Hardware rumärgere mache ich gleich was eigenes. Ich habe da vielleicht mehr Arbeit aber bestimmt auch einen niedrigeren Frustrationslevel. :D
Grüße
Erik
-
Sicher? Das kann ich mir momentan kaum vorstellen. Außerdem bleibt der Overhead das Du die relativen Zeiten immer mitrechnen musst, also zusätzliche Schreibzugriffe erzeugst.
Nope, funktioniert nicht! War ein ganz großer Denkfehler von mir. Denn ich habe vorausgesetzt das ich die Abstände schon kenne, dann würde das klappen aber so nicht :(
Wieso? Ich muss Doch meinen Timer nicht suchen (und wenn wir beide suchen müssten dann wäre der Baum wieder im Vorteil). Ich muss zwar einen Pointer mehr prüfen (um zu wissen welches der beiden Kinder noch da ist, was bei einem abgelaufenen Timer eigentlich klar ist da es keine Kinder mit früherem Ablaufzeitpunkt geben kann) als in einer bidirektional verketteten Liste aber das war es auch schon.
Ich weiß ja nicht von was für nem Baum wir hier sprechen, aber AVL und RB müssen beim Löschen ja wieder "repariert" werden und das ist auf jeden Fall aufwendiger als bei einer Queue.
Das Element das als nächstes Abläuft muss ich nicht suchen sondern ich hab immer einen extra Pointer da drauf.
Das ist clever! Da wäre ich jetzt gar nicht so schnell drauf gekommen, aber ich hätte mir auch überlegt wie ich immer die "kleinste" Node irgendwo speichern kann.
Das stimmt. Ich schreibe es nur ungerne (Du bist bestimmt schon genervt) aber ließ Dir noch mal die PIT-Variante in meinem Ursprungsport durch. Die Löst dieses Problem perfekt (egal wie viele CPUs). Das mit der hohen IRQ-Frequenz sehe ich nicht als so ernstes Problem, machen viele andere OSe ja auch so, jede Sache hat eben ihren Preis. Der einzigste echte Nachteil ist das damit die CPU nicht richtig tief schlafen kann um Energie zu sparen.
Also erstmal du nervst nicht, ich kann sonst solche Diskussionen nicht auf so einem Niveau und über so ein Thema führen!
Gegen den PIT Timer mit einer solch hohen Frequenz habe ich grundsätzlich was! Davon wirst du mich nicht abrücken können. Und das Linux die Frequenz ihres Schedulers wieder geändert (also wieder kleiner gemacht) haben sagt mir das ich nicht so falsch liegen kann ;)
Der Punkt welcher mih stört ist halt, ich kann den PIT auf einem SMP System nicht abschalten, egal welche Frequenz er hat und da möchte ich dann auch soviel es geht "sparen" (also im Endeffekt an Energie und CPU Zeit). Wenn der PC die meinste Zeit am nichts Tun ist, dann kostet das nur unnötig Energie und auch für diesen Fall muss geplant werden (sollte sich eventuell auf einem Laptop sehr sehr negativ auswirken!).
Also ich sehe da keine Vorteile. Vielleicht erklärst Du mir diese mal.
Präzision! Wie ich gerade in einem anderem Forum gelesen habe, macht sich da jemand gerade nen Kopf wie er die Schleife eines Games so umsetzen kann, das er auf max 60FPS kommt und somit die CPU nicht immer zu 100% auslastet. In diesem Zusammenhang meinte einer nimm einfach sleep(1) und dann ist noch rausgekommen, das sleep mindestens 15ms dauert (was ja logisch ist, da Windows nen periodischen Timer nutzt und ein Tick sind 15ms).
Und hier sage ich mir 15ms, das ist ne verdammt lange Zeit! Ich meine es gibt bestimmt genug Treiber die würden gerne wesentlich weniger warten (vielleicht irgendwo im µs Bereich) und bevor die busy-waiting machen, habe ich doch lieber eine Möglichkeit das ein Thread eine so kurze Zeit schlafen kann und in der Zeit kann die CPU schön andere Sachen machen. Das funktionier nun mal am besten mit nem One-Shot-Timer (zumal dein geliebter HPET eigentlich nur diesen Modus implementieren würde, aber aus legacy Gründen noch nen periodischen Modus hat, aber der ist optional)!
Jedes Mal wenn du weniger als 15ms (bei 400MHz sind das 6.000.000 Takte!) warten willst, müsstest du busy-waiting machen und das ganze noch als Real-Time Thread, damit du ja nicht unterbrochen wirst. Das ist ne absolute Ressourcen Verschwendung.
Desweiteren spare ich durch den One-Shot-Modus noch einige IRQs und das sollte sich ab einer Laufzeit von mehreren Stunden schon lohnen, was da gespart wird!
Darum geht es mir gar nicht primär, sondern um die Modularität des Quell-Codes. Wenn Du das Timing über mehrere Module verteilst wirst Du Dich irgendwann später mal ziemlich ärgern darüber. Stell Dir vor Du tauscht mal den Scheduler gegen einen anderen aus, dann gibt es Teile des Timing-Systems mehrmals (in jedem Scheduler). Wartbarer Code ist IMHO was anderes.
Das sehe ich ein wenig anders. Sieh es als ne Art Interface welches implementiert werden muss und wenn du sowieso den One-Shot-Modus nutzen musst (ist bei meinem Timer-Interface so vorgesehen), dann ist es auch kein Problem und Beinbruch diesen Timing-Code noch mit rein zu nehmen. Denn im Endeffekt bleibt das grobe Gerüst des Schedulers immer gleich:
//berechne die Zeit die wirklich verbraucht wurde
diff= thisCPU->timerStart - timerGetCountNSecs();
//ziehe die Zeit von der Zeit ab, die der Thread hätte laufen dürfen
thisCPU->currThread->time-= diff;
//gucke ob ein Thread in der Sleep-Queue ist
if(sleepQueue) {
//aktualisiere die Zeit des 1. Elements
sleepQueue->sleepTime-= diff;
//solange wie die Zeit die der Thread schlafen wollte kleiner ist als eine Konstante, weck ihn auf
while(sleepQueue->sleepTime <= TIME_KONSTANTE) {
//hole dir einen Pointer auf den Head der Queue
struct thread_t *t= sleepQueue;
//Head entfernen
sleepQueue= queueRemoveHead(sleepQueue);
//Thread aufwecken
threadWakeup(t);
}
//hole dir die Zeit wann der nächste Thread aufgeweckt werden soll
if(sleepQueue)
sleepTimeNext= sleepQueue->sleepTime;
}
//hier würde jetzt der eigentliche Scheduler kommen, also berechnen welcher Thread als nächstes dran ist oder ob der gleiche Thread nochmal laufen darf usw.
//jetzt stellen wir den Timer ein
if(sleepQueue && sleepTimeNext < thisCPU->currThread->time)
timerSetTimeSlice(sleeptime);
else
timerSetTimeSlice(thisCPU->currThread->time);
Wenn ich sowas voraussetze, dann gibt es auch keine Probleme was die Wartbarkeit betrifft. Wenn ich es mir noch "einfacher" machen wollte, dann könnte ich den Scheduler noch weiter "auslagern" indem ich sage, dieses Grobkonzept ruft erst den eigentlichen Scheduler auf! So kann ich dann auch den Code vom Scheduler Code fernhalten!
Wenn bei Dir jede CPU ne eigene Zeit hat dann machst Du IMHO was falsch. Bei mir wird es nur eine Zeit geben, die eine reicht mir einfach.
Damit meine ich eigentlich solche Konzepte, das jeder Core extra runtergetaktet werden kann und schlafen kann, obwohl ein andere Core weiter fleißig rechnet. In dem Moment bleibt für mich auf dem Core die Zeit "stehen".
Genau: Wofür? Ich glaube nicht das normale Programme was genaueres als ein paar Mikrosekunden brauchen. Fürs meiste dürften auch Millisekunden völlig reichen. Programme die wirklich was genaueres brauchen (dazu gehören bestimmt keine Multimediaprogramme o.ä.) machen das sicherlich über ne extra Library welche Du dann auf Dein OS portieren musst, da braucht diese Library bestimmt eh ein paar spezielle SYSCALLs oder die Library bekommt einen eigenen Timing-Treiber mit HW-Zugriff.
Wieso nicht gleich zur Verfügung stellen? Wie gesagt, kann ich mir durchaus vorstellen, das einige Treiber doch ne ganz schön hohe Auflösung bei nem Timer bräuchten.
Um nochmal auf die Multimediaanwendungen zurück zu kommen und auf dein Bsp. das man es nicht merkt wenn der Film zu schnell läuft.
Also da muss ich dir ganz doll wiedersprechen. Ich habe im Moment nur unter Windows 7 sowas von Probleme mit HD Filmen, das ist nicht mehr schön und nur unter Windows 7 unter XP hatte ich die nicht. Ich merke es ganz doll wenn der Film zu schnell läuft. In diesem speziellen Fall haut irgendwas mit der Synchronisation nicht hin, denn nicht mal der Ton läuft fehlerfrei und das beste daran ist, es scheint nicht mal unbedingt ein Treiberprobelm zu sein, denn ich bekomme mit jedem Programm (WMP, VLC, MPC) andere Ergebnisse und der WMP läuft da noch am besten.
Auf meinem Desktop Rechner ist es so schlimm das ich nicht mal ne DVD vernünftig gucken kann :(
So aber wieder back-to-topic.
Darf ich Dich daran erinnern das es noch viele andere Plattformen gibt außer x86? Die meisten dürften deutlich besser sein als x86.
Ich weiß, leider. Denn erstmal sind mir diese zu teuer (ich wäre an ARM und PowerPC interessiert). Dann ist die Situation auf der ARM Plattform nicht wirklich besser. Denn da müsste ich ja für jedes Board bzw. jedes SoC meinen Kernel anpassen, das wäre für mich schon fast wie ne neue Architektur, dann kommen noch die verschiedenen BEfehlssätze dazu.
Was aber alle Argumente schlägt ist einfach die Verbreitung. Warum sollte ich mich mit einer Architektur befassen, die ich in meinem Umfeld gar nicht zu Gesicht bekomme?
Einen Punkt für ARM gibt es aber noch, ich hoffe auf immer mehr Handys mit Android oder nem anderen Linux, so dass man vielleicht irgendwann mal sein eigenen OS auf nem Handy laufen lassen kann. Daran wäre ich wirklich sehr interessiert!
-
Hallo,
Ich weiß ja nicht von was für nem Baum wir hier sprechen,
Mit den Fachbegriffen dazu bin ich nicht vertraut. Jedes Element enthält einen Timer (mit absoluten Zeitpunkt) und 3 Pointer, einen für Parent und 2 für die Kinder. An Kind A kommen alle kleineren Zeitpunkte und an Kind B kommt alles was größer oder gleich ist.
aber AVL und RB müssen beim Löschen ja wieder "repariert" werden und das ist auf jeden Fall aufwendiger als bei einer Queue.
Eben deshalb lösche ich nur Elemente aus dem Baum die nur ein (oder gar kein) Kind haben. Das kostet zwar etwas Speicher aber erspart mir komplizierte Umbaumaßnahmen im Baum. Da der Baum in den Maschinen, für die er ursprünglich programmiert wurde, eh ständig komplett umgewürfelt wird (die meisten Timer hatten Laufzeiten von unter 10 Sekunden) hab ich mir jegliche Optimierungsbemühungen zur Laufzeit gleich ganz gespart.
Das Element das als nächstes Abläuft muss ich nicht suchen sondern ich hab immer einen extra Pointer da drauf.
Das ist clever!
Is ja auch von mir. ;)
Ne, das war einfach logisch, wenn ein Timer abläuft dann ist als nächstes einer seiner unmittelbaren Nachbarn dran und da spare ich mir natürlich das ewige neu suchen.
aber ich hätte mir auch überlegt wie ich immer die "kleinste" Node irgendwo speichern kann.
Eben, da wärst Du bestimmt auch zügig drauf gekommen, das ist einfach zu nahe liegend.
Also erstmal du nervst nicht, ich kann sonst solche Diskussionen nicht auf so einem Niveau und über so ein Thema führen!
;)
Gegen den PIT Timer mit einer solch hohen Frequenz habe ich grundsätzlich was!
Was genau? Mal vom verwehrten CPU-Tiefschlaf abgesehen. Und bis Du Dich ordentlichem Powermanagement bei x86 widmen kannst wirst Du erst mal einen dicken Haufen anderer Probleme lösen müssen, der Energieverbrauch ist IMHO nicht Dein dringenstes Problem.
Davon wirst du mich nicht abrücken können.
Ich will Dich gar nicht verrücken, ich will Dich so lange mit guten Argumenten locken bis Du von ganz alleine kommst. ;)
Oder Du mir bessere Gegenargumente bringst.
Und das Linux die Frequenz ihres Schedulers wieder geändert (also wieder kleiner gemacht) haben sagt mir das ich nicht so falsch liegen kann ;)
Ich weiß es nicht genau aber ich vermute dass das Powermanagement da ein wichtiges Ziel war. Das Linux auf den meisten Laptops eine kürzere Akku-Laufzeit erreicht als Windows ist sicher ein wichtiges Argument dafür (und leider auch heute noch die Regel).
Der Punkt welcher mih stört ist halt, ich kann den PIT auf einem SMP System nicht abschalten, egal welche Frequenz er hat und da möchte ich dann auch soviel es geht "sparen" (also im Endeffekt an Energie und CPU Zeit). Wenn der PC die meinste Zeit am nichts Tun ist, dann kostet das nur unnötig Energie und auch für diesen Fall muss geplant werden (sollte sich eventuell auf einem Laptop sehr sehr negativ auswirken!).
Die Last, welcher ein 1000Hz IRQ generiert, ist meiner Meinung nach nicht so hoch, sollte auf einer modernen CPU unter 0,1% betragen, und bei SMP trifft das ja auch nur eine CPU. Warum sollte man den PIT bei SMP nicht abschalten können? Wenn Du ihn nicht brauchst, z.B. wenn keine Timer aktiv sind oder der HPET da ist, dann kann man den PIT auch abschalten. Für die Zeitscheiben stehen Dir bei SMP ja garantiert die Local-APICs bereit.
Also ich sehe da keine Vorteile. Vielleicht erklärst Du mir diese mal.
Präzision!
Aber gerade die wirst Du mit dem PIT-One-Shot-Modus sicher nicht erreichen. Nach 1'080'000 Bildern, bei 60 fps, werden damit bestimmt nicht genau 5 Stunden vergangen sein. Außerdem ist das Beispiel schon vom Konzept her falsch, wenn die GraKa ein neues Bild will dann soll sie doch bitte einen IRQ auslösen.
Ich meine es gibt bestimmt genug Treiber die würden gerne wesentlich weniger warten (vielleicht irgendwo im µs Bereich)
Zu welchem Zweck? Die x86-Plattform ist zwar ziemlicher Schrott aber das man, wie auf nen C64, mal 2 NOPs nimmt um irgendeiner HW-Peripherie-Komponente ne Mikrosekunde Bedenkzeit zu geben um die letzten Daten zu schlucken, ist längst vorbei. Heutige Hardware hat FIFOs, kann IRQs auslösen oder holt sich die nötigen Daten selber (im eigenen Tempo) aus dem Speicher.
(zumal dein geliebter HPET eigentlich nur diesen Modus implementieren würde, aber aus legacy Gründen noch nen periodischen Modus hat, aber der ist optional)
Nein, der HPET läuft immer, außerdem hat er mehrere Comparatoren und damit mindestens einen Multi-Shot-Mode. Der monoton laufende Counter ist ja gerade der Unterschied zum PIT-One-Shot-Mode. Vom dem Moment an wo der PIT einen IRQ auslöst bis er dann endlich wieder läuft, mit der nächsten Zeitspanne, vergeht immer etwas Zeit, vor allem ist diese Zeit nicht konstant oder vorhersehbar. Für wirklich präzise Dinge (ich meine damit Langzeitgenauigkeit) ist der PIT-One-Shot-Mode nicht geeignet.
Desweiteren spare ich durch den One-Shot-Modus noch einige IRQs und das sollte sich ab einer Laufzeit von mehreren Stunden schon lohnen, was da gespart wird!
Klar sparst Du damit etwas CPU-Leistung ein, verlierst dafür aber auch die einzigste Möglichkeit auf ne präzise monotone Zeitquelle.
Damit meine ich eigentlich solche Konzepte, das jeder Core extra runtergetaktet werden kann und schlafen kann, obwohl ein andere Core weiter fleißig rechnet. In dem Moment bleibt für mich auf dem Core die Zeit "stehen".
Also wenn ich Abends ins Bett gehe, schlafe und Morgens wieder aufwache dann ist die Zeit doch auch nicht stehen geblieben. Leider! ;) Die Messung der absoluten Laufzeit Deines Systems darf nicht von irgend einer CPU abhängen.
Wie gesagt, kann ich mir durchaus vorstellen, das einige Treiber doch ne ganz schön hohe Auflösung bei nem Timer bräuchten.
Wofür? Der Treiber hat doch seine Hardware zur Verfügung, für die er zuständig ist, und kann dort auch IRQs bestellen wenn er auf einen längeren Vorgang warten muss. Auf moderner Hardware ist es übrigens gute Sitte gleich mehrere Jobs abzuliefern damit nicht zu viele IRQs anfallen.
Ich merke es ganz doll wenn der Film zu schnell läuft. In diesem speziellen Fall haut irgendwas mit der Synchronisation nicht hin, denn nicht mal der Ton läuft fehlerfrei und das beste daran ist,
Ich kann die Situation auf Deinem PC nicht beurteilen aber das klingt nicht nach mal 2 ms längerer Framedauer oder ähnlichen Kleinigkeiten. Außerdem hört man Ton-Aussetzer und Asynchronitäten sehr deutlich, das Ohr hat eine deutlich feinere zeitliche Auflösung als das Auge.
Darf ich Dich daran erinnern das es noch viele andere Plattformen gibt außer x86? Die meisten dürften deutlich besser sein als x86.
Ich weiß, leider.
Dann ist ja gut.
Denn erstmal sind mir diese zu teuer (ich wäre an ARM und PowerPC interessiert).
Klar kostet ein gutes Eval-Board etwas Geld aber wo da die Schmerzgrenze ist muss jeder selbst entscheiden. Meine Entwicklung mit mehreren FPGAs wird ganz sicher auch einiges an Geld verschlingen. Die TTL-Variante von Svenska ist aber auch nicht gerade preiswert. Ein echtes Hobby kostet eben auch mal Geld.
Dann ist die Situation auf der ARM Plattform nicht wirklich besser. Denn da müsste ich ja für jedes Board bzw. jedes SoC meinen Kernel anpassen, das wäre für mich schon fast wie ne neue Architektur,
Nein, das löst man über so genannte "Board-Specific-Packages" die dem Kernel, in Form von Treibern u.ä., die jeweilige Hardware des Boards zur Verfügung stellen. So lange die CPU die selbe ist bleibt der Aufwand sehr in Grenzen.
dann kommen noch die verschiedenen BEfehlssätze dazu.
Ja das wird bei ARM wohl ein echtes Problem werden, auf der anderen Seite sollte das ein guter Compiler nahezu komplett verbergen.
Was aber alle Argumente schlägt ist einfach die Verbreitung. Warum sollte ich mich mit einer Architektur befassen, die ich in meinem Umfeld gar nicht zu Gesicht bekomme?
Ich wette Du hast in Deiner unmittelbaren Umgebung mehr ARM und MIPS CPUs als x86. Denke mal an DVD-Player, Handy, Drucker und all die anderen elektronischen Spielzeuge in unserem Alltag. x86 ist das tatsächliche Nischenprodukt!
Einen Punkt für ARM gibt es aber noch, ich hoffe auf immer mehr Handys mit Android oder nem anderen Linux, so dass man vielleicht irgendwann mal sein eigenen OS auf nem Handy laufen lassen kann. Daran wäre ich wirklich sehr interessiert!
Ja darauf hoffe ich auch, vor allem darauf das diese Systeme ohne Abschottungsmechanismen kommen, das ist mir als mündigen Verbraucher sehr wichtig weshalb ich auch keine Apple-Produkte kaufe.
Grüße
Erik
-
aber AVL und RB müssen beim Löschen ja wieder "repariert" werden und das ist auf jeden Fall aufwendiger als bei einer Queue.
Eben deshalb lösche ich nur Elemente aus dem Baum die nur ein (oder gar kein) Kind haben. Das kostet zwar etwas Speicher aber erspart mir komplizierte Umbaumaßnahmen im Baum.
Entartet dir der Baum nicht ziemlich leicht in eine Liste, wenn du komplett auf das Ausgleichen verzichtest? Was natürlich den Vorteil hätte, dass du dann ständig nur ein Kind hast und ohne weiteres löschen kannst, aber ich glaube, das war trotzdem nicht ganz, was du im Sinn hattest. ;)
-
Hallo,
Entartet dir der Baum nicht ziemlich leicht in eine Liste, wenn du komplett auf das Ausgleichen verzichtest?
Ein bisschen bestimmt. Da der Baum, in der damaligen Maschine, eh jede Minute fast komplett abgearbeitet wurde und die Zeiten ziemlich gut verteilt waren bin ich davon ausgegangen das sich so ein extra Aufwand gar nicht lohnt. Ich muss aber auch ehrlich sagen das ich von solchen Bäumen quasi keine Ahnung hab. Ich hab damals etwas gesucht ob ich einen kleinen Algorithmus finde der bei jedem Einfügen und Löschen den Baum ein klein wenig optimiert aber ich hab nichts gefunden was mich überzeugt hätte, nur Algorithmen die den Baum als ganzes durchoptimieren und ausbalancieren. Ich hatte auch mal vor den Baum zu Laufzeit zu vermessen aber ihr kennt das Problem vielleicht: wenn ein Programm(teil) einmal fehlerfrei läuft dann bekommt man vom Chef keine Zeit mehr um noch Details nachjustieren zu können. Zumindest hatte ich eine Funktion die den Baum sehr gründlich auf Fehlerfreiheit prüft.
Es freut mich zumindest das dieser Thread tatsächlich noch von anderen gelesen wird obwohl er doch schon sooooooo lange Beiträge enthält. ;)
Grüße
Erik
-
Überfliegen trifft es besser, um ihn gründlich durchzulesen sind mir die Beiträge tatsächlich zu lang. ;)
Gerade dass der Baum ständig abgearbeitet wird, führt doch aber dazu, dass tendenziell immer links Knoten rausfliegen und immer rechts neue dazukommen, oder? Für mich sieht das wirklich wie die perfekte Ausgangssituation für einen Baum aus, der in eine Liste entarten möchte. Insofern frage ich mich, ob du nicht genauso gut rauskommen würdest und dir noch ein bisschen Komplexität sparst, wenn du gleich eine Liste nimmst.
Dieses "komplette" Ausbalancieren klingt zwar aufwendig, aber bei jeder Einfüge/Lösch-Operation machst du pro Knoten auf dem Weg zwischen dem eingefügten/gelöschten Knoten und der Wurzel maximal eine Operation; im Durchschnitt dürfte es einiges weniger sein. Das ist also eigentlich jedesmal nur ein bisschen optimieren - aber wenn man das konsequent macht, bleibt der Baum trotzdem als ganzes ausbalanciert.
Ob es sich in diesem speziellen Fall lohnt, einen Baum zu nehmen, musst du selbst wissen, aber zumindest ein unbalancierter Baum kommt mir nicht sinnvoll vor.
-
Hallo,
Gerade dass der Baum ständig abgearbeitet wird, führt doch aber dazu, dass tendenziell immer links Knoten rausfliegen und immer rechts neue dazukommen, oder?
Im Prinzip hast Du recht. Da die Timerlaufzeiten, die in den Baum kommen, alle unterschiedlich sind wird der Baum, zumindest auf der damaligen Maschine, nicht allzu linear. Die Check-Funktion hat auch die Ebene des tiefsten Elements im Baum ausgegeben und der war nie tiefer als die Hälfte des Baums. Wie schon geschrieben, zu einer genaueren Analyse bin ich leider nicht gekommen. Falls ich dieses System in mein OS übernehme werde ich aber bestimmt mal deutlich genauer hinschauen. Versprochen.
Zumindest bietet der komplexere Code die potentielle Möglichkeit das es nicht auf eine lineare Liste hinausläuft.
Dieses "komplette" Ausbalancieren klingt zwar aufwendig, aber bei jeder Einfüge/Lösch-Operation machst du pro Knoten auf dem Weg zwischen dem eingefügten/gelöschten Knoten und der Wurzel maximal eine Operation; im Durchschnitt dürfte es einiges weniger sein. Das ist also eigentlich jedesmal nur ein bisschen optimieren - aber wenn man das konsequent macht, bleibt der Baum trotzdem als ganzes ausbalanciert.
Klingt sinnvoll, kommt auf meine ToDo-Liste. Die Frage ist halt wie sinnvoll es wirklich ist einen Baumabschnitt zu optimieren der als nächstes abläuft.
Ob es sich in diesem speziellen Fall lohnt, einen Baum zu nehmen, musst du selbst wissen, aber zumindest ein unbalancierter Baum kommt mir nicht sinnvoll vor.
Ich denke es hat sich damals gelohnt, ob es sich auch bei einem klassischen General-Purpose-OS lohnt kann ich nicht wirklich beurteilen aber ich vermute das der Baum immer noch zumindest etwas besser als eine lineare Liste ist.
Grüße
Erik
-
Da die Timerlaufzeiten, die in den Baum kommen, alle unterschiedlich sind wird der Baum, zumindest auf der damaligen Maschine, nicht allzu linear. Die Check-Funktion hat auch die Ebene des tiefsten Elements im Baum ausgegeben und der war nie tiefer als die Hälfte des Baums.
Eine Höhe von n/2 ist aber schon ganz schön groß. Ein richtig ausbalancierter Baum kommt immerhin auf log(n).
Ich kann im Moment auch nicht richtig abschätzen, wie viele Knoten durchschnittlich im Baum sein werden (wahrscheinlich hätte ich eure Posts dazu mehr als nur überfliegen müssen ;)) - aber ich vermute entweder n ist groß genug, dass zwischen n/2 und log(n) ein nennenswerter Unterschied ist, oder es sind so wenige Knoten, dass eine Liste auch nicht wesentlich langsamer wäre.
-
Ich denke es hat sich damals gelohnt, ob es sich auch bei einem klassischen General-Purpose-OS lohnt kann ich nicht wirklich beurteilen aber ich vermute das der Baum immer noch zumindest etwas besser als eine lineare Liste ist.
Dazu müsste man mal konkret gucken, was für Zeiten so "geschlafen" werden. Denn wenn du davon ausgehst, das jedes neue Event was in den Baum kommt später endet als das davor, würde sich ein ausbalanzierter Baum schon lohnen.
Die Last, welcher ein 1000Hz IRQ generiert, ist meiner Meinung nach nicht so hoch, sollte auf einer modernen CPU unter 0,1% betragen, und bei SMP trifft das ja auch nur eine CPU. Warum sollte man den PIT bei SMP nicht abschalten können? Wenn Du ihn nicht brauchst, z.B. wenn keine Timer aktiv sind oder der HPET da ist, dann kann man den PIT auch abschalten. Für die Zeitscheiben stehen Dir bei SMP ja garantiert die Local-APICs bereit.
Ich muss doch aber auch an alte Systeme denken, wenn ich schon ne mindest Voraussetzung von nem Pentium habe, dann will ich auch das mein OS da vernünftig läuft und da machen sich 1000 IRQs doch sehr bemerkbar (vorallem wenn ich da an den worst-case mit nem Dual-P75 System denke ;) ).
Aber gerade die wirst Du mit dem PIT-One-Shot-Modus sicher nicht erreichen. Nach 1'080'000 Bildern, bei 60 fps, werden damit bestimmt nicht genau 5 Stunden vergangen sein. Außerdem ist das Beispiel schon vom Konzept her falsch, wenn die GraKa ein neues Bild will dann soll sie doch bitte einen IRQ auslösen.
Da haben wir dann wieder aneinander vorbei geredet ;)
Also wir sprechen jetzt erstmal nur von SMP Systemen und da brauche ich den PIT (oder halt den HPET so weit vorhanden) als globale Zeit! Und da nutze ich ihn ja auch im periodischen Modus, aber halt mit den 18,2Hz. Auf SMP Systemen nutze ich dann den APIC für die Scheduler der CPUs und die laufen im One-Shot Modus, weil da ist der Fehler nicht wichtig, der durch das neu Schreiben des Counter auftritt (zumal er da sowieso minimal sein sollte!). Alle Timer die <55,4ms warten, kommen in die Sleep-Queue einer CPU und dadurch das ich diese dort mit relativen Zeiten reinpacke ist halt auch der Jitter, der sich aufsummieren würde, egal. In der Sleep-Queue vom PIT (oder halt HPET) kommen alle Timer >55,4ms und dort nutze ich dann absolute Zeiten (wegen der von dir schon genannten Vorteile).
Jetzt zu den Single-CPU Systemen. Dort wo ich nur den PIT habe (also keinen APIC, was leider bis zu Athlon XP passieren kann), habe ich mir überlegt die RTC im periodischen Modus zu nutzen (z.B. dachte ich an nen Tick von 62,5ms) und da kommen dann wieder alle Timer mit ner Zeit >62,5ms rein und dort würde ich dann den PIT im One-Shot-Modus nutzen und da ist es dann ja wieder egal wie groß der Jitter, weil er sich nicht aufaddieren kann, da ja nur Timer mit ner Zeit <62,5ms da rein kommen. Ansonsten ist das Prinzip das gleiche.
Nein, der HPET läuft immer, außerdem hat er mehrere Comparatoren und damit mindestens einen Multi-Shot-Mode. Der monoton laufende Counter ist ja gerade der Unterschied zum PIT-One-Shot-Mode. Vom dem Moment an wo der PIT einen IRQ auslöst bis er dann endlich wieder läuft, mit der nächsten Zeitspanne, vergeht immer etwas Zeit, vor allem ist diese Zeit nicht konstant oder vorhersehbar. Für wirklich präzise Dinge (ich meine damit Langzeitgenauigkeit) ist der PIT-One-Shot-Mode nicht geeignet.
Was du mit den Comparatoren meinst ist im Endeffekt nen One-Shot-Modus. Der IRQ wird nur gefeuert wenn das Event erreicht ist und es liegt nicht unbedingt immer die selbe Zeit zwischen den IRQs, es werden also keine sinnlosen IRQs gefeuert, wo du nur nen Counter inkrementierst und sonst nichts machts, weil kein Event gefeuert werden muss.
Also wenn ich Abends ins Bett gehe, schlafe und Morgens wieder aufwache dann ist die Zeit doch auch nicht stehen geblieben. Leider! Wink Die Messung der absoluten Laufzeit Deines Systems darf nicht von irgend einer CPU abhängen.
Auch hier wieder hast du mich wahrscheinlich falsch verstanden. Das Problem auf SMP Systemen ist, das du nicht auf jeder CPU nen Counter haben kannst (auf meinem sowieso nicht, zwecks One-Shot und meinem speziellen idle System) und dann sagen kannst du nutzt den Counter jeder CPU als globale Zeit. Wenn ich von globaler Zeit rede meine ich die absolute Zeit die in der Realität vergangen ist, aber die Counter der CPUs driften irgendwann auseinander, genauso wie die TSCs. Deswegen brauche ich halt auf nem SMP System ne globale Zeit (in dem Fall über den PIT).
Ich wette Du hast in Deiner unmittelbaren Umgebung mehr ARM und MIPS CPUs als x86. Denke mal an DVD-Player, Handy, Drucker und all die anderen elektronischen Spielzeuge in unserem Alltag. x86 ist das tatsächliche Nischenprodukt!
Da muss ich dich in meinem Fall wohl leider enttäuschen (zumindest wenn wir von meiner Wohnung reden ;) ). Denn da können andere CPUs nicht mit meiner Sammlung an Boards und CPUs mithalten ;) Und andere Sachen habe ich nicht großartig (nicht mal nen DVD-Player ;) ).
Ich kann im Moment auch nicht richtig abschätzen, wie viele Knoten durchschnittlich im Baum sein werden (wahrscheinlich hätte ich eure Posts dazu mehr als nur überfliegen müssen Wink) - aber ich vermute entweder n ist groß genug, dass zwischen n/2 und log(n) ein nennenswerter Unterschied ist, oder es sind so wenige Knoten, dass eine Liste auch nicht wesentlich langsamer wäre.
Das ist ja im Endeffekt genau das Problem! Wie willst du das vorher wissen? Das geht nicht auf nem OS wo Programme laufen können, die nicht nur du geschrieben hast. Du kannst ja nicht wissen auf was für nette Ideen die Leute so kommen und dann hast du mit einmal ne Queue die 1000 und mehr Einträge hat und da würde sich dann nen ausbalanzierter Baum besser machen (ich seh ein meine Delta-Queue ist da mist ;) )!
-
Dazu müsste man mal konkret gucken, was für Zeiten so "geschlafen" werden. Denn wenn du davon ausgehst, das jedes neue Event was in den Baum kommt später endet als das davor, würde sich ein ausbalanzierter Baum schon lohnen.
Ich glaube nicht, dass das der Fall ist. Aber wenn es so wäre, wäre ein Baum jedenfalls definitv das falsche Mittel, dann würdest du eine einfache Queue wollen. Ein Baum lohnt sich nur dann, wenn du auch wirklich Suchen musst, am besten mit gleichverteilter Wahrscheinlichkeit, wo im Baum du das gesuchte Element tatsächlich findest.
Ich gehe davon aus, dass das bei der Timergeschichte der Fall ist, so dass sich ein balancierter Baum vielleicht tatsächlich lohnen könnte.
Das ist ja im Endeffekt genau das Problem! Wie willst du das vorher wissen? Das geht nicht auf nem OS wo Programme laufen können, die nicht nur du geschrieben hast. Du kannst ja nicht wissen auf was für nette Ideen die Leute so kommen und dann hast du mit einmal ne Queue die 1000 und mehr Einträge hat und da würde sich dann nen ausbalanzierter Baum besser machen (ich seh ein meine Delta-Queue ist da mist ;) )!
Wie auch immer - einen unbalancierten Baum halte ich für Blödsinn, egal welchen der Fälle du dir raussuchst. ;)
-
Aber wenn es so wäre, wäre ein Baum jedenfalls definitv das falsche Mittel, dann würdest du eine einfache Queue wollen.
Denkfehler meinerseits. Denn dann könntest du ja immer am Ende Anfangen zu suchen und das dürfte in dem Fall wesentlich schneller sein.
-
Hallo,
erstmal möchte ich mich für mein langes Delay entschuldigen, mein PC hat massiv gestreikt. Wer mir sein unendliches Mitleid bekunden möchte darf das gerne hier (http://forum.kubuntu-de.org/index.php?topic=13722) oder hier (http://forum.kubuntu-de.org/index.php?topic=13736) tun. :-D
Ein Baum lohnt sich nur dann, wenn du auch wirklich Suchen musst, am besten mit gleichverteilter Wahrscheinlichkeit, wo im Baum du das gesuchte Element tatsächlich findest.
Ich gehe davon aus, dass das bei der Timergeschichte der Fall ist, so dass sich ein balancierter Baum vielleicht tatsächlich lohnen könnte.
Ganz meine Meinung. Deshalb hab ich das ja damals auch gemacht, nur leider nicht zu Ende gebracht. :cry:
Wie auch immer - einen unbalancierten Baum halte ich für Blödsinn,
Auch da kann ich Dir nur zustimmen, auch wenn ich persönlich der Meinung bin das selbst ein nicht ganz optimaler Baum immer noch besser als eine lineare Liste ist.
Ich hab mir mal den AVL-Baum etwas näher angesehen und der schein mir recht geeignet und auch nicht zu komplex zu sein. Die B-Bäume machen auf mich keinen so guten Eindruck weil die Nodes ziemlich komplex sind und außerdem der eigentliche Inhalt zwischen den Nodes wechseln kann und noch eine zusätzliche Indirektion finde ich eher ungünstig, die B-Bäume sind wohl wirklich eher für Daten geeignet die lange Zugriffszeiten haben so das die komplexeren Baum-Nodes nicht so ins Gewicht fallen.
Ich muss doch aber auch an alte Systeme denken, wenn ich schon ne mindest Voraussetzung von nem Pentium habe, dann will ich auch das mein OS da vernünftig läuft und da machen sich 1000 IRQs doch sehr bemerkbar (vorallem wenn ich da an den worst-case mit nem Dual-P75 System denke ;) ).
Dann nimmst Du eben nur 100Hz oder gar 50Hz, das kannst Du doch beim OS-Start dynamisch festlegen. Bei einem Dual-CPU-System ist das Problem doch auch nur halb so schlimm, es belastet ja nur eine CPU.
Da haben wir dann wieder aneinander vorbei geredet ;)
Was meinst Du den dann mit Präzision? Die Laufzeit eines sleep(0815) dürfte kaum auf die Micro-Sekunde genau interessieren, schließlich sagt ja auch der Standard das ein sleep länger dauern darf. Für ein präzises nsleep() sehe ich keinen Bedarf, so alte Hardware wirst Du doch hoffentlich nicht mehr in Deinen PCs haben.
Also wir sprechen jetzt erstmal nur von SMP Systemen und da brauche ich den PIT (oder halt den HPET so weit vorhanden) als globale Zeit! Und da nutze ich ihn ja auch im periodischen Modus, aber halt mit den 18,2Hz. Auf SMP Systemen nutze ich dann den APIC für die Scheduler der CPUs und die laufen im One-Shot Modus, weil da ist der Fehler nicht wichtig, der durch das neu Schreiben des Counter auftritt (zumal er da sowieso minimal sein sollte!).
Ja, das klingt doch schon mal gut.
Alle Timer die <55,4ms warten, kommen in die Sleep-Queue einer CPU und dadurch das ich diese dort mit relativen Zeiten reinpacke ist halt auch der Jitter, der sich aufsummieren würde, egal.
Wenn Du einen Timer mit absoluten Ablaufzeitpunkt als relative Zeit in den Local-APIC-Timer eintragen willst dann benötigst Du eine Bezugszeit, also die aktuelle Ist-Zeit, möglichst in der selben Präzision. Was machst Du in der Situation wenn Du einen Timer mit 60ms hast und gleichzeitig ein neuer Thread laufen soll, dann wirst Du bestimmt erstmal die Zeitscheibenlänge (55,4ms) in den Local-APIC-Timer eintragen, wenn dann der Thread die Zeitscheibe nach etwa 20ms abgeben möchte (was ja nun wirklich nicht unwahrscheinlich ist) dann hat der Timer nur noch 40 ms übrig, trägst Du dann diesen in den Local-APIC-Timer ein und startest einen anderen Thread? Wenn ja, was ist wenn dieser Thread auch vorzeitig seine Zeitscheibe abgibt? Wie bestimmst Du dann wie viel Zeit er von seiner Zeitscheibe aufgebraucht hat, schließlich wurde ja nicht die Zeitscheibenlänge in den Local-APIC-Timer reingeladen? Dieses vermischen unterschiedlicher Dinge erscheint mir irgendwie ungeschickt.
In der Sleep-Queue vom PIT (oder halt HPET) kommen alle Timer >55,4ms und dort nutze ich dann absolute Zeiten (wegen der von dir schon genannten Vorteile).
:-D
Jetzt zu den Single-CPU Systemen. Dort wo ich nur den PIT habe (also keinen APIC, was leider bis zu Athlon XP passieren kann), habe ich mir überlegt die RTC im periodischen Modus zu nutzen (z.B. dachte ich an nen Tick von 62,5ms) und da kommen dann wieder alle Timer mit ner Zeit >62,5ms rein und dort würde ich dann den PIT im One-Shot-Modus nutzen und da ist es dann ja wieder egal wie groß der Jitter, weil er sich nicht aufaddieren kann, da ja nur Timer mit ner Zeit <62,5ms da rein kommen. Ansonsten ist das Prinzip das gleiche.
Kann der RTC periodische IRQs generieren?
Außerdem verstehe ich noch nicht wie du einen absoluten Timer und einen relativen Timer synchron halten willst. Ich denke dass das ziemlich Arbeit werden könnte. Also ich würde das nicht freiwillig versuchen.
Also wenn ich Abends ins Bett gehe, schlafe und Morgens wieder aufwache dann ist die Zeit doch auch nicht stehen geblieben. Leider! Wink Die Messung der absoluten Laufzeit Deines Systems darf nicht von irgend einer CPU abhängen.
Auch hier wieder hast du mich wahrscheinlich falsch verstanden. Das Problem auf SMP Systemen ist, das du nicht auf jeder CPU nen Counter haben kannst (auf meinem sowieso nicht, zwecks One-Shot und meinem speziellen idle System) und dann sagen kannst du nutzt den Counter jeder CPU als globale Zeit. Wenn ich von globaler Zeit rede meine ich die absolute Zeit die in der Realität vergangen ist, aber die Counter der CPUs driften irgendwann auseinander, genauso wie die TSCs. Deswegen brauche ich halt auf nem SMP System ne globale Zeit (in dem Fall über den PIT).
Also brauchst Du für die globale Zeit eine einzelne Instanz nimmst (ob PIT oder HPET ist erstmal egal) dann gibt es doch auch kein Problem, ein Lesezugriff sollte schließlich immer möglich sein. Die CPU-Lokalen-Timer sind für sowas prinzipiell nicht geeignet, eben weil man die CPUs auch mal schlafen legen will.
Da muss ich dich in meinem Fall wohl leider enttäuschen (zumindest wenn wir von meiner Wohnung reden ;) ).
Okay, aber Deine Wohnung ist offensichtlich nicht der Normal-Fall. Über die gesamte Erde betrachtet ist x86 definitiv ein Nischenprodukt.
Grüße
Erik
-
Auch da kann ich Dir nur zustimmen, auch wenn ich persönlich der Meinung bin das selbst ein nicht ganz optimaler Baum immer noch besser als eine lineare Liste ist.
Ich hab mir mal den AVL-Baum etwas näher angesehen und der schein mir recht geeignet und auch nicht zu komplex zu sein. Die B-Bäume machen auf mich keinen so guten Eindruck weil die Nodes ziemlich komplex sind und außerdem der eigentliche Inhalt zwischen den Nodes wechseln kann und noch eine zusätzliche Indirektion finde ich eher ungünstig, die B-Bäume sind wohl wirklich eher für Daten geeignet die lange Zugriffszeiten haben so das die komplexeren Baum-Nodes nicht so ins Gewicht fallen.
Ich bin ein Fan vom AVL-Baum, aber in dem Fall von einer Sleep-Queue muss ich dann auch zugeben, dass ein RB-Baum wahrscheinlich die bessere Wahl wäre. Denn in dem ist das Löschen schneller.
Was meinst Du den dann mit Präzision? Die Laufzeit eines sleep(0815) dürfte kaum auf die Micro-Sekunde genau interessieren, schließlich sagt ja auch der Standard das ein sleep länger dauern darf. Für ein präzises nsleep() sehe ich keinen Bedarf, so alte Hardware wirst Du doch hoffentlich nicht mehr in Deinen PCs haben.
Mit Präzision meine ich z.B. das ein Thread alle 40ms ein Bild berechnet und es dann ausgibt. Wenn ich jetzt nen periodischen Timer von 15ms habe, dann kann der Fehler zw 5ms und 20ms liegen, was ich schon arg ungenau finde. Ich sag mal der Grund ist doch erstmal egal wozu ich die Präzision brauche, das kann ich auch gar nicht wissen, aber ich hätte sie gerne. Das Prinzip läuft auf eine Diskussion der Art 64KiB RAM sind genug hinaus ;)
Um auf die alte Hardware zurück zu kommen. Du möchtest doch sicher das dein OS so schnell wie möglich startet und dem APIC sollte man schon ne gewisse Zeit geben damit er deine Befehle ausführen kann (konkret meine ich das Starten der APs) und wenn du dann jedes Mal als kleinste mögliche Wartezeit 15ms hast summiert sich das schnell zu einer sehr langen Zeit auf. Ich weiß nicht ob du jetzt genau wissen möchtest wie lange man wo warten sollte, aber wenn du es wissen möchtest, dann gucke ich nach und schreibe es noch!
Wenn Du einen Timer mit absoluten Ablaufzeitpunkt als relative Zeit in den Local-APIC-Timer eintragen willst dann benötigst Du eine Bezugszeit, also die aktuelle Ist-Zeit, möglichst in der selben Präzision. Was machst Du in der Situation wenn Du einen Timer mit 60ms hast und gleichzeitig ein neuer Thread laufen soll, dann wirst Du bestimmt erstmal die Zeitscheibenlänge (55,4ms) in den Local-APIC-Timer eintragen, wenn dann der Thread die Zeitscheibe nach etwa 20ms abgeben möchte (was ja nun wirklich nicht unwahrscheinlich ist) dann hat der Timer nur noch 40 ms übrig, trägst Du dann diesen in den Local-APIC-Timer ein und startest einen anderen Thread? Wenn ja, was ist wenn dieser Thread auch vorzeitig seine Zeitscheibe abgibt? Wie bestimmst Du dann wie viel Zeit er von seiner Zeitscheibe aufgebraucht hat, schließlich wurde ja nicht die Zeitscheibenlänge in den Local-APIC-Timer reingeladen? Dieses vermischen unterschiedlicher Dinge erscheint mir irgendwie ungeschickt.
Dein Bsp. ist erstmal ungeeignet, da der Thread ja erstmal in die Queue des PIT gehen würde, da er >55,4ms schlafen möchte.
Ich speichere wie gesagt immer die Zeit ab die ich in den APIC geschrieben habe und jedes Mal wenn der Scheduler aufgerufen wird (ob die Zeitscheibe nun aufgebraucht wurde oder der Thread abgegeben hat) berechne ich die Differenz zwischen der Zeit die ich eingetragen habe und der Zeit die noch übrig ist (kannst du ganz einfach machen, in dem du den Counter ausliest und mit der Zeit eines Ticks multiplizierst). Diese nutze ich dann zum rechnen.
Der Sinn hinter einem One-Shot-Timer ist, dass dieser nur feuert, wenn die Zeit die eingetragen wurde abgelaufen ist. Also ja ich trage genau die Zeit in den APIC ein die ein Thread laufen darf (oder halt die Zeit bis zu dem nächsten Thread der aufgeweckt werden muss, je nach dem was "kleiner" ist).
Praktisch sowas:
timeNextThread= currThread->prio * NETTE_KONSTANTE;
sleepNext= sleepQueue->sleepTime;
if(sleepNext < timeNextThread)
timeSet= apicSetTimeSlice(sleepNext);
else
timeSet= apicSetTimeSlice(timeNextThread);
Kann der RTC periodische IRQs generieren?
Außerdem verstehe ich noch nicht wie du einen absoluten Timer und einen relativen Timer synchron halten willst. Ich denke dass das ziemlich Arbeit werden könnte. Also ich würde das nicht freiwillig versuchen.
Also ja die RTC hat nen periodischen Modus aber immer nur 2er Potenzen als Frequenz.
Der Trick ist, dass ich die beiden Timer nicht synchron halten muss! Ich arbeite doch nur bei dem periodischen Timer mit absoluten Zeit und bei dem One-Shot-Timer arbeite ich mit relativen Zeiten.
Bei relativen Zeiten kann es mir doch egal sein, wie der Timer "aus dem Ruder läuft". Ich nutze dort keine Counter um die absolute Zeit zu verfolgen, sondern mich interessiert es nur, ab einem gewissen Zeitpunkt bis zu einem gewissen Zeitpunkt die Zeit so genau wie möglich zu erfassen und wenn der Timer in der Zeit 1ms ungenau ist, naund! Immernoch besser als was ich mit einem periodischen Timer erreichen kann.
Okay, aber Deine Wohnung ist offensichtlich nicht der Normal-Fall. Über die gesamte Erde betrachtet ist x86 definitiv ein Nischenprodukt.
Das habe ich schon verstanden und ist mir bekannt, aber ich dachte wir sind uns schon einig das wir ein OS für einen "normalen" PC schreiben! Denn was interessieren mich DVD-Player oder eingebettete Systeme in Autos oder Mikrowellen oder Hifi-Anlagen? Die PCs an denen wir arbeiten/spielen/gucken sind in der Mehrzahl x86er!
Ich würde mich sehr freuen auch nen potenten ARM-PC zu sehen, aber das ist leider noch nicht der Fall (und bezahlbar sollte er sein). Wenn es darum geht einen PC als User (damit meine ich nen normalen Menschen) zum Internet surfen, Dokumente schreiben, spiele Spielen und Filme gucken zu benutzen, dann sind alle anderen Architekturen Nischenprodukte! Ob das gut und schön ist, sei mal dahin gestellt!
-
Hallo,
Ich bin ein Fan vom AVL-Baum, aber in dem Fall von einer Sleep-Queue muss ich dann auch zugeben, dass ein RB-Baum wahrscheinlich die bessere Wahl wäre. Denn in dem ist das Löschen schneller.
Ich kenne mich damit (noch) gar nicht aus, meine Meinung basiert nur auf den Artikeln in der Wikipedia. Löschen betrachte ich nicht als komplexe Notwendigkeit, wenn ein Element 2 Kinder hat dann wird es eben nicht gelöscht sondern nur deaktiviert. Ein abgelaufener Timer kann prinzipiell maximal nur 1 Kind haben und ist damit garantiert immer mit wenig Aufwand zu löschen. Das kostet zwar etwas Speicher und macht den Baum minimal umfangreicher aber ich denke der gesparte Aufwand, Elemente mit 2 Kindern zu löschen und anschließend noch den Baum auszubalancieren, rechtfertigt das. Wirklich genau kann man das natürlich erst sagen wenn man beides probiert hat.
Mit Präzision meine ich z.B. das ein Thread alle 40ms ein Bild berechnet und es dann ausgibt.
Gerade das wird mit dem PIT-One-Shot-Modus nicht klappen weil ja der PIT immer wieder neu zeitaufwändig konfiguriert werden muss. Nach genau 360000 Bildern wird mit der PIT-One-Shot-Methode sicher etwas mehr Zeit als ganz exakt 4 Stunden vergangen sein. Wenn Du das anders siehst dann erkläre mir das bitte mal genauer.
Wenn ich jetzt nen periodischen Timer von 15ms habe, dann kann der Fehler zw 5ms und 20ms liegen, was ich schon arg ungenau finde.
Bei einer PIT-Periode von 15ms dürfte der Jitter für ein 25Hz-Timer zwischen 0ms und 10ms liegen. Wie Du da auf 20ms kommst verstehe ich nicht. Außerdem könnte man die PIT-Frequenz ja anstatt auf 66,6666Hz auch auf 50Hz legen, mit einer 20ms PIT-Periode wirst Du der 40ms Frame-Periode bestimmt besser gerecht. Eventuell ist eine variable PIT-Frequenz, die je nach vorhandenen Timern, CPU-Last oder Energie-Spar-Wünschen angepasst wird, doch die beste Lösung für ein PIT-Only-System.
... aber ich hätte sie gerne. Das Prinzip läuft auf eine Diskussion der Art 64KiB RAM sind genug hinaus ;)
Schon klar, ich verstehe das Du Präzision willst, geht mir genau so. Aber Du solltest erst mal klar definieren was Du unter Präzision verstehst. Willst Du das ein Film mit 216048 Frames bei 24fps genau 2:30:02 geht oder was möchtest Du?
Du möchtest doch sicher das dein OS so schnell wie möglich startet
Aber klar doch.
Genau deshalb will ich auf meiner Plattform kein BIOS o.ä., ein fest eingebauter Initial-Loader selektiert das gewünschte OS-Image im Plattform-Flash und startet es. Mein Micro-Kernel-OS initialisiert allen normalen RAM, ein paar Basis-Komponenten wie HPET u.ä. und als letztes alle CPUs und läuft dann los (es ist ab da voll einsatzfähig). Erst die User-Mode-Personality scannt anschließend den PCI(-Express)-Bus und aktiviert die gefundene HW bzw. startet die zugehörigen Treiber-Prozesse und führt dann ein Init-Script o.ä. aus. Ich hoffe damit in weniger als 10s vom Einschalten bis zu einer funktionierenden Shell (welche von der normalen HDD gestartet wurde) zu kommen. Mit einer SSD-HDD und spartanischer HW (also nur 1 mal SATA und 1 mal RS232 für Konsole) sind bestimmt auch weniger als 5s möglich. Ich hab schon verschiedene speziell angepasste Linuxe gesehen die einen graphischen Desktop in 3 bis 4 Sekunden hinbekommen, allerdings nicht auf x86 sondern auf ARM, MIPS und PowerPC. Eine einfache Shell ist da in weniger als 1 Sekunde einsatzbereit.
und dem APIC sollte man schon ne gewisse Zeit geben damit er deine Befehle ausführen kann (konkret meine ich das Starten der APs)
Echt? Ich bin geschockt! Das hätte ich im 20 Jahrhundert der x86-Plattform nicht mehr zugetraut das es noch HW gibt die so lange Bedenkzeit nur für sich selbst braucht. Die APICs haben doch keine nennenswerten externen Abhängigkeiten, wofür benötigen die mal einfach so Zeit? Kannst Du nicht alle APs gleichzeitig aktivieren?
und wenn du dann jedes Mal als kleinste mögliche Wartezeit 15ms hast summiert sich das schnell zu einer sehr langen Zeit auf.
Das kann ich natürlich nachvollziehen. Führst Du während der OS-Kernel-Initialisierung solche Wartezeiten über die selben Mechanismen wie für die User-Mode-Prozesse aus? Vielleicht lassen sich in dieser Zeit, wo ja noch keine User-Mode-Prozesse laufen, ein paar Dinge etwas anders handhaben.
Ich weiß nicht ob du jetzt genau wissen möchtest wie lange man wo warten sollte ...
Ne lass mal, ich bin wirklich geschockt das es sowas immer noch gibt. Ich dachte die Ära der C64 und ähnlicher Hardware-Komponenten ist längst vorbei.
da der Thread ja erstmal in die Queue des PIT gehen würde, da er >55,4ms schlafen möchte.
Davon bin ich auch ausgegangen. Es ging mir um den Teil wo die Restzeit kleiner als diese 55,4ms wird.
Ich speichere wie gesagt immer die Zeit ab die ich in den APIC geschrieben habe und jedes Mal wenn der Scheduler aufgerufen wird (ob die Zeitscheibe nun aufgebraucht wurde oder der Thread abgegeben hat) berechne ich die Differenz zwischen der Zeit die ich eingetragen habe und der Zeit die noch übrig ist (kannst du ganz einfach machen, in dem du den Counter ausliest und mit der Zeit eines Ticks multiplizierst). Diese nutze ich dann zum rechnen.
Das klingt für mich viel aufwändiger als es IMHO eigentlich nötig wäre. Du schreibst in den Local-APIC-Timer ja 2 verschieden Dinge rein, das finde ich persönlich verwirrend und möglicherweise etwas fehleranfällig. Was ist wenn kein APIC vorhanden ist?
Der Sinn hinter einem One-Shot-Timer ist, dass dieser nur feuert, wenn die Zeit die eingetragen wurde abgelaufen ist.
Das ist klar. Das man damit CPU-Last und Energie sparen kann ist auch klar. Beim HPET ist das auch wunderbar nutzbar weil dort ja der eigentliche Counter kontinuierlich monoton durchläuft. Beim PIT im One-Shot-Mode ist genau das nicht der Fall was bedeutet das keine vernünftige präzise Zeitquelle zur Verfügung steht (vom RTC mal abgesehen, aber ob das ne gute Idee ist wage ich zu bezweifeln).
Der Trick ist, dass ich die beiden Timer nicht synchron halten muss! Ich arbeite doch nur bei dem periodischen Timer mit absoluten Zeit und bei dem One-Shot-Timer arbeite ich mit relativen Zeiten.
Auch das erscheint mir unnötig kompliziert. Außerdem gibt es dann eine 2 Klassengesellschaft bei den Timern: solche die kürzer sind als diese 55,4ms und recht genau laufen und jene die länger als 55,4ms laufen und auf ein 55,4ms-Raster gedrückt werden (also wohl mindestens 110,8ms). Wie willst Du eigentlich den Startzeitpunkt eines Timers ermitteln (also den Moment wo z.B. ein sleep(20) aufgerufen wurde) um zu ermitteln ob er noch vor dem nächsten 55,4ms-Tick abläuft oder erst danach. Wenn Du nur diese 55,4ms-Ticks hast dann hast Du auch keine genauere absolute Zeitbasis, kannst also den Timer-Start auch nur auf 55,4ms genau bestimmen. Oder hab ich was übersehen? Oder war das die Idee mit dem auslesen des aktuellen PIT-Zählerwertes und diesen quasi als zusätzliche Genauigkeit (das meinte ich mit dem Nachkomma-Bits) zu benutzen?
aber ich dachte wir sind uns schon einig das wir ein OS für einen "normalen" PC schreiben!
Ne, also ich auf jeden Fall nicht. Den Stress tue ich mir nicht an. Vor gut 7 Jahren hatte ich mal mit dem Gedanken gespielt einen eigenen DOS-Extender, der auch ohne DOS starten können sollte, zu programmieren und mich in diesem Zusammenhang auch mal etwas mit der x86-Plattform (und nicht nur mit den x86-CPUs) beschäftigt. Ich bin dann nach einem guten halben Jahr zu dem Schluss gekommen dass das doch nichts für mich ist. Ich bin dann erstmal auf die FPGA-Programmierung gekommen und hab daher vor einiger Zeit die Idee entwickelt gleich selber ne komplette Plattform aufzubauen. Ohne all die Macken die ich in meiner Berufspraxis (und auch in privaten Projekten) mit den zur Zeit existierenden Plattformen immer wieder mal erlebe, damit will ich nicht sagen das es keine ordentlichen Plattformen gibt.
Die PCs an denen wir arbeiten/spielen/gucken sind in der Mehrzahl x86er!
Darf ich Dich an die vielen Smart-Phones erinnern? Es gibt einiges an tollen Nicht-x86-Systemen die für die normalen PC-Arbeiten absolut geeignet sind, z.B. verschiedene NetBooks mit ARM- oder MIPS-Innenleben. Das Problem, welches die Hersteller von einer aktiven Vermarktung abhält, ist einfach das kein Windows (und oft auch kein Flash) drauf läuft. Ich persönlich betrachte beides eher als Vorteil und nicht als Nachteil und hoffe das Android ein Erfolg wird und damit dann die Windows-Pflicht, die viele Hersteller empfinden, deutlich reduziert wird. Mit der Abkehr von Windows kann dann auch eine Abkehr von x86 erfolgen, ich denke beides wird langsam aber sicher an Bedeutung verlieren aber wohl auch nicht ganz verschwinden.
Ich würde mich sehr freuen auch nen potenten ARM-PC zu sehen, aber das ist leider noch nicht der Fall (und bezahlbar sollte er sein). Wenn es darum geht einen PC als User (damit meine ich nen normalen Menschen) zum Internet surfen, Dokumente schreiben, spiele Spielen und Filme gucken zu benutzen
Hast Du schon was vom iPad gehört? Die Restriktionen, die Apple künstlich einbaut, finde ich zwar ganz und gar nicht toll (deswegen werde ich wohl nie ein iPad besitzen) aber die Hardware als solche ist schon ziemlich gut (von ein paar fehlenden Schnittstellen abgesehen, die aber gewiss ganz leicht zu integrieren wären). Für ein paar Euro mehr wäre sicher auch Dual-Core und ordentlich RAM möglich, die nötigen Komponenten gibt es jedenfalls. Was der ARM-Plattform fehlt ist der Schritt in Richtung 64Bit. Das haben MIPS und PowerPC schon lange (schon vor x86) und erfolgreich (beide waren schon im High-Performance-Computing vertreten) erledigt und würden sich daher auch für dicke PCs empfehlen. Man darf also gespannt sein was die Zukunft so bringt.
Grüße
Erik
-
Ein abgelaufener Timer kann prinzipiell maximal nur 1 Kind haben und ist damit garantiert immer mit wenig Aufwand zu löschen.
Da kann ich nur sagen, du solltest dich noch ein wenig mit solch ausbalanzierten Bäumen beschäftigen ;) Denn es ist in dem Sinn egal wieviel Kinder ein Knoten hat, ob der Baum danach ausbalanziert werden muss, dass ist die entscheidene Frage. Ich würde dir ja den AVL-Baum als einstiegs Lektüre empfehlen, da ich ihn einfacher zu verstehen finde.
Gerade das wird mit dem PIT-One-Shot-Modus nicht klappen weil ja der PIT immer wieder neu zeitaufwändig konfiguriert werden muss. Nach genau 360000 Bildern wird mit der PIT-One-Shot-Methode sicher etwas mehr Zeit als ganz exakt 4 Stunden vergangen sein. Wenn Du das anders siehst dann erkläre mir das bitte mal genauer.
Den Vorteil den ich beim PIT und periodisch sehe ist, dass du genau sagen kannst wie der Jitter aussieht. Das ist bei der One-Shot Methode nicht möglich.
Ich denke mal das du immernoch mit deinem absoluten Zeiten rechnest ;) Wenn ich aber relative Zeiten nehme, dann ist der Jitter, der vor dem aktuellen Zeitpunkt aufgetretten ist, egal! So wird es ihn zwar geben, aber er summiert sich nicht auf.
Was mir aber gerade aufgefallen ist, das ich mir mit den 40ms selbst ein Ei gelegt habe ;) Denn dieser Timer wird immer in der Sleep-Queue der CPU bleiben (und dummer weise sogar immer auf der selben CPU, was aber nicht bedeutet das der Thread der das Event abfragt immer auf der selben CPU läuft).
Bei einer PIT-Periode von 15ms dürfte der Jitter für ein 25Hz-Timer zwischen 0ms und 10ms liegen. Wie Du da auf 20ms kommst verstehe ich nicht.
Gut, auch da fällt mir gerade auf, das der Jitter den ich meine nur beim 1. Mal auftritt. Denn best-case wäre, wenn der Thread dieses Event kurz bevor der PIT feuert erstellt, aber der worst-case wäre, wenn der Thread kurz nach dem der PIT gefeuert hat, das Event erstellt. Ich hoffe du kannst nachvollziehen wie ich das meine. Das Problem ist die "lange" Periode von 15ms. Du kannst ja schlecht wissen ob das Event am Anfang oder am Ende der Periode erstellt wird, aber der Wert des Counters, der absoluten Zeit, ist der selbe!
Schon klar, ich verstehe das Du Präzision willst, geht mir genau so. Aber Du solltest erst mal klar definieren was Du unter Präzision verstehst. Willst Du das ein Film mit 216048 Frames bei 24fps genau 2:30:02 geht oder was möchtest Du?
Ich muss dir ganz ehrlich sagen, das ich wo ich das System "entwickelt" habe, mir gar keinen Kopf über periodische Sachen gemacht habe, sondern mir war wichtig das wenn ich nen sleep(10) aufrufe, das so genau wie möglich sein sollte. Das will ich auch immernoch, aber ich muss halt mit den Nachteilen dieses Systems für periodische Sachen leben. Obwohl ich ja finde das durch mein 2-geteiltes System der Jitter ganz gut abgefangen wird.
Echt? Ich bin geschockt! Das hätte ich im 20 Jahrhundert der x86-Plattform nicht mehr zugetraut das es noch HW gibt die so lange Bedenkzeit nur für sich selbst braucht. Die APICs haben doch keine nennenswerten externen Abhängigkeiten, wofür benötigen die mal einfach so Zeit? Kannst Du nicht alle APs gleichzeitig aktivieren?
Problem ist, du sollst dem APIC Zeit geben, so dass er die Nachricht verschicken und die anderen CPUs diese auch empfangen können. Ich könnte alle APs gleichzeitig aktivieren (was ich in einer alten Version auch gemacht habe), aber das kann zu Problemen führen (auch wenn das sehr unwahrscheinlich ist). In dem Standard von ACPI und MPS ist vorgesehen, dass ne CPU auch als defekt vom BIOS markiert werden kann und diese CPU willst du nicht starten! So sage ich, lieber ein wenig mehr Zeit beim Starten der APs verbraten und dafür alle Eventualitäten aus dem Weg räumen!
Das Problem sind hier im Endeffekt halt auch wieder die alten Systeme. Wenn ich mich recht erinnere, dann wurde das busy-Flag im x2Apix-Mode entfernt, du brauchst dir da also keine Gedanken mehr machen, ob die Message verschickt wurde oder nicht (und brauchst somit auch nicht mehr warten).
Das "lustige" ist, man sollte lieber zu lange Warten als zu kurz. Denn ich hatte schon den Fall, das mein OS auf nem neuem Core2Duo PC alle Kerne starten konnte, aber auf nem alten Dual P3 System konnte mit einmal die 2. CPU nicht mehr gestartet werden. Als ich dann die Zeit zum Warten verlängert hatte, lief wieder alles.
Das klingt für mich viel aufwändiger als es IMHO eigentlich nötig wäre. Du schreibst in den Local-APIC-Timer ja 2 verschieden Dinge rein, das finde ich persönlich verwirrend und möglicherweise etwas fehleranfällig. Was ist wenn kein APIC vorhanden ist?
Wieso und wo schreibe ich 2 Dinge in den APIC? Jeder Timer der nen Counter hat kann so benutzt werden (also auch der PIT).
Auch das erscheint mir unnötig kompliziert. Außerdem gibt es dann eine 2 Klassengesellschaft bei den Timern: solche die kürzer sind als diese 55,4ms und recht genau laufen und jene die länger als 55,4ms laufen und auf ein 55,4ms-Raster gedrückt werden (also wohl mindestens 110,8ms). Wie willst Du eigentlich den Startzeitpunkt eines Timers ermitteln (also den Moment wo z.B. ein sleep(20) aufgerufen wurde) um zu ermitteln ob er noch vor dem nächsten 55,4ms-Tick abläuft oder erst danach. Wenn Du nur diese 55,4ms-Ticks hast dann hast Du auch keine genauere absolute Zeitbasis, kannst also den Timer-Start auch nur auf 55,4ms genau bestimmen. Oder hab ich was übersehen? Oder war das die Idee mit dem auslesen des aktuellen PIT-Zählerwertes und diesen quasi als zusätzliche Genauigkeit (das meinte ich mit dem Nachkomma-Bits) zu benutzen?
Du hast mich leider immernoch nicht richtig verstanden :(
Also zum ermitteln des genau Zeitpunktes (was leider im Falle des PITs "nur" auf 3*832ns genau wird) nutze ich den Wert des Counters! Also das was du vermutlich mit den Nachkomma-Bits meinst.
Nun zu meiner 2-Klassengesellschaft. Ich habe 2 Queues, eine für Timer >55,4ms und eine für Timer <= 55,4ms.
Wir lassen die periodischen Timer jetzt mal außen vor. Ich habe also einen Thread der will 100ms schlafen. D.h. er kommt auf jeden Fall erstmal in die Queue mit den Timern >55,4ms. Aber nach einem Tick (ich ignoriere die genaue Zeit jetzt mal um es einfacher zu machen) will der Timer ja nur noch 44,6ms warten und d.h. er wird aus der Queue für Timer >55,4ms entfernt und wird in die Queue <=55,4ms gepackt.
Ich hoffe du siehst nun das die Timer früher oder später alle in der Queue <=55,4ms landen und auch nur dort ausgelöst werden können. Die Queue für Timer >55,4ms ist nur dafür da um den Jitter so klein wenig möglich zu halten.
Darf ich Dich an die vielen Smart-Phones erinnern? Es gibt einiges an tollen Nicht-x86-Systemen die für die normalen PC-Arbeiten absolut geeignet sind, z.B. verschiedene NetBooks mit ARM- oder MIPS-Innenleben. Das Problem, welches die Hersteller von einer aktiven Vermarktung abhält, ist einfach das kein Windows (und oft auch kein Flash) drauf läuft. Ich persönlich betrachte beides eher als Vorteil und nicht als Nachteil und hoffe das Android ein Erfolg wird und damit dann die Windows-Pflicht, die viele Hersteller empfinden, deutlich reduziert wird. Mit der Abkehr von Windows kann dann auch eine Abkehr von x86 erfolgen, ich denke beides wird langsam aber sicher an Bedeutung verlieren aber wohl auch nicht ganz verschwinden.
Wie gesagt, Smart-Phones gehören nicht wirklich zu meinen Zielen! Zumal das OS-Deving schon kompliziert genug ist. Wenn ich mich dann auch noch damit auseinander setzen muss wie ich mein OS auf ein solches Smart-Phone bekomme und dann müsste ich noch Reverse-Enginering bertreiben, da die Platformen nicht offen sind und von den vielen total unterschiedlichen Platformen will ich erst gar nicht anfagen. Das wäre einfah nur der absolute Overkill!
Was Windows betrifft, glaube ich nicht das es je komplett verschwinden wird. Dann gibt es halt nen Windows für die anderen Platformen!
Wo gibt es denn diese Netbooks für normale Menschen (und zu normalen Preisen) zu kaufen? Die ARM-Netbooks werden zwar ständig angekündigt, aber kommen tut da nicht wirklich was und von MIPS-Netbooks habe ich noch gar nichts gehört.
Hast Du schon was vom iPad gehört? Die Restriktionen, die Apple künstlich einbaut, finde ich zwar ganz und gar nicht toll (deswegen werde ich wohl nie ein iPad besitzen) aber die Hardware als solche ist schon ziemlich gut (von ein paar fehlenden Schnittstellen abgesehen, die aber gewiss ganz leicht zu integrieren wären). Für ein paar Euro mehr wäre sicher auch Dual-Core und ordentlich RAM möglich, die nötigen Komponenten gibt es jedenfalls. Was der ARM-Plattform fehlt ist der Schritt in Richtung 64Bit. Das haben MIPS und PowerPC schon lange (schon vor x86) und erfolgreich (beide waren schon im High-Performance-Computing vertreten) erledigt und würden sich daher auch für dicke PCs empfehlen. Man darf also gespannt sein was die Zukunft so bringt.
Das iPad ist ja gut und schön (nicht wirklich ;) ), aber wie gesagt, die ganzen Beschränkungen und wer wirklich im Internet surfen will und da schließe ich das Mailschreiben, Forumsbeitragschreiben und Blogschreiben mit ein, der kommt einfach nicht ohne eine Tastatur aus. Zumindest möchte ich nicht solch langen Beiträge wie hier mit ner Tastatur auf nem Touchdisplay schreiben!
Ich kann zwar auch nicht in die Zukunft sehen, aber ich behaupte mal wenn Intel x86 überall haben will, dann bekommen die das auch hin! Ob du gut ist, sei mal dahin gestellt.
Das gleiche Problem gibt es momentan beim Auto. Ein Elektromotor ist was die Effizienz betrifft nem Benzin/Diesel-Motor sowas von überlegen, aber wen interessierts? Das selbe damals beim Video-System (VHS und Beta2000 oder so ähnlich). Wir leben im Kapitalismus und der normale Mensch ist dumm wie Knäckebrot (um es mal ganz überspitzt zu sagen). Der kauft was ihm die Werbung sagt und wer hat die beste Werbung, nicht zwangsläufig der mit dem besten Produkt, sondern der mit dem meisten Geld! Und Intel hat verdammt viel Geld.
Also aus meiner Sicht ist das Netbook ein verdammt gutes Bsp, das es egal ist wie gut oder schlecht ein Produkt ist (Apple fällt da auch rein ;) ). Ich kann mit den Dingern nichts Anfangen. Denn zu wenig Leistung und am Anfang viel zu kleiner Bildschrim. Ich bin Brillenträger und möchte nicht das meine Augen noch schlechter werden (bezieht sich auf bestimmte "hohe" Auflösungen auf nem viel zu kleinem Bildschirm).
Das Problem eines wirklich guten Produktes ist doch, es muss auch ne Firma mit entsprechenden finanziellen Mitteln dahinter stehen. Denn wenn PowerPC so toll wäre, warum haben wir den dann heute nicht im Mainstream bereich (ich weiß das sie im Serverbereich ganz gut sind)?
Das selbe wurde auch in nem anderem Forum diskutiert. Da ging es darum warum so wenig DAUs AMD wollen. Es mangelt einfach an Werbung und die kostet Geld.
So ich denke ich bin jetzt genug abgeschweift ;)
-
Um das Thema mal wieder zu beleben habe ich mir in letzter Zeit mal Gedanken gemacht, wie ich das Problem mit dem Jitter bei periodischen Events die kleiner (von der Zeit her) sind als der periodische Timer (im Falle des PIT <55,4ms).
Ich habe mir überlegt, das von den periodischen Events immer so viele "Kinder" von dem Event erstellt werden (und damit auch in die Queue wandern) das genau ein Kind soweit in der Zukunft liegt, das es in der Queue des periodischen Timers liegt. Damit bleibe ich auf lange Sicht Konstant, kann aber trotzdem die Events die zwischen zwei Ticks von dem periodischem Timer liegen, sehr genau feuern lassen.
Soweit so gut. Das Problem was jetzt aber kommt ist, dass man damit das System ganz leicht in die Knie zwingen kann, indem man einfach eine sehr kleine Periode nimmt (z.B. 20µs = 2770 "Kinder"-Events).
Ich sehe da jetzt 2 Lösungen, einfach ignorieren und hoffen das keiner auf die dumme Idee kommt oder die Zeit für eine Periode einschränken.
Auf der einen Seite möchte ich das man das System nicht so leicht in die Knie zwingen kann, aber auf der anderen Seite möchte ich es auch nicht künstlich beschränken. Obwohl scheinbar bisher niemand eine solch kleine Periode benötigt hat.
-
Ich antworte mal auf die anderen Sachen, die dir aber sicher schon bekannt sind.
Der E-Motor spielt keine nennenswerte Rolle im Automobilbereich (vgl. mit Benzin/Diesel), da du nicht genug Strom mitnehmen kannst, um hohe Reichweiten zu erzeugen. Im Bereich der Gabelstapler etc. (lokal begrenzt) sind die Teile Standard, Hybrid ist im Kommen.
VHS hat gewonnen, weil die Monopolisten der anderen Sorten jegliche Form von Pornographie auf ihren Medien verboten haben. Auf VHS waren diese erlaubt, und so verbreitete sich das System, trotzdem es qualitativ schlechter war.
Ich hab ein Netbook, mit 7" Display und 800x480 Auflösung (die Auflösung ist sehr gering). Wenn man das auf 10" und 1024x600 hochrechnet, kann man damit durchaus arbeiten. Und ich hab -10 Dioptrien. Praktisch ist halt die Größe - man hat es immer dabei, wiegt fast nix und hat ne vernünftige Akkulaufzeit. Ist mir in der Uni sehr wichtig. Richtig doof sind drei Dinge... die 2GB SSD (definitiv zuwenig, nächstemal mind. 4GB), der VIA C7 1GHz (ist halt nicht soo schnell, trotz Hardwarecrypto) und der VIA VX800 / Chrome9-Grafikchipsatz (Linux-Treiber sind unter aller Sau, kein 3D, kein XvMC, buggy Xv, kein DualScreen). Trotzdem möchte ich es nicht missen. Das hängt vom Anwendungsfall ab - mal schnell was nachgucken geht besser als ohne Rechner. Und ich hab einen schnellen SSH/VNC-Server zuhause...
ARM, MIPS haben wesentlich mehr Rechenleistung je Stromverbrauch als x86 oder PPC. Dafür hat x86 die maximale Rechenleistung pro CPU bei gegebenem Preis, da hält PPC nicht mit. Für mich wäre ein schnelles ARM-Netbook durchaus akzeptabel, aber solange sich keine Architektur durchsetzt, nehmen die Hersteller lieber einen Intel Atom und pappen nen Ubuntu drauf, als ein ARM mit Custom-Architektur, wo sie dann Kernel/Userland selber warten müssen. Gibt aber schon bestrebungen, ARM-Linux zu vereinheitlichen. Bei MIPS wird das prinzipiell nicht geschehen, da die Architektur nicht fest ist - bei ARM hast du recht enge Grenzen, die du einhalten musst, bei MIPS darfst du auch am Befehlssatz schrauben und es noch MIPS nennen. Dafür kannst du es besser synthetisieren und gleich mit anderer Hardware (DSL-Modem, ZigBee-/Bluetooth-Stack, TCP-Beschleuniger, ...) auf einen Chip packen. Das geht mit ARM nicht so gut.
So, jetzt weiter zum Topic ;-)
Gruß,
Svenska
-
Hallo,
dann schreibe ich in diesem Thread auch mal wieder etwas, hab ja schließlich angefangen mit diesem Thema.
Ich habe mir überlegt, das von den periodischen Events immer so viele "Kinder" von dem Event erstellt werden (und damit auch in die Queue wandern) das genau ein Kind soweit in der Zukunft liegt, das es in der Queue des periodischen Timers liegt. Damit bleibe ich auf lange Sicht Konstant, kann aber trotzdem die Events die zwischen zwei Ticks von dem periodischem Timer liegen, sehr genau feuern lassen.
Ich finde Dein Konzept immer noch irgendwie unnötig kompliziert. Wenn Du keine genaue Hardware zur Verfügung hast (also keinen HPET) dann kannst Du auch kaum genaues Timing für die Applikationen anbieten. Mit den Tricks legst Du Dir meiner Meinung nach nur ein faules Ei ins Nest, also Komplexität deren Nutzen in Relation zum Aufwand wahrscheinlich viel zu klein ist. Aber das ist nur meine persönliche Meinung, vielleicht könnten sich dazu auch mal andere Leute äußern.
Ich sehe da jetzt 2 Lösungen, einfach ignorieren und hoffen das keiner auf die dumme Idee kommt oder die Zeit für eine Periode einschränken.
Auf der einen Seite möchte ich das man das System nicht so leicht in die Knie zwingen kann, aber auf der anderen Seite möchte ich es auch nicht künstlich beschränken. Obwohl scheinbar bisher niemand eine solch kleine Periode benötigt hat.
Also ich denke das ich für periodische Events eine untere Grenze definiere oder das ich meine PopUp-Threads als Limit benutze (also für jedes Event ein PopUp-Thread erstellt wird aber nur wenn der PopUp-Thread vom letzten Event schon wieder ans System zurückgegeben wurde). Das Problem ist aber schon interessant, man will keine (potentiell nützlichen) Möglichkeiten unterbinden aber auch das System nicht in die Knie gehen lassen. Mich würde dazu mal interessieren wie andere OSe das lösen.
Auf http://www.openbsd.org/loongson.html sieht man ein interessantes Nettop mit MIPS-kompatiblem Innenleben. Aber der Godson-Prozessor will auch x86-kompatibel werden, offenbar sehen auch in China die Verantwortlichen einen gewissen Druck in Richtung Windows (die pressen ja schließlich auch die Backup-Kopien von Windows ;) ).
Leider muss ich Svenska recht geben, wenn hinter einer guten Idee nicht auch gutes Geld steht dann kommt leider nur selten ein gutes Produkt bei raus.
Grüße
Erik
-
Ich finde Dein Konzept immer noch irgendwie unnötig kompliziert. Wenn Du keine genaue Hardware zur Verfügung hast (also keinen HPET) dann kannst Du auch kaum genaues Timing für die Applikationen anbieten. Mit den Tricks legst Du Dir meiner Meinung nach nur ein faules Ei ins Nest, also Komplexität deren Nutzen in Relation zum Aufwand wahrscheinlich viel zu klein ist.
Kompliziert ist es bzw. wird es immer mehr, desto mehr Probleme ich "ausbügeln" muss ;)
Das Ziel ist es auch ohne HPET ein annährend genaues Timing zu haben. Dass das ganze kompliziert wird war mir klar.
... Mich würde dazu mal interessieren wie andere OSe das lösen.
In dem Sinne, gar nicht! Wenn du einen periodischen Timer nutzt ist die untere Grenze genau 1 Tick (im Falle von Windows 10ms oder 15ms). Ansonsten haben sich die jeweiligen Programmierer die kleinere und/oder genauere Events benötigten eben anderes beholfen. Z.B. indem das Video am Audio synchronisiert wird.
Ab Vista wird dann sogar der HPET genutzt (unter XP wird er zwar erkannt, aber nicht genutzt).
Wie das ganze unter Linux läuft weiß ich nicht, aber da auch Linux mal nen periodischen Timer hatte, gehe ich mal davon aus, dass für diesen Timer das gleiche gilt wie unter Windows.
Wie sie das dann mit dem tickless Timer gelöst haben müsste man auch nachgucken.
Was die MIPS Platform angeht. Nach dem was ich da gerade auf deinem Link gelesen habe, war das nicht gerade ein toller Start. Ich meine Hardwarefehler, welche ich dann umgehen muss, sonst friert das System ein. Auf solche Spielchen wollte ich mich eigentlich nicht einlassen. Dann lieber eine ARM-CPU, aber auch bei der ist das Problem, die werden zwar seit Jahren angekündigt, aber auf dem Markt kommen sie nicht wirklich an!
-
Hallo,
Kompliziert ist es bzw. wird es immer mehr, desto mehr Probleme ich "ausbügeln" muss ;)
Es könnte passieren das Du so viele Problemchen "ausbügeln" musst das Du am Ende Dein eigentliches Ziel verfehlst. Das wäre schade.
Das Ziel ist es auch ohne HPET ein annährend genaues Timing zu haben. Dass das ganze kompliziert wird war mir klar.
Nur mit dem PIT alleine ist das mMn unmöglich (entweder ist man auf eine konstante/niedrige PIT-IRQ-Frequenz festgelegt oder man verliert die Langzeitgenauigkeit wenn man immer wieder am PIT rumdreht), und wenn Du noch einen/mehrere Local-APIC-Timer benutzt kannst Du zwar theoretisch eine höhere Genauigkeit bekommen hast aber auch Probleme weil diese zwei Systeme nicht exakt Synchron sind und langsam aber sicher auseinander driften.
... Mich würde dazu mal interessieren wie andere OSe das lösen.
In dem Sinne, gar nicht!
Da hast Du wohl recht. Bei mir wird das sicher ähnlich enden, der PopUp-Thread läuft mit der Priorität seines Prozesses (also das Programm das den Timer angefordert hat) so kann zumindest kein einfaches User-Programm einen Root-Prozess, wie z.B. Geräte-Treiber u.ä., ausbremsen. Es ist mir persönlich schon wichtig das ich zumindest immer an eine Root-Shell komme um dort amok laufende Prozesse abschießen zu können.
Was die MIPS Platform angeht. Nach dem was ich da gerade auf deinem Link gelesen habe, war das nicht gerade ein toller Start. Ich meine Hardwarefehler, welche ich dann umgehen muss, sonst friert das System ein. Auf solche Spielchen wollte ich mich eigentlich nicht einlassen.
Das sind Anfangsprobleme, das Bild zeigt sicher einen Prototyp bzw. ein Exemplar einer Null-Serie (von denen es vielleicht 5 Stück gibt), da muss man immer noch mit dem einen oder anderen Hardware-Problem kämpfen. Bei den meisten Produktentwicklungen wo ich bis jetzt beteiligt war musste erst eine zweite oder dritte Hardware-Revision gefertigt werden bis alles Rund läuft. Einen Bug im Platinenlayout kann man nicht einfach mal so fixen wie einen Bug in der Software, da wird erst mal ein SW-Workaround programmiert und das Problem in die ToDo-Liste für die nächste Hardware-Revision aufgenommen. Wenn dann der Softi sagt das er keine weiteren Hardware-Probleme entdeckt hat dann startet man mit dem nächsten Entwicklungszyklus. Auf der nächsten Hardware-Revision baut man dann alle SW-Workarounds aus und schaut ob die Hardware nun sauber läuft, wenn nicht dann bekommt die Hardware-Abteilung vom Chef erklärt wie viel Geld diese Hardware-Revision eigentlich gekostet hat und es startet ein nächster Entwicklungszyklus. Bei guten Profis bzw. nicht zu exotischen Entwicklungen sind meistens nur ein oder zwei Entwicklungszyklen erforderlich, bei komplizierten oder neuartigen Sachen, wo keiner mit Erfahrung hat, sollte man besser ein oder zwei Entwicklungszyklen mehr annehmen. Das Management bestimmt dann das der richte Zeitpunkt ein Produkt auszuliefern dann ist wenn die SW-Workarounds für die verbleibenden Hardware-Bugs nicht mehr einfach zu erkennen sind, das bedeutet dann das der SW-Entwickler seine SW so gestalten muss das diese die exakte HW-Revision erkennt und die nötigen Workarounds aktiviert, da das nicht immer perfekt klappt bleiben manche Workarounds einfach immer drin. Schlimmer wäre es wenn Käufer der ersten Stunde keine SW-Updates bekommen könnten und noch schlimmer wäre es wenn der Kunde vor dem SW-Update die exakte HW-Revision bestimmen müsste (um den passenden Download zu selektieren) dann müsste man ja zugeben fehlerhafte Hardware ausgeliefert zu haben. Wer sich jetzt noch über so manche Probleme mit seinem Produkt wundert bzw. sich ärgert warum manche offensichtlichen (SW-)Bugs einfach nicht gefixt werden der sollte mal in großen Unternehmen dem Management über die Schulter schauen. Ich hab dort oft genug zu gesehen, eigentlich zu oft aber von irgendetwas muss man ja schließlich leben. :(
Dann lieber eine ARM-CPU, aber auch bei der ist das Problem, die werden zwar seit Jahren angekündigt, aber auf dem Markt kommen sie nicht wirklich an!
Das hat nichts mit ARM oder MIPS oder anderen CPU-Architekturen zu tun. Bis jetzt gibt es nur eine Firma die gute ARM-Systeme erfolgreich anbietet aber leider machen dort bestimmte Management-Entscheidungen, die die zugehörige Software betreffen (oder fehlende HW-Schnittstellen), diese Produkte für einen mündigen Käufer quasi gänzlich indiskutabel. :(
Grüße
Erik
-
Nur mit dem PIT alleine ist das mMn unmöglich (entweder ist man auf eine konstante/niedrige PIT-IRQ-Frequenz festgelegt oder man verliert die Langzeitgenauigkeit wenn man immer wieder am PIT rumdreht), und wenn Du noch einen/mehrere Local-APIC-Timer benutzt kannst Du zwar theoretisch eine höhere Genauigkeit bekommen hast aber auch Probleme weil diese zwei Systeme nicht exakt Synchron sind und langsam aber sicher auseinander driften.
Ahhh ;)
Deswegen nutze ich ja immer 2 Timer, einen der "tickless" läuft und einen der periodisch läuft, aber die Periode ziemlich lang ist (im Falle des Gespanns APIC/PIT 55,4ms) bzw. theoretisch wenn kein periodisches Event läuft, kann er (der periodische Timer) abgestellt werden.
Da das alles in meiner Freizeit als Hobby läuft mach ich es sowieso so, dass ich meine Idee implementiere und wenn ich dann irgendwann später feststelle die Idee war doch nicht so gut oder hat noch Lücken, dann bessere ich halt nach. Soll heißen ich habe mir keinen Plan für meine Entwicklung gemacht und ich überlege mir nicht schon vorher wie alles hinterher aussehen soll. Dadurch dauert es manchmal etwas länger bzw. muss oft Code komplett neu geschrieben werden, aber es geht schneller (was in dem Fall sehr relativ ist ;) ) voran.
Das hat nichts mit ARM oder MIPS oder anderen CPU-Architekturen zu tun. Bis jetzt gibt es nur eine Firma die gute ARM-Systeme erfolgreich anbietet aber leider machen dort bestimmte Management-Entscheidungen, die die zugehörige Software betreffen (oder fehlende HW-Schnittstellen), diese Produkte für einen mündigen Käufer quasi gänzlich indiskutabel.
Ich gehe mal davon aus du redest von Apple.
Nachdem was ich in letzter Zeit so in verschiedenen News gelesen habe, ist das Interesse an ARM System, besonders an Servern (im Hinblick auf den Energieverbrauch) aber groß genug.
Sagen wir es doch so wie es ist. Linux als alleiniges Betriebssystem verkauft sich nicht für die Masse und Windows gibt es nicht vernünftig für die ARM CPUs (von den Mobile Versionen mal abgesehen).
Was ich an den MIPS zu bemängeln hatte, war aber das die ja schon Netbooks herstellen und selbst die OpenBSD Entwickler gesagt haben, das sie nicht alle Work-Arounds implementieren werden und MIPS ist jetzt nicht gerade ne niegel nagel neue Architektur. Ich kenne mich da zwar leider auch nicht aus, aber ist es da nicht wie bei ARM, soll heißen du kaufst so zu sagen "Pläne" und kannst dann deine eigene CPU zusammen basteln?!
Naja, ich hoffe das bald ARM-Systeme in großer Stückzahl zu finden sein werden (im Net/Notebook und PC Segment). Wenn ich das Geld hätte, würde schon längst so ein schickes BeagleBoard bei mir zu Hause stehen!
-
Die MIPS-Architektur unterliegt weniger Restriktionen als die ARM-Architektur, d.h. man darf auch Befehle hinzufügen und/oder entfernen und es trotzdem noch als MIPS verkaufen. Außerdem ist MIPS einfacher gestrickt als ARM, daher findet man fast keine reinen MIPS-Prozessoren; da ist meist noch ziemlich viel dabei (z.B. DSL-Modem in den Fritzboxen, die CPUs sind von TI).
Bei ARM muss man recht enge Grenzen einhalten, was den CPU-Befehlssatz betrifft, so dass alle ARM-Chips garantiert kompatibel sind, wenn sie den gleichen Befehlssatz (ARMv4, Thumb, ...) sprechen.
Davon unabhängig ist leider die Systemarchitektur, weswegen es zwar immer wieder Versuche gibt, aber kein Linux-for-all-ARM. Das geht prinzipiell nicht. Naja, für Netbooks hat sich ein ARM-Consortium gegründet, welches eben diese Architektur standardisieren möchte, schaunmermal. Wird in jedem Fall noch ein paar Jahre dauern.
Das einzige ARM-(XScale-)System, was ich hier habe und wo Debian drauf installiert ist und läuft, ist ein NAS (Thecus N2100 / Allnet). Das Teil ist laut, hat einen nicht regelbaren Lüfter und die Performance ist unter aller Sau. (Hat 2x GBit Ethernet und schafft insgesamt keine 100 MBit/s ... außerdem müssen die Kernel stark gepatcht werden und Intel wartet die Patches nicht.) Enttäuschend.
Gruß
-
So ich melde mich auch mal wieder und möchte mal wieder was zum eigentlichen Topic beitragen.
Da ich mal wieder Zeit gefunden haben ein wenig an meinem System zu arbeiten und ich mich auch endlich mal mit der 3D-Programmierung befassen will, ist mir wieder eingefallen wozu man nen "High-Performance-Counter" braucht.
Bei Spielen möchtest du ja das sich die Spieler-Figur auf jedem Rechner (egal wie schnell oder langsam) gleich schnell bewegt. Dazu benutzt man solch einen "High-Performace-Counter". Um sagen zu können, so seit dem letzten Zeichnen ist ne bestimme Zeit vergangen und die Spielerfigur bewegt sich damit jetzt ne bestimmte Anzahl von "Pixeln".
Problem ist nun natürlich, wie implementiert man solch einen Counter im System. Ich habe nochmal ein wenig gesucht und habe jetzt hoffentlich nen brauchbares System dafür gefunden.
Ich werd dafür ne Kombination aus dem ACPI-PMT und dem PIT bzw. wenn möglich den TSC nehmen.
Den ACPI-PMT kann ich natürlich nur nutzen wenn ACPI auch vorhanden ist (da mein System ja auch PCs unterstützt die kein ACPI haben). Ist das System aber so alt das es kein ACPI hat, dann sollte ich davon ausgehen können das ich ohne Bedenken den TSC nutzen kann (ist dem so? konnten sich die CPUs damals schon runtertakten?).
Warum will ich den ACPI-PMT in Kombination mit dem PIT nutzen? Also erstens einmal gibt es das Problem das je nachdem wie der PMT implementiert ist, der Counter entweder 24bit oder 32bit groß ist. Er läuft also alle 4Sek oder alle 1130Sek über. Nutze ich diesen Counter jetzt in Kombination mit dem PIT, so erspare ich mir auch ständig den PIT lesen zu müssen (was ja ein Problem mit meinem System ist), da ich einfach bei jedem PIT-IRQ den Counter auslese und abspeichere. Will ich dann wissen wieviel Zeit seit dem letzten PIT-IRQ vergangen ist, brauche ich einfach nur den PMT auslesen und die Differenz zw dem aktuellen Wert und dem gespeicherten Wert ausrechnen (da kann ich dann auch relativ einfach den Überlauf behandeln). Desweiteren sollte ich damit auch das Problem umgehen, das der PMT wohl auch mal 4Sek oder mehr abtriftet (da ich ja immer nur die Differenz zw 2 Werten nehme und nicht den Counter nutze um die Werte aufzuaddieren).
Was den TSC betrifft, so würde ich diesen genauso benutzen wie den PMT.
Habe ich einen solchen "High-Performance-Counter" kann ich auch mein Event-System (also das mit "tickless"-Timer) einfacher umsetzen.
Optimal läuft das ganze natürlich erst mit dem HPET. Obwohl ich mal behaupte das ich so eigentlich alle Probleme der vielen Timer umgehen sollte. Das einzigste was ich dann nicht mehr machen kann, ist den PIT (als periodischen Timer) abschalten, wenn keine Events vorhanden sind. Denn ich möchte ja jetzt über diesen auch die Systemzeit und den "High-Performance-Counter" implementieren. Ich denke aber das ich damit leben kann ;)
So bin für Meinungen offen und bitte auch etwaige Fehler die in dem System stecken nennen!
-
Hallo,
.... und ich mich auch endlich mal mit der 3D-Programmierung befassen will
Womit Du dann aber doch wieder Off-Topic wirst. ;)
, ist mir wieder eingefallen wozu man nen "High-Performance-Counter" braucht.
Bei Spielen möchtest du ja das sich die Spieler-Figur auf jedem Rechner (egal wie schnell oder langsam) gleich schnell bewegt. Dazu benutzt man solch einen "High-Performace-Counter". Um sagen zu können, so seit dem letzten Zeichnen ist ne bestimme Zeit vergangen und die Spielerfigur bewegt sich damit jetzt ne bestimmte Anzahl von "Pixeln".
Das konnte DOOM bereits vor über 15 Jahren auch ohne den ganzen neumodischen Kram. Wäre natürlich mal sehr interessant zu schauen wie die das damals gemacht haben, der Source-Code ist ja wimre offen zugänglich.
Ich werd dafür ne Kombination aus dem ACPI-PMT und dem PIT bzw. wenn möglich den TSC nehmen.
.....
Ich habe ehrlich gesagt kaum etwas von dem verstanden was Du da schreibst. Vielleicht solltest Du mal die verschiedenen HW-Kombinationsmöglichkeiten (die Dein OS unterstützen soll) aufzählen und für jede einzeln und präzise erklären was Du genau vor hast.
Außerdem empfehle ich Dir ernsthaft Dich erst mal auf eine (eventuell auch zwei ähnliche) HW-Kombination fest zu legen und nur für diese zu programmieren, wenn das fertig ist kannst Du immer noch überlegen ob Du auch für andere HW-Kominationen noch Lust hast bzw. ob Dein Konzept da überhaupt läuft. Alles auf einmal angehen zu wollen könnte unter Umständen nicht so gut enden. Ich will Dir nicht absprechen das Du das alles erfolgreich hinbekommst, das ist nur ein gut gemeinter Rat von jemandem der auch schon mal daneben gegriffen hat.
Grüße
Erik
-
Um es kurz zu machen, implementiert war es 1 Tag nach dem Post ;)
Ich habe ehrlich gesagt kaum etwas von dem verstanden was Du da schreibst. Vielleicht solltest Du mal die verschiedenen HW-Kombinationsmöglichkeiten (die Dein OS unterstützen soll) aufzählen und für jede einzeln und präzise erklären was Du genau vor hast.
Du wolltest es so ;)
Also ältere PCs haben kein ACPI (auf denen sollte dann der TSC 100%ig laufen), aber nen PIT und die RTC. Ich nutze also den PIT für meinen One-Shot-Scheduler. Die RTC wird im periodischen Modus (62,5ms) programmiert und inkrementiert immer nen Counter, aber was viel wichtiger ist, bei jedem Aufruf des Interrupthandlers (von der RTC) speichere ich den aktuellen TSC Wert.
So kann ich ganz einfach sagen, wieviel "Ticks" (welche man dann auch "einfach" in nsek umrechnen kann) seit dem letzten RTC Interrupt vergangen sind. Damit hab ich nen wirklich Hoch-Präzisen-Counter (je nachdem wie schnell die CPU ist).
Hat man dann nen PC mit ACPI, kann man den ACPI-PMT (Performance Monitor Timer, wimre) nutzen, anstatt des TSCs. Sprich das System bleibt das gleiche, ich nutze den PIT für den One-Shot-Scheduler und die RTC für nen periodischen Interrupt. Anstatt des TSC als Counter nutze ich aber jetzt den ACPI-PMT, womit ich Probleme durch runtertakten oder ähnliches umgehen will.
Hat der PC dann auch noch nen APIC, den ich nutzen kann, ändert sich das System ein wenig. Der APIC wird für den One-Shot-Scheduler genutzt. Diesmal nehme ich den PIT im periodischen Modus (55ms) anstatt der RTC. Ansonsten funkioniert es hier wieder genauso. Beim Interrupthandler des PITs wird der aktuelle Wert des ACPI-PMTs gespeichert.
Bei SMP-System findet das gleiche System wie oben Anwendung.
Wie funktioniert jetzt der Hoch-Präzise-Counter?
Wenn ich ganz genau bin, ist das nicht irgendein Counter, sondern der wird sogar in nsek geführt. Soll heißen, wenn man sich den Wert holt und 1000 bekommt und der letzte Wert den man sich geholt hat war 500, dann sind "Pi mal Daumen" 500ns vergangen.
Ich rechne auf meinen globalen Counter (wird über RTC oder PIT implementiert) immer genau die nsek drauf, wie zwischen 2 Interrupts liegen.
Will dann ein Programm den Wert des Counters haben, mache ich folgendes (vereinfacht):
uint64t counter= nsecscounter, perf= perfcounterRead(), last= timeLastInt;
if(flags & USING_TSC)
return counter + ((perf - last) * tscTickNSecs);
else
return counter + ((perf - last) * acpiPMTTickNSecs);
Natürlich behandle ich in meinem Code noch überläufe, was beim ACPI-PMT sehr wichtig ist (da er entweder bei 4 Sek (24bit) oder 1130 Sek (32bit) überläuft), aber das ist für das Bsp nicht wichtig.
Das zu implementieren ist/war nicht schwer, ist auch nicht wirklich viel Code. SMP-Safe ist das ganze auch noch, sprich ich brauche keine Locks dafür nutzen (den Fall das sich der Counter während des auslesens ändert oder halt der Wert von "TimeLastInt" beachte ich in meinem Code auch).
Wie gesagt sollte ich nun alle Probleme, Schwächen und sonstige Sachen ausgebügelt haben. Ich habe alles was ich wollte, nen One-Shot-Scheduler, nen Hoch-Präzisen-Counter und ich kann meine Threads für sehr kurze Zeiten (<1ms) und das ganze noch mit ne verdammt vernünftigen Präzision schlafen legen.
Wenn ich die Zeit und Lust (da ich es bisher nicht wirklich brauche) finde, werde ich auch noch den HPET nutzen.
Da bin ich mir dann aber noch nicht sicher wie ich es mache. Aufjeden Fall wird der HPET dann den PIT, in seiner Funktion, ersetzen, aber ob ich dann auf nen 3. Counter verzichte (also auf TSC oder ACPI-PMT) weiß ich noch nicht. Am liebsten würde ich dafür dann wieder den TSC nutzen, was auf neueren CPUs ja wieder ohne Probleme möglich ist. Das hätte halt den Vorteil, das ich nicht ständig den HPET auslesen müsste (zwecks Counter-Wert) und ich würde so eine noch höhere Auflösung (da der TSC, wenn er an die CPU Frequenz geknüpft ist, ja ne verdammt hohe Freq hat) bekommen. Mal ganz davon abgesehen, dass das Auslesen des TSCs wohl schneller sein dürfte als das Auslesen des HPETS.
Ich hoffe ich war präzise genug, wenn nicht, wie gehabt, einfach fragen!
Edit::
Mir ist noch ein wunderbarer Vergleich eingefallen. Im Endeffekt entspricht das System einer Uhr mit Stunden- (periodischer Interrupt -> RTC/PIT) und Minutenzeiger (Counter -> TSC/ACPI-PMT) ;)
-
Ich würde mich nie Nie NIE auf den TSC verlassen, schon garnicht systemweit.
Den TSC gibt es erst ab i586 (gut, das kann man vernachlässigen), aber er ist grundsätzlich nicht stabil. Kein ACPI ist ein Hinweis, aber kein Grund - mobile Systeme mit Stromsparfunktionen gab es auch schon vorher (POWER.EXE). Obwohl es später nicht mehr so oft gemacht wurde, besteht auch bei APM die Möglichkeit, die CPU vom BIOS runtertakten zu lassen - das heißt, der TSC läuft langsamer. Außerdem gibt es Möglichkeiten zu Suspend und Standby, die vollständig vom BIOS gesteuert werden.
Mein 486er Notebook hat eine Hardwaretaste für Standby. Drückst du die, ist das Betriebssystem "aus", die PCMCIA-Verwaltung wird ebenfalls vom BIOS erledigt. Das OS kriegt nichtmal mit, dass es gerade abgewürgt wird. (Du kannst aber auch Start>Standby machen, aber auch das führt zu "klack">Standby.) Bei Pentiumsystemen ist das teilweise auch so.
Benutze den TSC für das, für das er gebaut wurde - Hochgeschwindigkeitszeitmessungen auf kurzen Zeiträumen. Alles andere ist nicht grundsätzlich verlässlich; ein Timingsystem darauf aufzusetzen ist ungünstig.
Gruß,
Svenska
-
@Svenska
Also ich habe deine Bedenken zur Kenntnis genommen. Ich weiß das der Pentium irgend so ein "SL Enhanced Power Management" hat, aber was das genau bedeutet konnte ich leider noch nicht finden.
Um mir meine Sache jetzt nicht unnötig schwer zu machen, nutze ich erstmal den TSC weiter. Im Moment ist das einzigste Problem was ich mir vorstellen kann, ein kurzzeitiges "stocken/stolpern" des Hoch-Präzisen-Counters. Der Vorteil ist ja, das er periodisch "synchronisiert" wird und damit etwaige Fehler des kleinen "zwischen"-Counters (TSC/ACPI-PMT) ausbügelt.
Wenn wir gerade schon beim TSC sind. Weiß jemand wie man bei Intel nachgucken kann (z.B. mittels CPUID) ob der TSC immer konstant aktualisiert wird? Ich weiß das es bei AMD dafür extra nen Flag bei CPUID gibt, habe aber bei Intel dazu noch nichts gefunden. Ansonsten müsste ich halt Family und Co auslesen und danach dann entscheiden ob ich ihn nutzen kann oder nicht.
@Offtopic
Weiß jemand ob man zu alten Sockel7 Zeiten das ACPI im BIOS aktivieren musste? Irgendwie findet mein Loader bestimmte ACPI Sachen nicht, obwohl diese vorhanden sein müssten (handelt ich um ein Board mit nem VIA MVP3 Chipsatz).
-
Vielleicht findest du in den Dokumenten zum i386SL/i486SL Informationen zum Power Management. Ich kann mich jedenfalls nicht daran erinnern, dass das beim Pentium groß beworben wurde; ich vermute, es wurde einfach von den Vorgängern übernommen.
Wenn die CPU hinreichend viele NOPs ausführt, [oder keine Bildschirm-/Tastatureingabe erfolgt,] kann das BIOS den CPU-Takt automatisch auf einen dort vorher eingetragenen Wert (z.B. CLK/16) senken, außerdem gibt es eine APM-Idle-Funktion. Dazu kommen dann noch Sachen wie Bildschirmabschaltung etc. Wichtig ist, dass das BIOS anhand von Systemeigenschaften entscheidet, ob der Takt nun runtergesetzt wird oder nicht und das Betriebssystem davon nichts(!) mitkriegen muss.
Ich hatte mal ein Pentium-Notebook, auch da wurde der TSC als instabil markiert. Bei den Desktop-Pentiums dürfte der TSC eigentlich immer stabil sein, aber solche Geräte lagere ich aus Platzgründen bei mir nicht mehr. Genau sowas macht aber Entscheidung schwieriger, da du zwischen aktivem/inaktivem Power-Management unterscheiden müsstest - was man im BIOS umstellen kann - ob der TSC nun immer stabil ist oder nicht.
Bedenke die Konsequenzen, was passiert schlimmstenfalls, wenn dein hochpräziser Counter groben Unfug enthält? Und denke auch daran, dass du bei _jeder_ Nutzung darauf Rücksicht nehmen musst. Wenn du nämlich dein Gesamttiming auf diesen Counter irgendwie aufbaust, wird das dir später böse in den Rücken fallen - möchtest du das Teil nur für kurzzeitige, exakte Messungen nutzen, reicht der TSC auch direkt aus und du sammelst dir keine Probleme ein.
Naja, und dann stelle ich mir halt noch die Frage, warum du auf so einem (langsamen) System einen Couter mit nsek-Auflösung überhaupt brauchst; bei allem, was irgendwie größer als klein ist (Browser, Officepaket, Mediaplayer) kannst du eh nicht mit der geforderten Latenz darauf reagieren. Und wenn du ein richtiges Real-Time-Betriebssystem schreiben möchtest, dann ist das ohnehin nur ein sehr kleiner Teil des Gesamtpaketes.
Gruß,
Svenska
-
Naja, und dann stelle ich mir halt noch die Frage, warum du auf so einem (langsamen) System einen Couter mit nsek-Auflösung überhaupt brauchst; bei allem, was irgendwie größer als klein ist (Browser, Officepaket, Mediaplayer) kannst du eh nicht mit der geforderten Latenz darauf reagieren. Und wenn du ein richtiges Real-Time-Betriebssystem schreiben möchtest, dann ist das ohnehin nur ein sehr kleiner Teil des Gesamtpaketes.
Naja, ich wollte halt ne Auflösung die <1ms ist ohne das ich nen periodischen Timer dafür nutze. Auf die nseks bin ich gekommen, weil es eine gute Auflösung auch für aktuelle Systeme ist und ich mir so die Arbeit am HAL (Hardware-Abstraction-Layer) vereinfachen wollte.
Bedenke die Konsequenzen, was passiert schlimmstenfalls, wenn dein hochpräziser Counter groben Unfug enthält? Und denke auch daran, dass du bei _jeder_ Nutzung darauf Rücksicht nehmen musst. Wenn du nämlich dein Gesamttiming auf diesen Counter irgendwie aufbaust, wird das dir später böse in den Rücken fallen - möchtest du das Teil nur für kurzzeitige, exakte Messungen nutzen, reicht der TSC auch direkt aus und du sammelst dir keine Probleme ein.
Im Moment schätze ich die Probleme als nicht so schwerwiegend ein (noch ;) ). Denn es kann "nur" zu Problemen innerhalb des Intervalls von 62,5ms (RTC) bzw. 54ms (PIT) kommen. Denn mit jedem Interrupt einer der beiden Timer, stimmt der Wert des Counters wieder ab dem Zeitpunkt. Wenn ich später wirklich feststellen sollte, dass das Intervall zu groß ist, könnte ich es immernoch verkleinern. Aber wie du selbst schon gesagt hast, braucht man "eigentlich" die hohe Auflösung auf solch alten Systemen nicht, also dürfte das etwaige "stoplern/stocken" auch kein Problem darstellen.
Vielleicht findest du in den Dokumenten zum i386SL/i486SL Informationen zum Power Management. Ich kann mich jedenfalls nicht daran erinnern, dass das beim Pentium groß beworben wurde; ich vermute, es wurde einfach von den Vorgängern übernommen.
Genau die Dokumente (vom 486) hab ich mir angeguckt und konnte leider nichts konkretes finden bzw. das was ich gefunden habe, legt nahe, das der TSC komplett stehen bleiben kann. Der Punkt ist aber, dass das ja nur passieren kann wenn die CPU nichts zu tun hat und dann wiederum benutzt auch keiner den Counter und somit gibt es für mich kein Problem.
Denn so wie ich dich und das Dokument verstanden habe, gibt es nur Probleme mit dem TSC, wenn die CPU absolut gar nichts zu tun hat und dann wird, wie gesagt, auch mein Counter in dem Moment nicht gebraucht. Ab dem Zeitpunkt wo er dann vielleicht wieder gebraucht wird und die CPU wieder was zu tun hat, funktioniert das System ja auch wieder. Denn die periodischen Interrupts kommen immer, egal in welchem Zustand sich die CPU befindet.
Mich würde noch interessieren was du genau unter Gesamttiming verstehst, also was da deiner Meinung nach alles dran hängt?
Im Moment nutze ich das nur als Hoch-Präzisen-Counter und eventuell bald um festzustellen, wie lange ein Thread gelaufen ist. Ansonsten um den Zeitpunkt festzustellen, wann ein Thread sich schlafen legen möchte (um den Aufweckzeitpunkt zu errechnen).
-
Naja, und dann stelle ich mir halt noch die Frage, warum du auf so einem (langsamen) System einen Couter mit nsek-Auflösung überhaupt brauchst; bei allem, was irgendwie größer als klein ist (Browser, Officepaket, Mediaplayer) kannst du eh nicht mit der geforderten Latenz darauf reagieren. Und wenn du ein richtiges Real-Time-Betriebssystem schreiben möchtest, dann ist das ohnehin nur ein sehr kleiner Teil des Gesamtpaketes.
Naja, ich wollte halt ne Auflösung die <1ms ist ohne das ich nen periodischen Timer dafür nutze. Auf die nseks bin ich gekommen, weil es eine gute Auflösung auch für aktuelle Systeme ist und ich mir so die Arbeit am HAL (Hardware-Abstraction-Layer) vereinfachen wollte.
Pass auf, dass du nicht von der gedachten, aber nicht erreichten Qualität deiner Messung abhängig wirst. Konkret heißt das, dass du nicht unbedingt davon ausgehen kannst, dass dein Timer dann einen monotonen, gleichmäßigen Verlauf hat.
Mal abgesehen scheinst du mit der Grundidee eine Auflösung garantieren zu wollen, die du aber nicht einhalten kannst. Sowas ist bei nem Realtime-System tödlich; für dich wahrscheinlich eh egal.
Bedenke die Konsequenzen, was passiert schlimmstenfalls, wenn dein hochpräziser Counter groben Unfug enthält? Und denke auch daran, dass du bei _jeder_ Nutzung darauf Rücksicht nehmen musst. Wenn du nämlich dein Gesamttiming auf diesen Counter irgendwie aufbaust, wird das dir später böse in den Rücken fallen - möchtest du das Teil nur für kurzzeitige, exakte Messungen nutzen, reicht der TSC auch direkt aus und du sammelst dir keine Probleme ein.
Im Moment schätze ich die Probleme als nicht so schwerwiegend ein (noch ;) ). Denn es kann "nur" zu Problemen innerhalb des Intervalls von 62,5ms (RTC) bzw. 54ms (PIT) kommen. Denn mit jedem Interrupt einer der beiden Timer, stimmt der Wert des Counters wieder ab dem Zeitpunkt. Wenn ich später wirklich feststellen sollte, dass das Intervall zu groß ist, könnte ich es immernoch verkleinern. Aber wie du selbst schon gesagt hast, braucht man "eigentlich" die hohe Auflösung auf solch alten Systemen nicht, also dürfte das etwaige "stoplern/stocken" auch kein Problem darstellen.
Für Zeitmessungen nicht. Wenn du davon dann allerdings deinen Scheduler abhängig machst und der TSC unter Umständen nicht nur stehen bleibt, sondern sogar kaputtgeht, kannst du große Probleme mit dem Scheduling kriegen, wenn du damit nicht rechnest.
Vielleicht findest du in den Dokumenten zum i386SL/i486SL Informationen zum Power Management. Ich kann mich jedenfalls nicht daran erinnern, dass das beim Pentium groß beworben wurde; ich vermute, es wurde einfach von den Vorgängern übernommen.
Genau die Dokumente (vom 486) hab ich mir angeguckt und konnte leider nichts konkretes finden bzw. das was ich gefunden habe, legt nahe, das der TSC komplett stehen bleiben kann. Der Punkt ist aber, dass das ja nur passieren kann wenn die CPU nichts zu tun hat und dann wiederum benutzt auch keiner den Counter und somit gibt es für mich kein Problem.
So einfach ist es, denke ich, nicht. Das BIOS kann ja an sich garnicht feststellen, ob die CPU nun fleißig arbeitet oder nicht - solange es nicht explizit aufgerufen wird. Auf einem Notebook, was ich hier habe (Highscreen 486SX25, ist aber ein SL-Typ) wird die Aktivität an Bildschirm- und Tastaturaktivität gemessen, und zwar ausschließlich! Neben HLT gibt es ja keine CPU-internen Inaktivitätsbefehle.
Das bedeutet, dass ein Prozess unter DOS, wenn er keine Bildschirmausgaben macht und nur rechnet, die CPU in den 2 MHz-Modus schaltet, wenn das Power Management im BIOS aktiviert ist; gleiches gilt im Übrigen unter Windows 95. Auf einem Pentium habe ich dieses Verhalten auch schon einmal beobachtet, bin mir aber nicht mehr sicher.
Denn so wie ich dich und das Dokument verstanden habe, gibt es nur Probleme mit dem TSC, wenn die CPU absolut gar nichts zu tun hat und dann wird, wie gesagt, auch mein Counter in dem Moment nicht gebraucht. Ab dem Zeitpunkt wo er dann vielleicht wieder gebraucht wird und die CPU wieder was zu tun hat, funktioniert das System ja auch wieder. Denn die periodischen Interrupts kommen immer, egal in welchem Zustand sich die CPU befindet.
APM definiert m.W. nur die Systemaktivität, nicht die CPU-Aktivität. Siehe oben.
Mich würde noch interessieren was du genau unter Gesamttiming verstehst, also was da deiner Meinung nach alles dran hängt?
Das hängt von der Nutzung ab.
Ich würde dem TSC - je nach Prozessortyp - im Allgemeinen keine langfristige Monotonie oder Stabilität zutrauen.
Im Moment nutze ich das nur als Hoch-Präzisen-Counter und eventuell bald um festzustellen, wie lange ein Thread gelaufen ist. Ansonsten um den Zeitpunkt festzustellen, wann ein Thread sich schlafen legen möchte (um den Aufweckzeitpunkt zu errechnen).
Wäre es da nicht sinnvoller, den Thread selbst den Aufweckzeitpunkt bestimmen zu lassen? ;-)
Gruß,
Svenska
-
Mal abgesehen scheinst du mit der Grundidee eine Auflösung garantieren zu wollen, die du aber nicht einhalten kannst. Sowas ist bei nem Realtime-System tödlich; für dich wahrscheinlich eh egal.
Ich sag mal alles unter 1ms ist doch schon gut, wie genau es dann unter 1ms wird, ist doch erstmal zweitrangig.
Um es genauer zu sagen ist es mir wichtig, wenn ein Thread in 55ms aufgeweckt werden will, das er auch in annährend 55ms aufgeweckt wird (nur mal so als Bsp.) und nicht erst in 60ms.
Für Zeitmessungen nicht. Wenn du davon dann allerdings deinen Scheduler abhängig machst und der TSC unter Umständen nicht nur stehen bleibt, sondern sogar kaputtgeht, kannst du große Probleme mit dem Scheduling kriegen, wenn du damit nicht rechnest.
Genau das hält mich im Moment noch davon ab, diesen Counter auch im Scheduler zu nutzen. Denn das "witzige" daran ist, der eigentliche Grund ihn zu nutzen ist der PIT. Es wäre halt viel schneller den Counter zu lesen als den PIT und ich rede hier von 2496ns, hört sich erstmal nicht nach viel an, aber wenn man das pro Scheduleraufruf sparen kann, so summiert sich das nach einer Weile ganz schön auf. Um jetzt nochmal auf das "witzige" zu kommen, wenn ich den PIT nicht mehr nutze (also dann den APIC), dann habe ich (mit Ausnahme von ein paar alten SMP-System) eigentlich auch den ACPI-PMT zur Verfügung und brauche den TSC nicht nutzen.
So einfach ist es, denke ich, nicht. Das BIOS kann ja an sich garnicht feststellen, ob die CPU nun fleißig arbeitet oder nicht - solange es nicht explizit aufgerufen wird. Auf einem Notebook, was ich hier habe (Highscreen 486SX25, ist aber ein SL-Typ) wird die Aktivität an Bildschirm- und Tastaturaktivität gemessen, und zwar ausschließlich! Neben HLT gibt es ja keine CPU-internen Inaktivitätsbefehle.
Das bedeutet, dass ein Prozess unter DOS, wenn er keine Bildschirmausgaben macht und nur rechnet, die CPU in den 2 MHz-Modus schaltet, wenn das Power Management im BIOS aktiviert ist; gleiches gilt im Übrigen unter Windows 95. Auf einem Pentium habe ich dieses Verhalten auch schon einmal beobachtet, bin mir aber nicht mehr sicher.
Wenn das so ist, dann nehme ich darauf erst recht keine Rücksicht! Denn das System funktioniert ja ohnehin nicht wirklich.
Ich würde dem TSC - je nach Prozessortyp - im Allgemeinen keine langfristige Monotonie oder Stabilität zutrauen.
Hier habe ich das Gefühl das du mich, genau wir erik auch, nicht ganz verstanden hast.
Der TSC wird nicht für langfristige Monotonie genutzt. Im Endeffekt musst du dir mein System so vorstellen als wenn du nur eine periodische Quelle (RTC/PIT) hast, die mit nem, verhältnismäßg, langem Intervall (>=55ms) läuft. Diese Quelle ist langfristig gesehen genau! Um jetzt aber auch die Zeit innerhalb dieses Intervalls genau zu kennen, nutze ich eine andere Quelle (TSC/ACPI-PMT).
Als mal als Bsp. die periodische Quelle macht bei jedem Aufruf des Handlers:
highPrecisionCounter+= nsecsPeriodicSourceIntervall;
timeLastInt= _rdtsc();
Wenn du jetzt den aktuellen Wert des Counters haben willst machst du das:
returnVal= highPrecisionCounter + (_rdtsc() - timeLastInt);
Damit erreiche ich das mit jedem Aufruf des Interrupthandlers der Wert des Counters wieder genau ist, egal was dazwischen mit dem TSC passiert ist!
Ich hoffe du hast es jetzt verstanden. Im Endeffekt nutze ich den TSC um "kurze" (<=62,5ms) Zeiten zu messen.
Wäre es da nicht sinnvoller, den Thread selbst den Aufweckzeitpunkt bestimmen zu lassen?
Auch hier hast du mich nicht ganz verstanden.
Ich meinte damit, dass der Thread die Sleep-Funktion aufruft (wo er als Parameter, die Zeit die er schlafen will angibt), ich den aktuellen Wert des Counters (siehe Oben) hole und darauf die Zeit die er schlafen will drauf rechne und damit weiß zu welchem Zeitpunkt ich ihn wieder aufwecken muss.
-
Hallo,
Das Du mit einem periodischem IRQ den TSC eichst, um ihn als zusätzliche Genauigkeit zu nutzen (das meinte ich mit den Nachkommabits), ist prinzipel eine gute Idee aber dafür ist weder der PIT/RTC noch der TSC geeignet. Um genau zu wissen wie viele TSC-Ticks pro IRQ kommen solltest Du das mehrmals messen und zum anderen darfst Du niemals die IRQs abschalten oder andere langwierige (FPU-)Befehle ausführen die in diese Messungen nen Jitter reinbringen könnten ansonsten kannst Du Dir die ns-Aulösung auch gleich ganz sparen. Dass das BIOS (eventuell ohne Dein Wissen) an der Taktfrequenz rumdreht ist denke ich prinzipiel auf jedem Computer möglich der neu genug ist um einen TSC zu haben (das kannst Du zumindest nicht ausschließen und warscheinlich auch nicht erkennen), und damit wird es quasie unmöglich aus dem aktuellen TSC-Stand auch nur abzulesen ob der letzte IRQ erst kurz vorbei ist oder ob gleich der nächste IRQ kommt. Das nächste ist das bei SMP ja mehrere TSCs da sind die garantiert nicht synchron laufen. Da der IRQ ja nur von einer CPU verarbeitet wird (für Dein Vorhaben hoffentlich immer von der selben) kannst Du auch nur diesen TSC als zusätzlichen Genauigkeitslieferanten benutzen und das geht nur wenn der User-Mode-Thread, der gerade sleep() aufruft, auch zufällig auf dieser CPU läuft den an fremde TSCs kommt man ganz sicher nicht ran. Ein weiterer Punkt ist das Du zum umrechnen der TSC-Ticks in Nanosekunden (oder irgendeiner anderen fixen Zeitauflösung) definitiv Gleitkomma-Arithmetik benötigst und selbst dann noch Tricks brauchst um den Jitter beim periodischen TSC auslesen auszugleichen (die einzelnen Taktfrequenzen werden nicht vom selben Quarz erzeugt Du musst also mit minimalen Geschwindigkeitsunterschieden rechnen die möglicherweise erst nach längerer Laufzeit sichtbar werden).
Damit erreiche ich das mit jedem Aufruf des Interrupthandlers der Wert des Counters wieder genau ist, egal was dazwischen mit dem TSC passiert ist!
Nein, damit kennst Du zwar wieder den aktuellen Wert des schnellen Counters aber seine Zählgeschwindigkeit kennst Du nur wenn Du über mehrere exakt getimmte (also jitterfreie und das dürfte bei normaler SW-Nutzung quasi unmöglich sein) Auslesungen den Counterwert beobachtest und genau diese Zählgeschwindigkeit brauchst Du ja damit Du auch einen Nutzen aus dem schnellen Counter ziehen kannst.
Noch eins: selbst wenn Du alle obigen Probleme lösen solltest bleibt das der TSC keine IRQs generieren kann. Wenn ein sleep(20) auch wirklich exakt 20ms dauern soll bleibt also nur aktives Warten.
Ob an den obigen Problemen der ACPI-PMT noch was bessert kann ich nicht sagen, den kenne ich nicht da ich mich nur sehr oberflächlich mit ACPI beschäftigt habe. Kann der ACPI-PMT Interrupts generieren? Zumindest gibt es diesen nur ein mal aber er ist wohl auch wieder über langsame I/O-Ports angebunden und da die Arbeitsfrequenz nur etwa das doppelte der vom PIT ist solltest Du Dir genau überlegen ob der Aufwand sich überhaupt lohnt.
Am Anfang dieses Threads hab ich doch ein schönes Konzept beschrieben das einfach und zuverlässig funktioniert und mit PIT zwar auskommt aber auch vom HPET profitiert.
Ich will nicht unhöflich sein aber ich habe das Gefühl das Du Dich da in ein unerreichbares Ziel verrannt hast.
Grüße
Erik
-
Nochmal was zur Genauigkeit. Was mir vorallem wichtig ist, das wenn ein Thread 20ms schlafen möchte und du nur ne periodische Quelle für nen Timer hast (z.B. den PIT) mit einem Intervall von 15ms, dann schläft der Thread mindestens 30ms (eventuell sogar mehr). Genau hier wollte ich ansetzen, ob der Thread dann im Endeffekt 20,05ms oder 20,25ms geschlafen hat, ist mir erstmal egal (und sollte mehr oder weniger zu vernachlässigen sein).
Ich nehme ne nsek Auflösung weil es sich damit am einfachsten Rechnet und ich mir nicht alzu große Sorgen über schnelle CPUs (>4GHz) machen muss, ob ich die dann auch erreiche kann und will ich gar nicht garantieren (aber 10µs-Auflösung sollte eigentlich drin sein).
Um genau zu wissen wie viele TSC-Ticks pro IRQ kommen solltest Du das mehrmals messen und zum anderen darfst Du niemals die IRQs abschalten oder andere langwierige (FPU-)Befehle ausführen die in diese Messungen nen Jitter reinbringen könnten ansonsten kannst Du Dir die ns-Aulösung auch gleich ganz sparen.
Ich weiß das meine Messung mit welcher Frequenz der TSC läuft nicht perfekt ist (ich bekomme auf einem AMD K6-200 ca. 197896???Hz), aber ich denke das ich mit der Genauigkeit leben kann. Eigentlich ist alles was genauer als 1ms ist doch schon verdammt gut, gerade auf solch alten System.
Ein weiterer Punkt ist das Du zum umrechnen der TSC-Ticks in Nanosekunden (oder irgendeiner anderen fixen Zeitauflösung) definitiv Gleitkomma-Arithmetik benötigst und selbst dann noch Tricks brauchst um den Jitter beim periodischen TSC auslesen auszugleichen (die einzelnen Taktfrequenzen werden nicht vom selben Quarz erzeugt Du musst also mit minimalen Geschwindigkeitsunterschieden rechnen die möglicherweise erst nach längerer Laufzeit sichtbar werden).
Also was das umrechnen betrifft, da nutze ich im Moment 64bit und halt nsek-Auflösung (oder sogar PSec, da bin ich mir gerade nicht sicher) und das sollte auch ohne Gleitkommazahlen reichen.
Meinst du mit den verschiedenen Taktfrequenzen PIT und TSC? Was den Unterschied betrifft, ich nutze für die langfristige Zeimessung im Endeffekt nur den PIT, daher ist es mir egal wie sehr der TSC und der PIT auseinandertriften! Zumal ich ja immer nur eine Differenz nutze, von daher summiert sich doch ein vorhandener Fehler nicht auf.
Nein, damit kennst Du zwar wieder den aktuellen Wert des schnellen Counters aber seine Zählgeschwindigkeit kennst Du nur wenn Du über mehrere exakt getimmte (also jitterfreie und das dürfte bei normaler SW-Nutzung quasi unmöglich sein) Auslesungen den Counterwert beobachtest und genau diese Zählgeschwindigkeit brauchst Du ja damit Du auch einen Nutzen aus dem schnellen Counter ziehen kannst.
Also in meinem Bootloader berechne/messe ich die Frequenz des TSC mit Hilfe des PITs (in einer Zeit von 110ms wimre). Da passiert außer einer Schleife wo "hlt" (was eventuell stören könnte) ausgeführt wird und dem PIT-Interrupt (wo nur ein Counter inkrementiert wird) nichts.
Noch eins: selbst wenn Du alle obigen Probleme lösen solltest bleibt das der TSC keine IRQs generieren kann. Wenn ein sleep(20) auch wirklich exakt 20ms dauern soll bleibt also nur aktives Warten.
Hier kommt doch wieder mein toller One-Shot-Scheduler ins Spiel ;) Mit Hilfe des Counters und diesem Scheduler kann ich, mehr oder weniger, genau die Threads wieder aufwachen.
Ob an den obigen Problemen der ACPI-PMT noch was bessert kann ich nicht sagen, den kenne ich nicht da ich mich nur sehr oberflächlich mit ACPI beschäftigt habe. Kann der ACPI-PMT Interrupts generieren? Zumindest gibt es diesen nur ein mal aber er ist wohl auch wieder über langsame I/O-Ports angebunden und da die Arbeitsfrequenz nur etwa das doppelte der vom PIT ist solltest Du Dir genau überlegen ob der Aufwand sich überhaupt lohnt.
Ich verstehe nicht ganz was du mit Aufwand meinst? Ich meine entweder ich machen nen "_rdtsc()" oder ich mache nen "ind(ACPI_PMT_PORT)".
Unterschiedlich sind nur, dass das Auslesen des PMT länger dauert, aber dafür kann ich ihn einfach und ohne Probleme auf SMP-Systemen verwenden. Ansonsten sind sie mehr oder weniger gleich. Beide machen nicht mehr als einen Counter zur Verfügung zu stellen, nur muss ich den PMT nicht ausmessen, sondern weiß wie lange ein Tick dauert.
Am Anfang dieses Threads hab ich doch ein schönes Konzept beschrieben das einfach und zuverlässig funktioniert und mit PIT zwar auskommt aber auch vom HPET profitiert.
Ich will nicht unhöflich sein aber ich habe das Gefühl das Du Dich da in ein unerreichbares Ziel verrannt hast.
Ich seh das nicht als unhöflich an, ist nur ne Motivation dich mit noch besseren Argumenten von meinem System zu überzeugen ;)
Aber mal ehrlich, ich finde so doll unterscheiden sich die beiden Systeme nicht, dein Intervall ist kürzer (1ms : 55ms/62,5ms). Wenn man es nur so betrachtet ist es, mehr oder weniger, gleich. Ich nutze halt noch ne 2. Quelle um auch Events innerhalb des Intervalls auslösen zu können.
Um nochmal auf die SMP-Systeme zurück zu kommen. Ich weiß jetzt nicht ab wann man davon ausgehen kann das solche Systeme ACPI haben, aber selbst wenn nicht, dann denke ich mal das dort auf keinen Fall die CPU irgendwie runtergetaktet wird. Da ich den TSC beim initialisieren meines Kernels auf allen CPUs synchronisiere sollte es da eigentlich keine Probleme geben (die dürften auf solch alten Systemen auch noch nicht auseinandertriften). Ich möchte meinen das mit dem auseinandertriften ist erstmals so richtig auf AMD K7 SMP-Systemen aufgefallen.
Edit::
Ich habe gerade mal meine Berechnung wie lange ein TSC-Tick dauert ein wenig verändert und siehe da ist schon genauer. Auf einem AMD K6-200 bekomme ich 200440990Hz und auf einem Celeron 400 bekomme ich 401767778Hz. Die Werte habe ich jetzt jedesmal (ich habe jeweils 3mal getestet) bekommen. Wenn ich an einer Konstante noch ein wenig Pfeile, dann komm ich vielleicht sogar noch genauer hin. Jedenfalls sollte die Genauigkeit meiner TSC-Messung in Ordnung gehen und sie funktioniert bis zu einer Taktfrequenz von 1000GHz!
-
Okay, ich wiederhole nochmal, was ich vorher gesagt habe...
Dieses System mit APM, dass die CPU runtergetaktet wird, wenn keine Bildschirm- oder Tastaturaktivität passiert, ist doch insofern sinnvoll, als dass bei Nutzeraktivität - also interaktiver Nutzung des Systems - die Leistung da ist, sonst aber sofort wieder Strom gespart wird.
Das geschieht bei APM im Auftrag des BIOS, unabhängig vom Betriebssystem - und zerstört dir u.U. den TSC bei frühen Pentiums.
Zweite Sache, betrifft neuere Systeme mit ACPI: Wie ich neulich auf irgendeiner Kernel-ML gelesen habe, haben moderne BIOSse ebenfalls im Zusammenhang mit Stromsparmodi die Möglichkeit, jederzeit die CPU anzuhalten und/oder in spezielle Modi (SMBUS, ...) zu schalten. Und zwar für Dauern jenseits einiger Millisekunden! Unabhängig vom Betriebssystem! Damit meine ich nicht runtertakten, sondern Selbstverwaltung. Runtertakten kriegst du ja wenigstens noch mit, bzw. kannst du im Zweifelsfall drauf achten.
Wenn das BIOS nun aber deine CPU unbenachrichtigt und ungewollt für 2ms abschalten kann, weil es selbst was tun will, dann ist deine Zeitgenauigkeit doch ohnehin fürn Popo. Das betrifft dann auch Systeme mit HPET.
Aber tu, was du nicht lassen kannst.
-
Dieses System mit APM, dass die CPU runtergetaktet wird, wenn keine Bildschirm- oder Tastaturaktivität passiert, ist doch insofern sinnvoll, als dass bei Nutzeraktivität - also interaktiver Nutzung des Systems - die Leistung da ist, sonst aber sofort wieder Strom gespart wird.
Wird so eine Logik tatsächlich implementiert? Das ist doch völlig kaputt. Wenn es grad keine Bildschirm- oder Tastaturaktvität gibt, dann warte ich vielleicht grad bis er den Kernel fertig durchgebaut hat (oder sonst irgendwas fertiggerechnet hat). Wenn er als Reaktion darauf den Kernel dann noch langsamer baut - ich weiß ja nicht...
-
Wenn das BIOS nun aber deine CPU unbenachrichtigt und ungewollt für 2ms abschalten kann, weil es selbst was tun will, dann ist deine Zeitgenauigkeit doch ohnehin fürn Popo. Das betrifft dann auch Systeme mit HPET.
Ich will ja nicht so aus der Haut fahren wie du, aber wenn sowieso alles "fürn Popo" ist, wozu dann der ganze Ärger ;)
Also CPU und HPET/PIT/ACPI-PMT (und auf neueren CPUs auch der TSC) laufen auch wenn die CPU irgendwie runtergetaktet oder abgeschaltet ist (bzw. wird das komplette Abschalten der CPU sowieso nicht gehen, weil es länger als 2ms dauern dürfte diesen Zustand zu erreichen und auch wieder aus ihm heraus zu kommen)!
Was APM betrifft, so kann dies im BIOS deaktiviert werden bzw. kannst du einstellen ob das BIOS eingreifen soll oder halt nicht.
Dieses System mit APM, dass die CPU runtergetaktet wird, wenn keine Bildschirm- oder Tastaturaktivität passiert, ist doch insofern sinnvoll, als dass bei Nutzeraktivität - also interaktiver Nutzung des Systems - die Leistung da ist, sonst aber sofort wieder Strom gespart wird.
Wie auch taljeth schon meinte, ist das "kaputt". Denn warum kann z.B. gerade keine Benutzeraktivität stattfinden? Vielleicht, weil der Nutzer darauf wartet das der PC fertig wird? Wenn dann auch noch die CPU runtergetaktet wird, dann dauert es ja noch länger und würde im Endeffekt heißen, du verbrauchst mehr Strom als wenn du die CPU nicht runtergetaktet hättest! Da ist also wirklich was kaputt ;)
Zumal viel interessanter wäre doch zu wissen, von was für Zeiten wir hier sprechen? Ich meine wird das gemacht, wenn der Nutzer mal 1s nichts macht oder erst nach 3Minuten? Das spielt dann nämlich schon eine Rolle.
Zweite Sache, betrifft neuere Systeme mit ACPI: Wie ich neulich auf irgendeiner Kernel-ML gelesen habe, haben moderne BIOSse ebenfalls im Zusammenhang mit Stromsparmodi die Möglichkeit, jederzeit die CPU anzuhalten und/oder in spezielle Modi (SMBUS, ...) zu schalten. Und zwar für Dauern jenseits einiger Millisekunden! Unabhängig vom Betriebssystem! Damit meine ich nicht runtertakten, sondern Selbstverwaltung. Runtertakten kriegst du ja wenigstens noch mit, bzw. kannst du im Zweifelsfall drauf achten.
Auch hier gilt wieder, wenn das wirklich so passiert, fällt das dem Nutzer auf oder es passiert zu Zeiten, wo es eh keinen interessiert. Wenn es dem Nutzer aber auffällt und das System ständig "stockt", dann wird er das Gerät zurückgeben und die werden das ganz schnell wieder ändern! Denn mehrere ms sind für einen PC, besonders für einen modernen, ne halbe Ewigkeit!
Wenn du mal die Quelle nennen könntest, dann könnte ich mal nachsehen, was da wo und wann passiert.
-
Was APM betrifft, so kann dies im BIOS deaktiviert werden bzw. kannst du einstellen ob das BIOS eingreifen soll oder halt nicht.
Womit du dann jegliche Form des Stromsparens abschalten kannst, richtig. Das geht im Übrigen auch per APM-Treiber (POWER.EXE kann das), dort kannst du das Gesamt-APM-System auch abschalten; zumindest auf diesem System.
Dieses System mit APM, dass die CPU runtergetaktet wird, wenn keine Bildschirm- oder Tastaturaktivität passiert, ist doch insofern sinnvoll, als dass bei Nutzeraktivität - also interaktiver Nutzung des Systems - die Leistung da ist, sonst aber sofort wieder Strom gespart wird.
Wie auch taljeth schon meinte, ist das "kaputt". Denn warum kann z.B. gerade keine Benutzeraktivität stattfinden? Vielleicht, weil der Nutzer darauf wartet das der PC fertig wird? Wenn dann auch noch die CPU runtergetaktet wird, dann dauert es ja noch länger und würde im Endeffekt heißen, du verbrauchst mehr Strom als wenn du die CPU nicht runtergetaktet hättest! Da ist also wirklich was kaputt ;)
Grundgedanke: Wenn ich etwas interaktiv tue, dann sehe ich Reaktionen auf dem Bildschirm, sei es der Mauszeiger, seien es die Logmeldungen beim Kernelbau. So falsch ist der Gedanke nicht. Ich rede im speziellen von Geräten Anfang der 90er Jahre! Und da führte eine Aktion auch meist zu einer schnellen Reaktion oder einer Fortschrittsanzeige... oder man bewegt halt mal kurz die Maus unter Windows oder drückt kurz Shift.
Zumal viel interessanter wäre doch zu wissen, von was für Zeiten wir hier sprechen? Ich meine wird das gemacht, wenn der Nutzer mal 1s nichts macht oder erst nach 3Minuten? Das spielt dann nämlich schon eine Rolle.
Im BIOS (nicht im Betriebssystem) einstellbar zwischen 1/4s und 1min, in zwei Stufen, die Taktreduktion einstellbar zwischen 1/1 CLK bis 1/16 CLK, bei 25MHz Grundtakt. (Also z.B. nach 1/4 Sekunde den Takt auf 12 MHz =1/2CLK reduzieren, nach 15 Sekunden dann auf 3 MHz =1/8CLK.)
Zweite Sache, betrifft neuere Systeme mit ACPI: Wie ich neulich auf irgendeiner Kernel-ML gelesen habe, haben moderne BIOSse ebenfalls im Zusammenhang mit Stromsparmodi die Möglichkeit, jederzeit die CPU anzuhalten und/oder in spezielle Modi (SMBUS, ...) zu schalten. Und zwar für Dauern jenseits einiger Millisekunden! Unabhängig vom Betriebssystem! Damit meine ich nicht runtertakten, sondern Selbstverwaltung. Runtertakten kriegst du ja wenigstens noch mit, bzw. kannst du im Zweifelsfall drauf achten.
Auch hier gilt wieder, wenn das wirklich so passiert, fällt das dem Nutzer auf oder es passiert zu Zeiten, wo es eh keinen interessiert. Wenn es dem Nutzer aber auffällt und das System ständig "stockt", dann wird er das Gerät zurückgeben und die werden das ganz schnell wieder ändern! Denn mehrere ms sind für einen PC, besonders für einen modernen, ne halbe Ewigkeit!
Ja, für den PC... dem Menschen wird diese halbe ms bestimmt nicht auffallen. Außerdem passiert das in der Regel ja auch nicht ständig alle 10 Takte, dass das System für 10000 Takte steht, sondern unter gewissen Randbedingungen (Standby, Akkuladestand-Grenzwert erreicht, Bildschirmhelligkeitstaster betätigt, ...)
Das macht die Sache natürlich noch interessanter, da es sich um seltene Ereignisse handelt.
Wenn du mal die Quelle nennen könntest, dann könnte ich mal nachsehen, was da wo und wann passiert.
Hab ich nicht mehr, ging mir um die Suche nach einem gebrauchbaren Grafiktreiber für mein Netbook (VIA VX800 / Chrome9 IGP) bzw. einem Scheduler für die sehr langsame 2GB-SSD dadrin. an der Stelle auch wurde das auch nicht näher ausgeführt, nur angerissen. Hab es allerdings nach längerer Suche nicht wiedergefunden. War auf der LKML.
Gruß,
Svenska
-
Auch hier gilt wieder, wenn das wirklich so passiert, fällt das dem Nutzer auf oder es passiert zu Zeiten, wo es eh keinen interessiert. Wenn es dem Nutzer aber auffällt und das System ständig "stockt", dann wird er das Gerät zurückgeben und die werden das ganz schnell wieder ändern!
Auf einem Desktop wird das Bisschen niemanden jucken. Aber RT-Systeme stört es teilweise schon, dass im SMM Zeit verbraten wird.
-
Auf einem Desktop wird das Bisschen niemanden jucken. Aber RT-Systeme stört es teilweise schon, dass im SMM Zeit verbraten wird.
Kommt halt wieder drauf an, wann es passiert. Wenn ich gerade einen HD-Film gucke und ACPI meint es müsste jetzt aus irgendeinem Grund mal die CPU schlafen legen oder runtertakten, dann dürfte der Film schon stocken. Das Beispiel ist jetzt insofern doof, weil ja die CPU arbeitet und auf dem Bildschirm tut sich ja auch was. Also dürfte ACPI da nicht auf solch eine Idee kommen.
Was mir da gerade noch auffällt, was hat der SMM jetzt mit meinem Timer zu tun? Die CPU läuft trotzdem weiter, genauso wie PIT/HPET und die anderen Sachen.
Womit du dann jegliche Form des Stromsparens abschalten kannst, richtig. Das geht im Übrigen auch per APM-Treiber (POWER.EXE kann das), dort kannst du das Gesamt-APM-System auch abschalten; zumindest auf diesem System.
Dann spricht diese "POWER.EXE" bestimmt APM übers BIOS an und das könnte ich zur Not auch machen.
Ich rede im speziellen von Geräten Anfang der 90er Jahre!
Problem ist jetzt, das es sich also um Prä-Pentium Systeme handelt und ich/man nicht weiß ob das dann auch auf die späteren Systeme übertragen wurde. Dann kommt noch hinzu das du vor dem Pentium sowas wie einen TSC nicht hattest und wie gesagt, die anderen Timer interessiert das nicht ob die CPU runtergetaktet ist.
Ja, für den PC... dem Menschen wird diese halbe ms bestimmt nicht auffallen. Außerdem passiert das in der Regel ja auch nicht ständig alle 10 Takte, dass das System für 10000 Takte steht, sondern unter gewissen Randbedingungen (Standby, Akkuladestand-Grenzwert erreicht, Bildschirmhelligkeitstaster betätigt, ...)
Und genau in diesen Randbedingungen kann ich dann mal auf die Genauigkeit verzichten ;) Weil brauchen tust du sie nur, wenn der Nutzer wirklich was macht, z.B. spielen, Film gucken oder ähnliches und dann dürften diese Sachen auch nicht auftreten.
-
Im Normalfall wird ein HD-Film im Voraus dekodiert, die Videodarstellung erfolgt meist über DMA in die entsprechenden Pages im Videospeicher in Form eines Overlays, welches von jeder halbwegs modernen 2D-Grafikkarte unterstützt wird. Außerdem gilt: 1/(2ms) = 500 Hz. Das fällt bei einem Video nicht auf.
Die Taktrate in modernen Systemen hängt von der aktuellen Auslastung der CPU ab und ändert sich während des Video-guckens trotzdem, da der Dekodieraufwand auch vom Inhalt des Videos abhängt.
Wenn die CPU sich im SMM befindet, läuft sie zwar weiter, aber du hast weder Informationen über den aktuellen Zustand der CPU, noch führt sie deinen Code aus. Und wenn zwischendrin der TSC auch noch kaputt geht (was ich in dem Szenario allerdings bezweifle), dann verwirrt das deinen Scheduler, wenn du ihn auf den TSC festpinnst.
POWER.EXE ist der APM-Treiber für MS-DOS. Er kann "POWER ON", "POWER OFF", "POWER AUTO" (=BIOS-Einstellungen, z.B. nur aktiv bei Akkubetrieb). Mehr kann er nicht.
Diese Art des Power Managements kann ich direkt bei einem 486er hier beobachten, der hat keinen TSC. Frühe Pentium-Systeme haben einen TSC - und das Power Management dürfte sich zwischen 486SL und Pentium-SL nicht wesentlich unterscheiden. Was nicht heißt, dass es überall genau so implementiert wurde, aber ich hatte ein Pentium-Notebook (P75), der ein ähnliches Verhalten zeigte. Zumindest war das Power Management recht seltsam. Ist ein - inzwischen defektes - TI Extensa gewesen.
Deinen letzten Nachsatz würde ich mir nochmal durch den Kopf gehen lassen... ein Scheduler, der dann (und nur dann) Amok läuft, wenn jemand die Bildschirmhelligkeit verändert und gleichzeitig das System nutzt... nun, das passiert in Vorlesungen bei uns öfter mal, dass man MATLAB nutzt und jemandem was zeigen will, oder ein Video guckt, oder oder oder...
Übrigens schweifen wir vom Thema inzwischen weitreichend ab. Ich wollte nur sagen, dass der TSC meiner Meinung nach - anhand von Beispielen, die ich real gesehen und wovon ich gelesen habe - nicht grundlegend für deinen Anwendungsfall geeignet ist und ich daher von dessen Verwendung in dem Zusammenhang abrate.
Gruß,
Svenska
-
Deinen letzten Nachsatz würde ich mir nochmal durch den Kopf gehen lassen... ein Scheduler, der dann (und nur dann) Amok läuft, wenn jemand die Bildschirmhelligkeit verändert und gleichzeitig das System nutzt...
Naja, der Scheduler läuft ja in dem Sinne nicht Amok (und noch nutze ich meinen Counter nicht für meinen Scheduler und werde es höchst wahrscheinlich auch nicht machen), das einzige was passiert ist, das er die Zeit welcher ein Thread gelaufen ist (dann zu wenig) falsch berechnet oder das er einen Thread zu früh aufweckt (was ich schon als schlimmer bezeichnen würde).
Dann kommt noch hinzu das es nur Prä-ACPI Systeme betrifft und ansich gab es ACPI schon zu Sockel7 Zeiten!
Im Normalfall wird ein HD-Film im Voraus dekodiert, die Videodarstellung erfolgt meist über DMA in die entsprechenden Pages im Videospeicher in Form eines Overlays, welches von jeder halbwegs modernen 2D-Grafikkarte unterstützt wird. Außerdem gilt: 1/(2ms) = 500 Hz. Das fällt bei einem Video nicht auf.
Ich muss nochmal auf die 2ms zurück kommen. Ich habe mir deinen Satz, wo du diese erwähnst, nochmal durchgelesen. Was meintest du da, dass das BIOS die CPU runtertaktet oder das es selbst etwas tun möchte (z.B. SMM)? Ersteres würde den TSC stören, letzteres nicht.
Und wenn diese 2ms nicht auffallen, dann fällt es auch nicht auf das mein Timingsystem kurz aus dem Tritt gebracht wurde. Denn selbst wenn ich jetzt davon ausgehe, das der TSC komplett (!!) stehen bleibt, dann "verechnet" sich mein Timingsystem bis zum nächsten periodischen Int (max 62,5ms - 2ms) um eben diese 2ms. Ich denke damit kann man leben, immernoch genauer als nur eine periodische Quelle mit einem Intervall von 15ms!
Der Vorteil bei meinem System ist doch, das es ziemlich fehlertolerant ist und genau solche Sachen wenig bis gar nicht stören, bzw. schnell wieder korrigiert sind.
Diese Art des Power Managements kann ich direkt bei einem 486er hier beobachten, der hat keinen TSC. Frühe Pentium-Systeme haben einen TSC - und das Power Management dürfte sich zwischen 486SL und Pentium-SL nicht wesentlich unterscheiden. Was nicht heißt, dass es überall genau so implementiert wurde, aber ich hatte ein Pentium-Notebook (P75), der ein ähnliches Verhalten zeigte. Zumindest war das Power Management recht seltsam. Ist ein - inzwischen defektes - TI Extensa gewesen.
Ich werde mir wohl mal ein oder ein paar alte Notebooks beim eBay ersteigern müssen. Wollte ich eh mal machen, damit ich was zum Testen habe und so habe ich gleich noch einen Grund mehr.
Übrigens schweifen wir vom Thema inzwischen weitreichend ab. Ich wollte nur sagen, dass der TSC meiner Meinung nach - anhand von Beispielen, die ich real gesehen und wovon ich gelesen habe - nicht grundlegend für deinen Anwendungsfall geeignet ist und ich daher von dessen Verwendung in dem Zusammenhang abrate.
Mein Problem ist nur, das es nichts anderes/besseres gibt und das ich mit den Unzulänglichkeiten leben kann, aus den Oben genannten Gründen. Auch gilt dies nur für, wie gesagt, Prä-ACPI Systeme. Alles was ACPI kann hat den PMT oder ist so neu, das ich mich (und Linux auch wieder, rein aus performance Gründen) wieder auf den TSC verlassen kann!
Um nochmal auf das Powermanagement zurück zu kommen, die hatten damals noch keine Internetwerbung im Sinn ;) Denn wenn der Bildschirm nicht ausgeht und/oder sich die CPU nicht runtertaktet, weil die Werbung sich ständig ändert (CPU + Bildschirmarbeit) wird gar kein Strom gespart ;)
-
Richtig. Nur noch eine Anmerkung als Nachsatz: Die gesamte SMM-Problematik trifft auf neuere Rechner mit ACPI zu. Der TSC ist auf den meisten aktuellen Systemen nicht stabil (zumindest behauptet Linux das bei mir).
Die von mir angesprochene Problematik betrifft dann alte/sehr alte Systeme ohne ACPI und kann - das vermute ich stark - andere Probleme auf den TSC haben.
Grüßle
-
Hallo,
Nochmal was zur Genauigkeit. Was mir vorallem wichtig ist, das wenn ein Thread 20ms schlafen möchte und du nur ne periodische Quelle für nen Timer hast (z.B. den PIT) mit einem Intervall von 15ms, dann schläft der Thread mindestens 30ms (eventuell sogar mehr).
Jedes System hat eben seine Grenzen, die überwiegende Mehrheit der anderen Betriebssysteme macht das jedenfalls nicht viel besser (zumindest als es noch keinen HPET gab).
ob der Thread dann im Endeffekt 20,05ms oder 20,25ms geschlafen hat, ist mir erstmal egal (und sollte mehr oder weniger zu vernachlässigen sein).
Ich verstehe Dich ehrlich gesagt nicht, erst schreibst Du von Nanosekunden (bis Du damit wirklich was sinnvolles anfangen kannst wird noch eine ziemlich große Menge an Silizium (oder gar was anderes) durch die Fabs der CPU-Hersteller fließen) und nun sind Dir mal eben so ganze 200000 davon einfach egal. Ich glaube Du solltest noch mal gründlich über Deine konkrete Zielvorstellung nachdenken.
Ich nehme ne nsek Auflösung weil es sich damit am einfachsten Rechnet
Für Dich vielleicht, aber die CPU hat am wenigsten Arbeit wenn sie direkt mit den Timer-Ticks umgehen darf (da muss dann gar nichts gerechnet werden) und die libc in den User-Programmen die Wünsche per GetTicksPerSecond passend umrechnet.
und ich mir nicht alzu große Sorgen über schnelle CPUs (>4GHz) machen muss
Mit ordentlicher Programmierung musst Du Dir über die Taktfrequenz der CPU eh keine Sorgen machen.
Also in meinem Bootloader berechne/messe ich die Frequenz des TSC
Wer garantiert Dir dass das BIOS die CPU mit Maximal-Frequenz übergibt. Es könnte doch auch sein dass das BIOS die CPU nur mit kleiner Kraft ins Rennen schickt (während eines typischen OS-Starts wartet die CPU eh meist darauf das die einzelnen OS-Teile von der HDD geliefert werden) und das hochtakten dem OS überlässt (ich hab das mal bei einem Business-PC gesehen).
(in einer Zeit von 110ms wimre)
Das ist IMHO zu kurz, ich hab das damals mit gut 2 Sekunden gemacht. Mit 18 Messwerten wo ich vor der Durchschnittsbildung noch den größten und den kleinsten Messwert entfernt habe.
Noch eins: selbst wenn Du alle obigen Probleme lösen solltest bleibt das der TSC keine IRQs generieren kann. Wenn ein sleep(20) auch wirklich exakt 20ms dauern soll bleibt also nur aktives Warten.
Hier kommt doch wieder mein toller One-Shot-Scheduler ins Spiel ;) Mit Hilfe des Counters und diesem Scheduler kann ich, mehr oder weniger, genau die Threads wieder aufwachen.
Hä, bitte genauer erklären. Willst du neben einem periodischen PIT-Timer noch parallel einen One-Shot-PIT-Timer starten?
Ich verstehe nicht ganz was du mit Aufwand meinst?
Na das Du überhaupt mit mehreren unterschiedlich schnellen Timern arbeiten möchtest. Ich persönlich bin der Meinung das Du Dir da einen dicken Haufen komplizierte Arbeit schaffst und im Endeffekt nicht viel besser wirst als wenn Du Deine Zeit in einen anderen Aspekt Deines OS investieren würdest.
ist nur ne Motivation dich mit noch besseren Argumenten von meinem System zu überzeugen ;)
Du kannst mich nicht überzeugen, auf meiner Plattform wird es etwas ähnliches zum HPET geben, einen 64Bit-Counter der monoton läuft, sich nicht beeinflussen lässt und eine auslesbare Frequenz benutzt zusammen mit 4 Comparatoren. Auf sowas wie den PIT würde ich mich freiwillig nicht mehr einlassen. Die Zeitscheiben sollen auf meiner Plattform die CPUs selber verwalten, ähnlich dem Local-APIC-Timer.
Aber mal ehrlich, ich finde so doll unterscheiden sich die beiden Systeme nicht
Ich finde schon das sich unsere Ideen da massiv unterschieden ich setze auf einen monotonen Counter (der breit genug ist damit er nicht ständig überläuft) mit flexiblen Comparator (welcher bei einem beliebigen Counter-Wert einen IRQ auslösen kann) und wenn das nicht in HW zur Verfügung steht dann würde ich das per SW und einem periodischem IRQ simulieren (nur eben mit deutlich kleinerer Zählgeschwindigkeit als bei der HW-Lösung). Für die User-Programme macht das dann keinen Unterschied, solange die immer brav in Ticks umrechnen.
Ich nutze halt noch ne 2. Quelle um auch Events innerhalb des Intervalls auslösen zu können.
Das mit dem "auslösen" musst Du mir bitte noch erklären. Weder TSC noch ACPI-PMT können das.
dann denke ich mal das dort auf keinen Fall die CPU irgendwie runtergetaktet wird.
Ich denke das Du da irrst. Gerade die PC-Zusammenschrauber die eher große Serien auflegen (wie DELL, HP oder Medion (soll keine Werbung sein)) bauen da manchmal eigene Dinge ein die nicht zwingenst zu irgendwelchen Standards passen. Wenn die dann ein eigenes proprietäres Windows-Programm fürs Power-Management aufspielen dann ist aus deren Sicht (die kennen NUR Windows) die Welt in Ordnung.
Da ich den TSC beim initialisieren meines Kernels auf allen CPUs synchronisiere
Was? TSCs synchronisieren, wie soll das denn bitte gehen? Und selbst wenn das gehen sollte, was denkst Du wie genau so eine Synchronisation per SW wäre?
die dürften auf solch alten Systemen auch noch nicht auseinandertriften
Das ist eine unbewiesene Annahme. Du solltest erst einmal (bis Du diese Annahme sicher bewiesen hast) vom Gegenteil ausgehen. Nach meiner Beobachtung driften die ganz sicher auseinander, die Frage ist nur wie schnell.
Ich habe gerade mal meine Berechnung wie lange ein TSC-Tick dauert ein wenig verändert und siehe da ist schon genauer. Auf einem AMD K6-200 bekomme ich 200440990Hz und auf einem Celeron 400 bekomme ich 401767778Hz.
Bist Du schon mal auf die Idee gekommen das die dafür benutzten Quarze alles andere als genau sind? Die sind in aller erste Linie billig. Mit ein bis zwei Prozent Abweichung vom Soll musst Du auf jeden Fall rechen. Und wieso eigentlich "Berechnung"? Du solltest das messen.
Wenn ich an einer Konstante noch ein wenig Pfeile
Solche Aussagen erwecken, zumindest bei mir, nicht gerade Vertrauen. Du musst die TSC-Frequenz messen und nicht irgendwie ins gewünschte Ziel hinrechnen!
und sie funktioniert bis zu einer Taktfrequenz von 1000GHz!
Da bin ich aber mal gespannt! Wenn ich ne passende CPU hab prüfe ich das nach. ;)
Grüße
Erik
-
Ich verstehe Dich ehrlich gesagt nicht, erst schreibst Du von Nanosekunden (bis Du damit wirklich was sinnvolles anfangen kannst wird noch eine ziemlich große Menge an Silizium (oder gar was anderes) durch die Fabs der CPU-Hersteller fließen) und nun sind Dir mal eben so ganze 200000 davon einfach egal. Ich glaube Du solltest noch mal gründlich über Deine konkrete Zielvorstellung nachdenken.
Ich wollte am Anfang vorallem besser sein, als Windows mit einer Zeitscheibe von 15ms. Bevor, vorallem ihr, mich auf die Unzulänglichkeiten mit meinem System aufmerksam gemacht habt, wollte ich schon noch irgendwie ne nsek Auflösung erreichen, bzw. ich erreiche sie bestimmt auch auf vielen Systemen (wenn der ACPI-PMT genutzt wird), aber halt nicht auf allen und wenn auf den alten System, wo es nur nen PIT und ne RTC gibt, die Ungenauigkeit maximal (und das ist das wichtige, im optimalen Fall wird es wesentlich genauer) 0,25ms ist, dann finde ich habe ich mein Ziel eigentlich ganz gut erreicht.
Für Dich vielleicht, aber die CPU hat am wenigsten Arbeit wenn sie direkt mit den Timer-Ticks umgehen darf (da muss dann gar nichts gerechnet werden) und die libc in den User-Programmen die Wünsche per GetTicksPerSecond passend umrechnet.
Das ist dem geschuldet das ich mehrere Zeitquellen nutze und da ist es am einfachsten wenn ich in nsek umrechne.
Mit ordentlicher Programmierung musst Du Dir über die Taktfrequenz der CPU eh keine Sorgen machen.
Dann müsste ich aber 128bit Zahlen benutzen und es war schon nicht einfach Code für ne 64bit Division zu finden, bzw. fehlt mir immernoch Code (der halbwegs genau und schnell ist) für eine "64bit div 64bit = 64bit" Division. Oder was meintest du?
Wer garantiert Dir dass das BIOS die CPU mit Maximal-Frequenz übergibt. Es könnte doch auch sein dass das BIOS die CPU nur mit kleiner Kraft ins Rennen schickt (während eines typischen OS-Starts wartet die CPU eh meist darauf das die einzelnen OS-Teile von der HDD geliefert werden) und das hochtakten dem OS überlässt (ich hab das mal bei einem Business-PC gesehen).
Das hast du leider recht, ich gehe halt immer davon aus das die PCs so konstruiert sind das auch alternative Betriebssysteme drauf laufen und dazu zähle ich dann auch DOS und da ist es eher unwahrscheinlich das es die CPU runter/hochtaktet! Aber ich behalte das Problem mal im Hinterkopf, bzw. betrifft dies auch wieder nur neuere Systeme (auf alten sollte das wohl eher nicht passieren).
Das ist IMHO zu kurz, ich hab das damals mit gut 2 Sekunden gemacht. Mit 18 Messwerten wo ich vor der Durchschnittsbildung noch den größten und den kleinsten Messwert entfernt habe.
Ich müsste meinen Code mal noch auf nen paar mehr PCs testen, aber mit der Länge wird dann nur die Ungenauigkeit bei den absolut letzten Stellen besser.
Hä, bitte genauer erklären. Willst du neben einem periodischen PIT-Timer noch parallel einen One-Shot-PIT-Timer starten?
Nope! Ich hatte doch erklärt das wenn die Zeit bis zu einem Event (jetzt mal als Bsp) kleiner ist als das Intervall des periodischen Timers, das dann das Event an den Scheduler weitergereicht wird. Dieser löst das dann im Endeffekt aus (weckt als z.B. einen Thread auf). Der Scheduler wird halt entweder vom PIT oder vom APIC befeuert (je nach dem was auf dem PC zur Verfügung steht).
Na das Du überhaupt mit mehreren unterschiedlich schnellen Timern arbeiten möchtest. Ich persönlich bin der Meinung das Du Dir da einen dicken Haufen komplizierte Arbeit schaffst und im Endeffekt nicht viel besser wirst als wenn Du Deine Zeit in einen anderen Aspekt Deines OS investieren würdest.
Das hat was mit meiner Motivation zu tun ;) Ich kann mich für die anderen Bereiche meistens nicht so richtig motivieren ;) Ansonsten hast du natürlich recht, aber da es ein Hobby-OS ist, sollte ich so viel Zeit wie nötig reinstecken, so dass ich meine gesteckten Ziele erreichen kann, auch wenn ich dann bis an mein Lebensende daran arbeite!
Du kannst mich nicht überzeugen, auf meiner Plattform wird es etwas ähnliches zum HPET geben, einen 64Bit-Counter der monoton läuft, sich nicht beeinflussen lässt und eine auslesbare Frequenz benutzt zusammen mit 4 Comparatoren. Auf sowas wie den PIT würde ich mich freiwillig nicht mehr einlassen. Die Zeitscheiben sollen auf meiner Plattform die CPUs selber verwalten, ähnlich dem Local-APIC-Timer.
Ich kann da noch nicht aus eigener Erfahrung sprechen, aber die Linuxleute sind nicht so sehr von dem HPET begeistert, wimre wird die Genauigkeit durch die Langsamkeit wieder weggemacht (Thema Hoch-Präziser-Counter) und sie nutzen am liebsten wieder den TSC. Wie das dann alles unter Linux zusammenarbeitet weiß ich nicht.
Das mit dem "auslösen" musst Du mir bitte noch erklären. Weder TSC noch ACPI-PMT können das.
Da kommt dann mein One-Shot-Scheduler zum tragen. Der liest so zu sagen, den aktuellen Wert aus und guckt dann wie lange es ist bis zum nächsten Event, ist die Zeit kürzer als die Zeit die der nächste Thread laufen darf, wird die Zeit bis der IRQ feuert auf die Zeit des Events gesetzt (ich hoffe das war jetzt nicht zu verwirrend).
Ich denke das Du da irrst. Gerade die PC-Zusammenschrauber die eher große Serien auflegen (wie DELL, HP oder Medion (soll keine Werbung sein)) bauen da manchmal eigene Dinge ein die nicht zwingenst zu irgendwelchen Standards passen. Wenn die dann ein eigenes proprietäres Windows-Programm fürs Power-Management aufspielen dann ist aus deren Sicht (die kennen NUR Windows) die Welt in Ordnung.
Mit den Problemen hat jedes alternative OS zu kämpfen und wenn jemand bereit ist, mein OS zu testen hat er genug wissen um das zu wissen und ich kann leider nicht alle Probleme der Welt mit meinem OS lösen, aber ich kann versuchen die Probleme so klein wie möglich zu halten. Denn eigentlich müsste ich mir jetzt schon ne Platte über fehlerhafte ACPI Tabellen machen, aber wozu!?
Was? TSCs synchronisieren, wie soll das denn bitte gehen? Und selbst wenn das gehen sollte, was denkst Du wie genau so eine Synchronisation per SW wäre?
Ist eigentlich ziemlich einfach und AMD hat dafür sogar nen extra Treiber. Du musst nur alle CPUs an eine Barriere zusammenholen und wenn dann alle eingetroffen sind, lässt du sie los und alle schreiben "0" in den TSC, damit sollten dann alle "Pi mal Daumen" synchronisiert sein. (alles schon seit Jahren implementiert ;) )
Das ist eine unbewiesene Annahme. Du solltest erst einmal (bis Du diese Annahme sicher bewiesen hast) vom Gegenteil ausgehen. Nach meiner Beobachtung driften die ganz sicher auseinander, die Frage ist nur wie schnell.
Ähm, das auseinanderdriften kommt durch das Runtertakten, sprich wenn sich die CPUs unterschiedlich runtertakten. Das kann so nicht auf alten Systemen passieren. Ich wage sogar zu behaupten das sich die alten Systeme, die kein ACPI unterstützen, gar nicht runtertakten können/es einfach nicht machen. Also ich meine Multi-CPU Systeme, welche damals ausschließlich als Workstation/Server genutzt wurden und nicht für Ottonormalverbraucher.
Bist Du schon mal auf die Idee gekommen das die dafür benutzten Quarze alles andere als genau sind? Die sind in aller erste Linie billig. Mit ein bis zwei Prozent Abweichung vom Soll musst Du auf jeden Fall rechen. Und wieso eigentlich "Berechnung"? Du solltest das messen.
Das Problem bei mir ist doch das Umrechnen, denn eigentlich müsste man Gleitkommazahlen nehmen, aber da das viel zu viel Zeit kostet, nehm ich halt ne psek Auflösung und rechne dann den TSC-Wert in nsek um und genau bei dieser Umrechnung muss man halt sehen wie man rechnet, damit er wenn möglich viele Sachen, die sowieso Konstanten sind, schon als genaue Werte bekommt.
Ich habe z.B. zuerst die Frequenz des TSC berechnet um dann im Kernel die Zeit für einen Tick zu berechnen, da geht verdammt viel Genauigkeit verloren. Jetzt berechne ich gleich im Loader die Zeit für einen Tick und gebe auch die Konstanten in psek Genauigkeit an (da habe ich vorher auch rechnen lassen). Die Konstanten habe ich jetzt mit dem Windowstaschenrechner berechnet (der leider auch nur 64bit Genauigkeit hat).
Solche Aussagen erwecken, zumindest bei mir, nicht gerade Vertrauen. Du musst die TSC-Frequenz messen und nicht irgendwie ins gewünschte Ziel hinrechnen!
Das interessante an meiner Messung ist, das die Ungenauigkeit immer Konstant war, egal was für eine CPU ich hatte. Desto schneller die CPU ist, desto kleiner wird die Ungenauigkeit damit auch.
Um nochmal auf die nsek-Auflösung zu kommen. Die werde ich sowieso nicht immer erreichen können, dafür gibt es zuviel Störquellen (z.B. den SMM), aber ich will die ja auch nicht garantieren, was ich garantieren möchte ist eine Genauigkeit <1ms mit der Tendenz zur nsek-Genauigkeit!
Auch mit dem HPET hast du das Problem, das dieser immer eine gewisse Ungenauigkeit hat, durch irgendwelche Störquellen halt. Wenn du sogar noch so einen Counter mit dem HPET machen willst, kommt noch hinzu das durch das Auslesen eines "Geräts" auch wieder Zeit verbrätst. Deswegen wollen die Linuxleute ja auch wieder auf den TSC zurück. Der ist aus reiner Performancesicht am besten! Und daher auch am genauesten (wenn er denn nutzbar ist). Wie gesagt sollte der TSC bei den neueren CPUs (ab Core2Duo und vorallem ab Nehalem) wieder 100%ig benutzbar sein!
-
die Ungenauigkeit maximal (und das ist das wichtige, im optimalen Fall wird es wesentlich genauer) 0,25ms ist, dann finde ich habe ich mein Ziel eigentlich ganz gut erreicht.
Also rechnest du in nsek, obwohl du eine (einigermaßen realistische) Wunschvorstellung von 250k davon hast.
Mal andersrum gedacht: 1 nsek =<>= 1 GHz ... du möchtest also eine Timerauflösung von (real) 4 Takten einhalten können? Wie lange braucht ein IRQ nochmal, bis du dich im Handler befindest...?
...es war schon nicht einfach Code für ne 64bit Division zu finden, bzw. fehlt mir immernoch Code (der halbwegs genau und schnell ist) für eine "64bit div 64bit = 64bit" Division.
Wieviele Takte braucht eine Division von 64-Bit-Zahlen? Wie lange auf einer 32-Bit-Plattform, die diese Division nicht in Hardware durchführen kann?
Wer garantiert Dir dass das BIOS die CPU mit Maximal-Frequenz übergibt. Es könnte doch auch sein dass das BIOS die CPU nur mit kleiner Kraft ins Rennen schickt (während eines typischen OS-Starts wartet die CPU eh meist darauf das die einzelnen OS-Teile von der HDD geliefert werden) und das hochtakten dem OS überlässt (ich hab das mal bei einem Business-PC gesehen).
Das hast du leider recht, ich gehe halt immer davon aus das die PCs so konstruiert sind das auch alternative Betriebssysteme drauf laufen und dazu zähle ich dann auch DOS und da ist es eher unwahrscheinlich das es die CPU runter/hochtaktet! Aber ich behalte das Problem mal im Hinterkopf, bzw. betrifft dies auch wieder nur neuere Systeme (auf alten sollte das wohl eher nicht passieren).
PCs sind NIE so konstruiert, dass alternative Betriebssysteme drauf laufen. NIE! Die sind billigst konstruiert, und zwar gerade so, dass Windows (in der aktuellen Version) darauf läuft. Und nichts weiter.
Nochmal als Rückgriff auf die alten PCs... das 486er Notebook taktet, bei hinreichender BIOS-Einstellung, bereits den Bootloader so stark herunter, dass der MS-DOS-Bootloader etwa 10sek (bei knapp unter 2 MHz) braucht. DOS wird auch runtergetaktet... und sehen kann ich das an einer netten LED, die mir den aktuellen Zustand anzeigt. Im Falle von Überhitzungen (herunterfahren, 3sek warten, einschalten, immernoch heiß!) hast du auch wieder hardwareseitig heruntergetaktete CPUs (Intel Core*), die sich später wieder hochtakten können, wenn sie kühler sind. Von BIOS-seitigen Stromsparmodi mal abgesehen.
Das hat was mit meiner Motivation zu tun ;) Ich kann mich für die anderen Bereiche meistens nicht so richtig motivieren ;) Ansonsten hast du natürlich recht, aber da es ein Hobby-OS ist, sollte ich so viel Zeit wie nötig reinstecken, so dass ich meine gesteckten Ziele erreichen kann, auch wenn ich dann bis an mein Lebensende daran arbeite!
Aha. Also willst du lieber 20 Jahre an einer niemals perfekt funktionieren könnenden hoch komplizierten Implementation für Timer arbeiten, als eine Treiberunterstützung für deine Testgeräte zu bauen... gut zu wissen.
Mit den Problemen hat jedes alternative OS zu kämpfen und wenn jemand bereit ist, mein OS zu testen hat er genug wissen um das zu wissen und ich kann leider nicht alle Probleme der Welt mit meinem OS lösen, aber ich kann versuchen die Probleme so klein wie möglich zu halten. Denn eigentlich müsste ich mir jetzt schon ne Platte über fehlerhafte ACPI Tabellen machen, aber wozu!?
Was du dir da vorstellst, schafft nichtmal Linux. Und eine seltsame, zweckfremde Hardwarenutzung soll, glaubst du, Probleme auf seltsamen Geräten vermeiden? Guck dir OS/2 an und den Grund, dass es sich auf den wenigsten Emulatoren vernünftig emulieren ließ (und lässt), dann weißt du, wie man Probleme mit der Hardware vermeidet - man macht es so, wie die anderen auch.
Was? TSCs synchronisieren, wie soll das denn bitte gehen? Und selbst wenn das gehen sollte, was denkst Du wie genau so eine Synchronisation per SW wäre?
Ist eigentlich ziemlich einfach und AMD hat dafür sogar nen extra Treiber. Du musst nur alle CPUs an eine Barriere zusammenholen und wenn dann alle eingetroffen sind, lässt du sie los und alle schreiben "0" in den TSC, damit sollten dann alle "Pi mal Daumen" synchronisiert sein. (alles schon seit Jahren implementiert ;) )
Aja - also mein Rechner schaltet beim Standby erstmal die CPUs nacheinander ab, und CPU0 fährt das System dann endgültig in den Standby. Das asynchronisiert das Verhalten. Außerdem kannst (und solltest) du die CPUs auch getrennt runtertakten können, je nach Last, auch das asynchronisiert dir deine TSCs wieder.
Was nicht vollsynchron geschaltet ist, kann nicht als vollsynchron angenommen werden, ganz einfach. Oder: Worst-Case-Denken.
Ähm, das auseinanderdriften kommt durch das Runtertakten, sprich wenn sich die CPUs unterschiedlich runtertakten. Das kann so nicht auf alten Systemen passieren. Ich wage sogar zu behaupten das sich die alten Systeme, die kein ACPI unterstützen, gar nicht runtertakten können/es einfach nicht machen. Also ich meine Multi-CPU Systeme, welche damals ausschließlich als Workstation/Server genutzt wurden und nicht für Ottonormalverbraucher.
Drift passiert unabhängig von externen Ereignissen, das unterscheidet sie nämlich von Reaktionen. Das kann schon durch Temperaturschwankungen auftreten. Oder leicht Asynchronizität der Taktleitungen des Mainboards. Und auch CPUs vor ACPI können runtertakten. Ob sie es tun, mag ich nicht einschätzen.
Aber du nimmst gerne idealisiertes Verhalten an, über alles gesehen und ausnahmslos. So dass du dir ein Konstrukt aufbauen kannst, welches nur unter diesen Annahmen funktioniert.
Meine Empfehlung: Sorge dafür, dass es wirklich so ist, und dann geh in die Politik und repariere die Welt. Da ist auch einiges im Argen.
Das Problem bei mir ist doch das Umrechnen, denn eigentlich müsste man Gleitkommazahlen nehmen, aber da das viel zu viel Zeit kostet, nehm ich halt ne psek Auflösung und rechne dann den TSC-Wert in nsek um und genau bei dieser Umrechnung muss man halt sehen wie man rechnet, damit er wenn möglich viele Sachen, die sowieso Konstanten sind, schon als genaue Werte bekommt.
Aha, psek-Auflösung. Wunderbar.
Realitätscheck: Bei 1 THz Taktfrequenz (= 1 psek) kann der Strom sich wie weit bewegen? (Strom- bzw. Informationsübertragung geht mit Lichtgeschwindigkeit) Die Information muss diese Strecke mindestens zweimal zurücklegen, um eine Antwort produzieren zu können. Nicht einbegriffen sind die Transistorschaltungen dazwischen. Gut, du kennst die maximale Ausdehnung der CPU. Wieviele Transistoren müssen da drin sein? Bei der Taktfrequenz verbrauchen sie wieviel Energie? (Energieverbrauch tritt - abgesehen von Leckströmen - nur während des Schaltvorgangs auf, bei "1" hast du keine Spannung, bei "0" keinen Strom = P=U*I~0; darum heißt höherer Takt auch mehr Energieverbrauch je Transistor.) Gut. Wie kriegst du jetzt die Wärme aus der CPU raus?
Bei der heutigen Technologie ist das, was du dir vorstellst und als Vorteil anpreist, einfach nur unmöglich.
Um nochmal auf die nsek-Auflösung zu kommen. Die werde ich sowieso nicht immer erreichen können, dafür gibt es zuviel Störquellen (z.B. den SMM), aber ich will die ja auch nicht garantieren, was ich garantieren möchte ist eine Genauigkeit <1ms mit der Tendenz zur nsek-Genauigkeit!
Unmöglich. Zumindest auf x86. Guck dir ne fremde Architektur an, z.B. einen ATMega oder PIC, die sind klein genug, dass du ein realtime-OS da drauf kriegst.
Wie gesagt sollte der TSC bei den neueren CPUs (ab Core2Duo und vorallem ab Nehalem) wieder 100%ig benutzbar sein!
Geschätzt baust du jetzt also eine Timerstruktur, die du auf SMP-Systeme mit PPro zuschneidest (weil kein HPET/ACPI), andererseits nimmst du an, dass der TSC ab Core2 zuverlässig sein sollte. Da fehlen dann irgendwie alle CPUs (AMD K6, VIA C7, Intel PII-PIV), die zeitlich dazwischen existierten.
Aber ich glaube, noch einen Realitätscheck brauche ich nicht machen, du glaubst mir ja eh nicht.
Gruß,
Svenska
-
Geschätzt baust du jetzt also eine Timerstruktur, die du auf SMP-Systeme mit PPro zuschneidest (weil kein HPET/ACPI), andererseits nimmst du an, dass der TSC ab Core2 zuverlässig sein sollte. Da fehlen dann irgendwie alle CPUs (AMD K6, VIA C7, Intel PII-PIV), die zeitlich dazwischen existierten.
Aber ich glaube, noch einen Realitätscheck brauche ich nicht machen, du glaubst mir ja eh nicht.
Ich fang mal damit an. Ich glaube dir, aber du scheinst meine Beiträge nicht richtig zu lesen!
AMD K6 kann, muss aber kein ACPI haben (also nutze ich den TSC nicht), VIA C7 hat auf jeden Fall ACPI, genau wie PII-PIV. Auf all den CPUs brauche ich den TSC nicht und nutze ihn auch gar nicht, da er halt wie du schon richtig festgestellt hast nicht wirklich funktionieren!
Also rechnest du in nsek, obwohl du eine (einigermaßen realistische) Wunschvorstellung von 250k davon hast.
Mal andersrum gedacht: 1 nsek =<>= 1 GHz ... du möchtest also eine Timerauflösung von (real) 4 Takten einhalten können? Wie lange braucht ein IRQ nochmal, bis du dich im Handler befindest...?
Wieso nagelt ihr mich immer alle auf 1nsek fest? was ist denn mit 1-1000nsek? Alles unter 1µs ist für mich nsek-Auflösung, genauso wie alles zw. 1000ns und 2000ns, also z.B. 1,554µs!
Aha. Also willst du lieber 20 Jahre an einer niemals perfekt funktionieren könnenden hoch komplizierten Implementation für Timer arbeiten, als eine Treiberunterstützung für deine Testgeräte zu bauen... gut zu wissen.
Die Smilies hast du aber gesehen, oder?
Aja - also mein Rechner schaltet beim Standby erstmal die CPUs nacheinander ab, und CPU0 fährt das System dann endgültig in den Standby. Das asynchronisiert das Verhalten. Außerdem kannst (und solltest) du die CPUs auch getrennt runtertakten können, je nach Last, auch das asynchronisiert dir deine TSCs wieder.
Also ich schicke meinen Rechner (und da gehe ich immer von Desktop aus) nie in den Standby-Modus. Beim Laptop nutze zumindest auch ich das nicht, aber egal. Der Standby-Modus wird vom OS durchgeführt (und das bekommt es auch mit und ich könnte dann den TSC neu synchonisieren) und jedes OS macht das so wie es, es für richtig hält.
Meine Empfehlung: Sorge dafür, dass es wirklich so ist, und dann geh in die Politik und repariere die Welt. Da ist auch einiges im Argen.
Wie schon beim letzten Mal, wieso schreibst du denn, wenn dir das hier alles "zu viel" wird?!
Aha, psek-Auflösung. Wunderbar.
Realitätscheck: Bei 1 THz Taktfrequenz (= 1 psek) kann der Strom sich wie weit bewegen? (Strom- bzw. Informationsübertragung geht mit Lichtgeschwindigkeit) Die Information muss diese Strecke mindestens zweimal zurücklegen, um eine Antwort produzieren zu können. Nicht einbegriffen sind die Transistorschaltungen dazwischen. Gut, du kennst die maximale Ausdehnung der CPU. Wieviele Transistoren müssen da drin sein? Bei der Taktfrequenz verbrauchen sie wieviel Energie? (Energieverbrauch tritt - abgesehen von Leckströmen - nur während des Schaltvorgangs auf, bei "1" hast du keine Spannung, bei "0" keinen Strom = P=U*I~0; darum heißt höherer Takt auch mehr Energieverbrauch je Transistor.) Gut. Wie kriegst du jetzt die Wärme aus der CPU raus?
Bei der heutigen Technologie ist das, was du dir vorstellst und als Vorteil anpreist, einfach nur unmöglich.
Wieder das selbe, was ist denn mit 1-1000psek?
Jetzt mal ein wenig Mathe. Wie willst du alles über 1GHz in nsek darstellen ohne Gleitkommazahlen zu nutzen? Dann wird dir vielleicht klar wieso ich psek nehme!
Unmöglich. Zumindest auf x86. Guck dir ne fremde Architektur an, z.B. einen ATMega oder PIC, die sind klein genug, dass du ein realtime-OS da drauf kriegst.
Das selbe wurde mal über das Fliegen, die Raumfahrt, ... gesagt ;)
-
x86 ist nur eingeschränkt echtzeitfähig, das liegt einerseits am Instruction Reordering, andererseits an der Systemumgebung, in die es eingebettet ist. Wenn du Latenzen im msek-Bereich einigermaßen einhalten möchtest, dann ja (soft realtime), mehr geht nicht.
Was das Festnageln betrifft... deine API stellt dir nsek zur Verfügung, sagt aber gleich an, dass "kleine" Werte unzuverlässig sind. Dann brauchst du sie ja nicht und könntest genausogut in Einheiten zu je 10 µsek rechnen. Das wäre zwar nicht so genau (und die Zahlen nicht so groß!), aber du könntest dann mit einigermaßen gegebener Sicherheit dort auch Einsen verwalten.
Mehr sag ich dazu mal jetzt nicht und ziehe mich, wie gewünscht, von hier zurück.
Und mach mich ab nächste Woche für nen Monat in den Urlaub.
Gruß,
Svenska
-
Mehr sag ich dazu mal jetzt nicht und ziehe mich, wie gewünscht, von hier zurück.
So war das nicht gemeint, sondern das du dich halt aufgeregt hast. Ich finde halt, gerade ne technische Diskussion kann auch ohne sowas laufen.
Und mach mich ab nächste Woche für nen Monat in den Urlaub.
Na dann viel Spaß!
Was das Festnageln betrifft... deine API stellt dir nsek zur Verfügung, sagt aber gleich an, dass "kleine" Werte unzuverlässig sind. Dann brauchst du sie ja nicht und könntest genausogut in Einheiten zu je 10 µsek rechnen. Das wäre zwar nicht so genau (und die Zahlen nicht so groß!), aber du könntest dann mit einigermaßen gegebener Sicherheit dort auch Einsen verwalten.
Meine API macht das bisher noch nicht so richtig, bisauf das ich den Counter in nsek zurückgebe. Ansonsten nehme ich solch große Zahlen um nicht einen rießen Fehler immer mitzuschleppen und mir Gleitkommazahlen zu ersparen.
x86 ist nur eingeschränkt echtzeitfähig, das liegt einerseits am Instruction Reordering, andererseits an der Systemumgebung, in die es eingebettet ist. Wenn du Latenzen im msek-Bereich einigermaßen einhalten möchtest, dann ja (soft realtime), mehr geht nicht.
Ich bin mir gerade nicht sicher, was genau das mit der Echtzeitfähigkeit war, aber ansich wollte ich das nicht erreichen.
-
Ich hab mich nicht aufgeregt, sorry wenn's so rüberkam. Ich halte nur das Ansinnen irgendwie für schwer umsetzbar. Und das Endergebnis für nicht erreichbar.
2^32 µs entsprechen etwa 70 Minuten, in einem Scheduler ist . Wenn du also als Zeitbasis 0.1µs nimmst, brauchst du nichtmal große Zahlen und kannst mit 32 Bit etwa 7 Minuten darstellen... besonders auf einer 32-Bit-Architektur haust du dir mit unnützen 64-Bit-Berechnungen im Scheduler nämlich dein schönes Timing weg. (Gut, Latenz ist jetzt nicht gleich Dauer, aber trotzdem.)
Interessant finde ich halt nur die Argumentation mit dem Fehler, das macht man ja schon in der Schule oft genug falsch... dass man Messergebnisse, die man "Pi * Daumen" abgeschätzt hat, dann nach der Rechnung mit sechs Nachkommastellen niederschreibt. Das meinte ich auch mit Realitätscheck. Wie genau sind deine Messungen - wie genau können sie technisch überhaupt sein - wie verlässlich sind sie überhaupt. Und da sehe ich (vermutlich nicht nur ich) schwarz.
Wenn du dein Timing möglichst genau machen willst, dann läuft das im Übrigen schon auf Echtzeitfähigkeit hinaus. Ein Multimedia-Betriebssystem muss per Definition echtzeitfähig sein, das heißt aber nicht sofortige (oder schnellstmögliche) Reaktion, sondern hinreichend schnelle Antwort.
Du zielst im Prinzip (unbewusst) auf eine hochgenaue Echtzeitfähigkeit ab.
Wann immer du Annahmen über etwas machst, dann überdenke auch immer, wann deine Annahmen nicht gelten. Da hab ich ein paar Sachen geschrieben, die für mich einige deiner Voraussetzungen verletzen und daher - vielleicht nicht grundsätzlich, aber durchaus in einigen Fällen - deine Ziele so verhindern.
Gruß,
Svenska
-
2^32 µs entsprechen etwa 70 Minuten, in einem Scheduler ist . Wenn du also als Zeitbasis 0.1µs nimmst, brauchst du nichtmal große Zahlen und kannst mit 32 Bit etwa 7 Minuten darstellen... besonders auf einer 32-Bit-Architektur haust du dir mit unnützen 64-Bit-Berechnungen im Scheduler nämlich dein schönes Timing weg. (Gut, Latenz ist jetzt nicht gleich Dauer, aber trotzdem.)
Ich glaube hier reden wir immernoch aneinander vorbei ;) Ich "brauche" beim TSC die psek, weil ich ab 1GHz Taktfrequenz, die Zeit für einen Tick des TSC nicht mehr bestimmen kann (die wäre dann immer "0").
Interessant finde ich halt nur die Argumentation mit dem Fehler, das macht man ja schon in der Schule oft genug falsch... dass man Messergebnisse, die man "Pi * Daumen" abgeschätzt hat, dann nach der Rechnung mit sechs Nachkommastellen niederschreibt. Das meinte ich auch mit Realitätscheck. Wie genau sind deine Messungen - wie genau können sie technisch überhaupt sein - wie verlässlich sind sie überhaupt. Und da sehe ich (vermutlich nicht nur ich) schwarz.
Das mit dem "Pi mal Daumen", da will ich nur sagen, das ich es nicht 100%ig genau hinbekomme (aus vielen auch hier genannten Gründen). Ich habe halt meinen Code auf einiges PCs und vielen CPUs getestet und da hat mein Code, innerhalb aktzepttabler Grenzen, soweit funktioniert (darüber habe ich auch selbst gestaunt ;) ).
Um mal das mit den Nachkommastellen noch zu rechtfertigen. Nachdem ich mir eine Konstante per Taschenrechner ausgerechnet habe (und nicht mehr per Compiler), sind meine Messungen mit einmal wesentlich genauer geworden.
Das Problem ist z.B. das es ein Unterschied macht ob du mit 2 oder mit 2,5 rechnest, vorallem wenn du dann mit Zahlen >10000 multiplizierst.
Wenn du dein Timing möglichst genau machen willst, dann läuft das im Übrigen schon auf Echtzeitfähigkeit hinaus. Ein Multimedia-Betriebssystem muss per Definition echtzeitfähig sein, das heißt aber nicht sofortige (oder schnellstmögliche) Reaktion, sondern hinreichend schnelle Antwort.
Du zielst im Prinzip (unbewusst) auf eine hochgenaue Echtzeitfähigkeit ab.
Wie du schon geschrieben hast, dann eher unbewusst. Ich wollte genau auf eine hinreichend schnelle Antwort hinaus, aber halt wesentlich besser als z.B. Windows (irgendwo muss man ja besser sein ;) ).
Wann immer du Annahmen über etwas machst, dann überdenke auch immer, wann deine Annahmen nicht gelten. Da hab ich ein paar Sachen geschrieben, die für mich einige deiner Voraussetzungen verletzen und daher - vielleicht nicht grundsätzlich, aber durchaus in einigen Fällen - deine Ziele so verhindern.
Problem bei, einigen von dir genannten Sachen, sehe ich darin, das es so wenig Systeme betrifft und ich die Zeit besser verwenden sollte, als mich auch noch um die Unsinnigkeiten von ein paar Systemen zu kümmern.
Zumal bei meinem Timing-System halt noch hinzukommt, dass ich damit rechne das es sich nicht weiter äußern wird (kann man unter fehlende Erfahrung verbuchen).
Ich kümmere mich im Moment um Desktopsysteme und halbwegs normale Laptops. Besonders interessant sind für mich SMP-Systeme, da ich vorallem gespant bin was man aus den älteren (<PII) noch so rausholen kann.
-
Hallo,
Sorry für mein langes Delay, ich hab zur Zeit ne Menge privater Probleme.
Bevor, vorallem ihr, mich auf die Unzulänglichkeiten mit meinem System aufmerksam gemacht habt
Dafür sind wir ja da. ;)
wollte ich schon noch irgendwie ne nsek Auflösung erreichen, bzw. ich erreiche sie bestimmt auch auf vielen Systemen (wenn der ACPI-PMT genutzt wird)
Ich denke das Du selbst auf den aktuellsten PCs nicht genauer als etwa in den einstelligen Mikrosekundenbereich kommst. Und mit dem ACPI-PMT schon gar nicht, der hat doch nur 3.58 MHz.
Für Dich vielleicht, aber die CPU hat am wenigsten Arbeit wenn sie direkt mit den Timer-Ticks umgehen darf (da muss dann gar nichts gerechnet werden) und die libc in den User-Programmen die Wünsche per GetTicksPerSecond passend umrechnet.
Das ist dem geschuldet das ich mehrere Zeitquellen nutze und da ist es am einfachsten wenn ich in nsek umrechne.
[....]
Dann müsste ich aber 128bit Zahlen benutzen und es war schon nicht einfach Code für ne 64bit Division zu finden, bzw. fehlt mir immernoch Code (der halbwegs genau und schnell ist) für eine "64bit div 64bit = 64bit" Division. Oder was meintest du?
Genau das meinte ich mit unnötigem Aufwand. Wenn Du innerhalb des Kernels gar nichts umrechnest sondern immer direkt mit Ticks arbeitest sparst Du Dir erheblichen (Rechen-)Aufwand (so ein DIV-Befehl kann auf verschiedene Arten Exceptions auslösen und die könnten innerhalb Deines Kernels unangenehm sein und eventuell zu einem Tripple-Fault führen). Und wie man eine Division mit überbreiten Zahlen realisiert ist IMHO Aufgabe des Compilers (der Deine libc compiliert).
betrifft dies auch wieder nur neuere Systeme (auf alten sollte das wohl eher nicht passieren)
Das, mit der PC-Serie wo die CPU mit gedrosselter Kraft vom BIOS ans OS übergeben wurde, war vor etwa 8 Jahren. Das war ein Pentium 4 System und die haben absichtlich ein möglichst schwaches Kühlungssystem verbaut (an jedem PC 5 Euronen gespart macht sich bei >= fünfstelligen Stückzahlen durchaus bemerkbar) und eben fürs Hochfahren die CPU gedrosselt bevor dann bei laufendem OS ein extra Programm den CPU-Takt je nach Last und Temperatur geregelt hat.
Hä, bitte genauer erklären. Willst du neben einem periodischen PIT-Timer noch parallel einen One-Shot-PIT-Timer starten?
Nope! Ich hatte doch erklärt das wenn die Zeit bis zu einem Event (jetzt mal als Bsp) kleiner ist als das Intervall des periodischen Timers, das dann das Event an den Scheduler weitergereicht wird. Dieser löst das dann im Endeffekt aus (weckt als z.B. einen Thread auf). Der Scheduler wird halt entweder vom PIT oder vom APIC befeuert (je nach dem was auf dem PC zur Verfügung steht).
Wenn der Scheduler auch nur mit dem selben PIT arbeitet dann hast Du doch keinen Genauigkeitsgewinn. Den könntest Du theoretisch haben wenn Du zusätzlich zum periodischen IRQ einen weiteren PIT-Zähler (der PIT hat doch 3 Zähler oder irre ich da) als One-Shot-Timer aufziehst. Bei Verwendung des Local-APIC-Timers hast Du natürlich auch die theoretische Möglichkeit auf einen Genauigkeitsgewinn. Diesen Gewinn erkaufst Du Dir aber in jedem Fall mit einiges an Mathematik im Kernel.
... auch wenn ich dann bis an mein Lebensende daran arbeite!
Mein Projekt ist auch Hobby aber bis an mein Lebensende möchte ich daran wirklich nicht arbeiten. In spätestens 5 bis 7 Jahren möchte ich auf meinem komplett selbst entwickeltem Computer das absolute Lieblings-Spiel meiner Jugend spielen können. (ich verzichte hier absichtlich auf Smilies)
aber die Linuxleute sind nicht so sehr von dem HPET begeistert, wimre wird die Genauigkeit durch die Langsamkeit wieder weggemacht (Thema Hoch-Präziser-Counter) und sie nutzen am liebsten wieder den TSC
Wo ist der HPET langsam? Der benutzt immerhin Memory-Mapped-I/O und sollte sich daher sehr einfach und effizient benutzen lassen. Für (Performance-)Messungen sehr kurzer Zeitspannen ist der HPET auch nie gedacht gewesen.
Du musst nur alle CPUs an eine Barriere zusammenholen und wenn dann alle eingetroffen sind, lässt du sie los und alle schreiben "0" in den TSC, damit sollten dann alle "Pi mal Daumen" synchronisiert sein.
Das dürfte etwa 100 bis 1000 Takte (bei richtig vielen CPUs und entsprechendem Cache-Kohärenz-Protokoll-Aufwand wohl noch mehr) Differenz ergeben. Naja, wenn Du meinst das sich dieser Aufwand lohnt dann nur zu.
Ich wusste gar nicht das die TSCs beschreibbar sind, wozu auch, die driften doch eh wieder auseinander (spätestens wenn das Powermanagement die unterschiedlichen CPUs in unterschiedliche Power-Modi schickt).
was ich garantieren möchte ist eine Genauigkeit <1ms mit der Tendenz zur nsek-Genauigkeit!
Das sind 6 (sechs) Zehnerpotenzen, das ist wirklich ein sehr ehrgeiziges Ziel. Respekt!
Auch mit dem HPET hast du das Problem, das dieser immer eine gewisse Ungenauigkeit hat
Das ist der Jitter, der ist tatsächlich kaum zu vermeiden, aber richtige Ungenauigkeit hat man beim HPET nicht (beim PIT im periodischen Modus ebenfalls nicht).
Guck dir OS/2 an und den Grund, dass es sich auf den wenigsten Emulatoren vernünftig emulieren ließ (und lässt)
Könntest Du Bitte diesen Grund etwas näher erläutern.
man macht es so, wie die anderen auch
Also das ist definitiv der schlechteste Vorschlag den man geben kann! Wir sind doch alle hier weil wir eben nicht alles so machen wollen wie alle anderen auch. Wir wollen neue Wege gehen!
z.B. einen ATMega oder PIC, die sind klein genug, dass du ein realtime-OS da drauf kriegst
Das liegt IMHO nicht daran das die klein sind sondern daran das die sehr deterministisch sind. Bei denen kannst Du u.a. für einen bestimmten Code-Abschnitt ganz genau sagen wie lange der braucht bei x86 geht das schon seit über 20 Jahren nicht mehr.
Also ich schicke meinen Rechner (und da gehe ich immer von Desktop aus) nie in den Standby-Modus.
Energie kostet Geld, wenn Dein OS damit nicht verantwortungsbewusst umgehen kann hat es grundsätzlich keine echte Chance.
Jetzt mal ein wenig Mathe. Wie willst du alles über 1GHz in nsek darstellen ohne Gleitkommazahlen zu nutzen? Dann wird dir vielleicht klar wieso ich psek nehme!
Selbst mit Gleitkommazahlen kannst Du nicht jede CPU-Takt-Frequenz exakt darstellen aber wenn Du Dich auf Pikosekunden in Integer festlegst hast Du für die heutigen CPUs nur maximal 8 signifikante Bits und das ist schon sehr knapp bemessen, dann lieber gleich Femtosekunden. ;) Außerdem haben die Gleitkommazahlen einen zusätzlichen Vorteil, man kann recht schnell mit ihnen rechnen (heutige FPUs sind ziemlich fix und besser als ne händische "64Bit / 64Bit = 64Bit" Division auf ner 32Bit-CPU ist die FPU alle mal).
aber halt wesentlich besser als z.B. Windows (irgendwo muss man ja besser sein ;) )
Dann nimm ne andere Plattform. Windows (zumindest in aktueller Version) dürfte x86 schon recht gut ausreizen, die haben ein ganzes Team an Vollzeit-Programmierern nur allein für den Kernel. Wenn Du dieses Ziel wirklich erreichen willst dann überlege Dir mal ob Du nicht z.B. bei mir mitmachen möchtest. ;) Zumindest "genaueres Timing als Windows" dürfte ein einigermaßen realistisches Ziel in meinem Projekt sein. Und kreative Leute die nicht immer nur in aus getrampelten Bahnen denken dürften in vielen Projekten sehr willkommen sein.
Grüße
Erik
-
Sorry für mein langes Delay, ich hab zur Zeit ne Menge privater Probleme.
Kein Problem, bin eh im "Urlaub" und private Probleme gehen eh vor!
Ich denke das Du selbst auf den aktuellsten PCs nicht genauer als etwa in den einstelligen Mikrosekundenbereich kommst. Und mit dem ACPI-PMT schon gar nicht, der hat doch nur 3.58 MHz.
Naja, wie gesagt ich meine damit, das ich z.B. wenn ein Event in 1µs gefeuert werden soll, das du das dann halt nicht nach 2µs sondern so nahe wie möglich an 1µs bekommst. Mir geht es im Endeffekt um die "Nachkommastellen". Das ich also schon nach 1,15µs (was dann für mich nsek-Auflösung wäre) und nicht erst nach 2µs das Event bekomme. Das du das auf älteren Systemen nicht hinbekommst ist mir klar, alleine schon weil die CPUs ja doch ne Weile brauchen um die Instruktionen abzuarbeiten.
Um es nochmal ganz genau zu sagen, mir gefällt der Gedanke nicht, das du ein Event nach 15ms haben möchtest, dieses aber frühestens nach 20ms bis zu 40ms später bekommst (wenn du nen periodischen Timer von 20ms nutzt).
Wenn mein worst-case dann mal 0,25ms daneben liegt, denke ich habe ich mein Ziel mehr oder weniger erreicht. Denn der average-case wird wesentlich genauer sein!
Ich denke das Du selbst auf den aktuellsten PCs nicht genauer als etwa in den einstelligen Mikrosekundenbereich kommst. Und mit dem ACPI-PMT schon gar nicht, der hat doch nur 3.58 MHz.
Ich glaube ich habe irgendwo µs und ms durcheinander gebracht, wenn ich auf nem PII mit nem ACPI-PMT µs-Auflösung bekomme, dann ist das doch schon verdammt gut und Welten besser als Windows :D
Genau das meinte ich mit unnötigem Aufwand. Wenn Du innerhalb des Kernels gar nichts umrechnest sondern immer direkt mit Ticks arbeitest sparst Du Dir erheblichen (Rechen-)Aufwand (so ein DIV-Befehl kann auf verschiedene Arten Exceptions auslösen und die könnten innerhalb Deines Kernels unangenehm sein und eventuell zu einem Tripple-Fault führen). Und wie man eine Division mit überbreiten Zahlen realisiert ist IMHO Aufgabe des Compilers (der Deine libc compiliert).
Also nochmal. Ich nutze mehrere Zeitquellen mit unterschiedlichen Ticks, also muss ich so oder so irgendwo umrechnen und um mir und dem Programmier/in das Leben etwas leichter zu machen, sage ich, dass ich gleich nsek zurückgebe.
Das mit den Exceptions dürfte nicht passieren (mir fällt da spontan eh nur die 0-Teiler-Exception ein).
Was die Division großer Zahlen betrifft, setzt du vorraus das ich ne libc habe (nutze ich nicht für meinen Loader und auch nicht für meinen Kernel). Ich habe bisher alles mehr oder weniger alleine geschrieben. Das ich nachher eine Libc für das Userland portieren werde ist klar. Obwohl ich mit der Lösung nicht so richtig glücklich bin und wahrscheinlich eher alles OS-Unabhängige "portieren" werde und den Rest mehr oder weniger neuschreiben werde.
Denn was nützt dir ein tolles OS mit neuen Ideen, wenn du dann bei der Libc schon ne Art Emulierungsschich hast.
Das, mit der PC-Serie wo die CPU mit gedrosselter Kraft vom BIOS ans OS übergeben wurde, war vor etwa 8 Jahren. Das war ein Pentium 4 System und die haben absichtlich ein möglichst schwaches Kühlungssystem verbaut (an jedem PC 5 Euronen gespart macht sich bei >= fünfstelligen Stückzahlen durchaus bemerkbar) und eben fürs Hochfahren die CPU gedrosselt bevor dann bei laufendem OS ein extra Programm den CPU-Takt je nach Last und Temperatur geregelt hat.
Also für mich eh nicht interessant, da ich auf diesen PCs keinen TSC nutze!
Wenn der Scheduler auch nur mit dem selben PIT arbeitet dann hast Du doch keinen Genauigkeitsgewinn. Den könntest Du theoretisch haben wenn Du zusätzlich zum periodischen IRQ einen weiteren PIT-Zähler (der PIT hat doch 3 Zähler oder irre ich da) als One-Shot-Timer aufziehst. Bei Verwendung des Local-APIC-Timers hast Du natürlich auch die theoretische Möglichkeit auf einen Genauigkeitsgewinn. Diesen Gewinn erkaufst Du Dir aber in jedem Fall mit einiges an Mathematik im Kernel.
Ihr versteht meine Kombinationen leider immernoch nicht :(
Also, entweder man hat nen alten PC ohne APIC, dann wird die RTC als periodische Quelle und der PIT für den One-Shot-Scheduler (eher sehr ungenau) genommen.
Hast du nen PC mit APIC (was SMP-Systeme mit einschließt) dann wird der PIT als periodische Quelle und der APIC für den One-Shot-Scheduler genommen.
Wenn ich dann mal soweit bin, dann wird der HPET als periodische Quelle und der APIC für den One-Shot-Scheduler genommen (wo ich dann auch die Events nicht mehr an den Scheduler weiterreichen brauche).
Wo ist der HPET langsam? Der benutzt immerhin Memory-Mapped-I/O und sollte sich daher sehr einfach und effizient benutzen lassen. Für (Performance-)Messungen sehr kurzer Zeitspannen ist der HPET auch nie gedacht gewesen.
Ich kann dir leider nicht sagen, worum es bei dem Code ging, den ich da mal gesehen hatte. Ich vermute mal um nen Counter (hochpräzise) und wenn du da jedesmal den HPET auslesen musst, dann ist der TSC einfach schneller und dein Counter somit genauer!
Mein Projekt ist auch Hobby aber bis an mein Lebensende möchte ich daran wirklich nicht arbeiten. In spätestens 5 bis 7 Jahren möchte ich auf meinem komplett selbst entwickeltem Computer das absolute Lieblings-Spiel meiner Jugend spielen können. (ich verzichte hier absichtlich auf Smilies)
Sorry, aber wer sich nicht im Klaren ist, dass ein OS nie fertig ist, der hat etwas nicht verstanden ;)
Ich weiß jetzt schon, das ich entweder mein OS nach 64bit portiere oder aber ein neues schreibe und meine (guten) Ideen und meine Erfahrungen mitnehme.
Das dürfte etwa 100 bis 1000 Takte (bei richtig vielen CPUs und entsprechendem Cache-Kohärenz-Protokoll-Aufwand wohl noch mehr) Differenz ergeben. Naja, wenn Du meinst das sich dieser Aufwand lohnt dann nur zu.
Der Punkt geht an dich ;)
Problem ist hier nur, dass ich das im Kernel machen muss. Wenn ich es mir gerade so recht überlege, ist das ganze aber eigentlich nicht notwendig, weil ...
Wenn ich ein altes SMP-System ohne ACPI habe, gehe ich jetzt mal frech davon aus, das die TSCs (von irgendwelchen Stromsparmaßnahmen mal abgesehen, da ich eh nicht glaube das es sowas auf solchen System gab und ich noch nichts gefunden habe, das der TSC dort Probleme macht) synchron sind und funktionieren.
Auf nem neuem System wo ICH den TSC dann wieder nutze, sind die eh synchron und funktionieren (das wird ja dort "garantiert", nach dem sich MS und "Linux" darüber beschwert hatten).
Also bräuchte ich diese Synchronisation eigentlich nicht mehr und könnte den Code auskommentieren.
Ich wusste gar nicht das die TSCs beschreibbar sind, wozu auch, die driften doch eh wieder auseinander (spätestens wenn das Powermanagement die unterschiedlichen CPUs in unterschiedliche Power-Modi schickt).
Gegenfrage, wenn die nicht schreibbar wären, wie soll die AMD dann per Treiber synchronisieren können?
Und wie oben schon geschrieben, passiert das ganz auseinanderdriften auf neueren CPUs halt nicht mehr! Ich gehe jetzt auch davon aus, das es auf Multi-Sockel-Systemen auf diesen CPUs auch alles funktioniert.
Energie kostet Geld, wenn Dein OS damit nicht verantwortungsbewusst umgehen kann hat es grundsätzlich keine echte Chance.
Ich gehe hier jetzt mal von einer privaten Nutzung aus und da macht der Standbybetrieb bei einem Desktop-Rechner für mich einfach keinen Sinn! Ich mach meinen Rechner dann einfach aus!
Zumal ich ja z.B. aus Energietechnischer Sicht keine periodische Zeitquelle mit einem Intervall von 1ms nutzen möchte ;)
Selbst mit Gleitkommazahlen kannst Du nicht jede CPU-Takt-Frequenz exakt darstellen aber wenn Du Dich auf Pikosekunden in Integer festlegst hast Du für die heutigen CPUs nur maximal 8 signifikante Bits und das ist schon sehr knapp bemessen, dann lieber gleich Femtosekunden. Wink Außerdem haben die Gleitkommazahlen einen zusätzlichen Vorteil, man kann recht schnell mit ihnen rechnen (heutige FPUs sind ziemlich fix und besser als ne händische "64Bit / 64Bit = 64Bit" Division auf ner 32Bit-CPU ist die FPU alle mal).
Diese Division findet einmal statt und zwar in meinem Bootloader. Selbst wenn die noch so langsam ist, dürfte das wohl kaum auffallen!
Es gibt da irgendwo so ne Regel das man keine FPU im Kernel nutzt und das halte ich genauso! Macht mir nur die Arbeit schwerer und ich komme bisher ohne ganz gut klar!
Dann nimm ne andere Plattform. Windows (zumindest in aktueller Version) dürfte x86 schon recht gut ausreizen, die haben ein ganzes Team an Vollzeit-Programmierern nur allein für den Kernel. Wenn Du dieses Ziel wirklich erreichen willst dann überlege Dir mal ob Du nicht z.B. bei mir mitmachen möchtest. Wink Zumindest "genaueres Timing als Windows" dürfte ein einigermaßen realistisches Ziel in meinem Projekt sein. Und kreative Leute die nicht immer nur in aus getrampelten Bahnen denken dürften in vielen Projekten sehr willkommen sein.
Kommt drauf an welche Windows-Version du meinst ;) Ich weiß gar nicht ob die inzwischen auch nen One-Shot-Scheduler haben.
Ich müsste mal nachgucken, wie lange so eine Division braucht, aber so lange sollte das nun auch wieder nicht dauern!
-
Mir ist gerade eingefallen warum der TSC an sich die beste Lösung fürs Timing (in Form eines Counters wäre und damit auch warum es von Linux bevorzugt wird) ist.
Leider ist es mit dem HPET nicht möglich ihn für einen Counter zu nutzen, den man auch im Userland, OHNE in den Kernel gehen zu müssen, nutzen kann.
Denn den TSC kann man ja auch im Userland auslesen (so fern es das OS zulässt) und damit ist der TSC nochmal schneller (was er ja ohnehin ist, da direkt in der CPU und nicht IO-Gerät), da nicht in den Kernel gegangen werden muss.
Ich habe mir nämlich gerade ne Rübe gemacht, wie man solch einen Counter auch direkt im Userland implementieren könnte und habe noch keine all-in-one Lösung gefunden.
Der Grund für genaues Timing wäre z.B. ein Emulator. Ich habe mich zwar noch nicht weiter mit der Programmierung beschäftigt (und anscheinend funktioniert es auch ohne genaues Timing), aber es würde die Sache bestimmt einfacher machen, wenn man ein Gerät (z.B. eine CPU) in der genauen Geschwindigkeit (also Frequenz) timen kann.
-
Hallo,
Kein Problem, bin eh im "Urlaub" und private Probleme gehen eh vor!
Du kennst meine momentanen Probleme nicht, sei froh.
Naja, wie gesagt ich meine damit, das ich z.B. wenn ein Event in 1µs gefeuert werden soll, das du das dann halt nicht nach 2µs sondern so nahe wie möglich an 1µs bekommst.
Das einzigste Werkzeug was ich dazu generisch in der Lage sehe ist der HPET. Der Local-APIC-Timer gibt den Event nur auf der CPU wo er läuft und ist somit zwar nutzbar aber nicht für jeden Zweck und der TSC (ebenso wie der ACPI-PMT) gibt gar keine Events ist also nur für Messung und kurzes aktives Warten (z.B. in nsleep) geeignet. Für Messungen ist der TSC natürlich perfekt weil man ihn schnell abfragen kann und weil er (Aufgrund der hohen Zählgeschwindigkeit) eine feine zeitliche Auflösung bietet, dafür bleibt das Problem das alles durcheinander gerät wenn das OS das User-Programm zwischendurch auf ne andere CPU schedult. Fürs Timing, also z.B. das Auslösen eines Event in möglichst exakt 30ms oder auch 2µs, ist der TSC eben gar nicht geeignet (er kann schlicht keine Events auslösen). Und wenn Du bei einem periodischen RTC/PIT-IRQ quasi die Nachkommastellen willst dann nimm lieber den ACPI-PMT oder den HPET, die laufen mit konstanter und verlässlicher Geschwindigkeit.
Wenn mein worst-case dann mal 0,25ms daneben liegt, denke ich habe ich mein Ziel mehr oder weniger erreicht. Denn der average-case wird wesentlich genauer sein!
Der worst-case wird deutlich mehr daneben liegen, das liegt in der Natur eines General-Purpose-OS. Auch der average-case wird kaum in den einstelligen Mikrosekundenbereich (wohl noch nicht mal in den zweistelligen) vordringen, das ist eher der selten erreichte best-case.
Ich glaube ich habe irgendwo µs und ms durcheinander gebracht
Das machst Du meiner persönlichen Meinung nach (und wohl auch nach Svenskas Meinung) schon seit ner ganzen Weile. ;)
wenn ich auf nem PII mit nem ACPI-PMT µs-Auflösung bekomme, dann ist das doch schon verdammt gut
Das ist nicht gut sondern unmöglich. Mit dem ACPI-PMT kannst Du höchstens prüfen ob ein sleep(6ms) noch vor dem nächsten RTC/PIT-IRQ fertig ist (damit bereits dort der entsprechende Thread wieder aufgeweckt werden kann) oder erst mit dem übernächsten IRQ sicher abgelaufen ist. Damit wirst Du höchstens zufällig mal eine Mikrosekundengenauigkeit erreichen wenn eben das sleep zufällig genau 6ms (+ eine winzige Reserve für Latenzen) vor dem nächsten IRQ aufgerufen wurde.
Ich nutze mehrere Zeitquellen mit unterschiedlichen Ticks
Also nochmal, genau darin sehen wir das Problem. Eben weil diese unterschiedlichen Zeitquellen kein exakt bekanntes Verhältnis zu einander haben (und dieses Verhältnis wohl auch Schwankungen und Drifts unterliegt) wirst Du viel Arbeit für (fast) nichts investieren müssen damit das ganze Konstrukt zumindest nicht schlechter läuft als die simple Lösung. Den Genauigkeitsvorteil den Du Dir davon versprichst sehe ich bis jetzt nur in der Theorie aber ich kann mir nicht vorstellen wie Du den in die Praxis bringen willst.
also muss ich so oder so irgendwo umrechnen
Ja, Du wirst an so vielen Stellen (verlustbehaftet) umrechnen müssen das am Ende von Deiner Genauigkeit nicht viel übrig bleibt.
Das mit den Exceptions dürfte nicht passieren (mir fällt da spontan eh nur die 0-Teiler-Exception ein).
DIV wirft auch ne Exception wenn das Ergebnis zu groß für ein Register ist, also z.B. bei 0x00000033_33333333 / 0x00000002 wäre das Ergebnis größer als 32Bit.
Was die Division großer Zahlen betrifft, setzt du vorraus das ich ne libc habe (nutze ich nicht für meinen Loader und auch nicht für meinen Kernel).
Nein, ich wollte damit sagen das die User-Mode-Programme ihre Zeitbedürfnisse in einer ihnen genehmen Einheit (meinetwegen auch Femtosekunden) verwalten sollen und die libc (oder ne andere lib) das dann passend in Ticks für den Kernel umrechnen muss (um das dann den Syscalls als Parameter mitzugeben) damit im Kernel überhaupt nichts gerechnet werden muss. So will ich das zumindest in meinem OS machen.
Ihr versteht meine Kombinationen leider immernoch nicht :(
Wir verstehen nicht wie Du glaubst trotz der ganzen Probleme, die die unterschiedlichen Komponenten beim Zusammenspiel bringen, noch einen Genauigkeitsgewinn erzielen zu können.
Also, entweder man hat nen alten PC ohne APIC, dann wird die RTC als periodische Quelle und der PIT für den One-Shot-Scheduler (eher sehr ungenau) genommen.
Damit wäre der PIT aber nur für relative Dinge (wie z.B. ein sleep) geeignet. Wenn Du z.B. einem Video-Player-Programm einen 24Hz Event geben möchtest damit ein Film mit 259200 Bildern bei 24fps auch ganz genau 3 Stunden läuft dann nützt Dir der PIT im One-Shot-Mode nicht viel. Für die Verwaltung der Zeitscheiben (auf einem Single-CPU-System), was ja auch relative Zeiten sind, taugt der One-Shot-PIT natürlich.
Hast du nen PC mit APIC (was SMP-Systeme mit einschließt) dann wird der PIT als periodische Quelle und der APIC für den One-Shot-Scheduler genommen.
Das Problem, zumindest bei SMP, ist IMHO das es mehrere Local-APICs gibt. Wie bestimmst Du den an welche CPU ein bestimmtes Event geht? Zur Verwaltung der Zeitscheiben braucht man mehrere CPU-Lokale Timer (genau dafür wurden die Local-APIC-Timer ja gedacht), da ja jeder laufende Thread seine eigene Zeitscheibe hat, aber fürs globale/generische Timing betrachte ich die er als ungeeignet.
Wenn ich dann mal soweit bin, dann wird der HPET als periodische Quelle und der APIC für den One-Shot-Scheduler genommen (wo ich dann auch die Events nicht mehr an den Scheduler weiterreichen brauche).
Der HPET ist keine periodische Quelle. Das ist ein garantiert monotoner und nicht beeinflussbarer Counter der an beliebigen vorherbestimmbaren Zeitpunkten IRQs senden kann. Natürlich kann man diese Zeitpunkte auch in ein festes Raster legen, was z.B. bei dem Beispiel mit dem Video-Player-Programm nötig wäre. Man kann aber den einen HPET für viele verschiedene Events benutzen, man muss bei einem Event (also im IRQ-Handler) immer nur den absoluten Zeitpunkt des nächsten Events in den HPET-Comparator laden (deswegen die sortierte Liste). Die Zeitscheiben für die laufenden Threads würde ich natürlich trotzdem mit den Local-APIC-Timern managen da ja der Event auf genau der CPU kommen soll wo die Zeitscheibe abläuft. Dazu ist der HPET nicht fähig, dessen IRQ wird an irgendeine CPU geleitet (eventuell auch immer an die selbe).
Trotzdem wüste ich gerne was Du mit "One-Shot-Scheduler" meinst.
Gegenfrage, wenn die nicht schreibbar wären, wie soll die AMD dann per Treiber synchronisieren können?
Ich wusste auch nicht das AMD die per SW synchronisiert. Auf so eine unsinnige Idee wäre ich auch nie gekommen, das kann gar nicht präzise funktionieren!
Und wie oben schon geschrieben, passiert das ganz auseinanderdriften auf neueren CPUs halt nicht mehr!
Wieso sollten die TSCs nicht mehr auseinander driften, gerade auf den modernen CPUs können alle CPU-Kerne ihre Taktfrequenz unabhängig und dynamisch ändern (bei den aktuellen Core i? eventuell sogar ganz ohne aktives zutun von OS oder BIOS). Und selbst bei den aller ersten Pentium-Pro Systemen war es nicht verboten CPUs mit unterschiedlichem Core-Takt auf ein Board zu stecken solange der Front-Side-BUS-Takt identisch war. Wie will man sowas synchronisieren? Von den ganzen physikalische Phänomenen wie schwankenden Temperaturen usw. mal ganz abgesehen. Stell Dir mal ein Dual-Sockel Core i7 System vor bei dem einer der beiden CPU-Lüfter leicht verschmutzt ist (in einem privaten PC sicher nicht auszuschließen) und der Turbo-Boost-Controller der betreffenden CPU alle ihre Kerne nicht ganz bis an die maximale Frequenz ran lässt (weil das CPU-Die am Temperatur-Limit ist). Dann hast Du 4 CPU-Kerne mit z.B. 2,6GHz und 4 mit 2,0GHz. Wie will man sowas synchronisieren?
Das synchronisieren der TSCs ist völliger Blödsinn, um die als Stoppuhr zu benutzen braucht man sie nicht zu synchronisieren.
Leider ist es mit dem HPET nicht möglich ihn für einen Counter zu nutzen, den man auch im Userland, OHNE in den Kernel gehen zu müssen, nutzen kann. ....
Das ist richtig. Der HPET ist aber nie als (hochpräzise) Stoppuhr gedacht gewesen, so wie der TSC nie fürs (generische) Timing gedacht wurde.
Grüße
Erik
-
Das einzigste Werkzeug was ich dazu generisch in der Lage sehe ist der HPET. Der Local-APIC-Timer gibt den Event nur auf der CPU wo er läuft und ist somit zwar nutzbar aber nicht für jeden Zweck und der TSC (ebenso wie der ACPI-PMT) gibt gar keine Events ist also nur für Messung und kurzes aktives Warten (z.B. in nsleep) geeignet. Für Messungen ist der TSC natürlich perfekt weil man ihn schnell abfragen kann und weil er (Aufgrund der hohen Zählgeschwindigkeit) eine feine zeitliche Auflösung bietet, dafür bleibt das Problem das alles durcheinander gerät wenn das OS das User-Programm zwischendurch auf ne andere CPU schedult. Fürs Timing, also z.B. das Auslösen eines Event in möglichst exakt 30ms oder auch 2µs, ist der TSC eben gar nicht geeignet (er kann schlicht keine Events auslösen). Und wenn Du bei einem periodischen RTC/PIT-IRQ quasi die Nachkommastellen willst dann nimm lieber den ACPI-PMT oder den HPET, die laufen mit konstanter und verlässlicher Geschwindigkeit.
Also nochmal ;)
Der TSC/ACPI-PMT wird nur als Counter um den aktuellen Zeitpunkt zu bestimmen genutzt.
Wenn ein ACPI-PMT oder HPET (zumindest wenn ich es denn endlich mal schaffe, den Code zu schreiben ;) ) vorhanden ist, dann nutze ich auch keinen TSC (abgesehen von den neueren CPUs).
Der worst-case wird deutlich mehr daneben liegen, das liegt in der Natur eines General-Purpose-OS. Auch der average-case wird kaum in den einstelligen Mikrosekundenbereich (wohl noch nicht mal in den zweistelligen) vordringen, das ist eher der selten erreichte best-case.
Im Endeffekt theoresiere ich hier viel, ihr aber auch ;) Aber so wie meine Theorie aussieht, sollte es eigentlich klappen.
Bei 250µs= 250000ns und nem P100, wo 1 Takt= 10ns und ich sage jetzt mal im Durchschnitt braucht eine Instruktion 20ns, komme ich auf 12500 Instruktionen die ausgeführt werden können in dieser Zeit. Das sollte für mehrere IRQs reichen. Ansonsten wüsste ich gerade nicht was mir noch dazwischen funken sollte (außer der SMM, aber der sollte ja eigentlich nicht lange dauern und auch nicht ständig auftreten).
DIV wirft auch ne Exception wenn das Ergebnis zu groß für ein Register ist, also z.B. bei 0x00000033_33333333 / 0x00000002 wäre das Ergebnis größer als 32Bit.
Äh, das sollte nicht passieren, da der Code den ich im Moment nutze das abfängt. Bzw. habe ich sogar Code gefunden, der schneller sein sollte als 2 divs, da ich die einzige große Division durch eine Konstante (1000) mache und da kann man irgendwie vereinfachen (richtig verstanden habe ich das nicht, aber funktionieren tut es ;) ).
Damit wäre der PIT aber nur für relative Dinge (wie z.B. ein sleep) geeignet. Wenn Du z.B. einem Video-Player-Programm einen 24Hz Event geben möchtest damit ein Film mit 259200 Bildern bei 24fps auch ganz genau 3 Stunden läuft dann nützt Dir der PIT im One-Shot-Mode nicht viel. Für die Verwaltung der Zeitscheiben (auf einem Single-CPU-System), was ja auch relative Zeiten sind, taugt der One-Shot-PIT natürlich.
Da kommen wir halt wieder zu meinen mehreren Zeitquellen.
Alles was soweit in der Zukunft liegt, das es ab dem aktuellen Zeitpunkt größer ist (zeitlich gesehen) als ein Intervall des periodischen Timers, kommt in eine Liste die der periodische Timer verwaltet.
Dieser guckt bei jedem IRQ nach, ob ein Event getriggert werden muss was noch vor dem nächsten IRQ liegt. Ist das der Fall, wird dieses Event an den Scheduler (der aktuellen CPU, auf SMP Systemen) weitergereicht und ab da läuft das ganze dann über relative Zeiten.
Sprich der Scheduler guckt bei jedem Aufruf, wie lange es bis zum nächsten Event ist. Ist diese Zeitspanne kürzer als die Zeitscheibe die der neue Thread hat, dann wird die Zeit bis zum nächsten Event genommen. Ansonsten die Zeit für den Thread.
Ich denke ein wenig Pseudocode hilft hier weiter:
uint64t diff= timeNow - timeStarted;
uint32t nextEventTime= -1; //ich weiß theoretisch falsch, aber ich wollte halt die größte unsigned Zahl haben und das ist so kürzer
if(eventQueue) {
eventQueue->time-= diff;
while(eventQueue->time == 0) {
threadWakeup(eventQueue);
eventQueue= eventQueue->next;
}
nextEventTime= eventQueue->time;
}
//hier kommt dann der eigentlich Scheduler
if(nextEventTime < threadTimeslice)
timerSetTimeslice(nextEventTime);
else
timerSetTimeslice(threadTimeslice);
timeStarted= timerGetNow();
Trotzdem wüste ich gerne was Du mit "One-Shot-Scheduler" meinst.
Damit meine ich "nur" das du keinen periodischen Timer nutzt, sondern nen One-Shot-Timer. Damit will ich mir die ständigen IRQs sparen (dafür wird es dann leider auf SMP System ein wenig "langsamer", zwecks IRQs an alle CPUs.
Wieso sollten die TSCs nicht mehr auseinander driften, gerade auf den modernen CPUs können alle CPU-Kerne ihre Taktfrequenz unabhängig und dynamisch ändern (bei den aktuellen Core i? eventuell sogar ganz ohne aktives zutun von OS oder BIOS). Und selbst bei den aller ersten Pentium-Pro Systemen war es nicht verboten CPUs mit unterschiedlichem Core-Takt auf ein Board zu stecken solange der Front-Side-BUS-Takt identisch war. Wie will man sowas synchronisieren? Von den ganzen physikalische Phänomenen wie schwankenden Temperaturen usw. mal ganz abgesehen. Stell Dir mal ein Dual-Sockel Core i7 System vor bei dem einer der beiden CPU-Lüfter leicht verschmutzt ist (in einem privaten PC sicher nicht auszuschließen) und der Turbo-Boost-Controller der betreffenden CPU alle ihre Kerne nicht ganz bis an die maximale Frequenz ran lässt (weil das CPU-Die am Temperatur-Limit ist). Dann hast Du 4 CPU-Kerne mit z.B. 2,6GHz und 4 mit 2,0GHz. Wie will man sowas synchronisieren?
Das synchronisieren der TSCs ist völliger Blödsinn, um die als Stoppuhr zu benutzen braucht man sie nicht zu synchronisieren.
Wie ich schon geschrieben habe, wird auf neueren CPUs ein konstanter TSC, sogar auf allen Kernen garantiert. Der ist ab Core2 nicht mehr an die CPU Frequenz gebunden!
Um dann nochmal auf die Variante mit den unterschiedlichen CPUs zu kommen. Den Fall betrachte ich erst gar nicht! 1. ist das ganze dann kein SMP- sondern ein AMP-System und die paar Systeme die es eventuell gibt, um die kümmere ich mich nicht! Mir ist durchaus klar, das ich nicht jedes System unterstützen kann, dafür wäre der Aufwand viel zu groß, genauso wie die Einschränkungen. Zumal Intel damals (zu Pentium Zeiten) schon gesagt hat, das sie nicht garantieren das solche Kombinationen laufen. Die wollten sogar das du 2 CPUs mit dem selben Stepping (und das ist bis heute in den Köpfen der Leute drin) nimmst. Das haben die sogar noch zu P3 Zeiten gesagt.
In dem Sinne gibt es offiziell gar keine AMP-Systeme auf der x86 Architektur.
Um nochmal was klarzustellen.
Ihr "werft" mir immer vor, den TSC für generisches (wie ihr es so schön nennt) Timing zu nehmen. Das stimmt so nicht. Im Endeffekt nutze (wenn ich ihn überhaupt nutze) ich ihn nur für relative und kurze Zeiten (also genau dafür wofür er gemacht wurde). Über das Intervall (also die Länge) lässt sich jetzt streiten, aber ansonsten nutze ich den TSC eben nicht für langfristige Zeiten.
Der Vorteil bei meinem System ist doch, das ich nen periodischen Timer habe, der nur eine Auflösung von 55ms Intervallen (am Bsp. des PIT) hat. Das ist natürlich viel zu grob. Für die "Nachkommestellen" (wie du es nennst) nutze ich dann den TSC.
Passiert mit dem TSC irgendwelcher Blödsinn (aus welchen Gründen auch immer) für 4ms (oder so), dann ist das ab dem nächsten periodischen IRQ wieder egal, ab diesem (so fern nicht wieder was mit dem TSC passiert) Zeitpunkt ist das "Timing" mit dem TSC wieder in Ordnung! Ich schleppe also keine Fehler mit.
-
Um nochmal auf meine Rumrechnerei zurück zu kommen (zwecks der Performance).
Ich habe es jetzt nur mal auf nem AMD K6-200, nem dual Celeron 400 und Qemu getestet.
Also auf dem K6 ist "div" schneller als eine Version ohne Division, auf dem Celeron 400 (der genauso lange braucht wie der K6 ;) ) ist die Version ohne Division geringfügig schneller und in Qemu ist die Version ohne Division um den Faktor 6 schneller.
Erstmal bin ich überrascht, das der K6 genauso schnell (trotz der halben Taktrate) ist wie der Celeron. Das nächste ist, das ich bei meinem "div" bleibe, da es auf den CPUs wo es drauf ankommt, schneller ist.
Desweiteren reden wir hier von ca. 40 Takten und ich denke, die sind zu verschmerzen!
-
Hallo,
ich hab mir noch mal die letzten paar Beiträge durchgelesen und blicke ehrlich gesagt gar nicht mehr welche HW-Kombinationen Du eigentlich unterstützen möchtest und wie die SW sich dann jeweils verhalten soll. Ich habe eher den (subjektiven) Eindruck das Du in jedem Satz immer gleich von mehreren HW-Kombinationen schreibst. Ich bin ziemlich verwirrt.
Am besten wäre es wenn Du die einzelnen HW-Kombinationen (vielleicht nicht alle aber zumindest einige) mal konkret (unabhängig voneinander) beschreibst, erklärst nach welchen Kriterien die jeweils selektiert werden und dann mit ein paar Beispielen jeweils das Verhalten von periodischen/einmaligen langen/kurzen Events beschreibst, ohne Dich dabei auf andere Kombinationen zu beziehen. Ich weiß dass das etwas Arbeit ist aber keiner hier kann in Deinen Kopf reinsehen und vielleicht gibt Dir das auch selber etwas mehr Klarheit. Anhand verschiedener konkreter Beispiele können wir dann auch mal überlegen welche Genauigkeit (best/average/worst-cases) damit ungefähr jeweils möglich sein sollte.
Zum TSC bin ich ebenfalls etwas verwirrt. Meinst Du wirklich das Intel garantiert das der TSC in allen Kernen (auf dem selben Die oder im gesamten System?) synchron ist? Klar kann man alle Kerne auf einem Die auf den selben Zähler lesend zugreifen lassen aber wenn die Kerne mit unterschiedlichen Taktraten laufen und der TSC noch mal nen anderen Takt hat (welchen eigentlich?) dann kommt es doch zu Jitter und anderen Phänomenen (nebst den Latenzen beim Überführen der Zählerwerte in eine andere Takt-Domäne). Wenn der TSC nicht mehr mit der selben Frequenz wie der eigentliche CPU-Kern läuft dann ist er doch für kurze (taktgenaue) Performancemessungen kleiner Code-Abschnitte kaum noch zu gebrauchen, gerade die enge Kopplung dieses Zählers an die tatsächliche Arbeitsgeschwindigkeit der CPU macht ihn dafür so interessant. Im Prinzip hätte Intel den TSC mit diesem Schritt zu einem weiteren globalen Zähler degradiert (davon gibt es doch nun schon mehr als genug). Wenn man schon so einen globalen Zähler möchte dann hätte Intel dafür besser einen neuen erstellen sollen anstatt den TSC seines besonderen Alleinstellungsmerkmales zu berauben.
Grüße
Erik
-
Also gut fangen wir mit dem Minimum an.
Der PC unterstützt kein ACPI und hat keinen APIC.
Für die periodische Zeitquelle nehme ich die RTC und für meinen Scheduler den PIT.
Der RTC wird auf ein Intervall von 62,5ms gestellt (sprich alle 62,5ms wird ein IRQ ausgelöst).
Was wichtig ist, ein Event was (zeitlich gesehen) >= 62,5ms in der Zukunft liegt kommt in die Event-Queue der RTC und ein Event < 62,5ms kommt in die Event-Queue des Schedulers.
(Ich beschreibe erstmal ein einmaliges Event (z.B. ein Sleep))
Innerhalb des IRQ-Codes wird ein Counter um 62500000ns erhöht. Desweiteren wird in der Event-Queue (dort wo alle Events drin sind; hier wird mit absoluten Zeiten gearbeitet) geguckt ob das 1. Event (sprich das was als nächstes kommt) innerhalb einer Zeit < 62,5ms ausgelöst werden muss. Ist das nicht der Fall braucht nichts gemacht zu werden und der IRQ ist fertig.
Ist da aber ein Event was innerhalb einer Zeit < 62,5ms ausgelöst werden muss, wird es aus dieser Queue entfernt und wird an den Scheduler "weitergereicht".
Der Scheduler packt das Event in seine Event-Queue (das ist ne andere als die von der RTC!). Als Zeit wird ab jetzt die relative Zeit genommen (sprich wie lange noch bis das Event auszulösen ist). Auf diese wird die Zeit drauf gerechnet wie lange seit dem letzten Scheduleraufruf vergangen ist (macht die Rechnung nachher einfacher).
Dann macht der Scheduler sein "scheduler-Ding" (es wird ein neuer Thread ausgewählt, der an der Reihe ist).
Da ich einen One-Shot-Scheduler (was so viel heißt das der Scheduler (und damit auch der IRQ) erst wieder aufgerufen wird, wenn der Thread seine Zeitscheibe verbraucht hat oder der Thread abgegeben möchte) implementiert habe, wird nun geguckt was von der Zeit her "kleiner" ist. Also ob das nächste Event zeitiger passiert oder das Ende des Threads.
Der PIT wird dann auf den jeweiligen Wert gesetzt und dieser Wert wird gespeichert (damit ich ihn beim nächsten Scheduler-Aufruf nutzen kann).
Jedes Mal wenn der IRQ des Schedulers aufgerufen wird (also der PIT einen IRQ auslöst oder der Thread den Scheduler aufruft) wird der Counter des PITs ausgelesen und es wird die Differenz zwischen dem ausgelesenen Wert und dem gespeicherten Wert ausgerechnet (um die Zeit zu berechnen die vergangen ist).
Diese Differenz wird dann vom 1. Eintrag in der Event-Queue abgezogen. Ist der Wert gleich "0" oder zu klein (da habe ich noch keinen Wert festgelegt, aber z.B. < 4µs) wird das Event ausgelöst (und aus der Liste gelöscht).
(Jetzt kommen wir zu den periodischen Events, die habe ich noch nicht implementiert, da ich noch nicht alles fertig gedacht habe)
Der Unterschied zu den einmaligen Events ist, das ich soviele Events in die Event-Queue (>= 0; die Event-Queue des Schedulers) packe das genau 1 Event >= 62,5ms in der Zukunft liegt.
Warum will ich das so machen?
Die Genauigkeit des Schedulers ist natürlich bescheiden und damit bekomme ich, gerade bei periodischen Events, keine vernünftige langzeit Genauigkeit hin.
Um diesen Umstand zu kaschieren will ich immer genau 1 Event in der Queue der RTC haben, denn diese hat eine sehr gute langzeit Genauigkeit.
Ist dann der Zeitpunkt erreicht, dass das Event (welches in der Event-Queue der RTC steht) an den Scheduler weitergegeben werden muss, dann packe ich wieder soviele Events in die Queue, das genau 1 in der Queue der RTC "landet".
Im Moment nutze ich für die "simulation" periodischer Events noch viele einmalige Events. Das wird noch "schöner" gemacht (irgendwie ;) ).
Das hört sich jetzt alles erstmal komplizierter an als es eigentlich ist. Denn der Code ist eigentlich gar nicht so kompliziert (dank dessen das ich "nur" ein Interface implementiere).
Zum TSC bin ich ebenfalls etwas verwirrt. Meinst Du wirklich das Intel garantiert das der TSC in allen Kernen (auf dem selben Die oder im gesamten System?) synchron ist? Klar kann man alle Kerne auf einem Die auf den selben Zähler lesend zugreifen lassen aber wenn die Kerne mit unterschiedlichen Taktraten laufen und der TSC noch mal nen anderen Takt hat (welchen eigentlich?) dann kommt es doch zu Jitter und anderen Phänomenen (nebst den Latenzen beim Überführen der Zählerwerte in eine andere Takt-Domäne). Wenn der TSC nicht mehr mit der selben Frequenz wie der eigentliche CPU-Kern läuft dann ist er doch für kurze (taktgenaue) Performancemessungen kleiner Code-Abschnitte kaum noch zu gebrauchen, gerade die enge Kopplung dieses Zählers an die tatsächliche Arbeitsgeschwindigkeit der CPU macht ihn dafür so interessant. Im Prinzip hätte Intel den TSC mit diesem Schritt zu einem weiteren globalen Zähler degradiert (davon gibt es doch nun schon mehr als genug). Wenn man schon so einen globalen Zähler möchte dann hätte Intel dafür besser einen neuen erstellen sollen anstatt den TSC seines besonderen Alleinstellungsmerkmales zu berauben.
Also auf dem gleichen Sockel garantiert das Intel auf jeden Fall. Was sie jetzt geändert haben ist, dass sie nicht mehr sagen an welchen Taktgeber der TSC geknüpft ist. Aber meistens wohl die höchste Taktfrequenz mit der die CPU gestartet wird.
Ich bin mir nicht sicher, aber ich glaube das sie sagen, das die Frequenz mind. der höchsten CPU-Frequenz entspricht. Damit kann man doch sehr gut leben.
Dies wurde vorallem auf Grund von MS und Linux so gemacht (da es halt keinen verlässlichen hoch präzisen Counter gab).
Ich finde es so auch besser, macht dir (als OS Programmierer) das Leben leichter. Vorallem ist so ein Counter möglich der auch noch performant umgesetzt werden kann (komplett im Usermode).
-
Ich hab mir das jetzt nicht mehr durchgelesen.
Allerdings habe ich nach dem letzten Kernel-Update mir die Kernelmessages vom Bootvorgang angeschaut:
"Marking TSC unstable due to TSC halts in idle".
Sowohl auf meinem Core2 Duo, als auch auf dem VIA C7.
Gruß,
Svenska
-
Erstmal willkommen zurück aus dem Urlaub.
Also das der VIA C7 keinen konstanten TSC unterstützt habe ich eigentlich erwartet, aber was mit dem Core2Duo ist weiß ich auch nicht.
Eine schnelle Suche per Google hat mich nur soweit gebracht, das es wohl was mit tieferen Schlafmodi (<=C2) zu tun hat und da beeinflusst das mein System nicht und selbst wenn, dann muss ich halt die Anforderungen für den TSC höher setzen.
Ich müsste direkt mal nachgucken wie lange es dauert aus einem Schlafmodi <= C2 wieder raus zukommen, bzw. wie groß die Zeitspanne ist da rein und wieder raus zukommen.
-
Was ich damit nur anmerken wollte, ist, dass der TSC grundsätzlich als "nicht zuverlässig" zu bewerten ist, was meine Ursprungsaussage war. Umkehrschluss heißt, dass die Zeitmessung im Bereich des TSC ungenau ist (was deinem Grundgedanken widerspricht) oder du eine Whitelist über CPUs führen musst, bei denen der TSC stabil ist.
Ich vermute, eine Whitelist wäre kürzer als eine Blacklist. Einen Pentium III Coppermine (Family 6, Model 8, Stepping 10) markiert Linux nicht als "unstable TSC", meinen Core2 Duo T5500 (Family 6, Model 15, Stepping 6) und meinen VIA C7 (Family 6, Model 13, Stepping 0) jedoch schon. Andere Systeme habe ich nicht zum Testen hier.
Hoffe, es hilft dir weiter. Urlaub war herrlich, jetzt kommt der letzte Prüfungshaufen. ;-)
Gruß,
Svenska
-
Was ich damit nur anmerken wollte, ist, dass der TSC grundsätzlich als "nicht zuverlässig" zu bewerten ist, was meine Ursprungsaussage war. Umkehrschluss heißt, dass die Zeitmessung im Bereich des TSC ungenau ist (was deinem Grundgedanken widerspricht) oder du eine Whitelist über CPUs führen musst, bei denen der TSC stabil ist.
Wenn dann wollte ich das sowieso über eine "Whitelist" machen. Interessant das es auf nem P3 noch funktioniert, aber auf nem P3-M leider nicht.
Einen Pentium III Coppermine (Family 6, Model 8, Stepping 10) markiert Linux nicht als "unstable TSC", meinen Core2 Duo T5500 (Family 6, Model 15, Stepping 6) und meinen VIA C7 (Family 6, Model 13, Stepping 0) jedoch schon.
Laut nem Wikipedia-Artikel (nicht das ich dem 100%ig vertraue) steht das dein Core2 Duo eigentlich schon solch einen konstanten TSC haben müsste und laut dem was ich auf die schnelle bei Google gefunden habe, funktioniert der TSC schon, halt nur nicht mehr wenn du in einen Schlafmodi <= C2 gehst und da ist ja der PC schon fast aus ;)
Ich werd dazu mal die Intel Manuels befragen.