Zitat von: 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).Zitat von: erik
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).
Zitat von: erik
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
).Zitat von: erik
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:
Code: [Auswählen]
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();
Zitat von: erik
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.
Zitat von: erik
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?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!
Das synchronisieren der TSCs ist völliger Blödsinn, um die als Stoppuhr zu benutzen braucht man sie nicht zu synchronisieren.
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.

Übersicht
Wiki
Hilfe
Suche
Einloggen
Registrieren
Drucken

Gespeichert