std::vector verbraucht ungewöhnlich viel CPU-Auslastung



  • Hallo,

    in einem meiner Programme wird eine Funktion mittels eines Timers 40mal pro Sekunde ausgeführt.
    Leider führt diese Funktion durch Zugriffe auf eine std::vector-Referenz zu einer dauerhaft erhöhten CPU-Auslastung durch das Programm von 30-50% auf einem Dual-Core-Prozessor(2,9GHz pro Core).

    Der Code sieht in etwa so aus:

    vector<int>* vtr;
    vtr=new vector<int>(600);
    
    for(unsigned int i=0;i<600;i++)
    {
        vtr->at(i)=i;
    }
    
    void funktion(void)
    {
      double x;
      for(unsigned int i=0;i<600;i++)
      {
        //wird die folgende Zeile weggelassen, liegt die vom Programm genutzte CPU-Auslastung bei 0-3%
        x=vtr->at(i);
        //x wird danach weiterverarbeitet
      }
    }
    

    Warum verbraucht der Abruf des entsprechenden Vector-Elements soviel CPU-Auslastung?
    1200*40 Berechnungen pro Sekunde dürfte niemals so viel CPU-Auslastung verbrauchen.
    Liegt das Problem evtl da, dass vtr als Referenz definiert wurde und deshalb immer dereferenziert werden muss?



  • Wozu legst du den vector mir new an? oO
    Im Debug Modus kompiliert?
    Sicher dass du at() und nicht operator[] willst?



  • Den vector lege ich mit new an, um einen Zeiger auf den erstellten vector zu erhalten.

    Ja, im Debug-Modus kompiliert.

    Ist at() und [] nicht das Gleiche?



  • Taeli schrieb:

    Den vector lege ich mit new an, um einen Zeiger auf den erstellten vector zu erhalten.

    Du kannst dir auch einfach die Adresse eines std::vector auf dem Stack holen. Unabhaengig davon: Wozu brauchst du den Zeiger ueberhaupt?

    Taeli schrieb:

    Ja, im Debug-Modus kompiliert.

    Da hast du den Grund.

    Taeli schrieb:

    Ist at() und [] nicht das Gleiche?

    Nein. at() fuehrt Range-Checks durch.


  • Mod

    Die Argumentation mit der CPU-Auslastung ist auch irgendwie komisch. Schließlich sollte ein Programm möglichst 100% verbrauchen (oder besser noch mehr, wenn man parallel programmiert), dafür aber eben schneller fertig sein. Wenn das nicht so ist, dann ist das also schlecht. Das dürfste hier am Debugmodus liegen.



  • Stimmt, liegt tatsächlich am Debug-Modus!

    Hätte nicht gedacht, dass da so ein großer Performance-Unterschied zwischen Debug- und Release-Modus ist...

    Vielen Dank für die Hilfe!

    Den Zeiger brauche ich, weil der vector recht viele Elemente enthält und öfters an andere Funktionen als Parameter übergegeben werden soll.



  • SeppJ schrieb:

    Die Argumentation mit der CPU-Auslastung ist auch irgendwie komisch. Schließlich sollte ein Programm möglichst 100% verbrauchen (oder besser noch mehr, wenn man parallel programmiert), dafür aber eben schneller fertig sein. Wenn das nicht so ist, dann ist das also schlecht. Das dürfste hier am Debugmodus liegen.

    Naja, das Problem war ja auch nicht, dass überhaupt die CPU ausgelastet wurde, sondern das Ergebnis, das danach rauskommt.

    Natürlich kann ich eine Variable 500.000 mal mit dem gleichen Wert initialisieren.

    Aber das wäre nicht sinnvoll, weil am Ende das Gleiche rauskommt, als hätte ich die Variable nur einmal initialisiert. Nur die CPU wird beim ersten Fall sehr viel mehr ausgelastet.



  • Mal wieder ein lustige Formulierung: "verbraucht viel CPU-Auslastung". Auslastung verbraucht man in der Regel nicht. Entweder erzeugt das Programm eine hohe CPU-Auslastung oder es verbraucht viel CPU 🙄 .



  • besserwisser schrieb:

    Mal wieder ein lustige Formulierung: "verbraucht viel CPU-Auslastung". Auslastung verbraucht man in der Regel nicht. Entweder erzeugt das Programm eine hohe CPU-Auslastung oder es verbraucht viel CPU 🙄 .

    Ja, das sollte man glaube ich nicht allzu ernst nehmen.
    Man kann ja immerhin auch nicht wirklich Strom "verbrauchen". 😃

    Besser wäre vielleicht zu sagen, das Programm beansprucht CPU-Auslastung für sich.



  • Taeli schrieb:

    Besser wäre vielleicht zu sagen, das Programm beansprucht CPU-Auslastung für sich.

    Die Auslastung ist also immer da, das Programm beansprucht sie nur für sich? Ne ne, das üben wir noch mal. 🤡
    Aber wichtiger:

    Taeli schrieb:

    Den Zeiger brauche ich, weil der vector recht viele Elemente enthält und öfters an andere Funktionen als Parameter übergegeben werden soll.

    Aua. Guck dir dringend mal Referenzen und den Adress-Operator an. (Oder wie das heißt. Der sieht jedenfalls so aus: "&variable", und gibt dir die Adresse einer Variablen.)
    Für den Zweck ist new jedenfalls nicht.



  • cooky451 schrieb:

    Taeli schrieb:

    Besser wäre vielleicht zu sagen, das Programm beansprucht CPU-Auslastung für sich.

    Die Auslastung ist also immer da, das Programm beansprucht sie nur für sich? Ne ne, das üben wir noch mal. 🤡

    Naja egal, ich glaube so langsam weiß jetzt jeder was damit gemeint ist... 🙂

    Aber ist new nicht eigentlich dafür da, während der Laufzeit dynamisch Speicher zu reservieren und die Adresse des dynamisch angelegten Speicher zurückzugeben?

    Etwa wie hier:

    int size=3;
    int* a[size];
    //Gibt einen Fehler
    
    int* a=new int(size);
    //ok
    


  • Taeli schrieb:

    Aber ist new nicht eigentlich dafür da, während der Laufzeit dynamisch Speicher zu reservieren und die Adresse des dynamisch angelegten Speicher zurückzugeben?

    Doch schon, aber so wie du benutzt man es nicht. Die Adresse einer Variablen bekommst du mit & (oder du nutzt gleich Referenzen), egal wie die Variable angelegt wurde. Hier ist new absolut überflüssig. (Und ganz ganz schlechter Stil.) new benutzt du auch so gut wie nie, und wenn, dann in Kombination mit einem RAII Objekt wie std::unique_ptr. Nur ohne new könnten die Standardcontainer (vector, list, ..) eben halt nicht funktionieren. Aber jede Ebene darüber wird es vermeiden.



  • Taeli schrieb:

    int size=3;
    int* a[size];
    //Gibt einen Fehler
    
    int* a=new int(size);
    //ok
    

    warum gibt das erste nen Fehler? Du erstellst ein Array auf dem Stack mit 3 int*. beim zweiten erstellst du ein int auf dem heap mit dem Wert 3. Das sind zwei verschiedene Dinge.



  • Cyres schrieb:

    Taeli schrieb:

    int size=3;
    int* a[size];
    //Gibt einen Fehler
    
    int* a=new int(size);
    //ok
    

    warum gibt das erste nen Fehler? Du erstellst ein Array auf dem Stack mit 3 int*. beim zweiten erstellst du ein int auf dem heap mit dem Wert 3. Das sind zwei verschiedene Dinge.

    error C2057: Konstanter Ausdruck erwartet
    error C2133: 'a': Unbekannte Größe
    error C2466: Zuordnung eines Arrays der konstanten Größe 0 nicht möglich.



  • Taeli schrieb:

    [...] Dual-Core-Prozessor (2,9GHz pro Core).

    wow, das sind dann ja ~ 5,8 GHz!!
    Heißt das, meine zwei Hexacore Xeons mit 4,25 GHz pro Core haben dann ~ 51 GHz? 😃



  • Taeli schrieb:

    error C2057: Konstanter Ausdruck erwartet
    error C2133: 'a': Unbekannte Größe
    error C2466: Zuordnung eines Arrays der konstanten Größe 0 nicht möglich.

    Vielleicht solltest du mal lesen, was da steht.. 🙄



  • Nymer schrieb:

    Vielleicht solltest du mal lesen, was da steht.. 🙄

    Hat er. Aber du und Cyres sollten das noch mal üben. Auch wenn in dem Beispiel Schönheitsfehler sind (er meinte int a[size] statt int* a[size] und new int[size] statt new int(size)), passt es dennoch zu seiner Aussage kann man sich zusammen mit seiner Aussage zumindest zusammenreimen, was er meinte.



  • Uebergib den vector einfach per Referenz:

    void foo(vector<int>& v)
    {
        ...
    }
    
    ...
    
    vector<int> v;
    foo(v);
    

    Mit Zeiger wuerde es so funktionieren:

    void foo(vector<int>* v)
    {
        ...
    }
    
    ...
    
    vector<int> v;
    foo(&v);
    


  • Taeli schrieb:

    Besser wäre vielleicht zu sagen, das Programm beansprucht CPU-Auslastung für sich.

    Entschuldigt, aber ich kann nicht anders. Das ist doch wirklich zu köstlich.

    Ich habe 2 Formulierungen vorgeschlagen, aber Du schlägst wieder so eine Stilblüte vor. Die Auslastung ist nicht einfach da und das Programm beansprucht sie für sich, sondern die CPU-Auslastung wird erst vom Programm erzeugt. Ist das so schwer zu verstehen?

    Es ist so wie mit einem Parkplatz. Ich kann einen Parkplatz beanspruchen, aber wenn der Parkplatz gerade belegt ist, dann kann ich nicht diese Belegung für mich beanspruchen.

    Na mich wundert nicht, dass Du das mit den Zeigern auch nicht verstehst. Irgendwie passen die Probleme zusammen.



  • Kellerautomat schrieb:

    Uebergib den vector einfach per Referenz:

    void foo(vector<int>& v)
    {
        ...
    }
    
    ...
    
    vector<int> v;
    foo(v);
    

    Wär ein Start-End Iteratoren-Paar nicht schöner? 🤡



  • Nein.


Anmelden zum Antworten