Anzeige:
Ergebnis 1 bis 6 von 6

Thema: Systemgrenzen???

  1. #1
    Registrierter Benutzer
    Registriert seit
    02.07.2004
    Beiträge
    456

    Systemgrenzen???

    Hallo Leute,

    ich hab hier ein Programm, das eine Gruppe "Teilnehmer" simuliert. Also es werden haufenweise Sockets geöffnet und Dateien hin und her geschoben. Jeder Teilnehmer hat so bis zu 4 Filehandles zeitgleich offen.

    Erst konnte ich zwischen 250 und 300 Teilnehmer simulieren, bis socket() mir sagte, daß zuviele Filehandles offen sind. Das Limit hab ich erhöht auf 4096. Jetzt kann ich immer noch nur zwischen 250 und 300 Teilnehmern simulieren, bis accept() mit Fehler zurück kommt. accept() liefert mir dann "Resource temporarily unavailable" auf seinem Socket zurück.

    Kann mir jemand sagen, woran das liegen kann? Gibt es noch irgendwelche Begrenzungen für socket() mit SOCK_DGRAM?

    Ist äußerst wichtig für mich! Ich muss das Problem hier bis Freitag gelöst haben.

  2. #2
    Registrierter Benutzer
    Registriert seit
    25.10.2004
    Beiträge
    819
    Womit hast du das Limit erhöht? ulimit -n?

  3. #3
    Registrierter Benutzer
    Registriert seit
    02.07.2004
    Beiträge
    456
    mit setrlimit im Programm selbst, mit Anpassungen in der limits.h des Kernels etc... wenn ich ein Dummy-Programm schreibe, das stumpf Sockets aufmacht, sagt mir das nach 4093 Sockets, daß Sense ist. Aber mit der Fehlermeldung "Too many open files" oder so ähnlich. Nicht mit "Resource temporarily unavailable".

    In dem Zustand, wo accept letztgenannte Fehlermeldung liefert, hat mein Programm laut dem Befehl

    Code:
    ls -l /proc/PID/fd |wc -l
    was bei 1033 Filehandles geöffnet. Es sollte also noch massig Platz sein. Trotzdem gibt mir accept() letztgenannten Fehler zurück, obwohl der FD, den accept() als Serversocket (1. Argument) kriegt, gültig ist.

    btw: Kernel ist linux-2.6.7

  4. #4
    Registrierter Benutzer
    Registriert seit
    02.07.2004
    Beiträge
    456
    Ich habe jetzt ein kleines Dummy Programm geschrieben, das einen Server Socket aufmacht und 4096 Verbindungen dahin aufzubauen versucht (Parent Prozess macht Server, Child macht die 4096 Verbindungen dahin).

    Da sagt mir dann Select nach dem 1024. akzeptierten Client, daß Schluss ist, mit der Fehlermeldung "Bad File Descriptor".

    Im Anhang mal das Dummy Programm... nicht ganz fehlerfrei, sollte aber demonstrieren, was ich meine.

    EDIT: also da habe ich jetzt heraus gefunden, daß es an der maximalen Anzahl Filehandles pro fd_set (1024) für Select liegt. Wie kann man diese Grenze effektiv erhöhen?

    EDIT: kann mir desweiteren jemand erklären, wie man poll() benutzt, bzw. zeigen, wo ich detailierte Informationen über die Benutzung finde? Mit Codebeispielen wenn möglich. Danke
    Geändert von 7.e.Q (20-09-2005 um 11:13 Uhr)

  5. #5
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Bei poll() legst du ein Array von polldf Strukturen an und übergibst das mit dern Anzahl der benutzen Elemente.

    poll() liefert dir dann die Anzahl der aktivierten Elemente zurück, aber ändert dein Array nicht, d.h. du gehts dann dann das Array durch und überprüfst die Elemente deren revents != 0 sind.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  6. #6
    Registrierter Benutzer
    Registriert seit
    02.07.2004
    Beiträge
    456
    Hi Leute,

    ich wollte euch nur mitteilen, daß die Umstellung auf poll() das Problem gelöst hat. Ich bin auf folgende Hürden gestoßen, die es zu umschiffen galt:

    Erstmal war es notwendig, wie schon gesagt, die maximalen Filehandles pro Prozess anzuheben. Dazu reichte es, mit setrlimit() das entsprechende Feld zu setzen

    Code:
    		struct rlimit rl;
    		rl.rlim_cur = 4096;
    		rl.rlim_max = 8192;
    
    		setrlimit(RLIMIT_NOFILE, &rl);
    Ob jetzt rlim_cur und rlim_max gleich sein sollten oder nicht, hab ich nicht getestet. Es funktioniert so, wie es hier steht, und das reicht mir.

    Das nächste war die Umstellung von select() auf poll() selbst. Dazu hab ich drei Funktionen und ein statisches Array angelegt. Das Array besteht aus einer Menge Elementen vom Typ struct pollfd, entsprechend der gesetzten Anzahl in rlim_cur. Anfänglich wurden von mir alle Filehandles in diesem Array (Feld 'fd' der Struktur pollfd) auf -1 gesetzt, um sie für poll() zu deaktivieren. Die Funktionen dienen nun dazu, Filehandles in diesem Array zu aktivieren und entsprechende Überwachungs-Flags (z.B. POLLIN, POLLOUT) zu setzen, bzw. zu deaktivieren/löschen. Eine dritte Funktion fragt das Element eines Arrays anhand des Filehandles auf ein bestimmtes Überwachungs-Flag ab.

    Code:
    	int inline Poll(int interval)
    	{
    		int retval = ::poll(poll_handles, fd_max+1, interval);
    		return retval;
    	}
    
    	void inline AddToFDSet(SHANDLE fd, int mode) // fd = FileHandle, mode = POLLIN/POLLOUT
    	{
    		poll_handles[fd].fd = fd;
    		poll_handles[fd].events |= mode; // Flag setzen
    	}
    
    	void inline RmFromPollFDs(SHANDLE fd, int mode) // fd = FileHandle, mode = POLLIN/POLLOUT
    	{
    		poll_handles[fd].events = (poll_handles[fd].events & ~mode); // Flag ausschalten
    		if(poll_handles[fd].events == 0) // Wenn alle Flags in events gelöscht werden, kann auch das fd entfernt werden (Funktionalität deaktiviert)
    		{
    			poll_handles[fd].fd = -1; // fd deaktivieren
    		}
    	}
    
    	bool inline IsPollMode(SHANDLE fd, int mode) // FileHandle auf Flag abfragen
    	{
    		if( ( poll_handles[fd].revents & mode ) == mode)
    			return true;
    
    		return false;
    	}
    Das nächste war, die Funktionen auf Performance zu trimmen. Anfänglich hatte ich für jedes neue FD zuerst einen Schleifendurchlauf auf dem Array gemacht, um nach dem ersten Element zu suchen, dessen Feld 'fd' auf -1 steht, welches also frei war. Da habe ich dann das neue Filehandle eingehängt. Das war sehr zeitaufwändig. Dann habe ich das so gemacht, daß das Filehandle einfach an der Stelle im Array eingehängt wird, die seinem Wert entspricht. Das ist wesentlich performanter. Auch if-Abfragen gingen gehörig auf die Systemlast, weshalb ich sie auf eine reduziert habe.

    fd_max ist ein Wert, der in einer anderen Funktion jeweils auf das bisher höchste genutzte Filehandle gesetzt wird. Dies war aber Funktionalität, die bei select() bereits vorhanden war. Ich konnte sie direkt übernehmen.

    Achtung, einer der Fehler, die ich gemacht habe war, ein Flag mit dem Operator ^= löschen zu wollen. Da es sich dabei um ein Exklusiv-Oder handelt, war der Effekt immer der, daß das Flag zwar deaktiviert wurde, wenn es aktiviert war, jedoch wurde es auch immer aktiviert, wenn es zu dem Zeitpunkt deaktiviert war - was logischerweise sehr nervige Effekte nach sich zog. Der Einsatz des Operators &= mit dem bitweisen Komplement ~ des zu löschenden Flags erzielte den gewünschten Effekt.



    Vielleicht helfen diese Ausführungen einigen, die mit den selben Problemen zu kämpfen haben. Tatsache ist, in einem Standard-Linux (LFS) ist select() hart begrenzt auf 1024 Filehandles. Dabei scheint es egal zu sein, auf welchen Wert man rlim_cur/rlim_max setzt und auch, auf welche maximale Größe man FD_Sets aufbohrt. Bei 1024 war bei mir Schluss.

    Die Poll-Lösung ist genau so performant, jedoch nicht auf diese 1024 Handles begrenzt.

    Danke allen für ihre Hilfe bei diesem Problem.

    Viele Grüße,
    Hendrik
    Geändert von 7.e.Q (29-09-2005 um 13:20 Uhr) Grund: Fehler im beschriebenen Code

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •