ubuntuusers.de

Sehr hohe CPU Auslasung für den Server. Warum???

Status: Ungelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

Njutik

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo!

Ich habe einen Server, der einen MPEG1 Videostream an 2 Empfänger streamt. Während des Streamens braucht der Server so um die 9% der CPU Rechenleistung. Wenn das versenden der Daten abgeschlosen ist und der Server eigentlich nur noch auf weitere Clientanfragen warten sollte, steigt sein Verbrauch der CPU Leistung auf 80% - 97% an. Ich habe mir bei der Systemüberwachung diesen Prozess angesehen und festgestellt, dass er sich beim Streamen der Daten im Zustand "sleep" befindet, eben dann, wenn er die 9% der Rechenleistung benötigt. Wenn aber das Streamen vorbei ist, wechlelt er in den Zustand "running" und benötigt dann um die 90% der Leistung. Dieser Zustand dauert ungefähr eine Minute. Danach scheint der Server wirklich nur auf die ankommende Clientanfrage zu warten, denn sein Verbrauch der CPU Rechenleistung sinkt auf unter 1%.

Jetzt meine Frage: woran kann das liegen??? Ist es so, dass der Server nach dem Streamen sein Sendepuffer reinigen muss und parallel auf die Clientanfragen wartet? Was kann es noch für Ursachen geben? Kann ich irgendetwas tun, um diesen enorm hohen CPU Verbrauch zu reduzieren?

Als Server verwende ich die OpenSource Libraries von www.live555.com. Ich habe zwar die Quellcodes von "live555mediaServer" (so heißt der Server) studiert, aber da ich ziemlich neu in der C/C++ Programmierung bin und die Codes wahnsinnig komplex sind, bin ich nicht weit gekommen.

Wäre super, wenn jemand mir helfen könnte.

liebe Grüße

Anna

oxe1976

Anmeldungsdatum:
5. Februar 2008

Beiträge: 759

Hallo,

schoen das Du schon weitergekommen bist mit Deinem Projekt... ☺.

Kenne mich mit den Libraries jetzt nicht so aus, aber hast Du vielleicht schon mal daran gedacht gprof zu verwenden um zu schauen wo die Rechenzeit verbraten wird?

Oder halt im Debugger mal anhalten wenn die CPU Last hoch ist und Dir den Stack anzeigen lassen, vielleicht geben Dir die Funktionsnamen Aufschluss darueber was gerade passiert.

Vielleicht hilft es Dir ja weiter ...

Gruss

Hello_World

Anmeldungsdatum:
13. Juni 2006

Beiträge: 3620

Kompiliere Dein Programm mit Debugging-Informationen (-g) und hänge Dich dann mit gdb an den Prozess. Das sollte Aufschluss darüber geben, wo der Prozess gerade steht.

Njutik

(Themenstarter)

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo oxe1976!

Danke für den Tip. Ich denke, gprof ist genau das Tool, das mir helfen könnte. Das Problem ist nur, ich weiss nicht, wie ich es zum Laufen bringe.

Also, diese LIVE555 codes bestehen aus haufenweise Verzeichnissen und Unterverzeichnissen und fast in jedem ist ein Makefile drin. Um die Codes zu bauen, musste ich ganz am Anfang

1
./genMakefiles linux

ausführen und dann einfach

1
make

eingeben. Das nur so zur Info.

Ich habe hier ein "Tutorial" für gprof gefunden: http://74.125.77.132/search?q=cache:-ByNpxMrA6oJ:linuxgazette.net/100/vinayak.html+gprof+Linux+Tutorial&hl=de&ct=clnk&cd=1&gl=de

Dort steht: How to gather profiling information ?? The source code has to be compiled with the -pg option ( also with -g if you want line-by-line profiling ). If the number of lines in the Make file is small you can append these options to each compilation command. However if the number of compilation commands is large then you can define/redefine the CFLAGS/CXXFLAGS parameter in the makefile and add this to every compilation command in the makefile. I will demonstrate the use of gprof using the gnu make utility. Unpack the gzipped tarball $ tar zxf make-3.80.tar.gz $ cd make-3.80 Run the configure script to create the makefiles $ ./configure [configure output snipped] Edit the CFLAGS parameter in the makefile generated to remove optimization flags and add -pg to CFLAGS. GCC optimization flags are removed as compiler optimization can sometimes cause problems while profiling. Especially if you are doing line-by-line profiling, certain lines may be removed while optimizing source code. Build the source code $ make [build output snipped] We can use this make to build other software such as Apache, lynx and cvs. We build apache using this make as an example. When we untar, configure and run make on the source of Apache , a file called gmon.out containing profiling information is generated. You may observe that make may run slower than expected as it is logging the profile data. An important thing to be remembered while collecting profile data is that we have to run the program giving it the inputs we give it normally and then exiting when it is all done. This way you would have simulated a real-world scenario to collect data.

