Kann mir mmap "in den fuß schießen"?



  • Hi,

    Ich habe eine Matrix der Größe nxn wobei n quasi beliebig groß sein kann. Das heißt diese Matrix kann gut und gerne nur 1GB groß sein, aber auch 256GB oder 1TB.

    Ich wollte das jetzt mithilfe von mmap lösen, also das ich eine Datei anlege, die auf die richtige Größe skaliere und sie dann in den Speicher mappe. Danach berechne ich die Matrix, speicher sie in dem Bereich und arbeite von da an nur noch lesend (eventuell muss ich hinterher nochmal die komplette matrix mit anderen Parametern neu berechnen).

    Der Gedanke ist, dass, wenn ich nur 1GB brauche, alles super in den Speicher passt, aber wenn nicht ich dann die Festplatte als erweiterten Arbeitsspeicher(aka swap) automatisch verwenden kann.

    Das funktioniert auch. Nun hier die Frage: muss ich im 1GB-Fall einen nennenswerten Performanceeinbruch erwarten? Das bei unmap alles in die Datei geschrieben wird, ist okay, auch wenn ich das nicht brauche. Aber wird der Zugriff auf den Speicher während der Berechnung langsamer?



  • Wenn ich mich recht erinnere, bleibt bei diesem Vorgehen die Festplatte nicht mehr stehen, weil er alle Idle-Zeit damit verbringt, veränderte Seiten rauszuschreiben, selbst wenn alles ins Ram passen würde.

    Aber die bleibt eh nicht stehen, wenn nicht alles ins Ram passt. Und wenn alles passt, wird nur geschrieben, was dank DMA kostenlos ist, es gibt keine Verzögerung durch verlangsamtes Lesen.

    edit: Ach nein, sorry. Das Dauerschreiben war unter Windows. Wie Linux damit umgeht, weiß ich nicht.



  • otze schrieb:

    Hi,

    Ich habe eine Matrix der Größe nxn wobei n quasi beliebig groß sein kann. Das heißt diese Matrix kann gut und gerne nur 1GB groß sein, aber auch 256GB oder 1TB.

    Ich wollte das jetzt mithilfe von mmap lösen, also das ich eine Datei anlege, die auf die richtige Größe skaliere und sie dann in den Speicher mappe. Danach berechne ich die Matrix, speicher sie in dem Bereich und arbeite von da an nur noch lesend (eventuell muss ich hinterher nochmal die komplette matrix mit anderen Parametern neu berechnen).

    Der Gedanke ist, dass, wenn ich nur 1GB brauche, alles super in den Speicher passt, aber wenn nicht ich dann die Festplatte als erweiterten Arbeitsspeicher(aka swap) automatisch verwenden kann.

    Das funktioniert auch. Nun hier die Frage: muss ich im 1GB-Fall einen nennenswerten Performanceeinbruch erwarten? Das bei unmap alles in die Datei geschrieben wird, ist okay, auch wenn ich das nicht brauche. Aber wird der Zugriff auf den Speicher während der Berechnung langsamer?

    verwende halt anonymes Mapping, dann gibts keine Datei in die zurückgeschrieben wird.
    Und mmap macht das, was man erwartet: es ordnet deinem Prozess virtuellen Speicher zu. Der Zugriff auf diesen Speicher ist genauso schnell/langsam wie wenn du dir Speicher mit new/delete holst und dann darauf zugreist.
    Letztlich ist ja new wahrscheinlich auch nur mit mmap implementiert (früher über sbrk).



  • mmaper schrieb:

    verwende halt anonymes Mapping, dann gibts keine Datei in die zurückgeschrieben wird.

    Wenn mir das helfen würde, würde ich new verwenden. Ich brauche das Filebacking, weil ich in vielen Fällen nicht genug RAM habe, aber das ist a-priori nur zu bestimmten, wenn ich weiß, wieviel RAM mein restliches programm braucht und wieviel insgesamt zur Verfügung steht. Mir ist nicht geholfen, wenn ich erstmal checken muss, wieviel Speicher ich noch allokieren darf. Das tolle an mmap ist, dass es nicht mit new/malloc kollidiert. wenn new speicher anfordert und nicht mehr genug da ist, dann werden die pages deallokiert und in die Datei geschrieben und ich muss mich um _nichts_ kümmern.



  • mmap sollte genauso schnell wie normaler Speicherzugriff sein, wenn die Daten im RAM liegen. Früher gab es da mal einen Context-Switch, mittlerweile gibt es das Problem nicht mehr.

    Das Problem mit dem andauernden Ins-File-Schreiben während der Festplatten-Idle-Time (siehe volkard) gibt es, kann aber mit MAP_NOSYNC ausgeschaltet werden. Dann gibt es noch Unter Linux gibt es noch madvice, damit kannst du "mmap-Cache-Misses" minimieren. Hab aber keine Erfahrung, wie viel du dir davon erhoffen kannst.



  • SO, ich habe mir inzwischen selbst die Frage beantwortet:

    Kann mir mmap "in den fuß schießen"?

    Experiment mit einer 10000x10000 Matrix
    ohne mmap: 98s
    mit mmap: 221s

    => ja 😞

    Eventuell sieht ja jemand den Fehler(ohne störende Fehlerbehandlung):

    int createFile(std::size_t size, std::string const& filename){
    	std::size_t memorySize = size*size * sizeof(Qfloat);
    
    	//create kernel file
    	int fileDescriptor = open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600);
    
    	//stretch file to the desired size
    	lseek(fileDescriptor, memorySize-1, SEEK_SET);
    
    	return fileDescriptor;
    }
    
    float* mapFile(std::size_t size, int fileDescriptor){
    	std::size_t memorySize = size*size * sizeof(float);
    	//map file to memory
    	return (float*) mmap(0, memorySize, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, 0);
    }
    
    //...
    std::size_t n = 10000
    int fileDescriptor = createFile(n,"matrix.cache");
    float* memory = mapFile(n,fileDescriptor);
    
    //nun die matrix füllen...
    

    Am Anfang läuft alles wie gewohnt, nach ca 60% der Berechnung zeigt mir top an, dass die CPU zu weniger als 10% belastet ist und die Festplatte fängt an zu rödeln. Ram ist selbstverständlich noch frei, also gibt es keinen Grund zu warten 😞



  • Hast du meinem Post gelesen und schonmal MAP_NOSYNC probiert?



  • mappus schrieb:

    Hast du meinem Post gelesen und schonmal MAP_NOSYNC probiert?

    gibts nicht unter linux und ist auch nicht teil des posix standards. Leider.

    //edit scheints nur unter freeBSD zu geben.



  • Stackoverflow hat mein Problem gelöst!

    http://stackoverflow.com/questions/19358421/performance-degradation-when-using-mmap

    DIe Antwort war, dass das vm-subsystem so konfiguriert werden muss, dass es eher im Hintergrund swappt und den Prozss nicht so früh für writes stoppt. Ich halte das generell für ein sinnvolles setting auch abseits von meinem Problem.


Anmelden zum Antworten