Schneller speichern und laden



  • Ich suche nach einer Möglichkeit Daten schneller zu speichern. Denn ich finde über 100sec sind ein bisschen zuviel für 96MB.

    Mein Code zum Speichern:

    void World::save(std::ofstream& file)
    {
    	unsigned int tmp;
    
    	for(unsigned int i = 0; i < 512; i++)
    	{
    		for(unsigned int j = 0; j < 512; j++)
    		{
    			for(unsigned int k = 0; k < 128; k++)
    			{
    				tmp = this->get_ID(i, j, k);
    
    				file.put((unsigned char) (tmp >> 8));
    				file.put((unsigned char) tmp);
    				file.put((unsigned char) ((this->get_Sub_ID(i, j, k) << 2) | this->get_direction(i, j, k)));
    			}
    		}
    	}
    }
    

    Laden:

    void World::open(std::ifstream& file)
    {
    	char *chr = new char[3]();
    
    	for(unsigned int i = 0; i < 512; i++)
    	{
    		for(unsigned int j = 0; j < 512; j++)
    		{
    			for(unsigned int k = 0; k < 128; k++)
    			{
    				file.read(chr, 3);
    
    				this->set_ID(i, j, k, (chr[0] << 8) | chr[1], (chr[2] >> 2) & 63, chr[2] & 3);
    			}
    		}
    	}
    
    	delete chr;
    }
    

    Wenn irgendwelche Infos fehlen, einfach bescheidsagen...



  • Alles im RAM vorbereiten und dann komplett schreiben - oder zumindest in 1 - 10 MB Chunks.



  • Wie geht das?



  • Speicher reservieren, reinlesen, Daten interpretieren? ^^

    void blubb(std::istream& stream)
    {
      std::vector<char> buf(0x10000);
      stream.read(buf.data(), buf.size();
      // stream.gcount() sagt dir wie viel gelesen wurde
    }
    


  • ok. danke und schneller speichern?



  • Na das selbe. Daten vorbereiten und in dann auf ein mal schreiben.



  • Guck erstmal ob es nicht an deinen get_ID()/set_ID() Funktionen liegt.
    z.B. mal so porbieren:

    void World::save(std::ofstream& file)
    {
        unsigned int tmp = 0;
    
        for (unsigned int i = 0; i < 512; i++)
        {
            for (unsigned int j = 0; j < 512; j++)
            {
                for (unsigned int k = 0; k < 128; k++)
                {
                    tmp ^= this->get_ID(i, j, k);
                    tmp ^= this->get_Sub_ID(i, j, k);
                    tmp ^= this->get_direction(i, j, k);
                }
            }
        }
    
        file.put((unsigned char) (tmp >> 24));
        file.put((unsigned char) (tmp >> 16));
        file.put((unsigned char) (tmp >>  8));
        file.put((unsigned char) (tmp >>  0));
    }
    

    Das wird die Geschwindigkeit sein die du maximal erreichen kannst. Wenn das schon zu langsam ist, dann musst du erstmal get_ID/get_Sub_ID/get_direction optimieren.


  • Mod

    100 s für 96 MB? Da ist klingt falsch. Flusht (z.B. durch ein endl) du zwischendurch versehentlich? Bei mir schreibe ich diese Datenmenge in deutlich weniger als 10 Sekunden, ebenfalls mit sehr komplexen Formatierungen



  • SeppJ schrieb:

    100 s für 96 MB? Da ist klingt falsch. Flusht (z.B. durch ein endl) du zwischendurch versehentlich? Bei mir schreibe ich diese Datenmenge in deutlich weniger als 10 Sekunden, ebenfalls mit sehr komplexen Formatierungen

    put macht afair ein je ein lock. Das könnte echt aufs Gemüse gehen.



  • ich will ja auch nicht nach jedem byte flushen, aber wie mache ich das am besten?

    Edit:

    Kleiner Fortschritt: Nur noch 78 sec mit folgendem Code:

    void World::save(std::ofstream& file)
    {
    	unsigned int tmp;
    	Block_Container* block;
    	Chunk* chunk;
    	vector<char> buf(196608);
    
    	for(unsigned int ci = 0; ci < 64; ci++)
    	{
    		for(unsigned int cj = 0; cj < 64; cj++)
    		{
    			for(unsigned int ck = 0; ck < 16; ck++)
    			{
    				chunk = &this->chunks[ci][cj][ck];
    
    				for(unsigned int i = 0; i < 8; i++)
    				{
    					for(unsigned int j = 0; j < 8; j++)
    					{
    						for(unsigned int k = 0; k < 8; k++)
    						{
    							block = &chunk->blocks[i][j][k];
    
    							tmp = block->get_ID();
    
    							file.put((unsigned char) (tmp >> 8));
    							file.put((unsigned char) tmp);
    							file.put((unsigned char) ((block->get_Sub_ID() << 2) | block->get_direction()));
    						}
    					}
    				}
    			}
    		}
    	}
    }
    


  • Machst du da nicht irgendwie das Gleiche wie vorher?



  • Am schnellsten wäre immer noch, für ein ordentliches Speicherlayout zu sorgen und dann die einzelnen Chunks komplett in einem Rutsch zu schreiben.



  • Da du "buf" bereits angelegt hast, solltest du ihn jetzt auch nutzen.
    Wenn du damit fertig bist, empfiehlt es sich auch, einen schnellen Kompressionsalgorithmus wie LZO anzuwenden, da deine 100 MB wahrscheinlich weitgehend redundant sind.



  • Des Weiteren solltest du dein Chunk-Format dahingehend optimieren, dass keine Verschiebungen von Daten innerhalb der Datei vorkommen wenn neue Chunks generiert werden. cooky und ich haben das damals über eine zweite Indizierungs-Datei gelöst.



  • Die erinnerung schrieb:

    ich will ja auch nicht nach jedem byte flushen, aber wie mache ich das am besten?

    Edit:

    Kleiner Fortschritt: Nur noch 78 sec mit folgendem Code:

    void World::save(std::ofstream& file)
    {
    	unsigned int tmp;
    	Block_Container* block;
    	Chunk* chunk;
    	vector<char> buf(196608);
    	
    	for(unsigned int ci = 0; ci < 64; ci++)
    	{
    		for(unsigned int cj = 0; cj < 64; cj++)
    		{
    			for(unsigned int ck = 0; ck < 16; ck++)
    			{
    				chunk = &this->chunks[ci][cj][ck];
    
    				for(unsigned int i = 0; i < 8; i++)
    				{
    					for(unsigned int j = 0; j < 8; j++)
    					{
    						for(unsigned int k = 0; k < 8; k++)
    						{
    							block = &chunk->blocks[i][j][k];
    				
    							tmp = block->get_ID();
    				
    							file.put((unsigned char) (tmp >> 8));
    							file.put((unsigned char) tmp);
    							file.put((unsigned char) ((block->get_Sub_ID() << 2) | block->get_direction()));
    						}
    					}
    				}
    			}
    		}
    	}
    }
    

    Da denke ich an

    void World::save(std::ofstream& file)
    {
    	unsigned int tmp;
    	Block_Container* block;
    	Chunk* chunk;
    	vector<char> buf(196608);
    
    	for(unsigned int ci = 0; ci < 64; ci++)
    	{
    		for(unsigned int cj = 0; cj < 64; cj++)
    		{
    			for(unsigned int ck = 0; ck < 16; ck++)
    			{
    				chunk = &this->chunks[ci][cj][ck];
                    unsigned char buffer[8*8*8*3];//oder stringstream oder vector oder array
                    unsigned char* writePos=buffer;
    				for(unsigned int i = 0; i < 8; i++)
    				{
    					for(unsigned int j = 0; j < 8; j++)
    					{
    						for(unsigned int k = 0; k < 8; k++)
    						{
    							block = &chunk->blocks[i][j][k];
    
    							tmp = block->get_ID();
    
    							*writepos++=(unsigned char) (tmp >> 8));
    							*writepos++(unsigned char) tmp);
    							*writepos++(unsigned char) ((block->get_Sub_ID() << 2) | block->get_direction()));
    						}
    					}
    				}
    				file.write(buffer,sizeof(buffer));
    			}
    		}
    	}
    }
    


  • So konnte ich auf 40 sec reduzieren!

    void World::save(std::ofstream& file)
    {
    	unsigned int tmp;
    	Block_Container* block;
    	Chunk* chunk;
    	vector<char> buf(100663296);
    	int count = 0;
    
    	for(unsigned int ci = 0; ci < 64; ci++)
    	{
    		for(unsigned int cj = 0; cj < 64; cj++)
    		{
    			for(unsigned int ck = 0; ck < 16; ck++)
    			{
    				chunk = &this->chunks[ci][cj][ck];
    
    				for(unsigned int i = 0; i < 8; i++)
    				{
    					for(unsigned int j = 0; j < 8; j++)
    					{
    						for(unsigned int k = 0; k < 8; k++)
    						{
    							block = &chunk->blocks[i][j][k];
    
    							tmp = block->get_ID();
    
    							buf[count] =	 ((unsigned char) (tmp >> 8));
    							buf[count + 1] = ((unsigned char) tmp);
    							buf[count + 2] = ((unsigned char) ((block->get_Sub_ID() << 2) | block->get_direction()));
    
    							count += 3;
    						}
    					}
    				}
    			}
    		}
    	}
    
    	file.write(buf.data(), buf.size());
    }
    

    Geht da mehr?



  • Die erinnerung schrieb:

    Geht da mehr?

    Nein. Ob man in 1k großen Blöcken schreibt oder in 64k großen, das macht nur noch ein Prozent aus. Wir sind jetzt bei 1.5k. Du solltest damit schon dicht an der Maximalgeschwindigkeit sein.

    Was jetzt Zeit frißt, ist nicht mehr das Speichern, sondern es müssen Deine Zugriffe zum Auslesen der Daten sein.
    Schon alle Compiler-Optimierungen an?

    edit: Ups, hast ja alles auf einmal geschrieben. Dann erst recht. Schneller schreiben geht "eigentlich" nicht.

    Die reine Schreibzeit ist bei mir

    void save(std::ofstream& file)
    {
        vector<char> buf(100663296);
        int count = 0;
    
        file.write(buf.data(), buf.size());
    }
    

    um 60 Millisekunden.
    Der schreibt ja erstmal ins RAM, also den Festplattencache und dann erst die Daten raus auf die Platte, wenn die lahme Platte mal Lust hat, die passenden Sektoren vorbeizuschicken.
    Es muß am Auslesen liegen.



  • Mit Sicherheit geht da mehr. Nur mal zur Orientierung, das ganze sollte nicht viel länger als eine Sekunde dauern - und auch das nur auf einem Billig-Netbook.

    Zeig doch mal etwas mehr Code, z.B. die Implementierung der Block-Methoden.

    Edit: auch alles auf einmal schreiben muss bei größeren Datenmengen wie hier nicht unbedingt vorteilhaft sein. Bei kleineren Chunks kann sich das OS nebenbei darum kümmern, während du den nächsten vorbereitest. Probiere es mal mit 64 write()-Aufrufen.



  • WTF!!!!!!!!
    Kaum hau ich optimierungen rein, schon bin ich bei 4 sekunden...

    Das ist schnell genug. Danke!



  • Du hast ohne Optimierungen gemessen? 😃
    Übrigens, ich hab auch mal gemessen und mit folgender Dummy-Klasse und 64 Schreibeinheiten (also nach jedem Durchlauf der äußeren Schleife) dauert das bei mir 0.2 Sekunden:

    struct World
    {
      struct Chunk
      {
        struct Block
        {
          Block() : id(1), subID(2), direction(3) {}
          int id;
          int subID;
          int direction;
    
          int get_ID() const {return id;}
          int get_Sub_ID() const {return subID;}
          int get_direction() const {return direction;}
        };
        Block blocks[8][8][8];
      };
      Chunk chunks[64][64][16];
    
      void save(std::ofstream& file);
    };
    

    Wenn dir danach ist, kannst du evtl. also auch noch mehr rausholen.


Anmelden zum Antworten