SFML CPU-Auslastung



  • Hi,

    ich verstehe nicht, warum ein Kern hier zu 100% ausgelastet wird?

    int main(int argc, char *argv[])
    {
      sf::Window window(sf::VideoMode(800, 450, 32), "Test", 
        sf::Style::Close, sf::WindowSettings(24, 8, 0));
      window.UseVerticalSync(true);
      window.SetFramerateLimit(60);
    
      while (window.IsOpened())
      {
        for (sf::Event event; window.GetEvent(event); )
        {
          if (event.Type == sf::Event::Closed)
            window.Close();
        }
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        window.Display();
      }
      return 0;
    }
    

    Eigentlich sollte doch sogar UseVerticalSync() reichen? Gibt es da denn nichts anderes als sf::Sleep()?
    Lustigerweise werden die FPS korrekt begrenzt, aber die CPU-Auslastung sinkt trotzdem nicht.

    Edit:
    Zum Verständnis: sf::Sleep() hat leider eine recht geringe Auflösung, sodass ich 125 statt gewünschten 120 FPS bekomme wenn ich mir das selbst baue. (Wobei SetFramerateLimit() wahrscheinlich auch nur sf::Sleep() nutzt.. 🙄 )
    Wie auch immer, das reicht zwar für die CPU-Last, aber VerticalSync kann man so vergessen. Weiß jemand warum das nicht funktioniert?



  • Hm.
    Bin kein OpenGL Experte, aber vielleicht gibt es immer noch Video-Treiber deren OpenGL Implementierung VSync nicht korrekt unterstützt?
    Oder vielleicht macht die SFML diesbezüglich was falsch?

    Bei so spezifischen Problemen würde ich einfach mal im SFML Forum nachfragen.



  • Hm.. ich glaube nicht, dass das was mit OpenGL zu tun hat, das müsste eigentlich Windows-Zeugs sein. (SwapBuffers oder so)
    Werde mal da im Forum fragen.



  • Hallo,

    deine Frage lässt sich sehr einfach beantworten. Du durchläufst deine while-Schleife und hast keinen Stop/Sleep mit eingebaut. Das Programm durchläuft die Schleife immer und immer wieder. Das führt zu einer 100% CPU Last.

    Baue z.B. einen Sleep-Befehl ein, der 0 ms oder 1 ms den Thread anhält. Dann fällt die CPU-Last weit runter. Max. 99%

    Gruß, Thomas



  • Hallo,

    bitte erst den Beitrag richtig lesen, dann antworten. (Und sich vorher fragen was man unter Vertikaler Synchronisation versteht.

    (Und das berühmt berüchtige Windows-Sleep mit seiner 15ms Auflösung kannst du hier wohl total vergessen. :))


  • Mod

    cooky451 schrieb:

    Hallo,

    bitte erst den Beitrag richtig lesen, dann antworten. (Und sich vorher fragen was man unter Vertikaler Synchronisation versteht.

    kannst du daraus bitte die stelle quoten die irgendwas mit cpu auslastung zu tun hat? hoere ich hier zum ersten mal.



  • rapso schrieb:

    kannst du daraus bitte die stelle quoten die irgendwas mit cpu auslastung zu tun hat? hoere ich hier zum ersten mal.

    Ich würde erwarten, dass gängige Betriebssysteme bei swap() mit aktiviertem VSync kernelgesteuert warten.
    Wobei Hustbär's Vermutung korrekt sein könnte, da ich DirectX Programme über Treiber zu CPU-entlastendem VSync zwingen kann, OpenGL Programme aber nicht.



  • Probiere vielleicht mal SFML2. Wenn ich bei mir VSync einschalte geht die CPU-Auslastung stark zurueck.



  • Macht auch Sinn. VSync bremst dein Programm ja absichtlich ein wenig ab. Wenn du es volle Möhre durchbrettern lässt, ist es für mich nicht unlogisch, dass es auf 100% CPU Auslastung hinausläuft. Zumindest bei einer Anwendung wie deiner, wo die Grafikkarte fast nicht beansprucht wird und du somit CPU-Limitiert bist (Dafür läufts halt dann mit 1000 oder 10000 FPS anstatt mit 60).

    edit: Wobei ich mir grad nicht sicher bin, ob Vsync nicht einfach komplett auf der Grafikkarte läuft. Dann wäre das ganze natürlich Müll 🙂



  • VSync läuft afaik parallel, d.h. nach einem swap befehl wartet nur die grafikkarte, nicht dein programm. Halte ich für sinnvoll, weil ein "erzwungener" sleep in deinem Programm, obwohl die zeit gerne für etwas anderes verwenden würdest, wär ja doof. Ich hab das nur in der Kombination SDL/OpenGL so gelesen, denke aber bei SFML/OpenGL sollts nicht anders sein.



  • Ich muss zugeben, dass ich nicht weiß wie VSync implementiert ist, aber die Argumentation mit "die Zeit für etwas anderes nutzen" halte ich für nicht sinnvoll. Man macht schließlich alles vor dem Swap() und nicht danach. Und irgendwann muss VSync ja warten, oder es werden ohne Ende Frames verworfen, was irgendwie auch nicht sinnvoll ist.



  • Nach dem Swap ist vor dem Swap - und man macht unbedingt eben nicht "alles" vor dem swap - z.B. schonmal daten von der platte in den ram laden und dekomprimieren ist etwas, was man gerne macht BEVOR die Daten gebraucht werden, um so Ladezeiten zu verhindern. Kann man dann ja (scheibchenweise) machen, während man "alles" fertiggemacht hat und auf den swap vom vsync wartet.
    Schlimmer wirds noch, wenn man die framerate wegen zu anspruchsvollen berechnungen nicht ganz einhalten kann - wenn vsync da wieder wartet und mein programm blockiert rechnet es nicht nur zu langsam, sondern idlet auch noch (im schlimmsten Fall fast 50% der Zeit)

    vsync ist dazu da tearing zu verhindern, nicht um das spiel zu verlangsamen. Ich versteh nicht, warum man sich als Programmierer unbedingt unvermeidbare Nebeneffekte einkaufen wollen würde.



  • KTM schrieb:

    Ich versteh nicht, warum man sich als Programmierer unbedingt unvermeidbare Nebeneffekte einkaufen wollen würde.

    🙂



  • Hallo cooky451,

    nur ein Timer hat unter Windows die 15ms Grenze, nicht aber ein Sleep.
    Mach mal wie vorgeschlagen ein Sleep(0) oder Sleep(1) am Ende deiner Schleife rein...



  • Ich muss doch bitten, zumindest den Eingangspost zu lesen.

    cooky451 schrieb:

    Zum Verständnis: sf::Sleep() hat leider eine recht geringe Auflösung, sodass ich 125 statt gewünschten 120 FPS bekomme wenn ich mir das selbst baue. (Wobei SetFramerateLimit() wahrscheinlich auch nur sf::Sleep() nutzt.. 🙄 )
    Wie auch immer, das reicht zwar für die CPU-Last, aber VerticalSync kann man so vergessen. Weiß jemand warum das nicht funktioniert?

    So viel zu sf::Sleep(). Und zur Auflösung des Windows-Sleep: (abgesehen davon, dass ich SFML und OpenGL nur nutze um plattformunabhängig zu bleiben..)
    http://www.c-plusplus.net/forum/269324

    KTM schrieb:

    Nach dem Swap ist vor dem Swap

    Ganz genau und deshalb sehe ich auch keinen Sinn darin, etwas nach Swap() zu machen. Das kommt auf's Selbe raus. Allerdings muss ich dir zum Blockieren recht geben, es scheint wirklich sinnvoller, Swap() direkt zurückkehren zu lassen. Ich frage mich nur, warum Microsoft das bei DirectX anders macht.



  • cooky451 schrieb:

    Ich muss doch bitten, zumindest den Eingangspost zu lesen.

    cooky451 schrieb:

    Zum Verständnis: sf::Sleep() hat leider eine recht geringe Auflösung, sodass ich 125 statt gewünschten 120 FPS bekomme wenn ich mir das selbst baue. (Wobei SetFramerateLimit() wahrscheinlich auch nur sf::Sleep() nutzt.. 🙄 )
    Wie auch immer, das reicht zwar für die CPU-Last, aber VerticalSync kann man so vergessen. Weiß jemand warum das nicht funktioniert?

    So viel zu sf::Sleep(). Und zur Auflösung des Windows-Sleep: (abgesehen davon, dass ich SFML und OpenGL nur nutze um plattformunabhängig zu bleiben..)
    http://www.c-plusplus.net/forum/269324

    Edit:

    Ähm, mit einer #define kannst du doch denn Befehl für Windows, Linux, BSD, .... implementieren. Ansonsten, boost ist dein Freund
    http://www.boost.org/doc/libs/1_47_0/doc/html/thread/thread_management.html#thread.thread_management.this_thread.sleep
    this_thread.sleep oder this_thread.yield

    Zu V-Sync:
    Die Implementation hängt vom Framework ab. Jeder Implementiert es anders. Meistens wartet nur die Grafikkarte und die CPU berechnet meist schon den nächsten Durchlauf. Ich habe auch schon eine Implementation mit busy-wait gesehen. Ala

    while (true)
    {
      if (vsync_nextFrame())
        break;
    }
    

    Eine Implementation von dieser Art verursacht ebenfalls eine 100% CPU Last.


  • Mod

    was soll ein treiber denn auch anderes machen als entweder einen wait spin oder ein sleep aufrufen?
    windows arbeitet nunmal auf timeslice basis und es ist auch kein echtzeit OS, was der "system idle process" bekommt ist also in der granularitaet zwischen 10ms und 15ms auf dem default setting und wer will schon, dass ein treiber bei 16ms frametime bis 15ms ans OS abgibt?



  • rapso schrieb:

    was soll ein treiber denn auch anderes machen als entweder einen wait spin oder ein sleep aufrufen?

    Der Treiber legt den Thread schlafen, und weckt ihn in einem Hardware-Interrupt wieder auf. (Genauer: im DPC, der im Interrupt-Handler angefordert wurde, kommt aber auf's selbe raus)

    windows arbeitet nunmal auf timeslice basis und es ist auch kein echtzeit OS, was der "system idle process" bekommt ist also in der granularitaet zwischen 10ms und 15ms auf dem default setting und wer will schon, dass ein treiber bei 16ms frametime bis 15ms ans OS abgibt?

    Ja, das gilt so lange keine Threads über Interrupts aufgeweckt werden.

    Deine Argumentation könnte man so auch auf 1000 andere Dinge anwenden. Wenn man das konsequent weiterdenkt, würde es bedeuten dass auch IO über SATA oder Ethernet mit "busy waiting" läuft, da die IOs viel weniger als 10ms dauern, und man ja keine Zeit verschenken will. Was definitiv nicht so ist.


  • Mod

    hustbaer schrieb:

    rapso schrieb:

    was soll ein treiber denn auch anderes machen als entweder einen wait spin oder ein sleep aufrufen?

    Der Treiber legt den Thread schlafen, und weckt ihn in einem Hardware-Interrupt wieder auf. (Genauer: im DPC, der im Interrupt-Handler angefordert wurde, kommt aber auf's selbe raus)

    das ist kein echtzeit OS, ein interrput triggert sofort einen haendler, ja, aber diese sets nur einen thread auf aktiv, erst der scheduler wird diesen wieder rechenzeit geben. Das ist keine bessere granularitaet als ein sleep

    windows arbeitet nunmal auf timeslice basis und es ist auch kein echtzeit OS, was der "system idle process" bekommt ist also in der granularitaet zwischen 10ms und 15ms auf dem default setting und wer will schon, dass ein treiber bei 16ms frametime bis 15ms ans OS abgibt?

    Ja, das gilt so lange keine Threads über Interrupts aufgeweckt werden.

    Deine Argumentation könnte man so auch auf 1000 andere Dinge anwenden. Wenn man das konsequent weiterdenkt, würde es bedeuten dass auch IO über SATA oder Ethernet mit "busy waiting" läuft, da die IOs viel weniger als 10ms dauern, und man ja keine Zeit verschenken will. Was definitiv nicht so ist.

    obwohl seit WDM das viel weniger geworden ist (z.b. laufen die SATA IO ueber ein memory mapped bereich und der sata controller kuemmert sich selbst drum alles zu kopieren, es gibt nicht millionen interrupts/s damit man bei den winzigen caches trotzdem 500MB/s verschieben kann), kann es einen flip interrupt geben, aber genau so kann es ueber eine memory map laufen. ein device kann seinen "treiber-thread" schlafen legen bis ein interrupt kommt, dieser wird aber ebenfalls nur einen haendler aufrufen der den "treiber-thread" auf aktiv setzt.
    du kannst dir vorstellen dass interrupt haendler in kritisch kurzer zeit ablaufen muessen und es ne menge davon geben kann, wenn einer zu lange laufen wuerde oder zu hohe priority hat, verschluckt das OS eventuell ankommende interrupts. Das soll nicht sein, und deswegen das umstaendliche system.
    wenn du sound streams, kann es sein, dass es ein buffer swap noch als haendler gibt, der flagt dann aber den "mixer thread" den leeren buffer nachzufuellen, ich glaube nicht, dass ein aufwendiges mixen im haendler passieren wuerde.

    Entsprechend weiss ich nicht, wie ein haendler der sofort zurueck kommen soll, mehr machen koennte als ein notify+active an einen wartenden driver thread vergibt. ich bezweifle ernsthaft, dass aus einem interrupt ein user-space thread anfaengt zu laufen, am scheduler vorbei, der ja die system time verteilen sollte.


Anmelden zum Antworten