Timed Semaphore in linux



  • Wenn Du Fragen stellst, dann solltest Du auch Deinen Stand erwähnen. Die erste Antwort war eigentlich ein 100%-Treffer.

    Q: Ich möchte von A nach B fahren. Wie mache ich das?

    A: Nimm doch das Auto.

    Q: Auto kennen ich schon, aber meins springt nicht an. Eigentlich wollte ich wissen, wer mein Auto reparieren kann.

    Du willst doch eigentlich wissen, warum sem_timedwait CPU verbraucht.



  • tntnet schrieb:

    Du willst doch eigentlich wissen, warum sem_timedwait CPU verbraucht.

    Entweder das, oder eben eine alternative Lösung. Ich hab allerdings noch nicht den Rückgabewert von sem_timedwait bzw. errno geprüft. Das sollte ich vielleicht auch mal noch machen.

    Fakt ist aber, dass ne Semaphore, die Last macht, keinen Sinn macht 😉



  • Wie gross ist denn dein Timeout, wie stellst du sicher, dass 3% vom sem_timedwait kommen, welchen Prozessor hast du ... ?

    Poste ein minimales Testprogramm, das das Verhalten zeigt!



  • knivil schrieb:

    Wie gross ist denn dein Timeout, wie stellst du sicher, dass 3% vom sem_timedwait kommen, welchen Prozessor hast du ... ?

    Das Timeout ist 1ms.

    Sicher gestellt habe ich das, indem ich ersatzweise usleep verwendet habe. Zudem hab ich eben ausgeschlossen, dass die Semaphore signalisiert wird.

    Es handelt sich bei dem Projekt um eine etwas kompliziertere Serverkonstruktion, aber ich versuche mal ein minimalbeispiel zu erzeugen.

    Aber wenn ihr euch SICHER seid, dass sem_timedwait KEINE Last machen darf,dann weiß ich zumindest, dass der Fehler nicht im PC sondern davor sitzt 😉



  • Aber wenn ihr euch SICHER seid, dass sem_timedwait KEINE Last machen darf,dann weiß ich zumindest, dass der Fehler nicht im PC sondern davor sitzt

    Selbstverstaendlich darf Last erzeugt werden, beispielsweise wenn die Zeitangabe zu klein ist und mit einem Spincount auf die Freigabe gewartet wird. Das ist aber implementationsspezifisch.



  • It0101 schrieb:

    knivil schrieb:

    Wie gross ist denn dein Timeout, wie stellst du sicher, dass 3% vom sem_timedwait kommen, welchen Prozessor hast du ... ?

    Das Timeout ist 1ms.

    Sicher gestellt habe ich das, indem ich ersatzweise usleep verwendet habe. Zudem hab ich eben ausgeschlossen, dass die Semaphore signalisiert wird.

    Es handelt sich bei dem Projekt um eine etwas kompliziertere Serverkonstruktion, aber ich versuche mal ein minimalbeispiel zu erzeugen.

    Aber wenn ihr euch SICHER seid, dass sem_timedwait KEINE Last machen darf,dann weiß ich zumindest, dass der Fehler nicht im PC sondern davor sitzt 😉

    Wie hast Du denn festgestellt, dass innerhalb der einen Millisekunde die CPU Last, die Dein Prozess erzeugt 3% ist? Ich denke das ist sehr schwierig, das zu messen und eine qualifizierte Aussage zu treffen. Ich kann mir auch kaum vorstellen, dass sem_timedwait CPU-Last während der Wartezeit erzeugt.

    Mach doch einfach mal ein minimales Programm, welches ein sem_timedwait über beispielsweise 10 Sekunden ausführt und dann schaust Du mal, ob das Programm CPU verbraucht hat.



  • Naja ich habe die Applikation im "top" gesehen. Mit "usleep" an gleicher Stelle war das eben genau nicht der Fall. Das ist auch bisher mein einziger Anhaltspunkt.

    Vielleicht war ich da auch mit meiner Diagnose zu voreilig...


  • Mod

    top ist kein Tool zum Programmprofiling.



  • Ich habs jetzt etwas näher beleuchtet.

    Ich habe die Semaphore falsch benutzt, denn die verlangt keine relative Zeit, sondern eine absolute fuer ihr TimeOut. Aus meiner Sicht völlig behämmert, da es gefühlte x-Mio Zeitbibliotheken gibt...

    errno liefert den Wert 110 ( ETIMEDOUT ).

    Das bedeutet laut manual, dass die absolute Zeit bereits vergangen ist, wenn ich
    sem_timedwait aufrufe.

    Ich berechne das absolute Timeout jetzt folgendermaßen:

    unsigned int uiTimeOut = unsigned( waittime );   // timeout in msec
    
    			struct timespec CurrentTime;
    			clock_gettime( CLOCK_REALTIME, &CurrentTime );
    
    			struct timespec TimeOut = CurrentTime;
    			TimeOut.tv_nsec += uiTimeOut * 1000000;
    			TimeOut.tv_sec += TimeOut.tv_nsec  / 1000000000;
    			TimeOut.tv_nsec %= 1000000000;
    
    			std::cout << CurrentTime.tv_sec << " " << CurrentTime.tv_nsec << std::endl;
    			std::cout << TimeOut.tv_sec << " " << TimeOut.tv_nsec << std::endl;
    
    			int res = sem_timedwait( &hSem, &TimeOut );
    

    Der Fehlercode tritt aber immer noch auf. Nehme ich die falsche Zeitbibliothek? Sind meine Berechnungen falsch?



  • Der Fehlercode ist scheinbar in Ordnung. Die Timeoutzeit passt jetzt. Hab es mal mit 10sec und mal 500ms versucht und beide Wartezeiten passen jetzt.



  • It0101 schrieb:

    Der Fehlercode ist scheinbar in Ordnung. Die Timeoutzeit passt jetzt. Hab es mal mit 10sec und mal 500ms versucht und beide Wartezeiten passen jetzt.

    Errno ist nur gültig, wenn sem_timedwait auch -1 zurückgegeben hat. Ist das der Fall?



  • Ansonsten guck dir doch einfach die Manpage (man 3 sem_wait) an. Da ist auch Beispielcode für sem_timedwait inklusive Errorhandling zu finden.



  • kotnascher schrieb:

    It0101 schrieb:

    Der Fehlercode ist scheinbar in Ordnung. Die Timeoutzeit passt jetzt. Hab es mal mit 10sec und mal 500ms versucht und beide Wartezeiten passen jetzt.

    Errno ist nur gültig, wenn sem_timedwait auch -1 zurückgegeben hat. Ist das der Fall?

    Ja. sem_timedwait liefert nachwievor -1 und der errorcode ist 110. Er wartet aber jetzt korrekt die gewünschte Zeit ( wenns kein Signal gibt ). Wie das mit dem Errorcode zusammenpasst, ist mir auch noch nicht ganz klar.



  • Ich habe jetzt mal mein "Problem" reduziert.

    Gebaut unter Kubuntu 12.10 im Release mit g++ und O3

    #include <semaphore.h>
    #include <errno.h>
    #include <sys/time.h>
    #include <iostream>
    
    int main( int argc, char **argv )
    {
    	sem_t hSem;
    	sem_init( &hSem, 0, 0 );
    	long waittime = 1;
    
    	while ( true )
    	{
    		struct timespec CurrentTime;
    		clock_gettime( CLOCK_REALTIME, &CurrentTime );
    		struct timespec TimeOut = CurrentTime;
    		TimeOut.tv_nsec += waittime * 1000000;
    		TimeOut.tv_sec += TimeOut.tv_nsec  / 1000000000;
    		TimeOut.tv_nsec %= 1000000000;
    		int res = sem_timedwait( &hSem, &TimeOut );
    		//std::cout << "Semaphore result: " << res << " " << errno << std::endl;
    
    	}
    	sem_destroy( &hSem );
    	return 0;
    }
    

    Ausgabe habe ich mal bei 1000ms ausgeben lassen, und da ist res = -1 und errno = 110 ( TIMEOUT ).
    Bei 1000ms liegt keine Last vor. Ab 10ms ist sie fuer "top" messbar, mit fallender Wartezeit steigt die Last.

    Nachwievor macht das System auch in der Form "Last" ( top ) was ich so nicht erwarten würde. Insbesondere wenn man mehrere Threads von der Sorte hat, addiert sich die Last.

    Mach ich hier noch was falsch?
    liegts an meiner Hardware? ( bescheidenes AMD DualCore Notebook )
    liegts am Linux? ( Kubuntu 12.10 )
    liegts am Compileprozess? ( besondere Flags notwendig )



  • Was genau ist das Problem?

    for (;;)
         usleep(10);
    

    erzeugt bei mir auch 6% CPU-Last.



  • semiprof schrieb:

    Was genau ist das Problem?

    for (;;)
         usleep(10);
    

    erzeugt bei mir auch 6% CPU-Last.

    1. Hast du schonmal mit 10 Threads gearbeitet? Ich jedenfalls würde das gern 😉

    2. Unter Windows macht ein 1ms Wait mit der Semaphore keine Last, selbst 10 wartende Threads sind dort nicht messbar. Ich erwarte, dass Linux das genauso hinbekommt.

    Es muss dafür ne bessere Lösung geben. Ich bin schließlich nicht der einzige der unter Linux mehrere Threads betreiben will, bzw. es tut.

    Vielleicht kann ich auch meine Konstruktion so umbauen, dass die wartende Semaphore nicht notwendig ist.

    Es handelt sich bei meinen Threads im wesentlichen um Sockethandler. D.h. die beschäftigen sich mit select, accept, recv und send.

    Insbesondere bei den Threads, die Sockets lesen sind natürlich längere Wartezeiten nicht akzeptabel, da sie die Latenz in die Höhe schrauben. Es ist in dem Fall so, dass dieser besagte Thread nicht nur auf ein recv wartet sondern auch auf serverinterne Messages aus einer Queue.

    Die Semaphore soll auch nur dann warten, wenn der Thread nichts zu tun hatte ( nichts received und auch nichts aus der internen Queue verarbeitet ).



  • It0101 schrieb:

    Es muss dafür ne bessere Lösung geben. Ich bin schließlich nicht der einzige der unter Linux mehrere Threads betreiben will, bzw. es tut.

    Das Problem ist, das deine Lastmessungen utter crap sind. (Wie Linus sagen würde)
    Es gibt da tausend versteckte Effekte, z.B. taktet Linux die CPU runter, wenn nichts gemacht wird.

    Nochmal ein Vergleich (10ms, 100000 Durchgänge):

    semaphore-wait      : 0.54s user 1.06s system 16% cpu 9.709 total
    usleep              : 0.11s user 1.42s system 15% cpu 9.527 total
    usleep+clock_gettime: 0.51s user 1.03s system 15% cpu 9.753 total
    

    usleep ist genauso lahm wie semaphore. Folgt daraus, dass usleep ein Busy-Wait ist?

    It0101 schrieb:

    1. Hast du schonmal mit 10 Threads gearbeitet? Ich jedenfalls würde das gern 😉

    Hast du schonmal mit 10 Threads einen Unterschied gemessen? Nicht %CPU sondern absolut?

    Nein? Dann mach bevor du irgendwelchen Mist in fehlerhafte Messungen reininterpretierst.


  • Mod

    Ich habe es schon einmal gesagt und ich sage es noch einmal:

    SeppJ schrieb:

    top ist kein Tool zum Programmprofiling.

    Nimm einen Profiler, wenn du wissen möchtest, wie viel CPU-Last dein Programm wirklich erzeugt.



  • Das ist mir schon klar, aber wenn ich 10 Threads starte und dort zehnmal immer 1ms warten lasse, dann habe ich eben 10 x 2% = 20% CPU-Last.

    Irgendwann entkräftet sich auch dein Argument mit dem Profiler. 20% Last, selbst wenn sie "nur" von "top" gemeldet werden, kann man wohl nicht mehr wegdiskutieren und wenn in Wirklichkeit tatsächlich keine Last vorliegt, aber "top" 20% anzeigt, dann muss irgendwann einfach mal zu der Erkenntnis kommen, dass Linux doch nicht so der Oberbrüller ist.



  • It0101 schrieb:

    Es muss dafür ne bessere Lösung geben. Ich bin schließlich nicht der einzige der unter Linux mehrere Threads betreiben will, bzw. es tut.

    Vielleicht kann ich auch meine Konstruktion so umbauen, dass die wartende Semaphore nicht notwendig ist.

    Es handelt sich bei meinen Threads im wesentlichen um Sockethandler. D.h. die beschäftigen sich mit select, accept, recv und send.

    Insbesondere bei den Threads, die Sockets lesen sind natürlich längere Wartezeiten nicht akzeptabel, da sie die Latenz in die Höhe schrauben. Es ist in dem Fall so, dass dieser besagte Thread nicht nur auf ein recv wartet sondern auch auf serverinterne Messages aus einer Queue.

    Die Semaphore soll auch nur dann warten, wenn der Thread nichts zu tun hatte ( nichts received und auch nichts aus der internen Queue verarbeitet ).

    Dein Konzept ist falsch. Es macht keinen Sinn auch nur kurz zu warten. Entweder der Thread hat was zu tun oder er wartet, dass er was zu tun bekommt. Und wenn er wartet, dann sollte es kein Busy-Wait sein und auch kein ein wenig Busy-Wait indem Du nur mal immer kurz wartest, so wie Du es versuchst.

    Dein Thread soll also auf Daten vom Socket und gleichzeitig auf eine Semaphore warten. Das geht so nicht. Du kannst unter Linux/Unix auf mehrere Sachen Warten, wenn es Filedeskriptoren sind. Dann kannst Du mit select oder poll (oder unter Linux epoll) auf Ereignisse warten. Der Thread kann dann mit einem unendlichen Timeout warten. Er wird dann erst geweckt, wenn wirklich was zu tun ist.

    Das löst man normalerweise so, dass man in den select oder poll neben dem Socket-Deskriptor noch eine Pipe dazu packt. Wenn ein anderer Thread dann dem Thread eine Nachricht schicken will, schreibt er in die Pipe und unterbricht das Warten. Der wartende Thread kann dann darauf reagieren.

    Wenn Du dann 10 oder 100 oder 1000 Threads hast, die alle auf select oder poll warten, dann erzeugt das keine Last.


Anmelden zum Antworten