Daraufhin habe ich die config.linux-Datei geöffnet und das -pg eigefügt. Meine jetzige config.linux-Datei sieht jetzt so aus:

COMPILE_OPTS =		$(INCLUDES) -I. -O2 -pg -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
C =			c
C_COMPILER =		cc
C_FLAGS =		$(COMPILE_OPTS)
CPP =			cpp
CPLUSPLUS_COMPILER =	c++
CPLUSPLUS_FLAGS =	$(COMPILE_OPTS) -Wall -DBSD=1
OBJ =			o
LINK =			c++ -o
LINK_OPTS =		-L.
CONSOLE_LINK_OPTS =	$(LINK_OPTS)
LIBRARY_LINK =		ld -o
LIBRARY_LINK_OPTS =	$(LINK_OPTS) -r -Bstatic
LIB_SUFFIX =			a
LIBS_FOR_CONSOLE_APPLICATION =
LIBS_FOR_GUI_APPLICATION =
EXE =

Die -pg Option habe ich gleich in die erste Zeile eingefügt.

So. Dann habe ich wieder

./genMakefiles

aufgerufen und dann

make

. Laut dem Tutorial soll jetzt ein binäres File da sein, dass ich mit

gprof make gmon.out > name.txt

in eine für Menschen lesbare Datei umwandeln kann, wo dann drin steht, welche Funktion wieviel Zeit braucht.

Nur gibt es bei mir die Datei gmon.out nicht. Wird nicht erzeugt. Woran kann das liegen?

@Hello World!

An gdb hatte ich auch gedacht, aber hier brauche ich wirklich zu wissen, welche Funktion wieviel Zeit benötigt und das kann mir gdb doch nicht sagen. Danke aber für den Tip.

liebe Grüße

Anna

oxe1976

Anmeldungsdatum:
5. Februar 2008

Beiträge: 759

Hallo,

das mit -pg war schonmal richtig. Aber nimm lieber das debug config file: config.linux-gdb. Entsprechend:

./genMakefiles linux-gdb

Dann darauf achten das wirklich alles neu gebaut wird (make clean?).

Jetzt bekommst Du ein Serverprogramm (denke ich doch das der make Prozess ein Programm generiert das Du dann startest, oder?) das profiling informationen erzeugen kann, wenn es denn laeuft. Wenn das Programm durchgelaufen ist bekommst Du ein gmon.out file. Ich denke das der Serverprocess aber korrekt durchlaufen muss (vernuenfig beenden, nicht abschiessen oder so) damit dieses file erzeugt wird. In dem File stehen halt informationen drin wie oft jede Funktion aufgerufen wurde und wieviel Zeit dabei verbraten wurde. Aber Achtung: Das mit -pg uebersetzte Programm ist insgesamt um einiges langsamer als ein optimiertes (ohne -pg ...) Programm.

Jetzt kannst Du die Infos in lesebare Form bringen:

gprof <server-programm> <gmon.out>  > profile.txt

Um es besser zu verstehen empfehle ich dir ein kleines Hello-World-Programm (profTest.C) zu machen in der Du das ganze ausprobiert:

g++ profTest.C -g -pg -o profTest.exe
./profTest.exe   ;# Programm tut irgendwas (wenn moeglich ein paar Funktionsaufrufe etc.)

# jetzt muesste gmon.out da sein
gprof ./profTest.exe gmon.out > profile.txt
cat profile.txt

Gruss

Njutik

(Themenstarter)

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo oxe1976!

Ok, also wird dieses Outputfile erst generiert, wenn das Programm ordnungsgemäß abgeschlossen wurde. Daran arbeite ich gerade. Denn dieser LIVE555-Server wurde von den Entwicklern so konzipiert, dass er bis in alle Ewigkeiten läuft und kann erst mit CTRL-C gewaltsam beendet werden. Jetzt versuche ich die Stelle im Code zu finden, wo ich das ändern kann. Und das wird dauern...

