Autor Thema: Konzept für periodische Events  (Gelesen 28655 mal)

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« 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
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 22. April 2010, 21:22 »
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.
« Letzte Änderung: 22. April 2010, 22:20 von FlashBurn »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 22. April 2010, 22:14 »
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

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 22. April 2010, 22:28 »
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
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 22. April 2010, 22:38 »
Zitat von: Svenska
...hat man mit einem 100 Hz-PIC wenigstens eine konstante, streng monotone Zeitquelle.
Bitte PIT, da ansonsten Verwirrung gestiftet wird ;)

Zitat von: Svenska
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 ;)

Zitat von: erik
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.

Zitat von: erik
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.

Zitat von: erik
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).
« Letzte Änderung: 22. April 2010, 22:45 von FlashBurn »

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 22. April 2010, 22:53 »
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
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 22. April 2010, 23:00 »
Zitat von: 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!).

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 22. April 2010, 23:42 »
Zitat von: Svenska
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

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 23. April 2010, 08:17 »
Zitat von: 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.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 23. April 2010, 11:31 »
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.
Dieser Text wird unter jedem Beitrag angezeigt.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 23. April 2010, 13:58 »
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).

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 23. April 2010, 14:18 »
Zitat von: Svenska
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ß)

Zitat von: Svenska
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.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 23. April 2010, 15:50 »
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

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 23. April 2010, 16:22 »
Zitat von: 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.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 23. April 2010, 21:51 »
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.

Zitat von: Svenska
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
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 23. April 2010, 22:25 »
Zitat von: 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.

Zitat von: erik
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?

Zitat von: erik
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).

Zitat von: erik
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) :(

Zitat von: erik
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).

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 24. April 2010, 03:23 »
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

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 24. April 2010, 08:52 »
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.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 25. April 2010, 16:19 »
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.


Zitat von: 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.
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
Reality is that which, when you stop believing in it, doesn't go away.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 25. April 2010, 17:10 »
Zitat von: 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.

Zitat von: erik
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 ;) ).

Zitat von: erik
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)?

Zitat von: erik
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.

 

Einloggen