Busywait CPU Auslastung verringern



  • Hallo zusammen

    Ich entwickle einen Chip8-Emulator in C/C++, mit SDL2 und wxWidgets.
    Das Ganze funktioniert auch recht gut, allerdings habe ich ein kleines Schönheitsproblem: Damit die Taktzeit genau bleibt, polle ich in einer Schleife SDL_GetPerformanceCounter() (https://wiki.libsdl.org/SDL_GetPerformanceCounter) als Busywait bis die Zeit abgelaufen ist.
    Damit ist die CPU Auslastung (eines Kerns) praktisch auf 100%.
    Die originale (was ich im Netz dazu gefunden habe) Taktfrequenz des Emulators ist 540Hz, sprich knappe zwei Millisekunden soll zwischen den einzelnen Takten gewartet werden. Ausserdem habe ich eine Option eingebaut, mit der sich diese Frequenz um einen Faktor ändern lässt, in beide Richtungen, die Zeit kann sich also auch in den Mikrosekundenbereich verlagern..
    Problem ist, dass ein Normales SDL_Delay() -> (Sleep() in der Winapi) in Millisekunden funktioniert, und idr deutlich länger als 1ms benötigt, falls ich für eine ms warten will.
    Es ist mir bewusst dass ich unter Windows keine genaue Zeit via Sleep() warten kann. Gibt es eine andere Möglichkeit, wie sich die CPU Last reduzieren lässt, ohne dass ich (nennenswerte) Genauigkeit verlieren würde?

    Grüsse

    XXXBold

    Für diejenigen dies interessiert, das Projekt befindet sich hier: https://github.com/XXXBold/Chip8Emulator



  • Es ist überhaupt nicht nötig, das der Emulator mit genau der Geschwindigkeit läuft. Wichtig ist nur, das du alle Ein- und Ausgaben im richtigen Moment rein/rausgibst sie können aber vorher oder danach auch noch ein Queue kommen. Beispiel du drückst ein Taste und auf dem Bildschirm erscheint dann irgendwann dieser Buchstabe. Man muss jetzt nicht jeden Takt des Emulators super langsam abarbeiten, sondern sich erstmal in irgendeiner Message die Tasten mit Zeitstempel abspeichern (also z.B. bei WM_KEY). Dann muss man nur noch früh genug vor der Ausgabe den Emulator loslaufen lassen um alle Takte vor der Bildschirmausgabe zu schaffen, das kann ruhig auch früher sein, dann speichert man die Bildschirmausgabe einfach zwischen, bis sie benötigt wird z.B. indem man DoubleBuffering mit VSync macht.



  • @TGGC

    Danke für deine Antwort.

    Es ist mir bewusst und auch so implementiert, der Bildschirm wird (ungefähr) anhand dessen Frequenz (bei mir 60Hz) aktualisiert (Also, die Anzeige des Emulators), zugleich wird auch die Tastatur via SDL_GetKeyState abgefragt und die Eingaben gespeichert.
    Der Takt in dem der Emulator, also in dem die Instruktionen abgearbeitet werden (eben die 540Hz), ist ein eigener Thread, der muss sehr wohl genau laufen, ansonsten sieht das Ganze extrem zäh aus (=läuft merkbar langsamer ab) als es eigentlich sollte.

    Edit: Ah, da war ich wohl zu vorschnell. Ich glaub ich weiss was du meinst. Du würdest also quasi rechnen, wieviele Takte zwischen dem aktualisieren des Monitors ausgeführt werden müssen, führst diese (ohne Verzögerung) hintereinander aus und schläfst dann bis zum VSync, danach wieder dasselbe, hab ich das so ungefähr richtig verstanden?



  • Ja genau, das wäre zum Beispiel eine Idee. Auf was genau man wartet ist eigentlich egal, du könntest genauso gut "sleep(10)" machen und dann berechnen wieviel Takte du nach den 10ms aufholen musst. Je nachdem was du machen willst ist das schon gut genug, aber es kommt so natürlich zu einem 10ms Lag bei gewissen Dingen. Daher kann man dann eben gegenarbeiten und sich mit was sinnvollen synchronisieren wie dem VSync.


Log in to reply