Danke Dir erstmal für Deinen Tip!

liebe Grüße

Anna

oxe1976

Anmeldungsdatum:
5. Februar 2008

Beiträge: 759

Hallo,

Du kannst relativ einfach das CTRL-C im Server abfangen und dann sauber beenden. Suche dafuer die main() Funktion und fuege ziemlich am Anfang folgendes ein:

int main(...) {

   ...
   signal(SIGINT,  myExit); /* Ctrl+C-Interrupt */
   ...

Im gleichen File dann myExit als Funktion:

static void myExit(int par) 
   signal(SIGINT, SIG_IGN);
   cerr << "Abbruch" << endl;
   exit(0);
}

Nun wird das Programm bei einem Ctrl-C einigermassen sauber verlassen.

Gruss

Njutik

(Themenstarter)

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo oxe1976!

Danke Dir nochmal, dass Du hilfsbereit bist und immer so schnell antwortest.

Ich habe jetzt die von Dir vorgeschlagene Methode implementiert, alles gebaut, es läuft alles, aber wenn ich dann auf CTRL-C drücke und den Server stoppe, wird trotzdem keine Profilsammeldatei generiert. Vielleicht habe ich es an falscher Stelle abgelegt?

Die Struktur von meinem Server sieht so aus. im Verzeichnis /live sind die ganzen config-Dateien, die Haupt-Makefile-Datei, sowie zahlreiche Unterverzeichnisse, wo die ganzen Test-, Anwendungs- und Unterprogramme sind. Um den Server zum Laufen zu bringen muss ich in diesem /live-Verzeichniss

./genMakefiles linux

aufrufen und dann alles mit make bauen. Die Option -pg habe ich auch in dieses Makefile integriert. So. Der Server (live555MediaServer) befindet sich im Unterverzeichnis von /live, nämlich in /mediaServer. Dort gibt es auch eine Makedatei. Ich habe da mal geschaut und das -pg war dort auch mit drin, nachdem ich es in das Hauptmakefile geschrieben und dieses gebaut habe.

In dem Programm live555MediaServer.cpp ist die main-Funktion drin, die den Server startet. In diese Main-funktion habe ich Deine vorgeschlagene Funktion integriert, gespeichert, sowohl in /mediaServer, als auch in /live make ausgeführt und den Server gestartet. Der läuft jetzt deutlich langsamer, aber das würde mir ja nichts ausmachen, wenn diese Profilsammeldatei da wäre, wenn ich dann nach ein paar Minuten auf CTRL-C gehe. Aber die Datei erscheint nicht. Weder im /mediaServer noch im /live. Ich habe auch bei ./genMakefiles nicht linux, sondern linux-gdb eingegeben, aber das nützte nichts.

Jetzt habe ich folgende Idee. Vielleicht muss ich die Funktionen doch nicht in der main-Funktion direkt eingeben, sondern tiefer in die Materie hineindringen. Wenn ich nämlich mit ./live555MediaServer den Server starte, bringt er mir ein paar allgemeine Infos auf den Bildschirm, was ich alles beachten muss und welche Formate er unterstützt. Wenn er damit fertig ist, ruft er die Funktion doEventLoop() auf, die in einem ganz anderen Verzeichnis implementiert ist und die dann ein Objekt der Klasse RTSPServer erzeugt, die Sockets generiert, bind(), listen(), usw. ausführt und dann letztendlichdie Dateien streamt. Diese doEventLoop() liefert nie einen Ausgabewert. Daher läuft der Server ewig (so zumindest der schichte Kommentar im Programm). Vielleicht muss ich Deine Funktionen einfach irgendwo in der doEventLoop() Funktion unterbringen? Hast Du da eine Meinung?

liebe Grüße

Anna

oxe1976

Anmeldungsdatum:
5. Februar 2008

Beiträge: 759

Hi,

ich denke in main() sollte es reichen. Es wird mit signal() im Prinzip ein Signalhandler registriert der aufgerufen wird wenn das Signal CTRL-C bei Deiner Anwendung ankommt. Eigentlich sollte gmon.out im Verzeichnis erstellt werden wo Du den Server gestartet hast (working directory).

Vielleicht habe ich morgen mehr Zeit, dann schau ich mir das live Zeugs mal genauer an.

Ersteinmal Gruß

oxe1976

Anmeldungsdatum:
5. Februar 2008

Beiträge: 759

Hi, hab doch nochmal kurz reingesehen ☺.

Es fehlt das -pg auch bei den link optionen (linux-gdb):

...
LINK_OPTS =		-pg -L.
...

Dann bekomme ich ein gmon.out. Hoffe Du kannst damit was anfangen ...

Übrigens: Der Vorteil wenn es nicht immer so auf Anhieb klappt ist, daß man wenigstens einen Lerneffekt hat.

Wenn Du Probleme mit dem Callgraph hast ... sag bescheid.

Gruß

Njutik

(Themenstarter)

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo oxe1976!

Danke Dir für Deinen Tip. Langsam komme ich mir ziemlich blöd vor, weil es scheinbar so einfach ist, dieses gprof zu implementieren und ich schaffe es immer noch nicht. Was mache ich bloß falsch???

Also, meine Datei config.linux-gdb sieht jetzt folgendermaßen aus:

COMPILE_OPTS =		$(INCLUDES) -I. -O -DSOCKLEN_T=socklen_t -pg -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
C =			c
C_COMPILER =		cc
C_FLAGS =		$(COMPILE_OPTS)
CPP =			cpp
CPLUSPLUS_COMPILER =	c++
CPLUSPLUS_FLAGS =	$(COMPILE_OPTS) -Wall -DBSD=1
OBJ =			o
LINK =			c++ -o
LINK_OPTS =		-pg -L.
CONSOLE_LINK_OPTS =	$(LINK_OPTS)
LIBRARY_LINK =		ld -o
LIBRARY_LINK_OPTS =	$(LINK_OPTS) -r -Bstatic
LIB_SUFFIX =			a
LIBS_FOR_CONSOLE_APPLICATION =
LIBS_FOR_GUI_APPLICATION =
EXE =

Nachdem ich dieses -pg auch bei LINK_OPTS eigefügt habe (gespeichert natürlich auch) führe ich folgendes aus:

make clean
./genMakefiles linux-gdb
make

Dann kompiliert und linkt er eine Weile und dann bekomme ich folgende Fehlermeldung:

ld: unrecognized option '-pg'
ld: use the --help option for usage information
make[1]: *** [libliveMedia.a] Fehler 1
make[1]: Verlasse Verzeichnis '/home/anna/live_test/liveMedia'
make: *** [liveMedia/libliveMedia.a] Fehler 2

Warum erkennt er das nicht? Fehlt mir irgendein Paket?

Ich habe auch versucht, diese -pg Option nicht bei config.linux-gdb, sondern einfach bei config.linux bei den LINK_OPTS eizufügen. So. Dann habe ich

make clean
./genMakefiles linux
make

ausgeführt und die gleiche Fehlermeldung wie oben erhalten. Weisst Du zufällig woran das liegen kann?

Wenn ich die Änderung bei LINK_OPTS bei config.linux-gdb ausführe, dann aber einfach

make clean
./genMakefiles linux
make

ausführe, kommt zwar keine Fehlermeldung, aber auch nirgendwo eine gmon.out-Datei.

liebe Grüße

Anna

oxe1976

Anmeldungsdatum:
5. Februar 2008

Beiträge: 759

Hm,

komisch, bin gerade auf einen anderen Rechner und bekomme die gleiche Fehlermeldung wie Du (ld: unrecognized option '-pg'). Kann jetzt nicht sagen warum es gestern funktioniert hat, kann ich erst heute abend wieder rein schauen.

Habs jetzt aber auch hier hinbekommen, hier am besten meine komplette config.linux-gdb:

COMPILE_OPTS =		$(INCLUDES) -I.  -DSOCKLEN_T=socklen_t -g -pg -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
C =			c
C_COMPILER =		cc
C_FLAGS =		$(COMPILE_OPTS)
CPP =			cpp
CPLUSPLUS_COMPILER =	c++
CPLUSPLUS_FLAGS =	$(COMPILE_OPTS) -Wall -DBSD=1
OBJ =			o
LINK =			c++ -o
LINK_OPTS =	        -L.
CONSOLE_LINK_OPTS =	-pg $(LINK_OPTS)
LIBRARY_LINK =		ld -o
LIBRARY_LINK_OPTS =	$(LINK_OPTS) -r -Bstatic
LIB_SUFFIX =			a
LIBS_FOR_CONSOLE_APPLICATION =
LIBS_FOR_GUI_APPLICATION =
EXE =

Gruss

Antworten |