vector<bool> na dysk i z powrotem, poprawa wydajności
Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Zarejestruj się!

vector<bool> na dysk i z powrotem, poprawa wydajności

AutorWiadomość
Temat założony przez niniejszego użytkownika
vector<bool> na dysk i z powrotem, poprawa wydajności
» 2018-07-07 16:44:13
Cześć. Piszę klasę, która pozwala mi z dysku zrobić RAM, tzn chcę adresować więcej przestrzeni niż powala pamięć. Dane dzielę na chunki, obliczam który chcę zapisać/wczytać z dysku i trzymam dziada w polu typu vector<bool> chunk.

Mam szybki odczyt z dysku, ale powolny zapis. Robiłem testy, czy mój dysk nie jest jakiś lewy pod względem zapisu, losowe dane pokroju gigabajta zapisuje, powiedzmy, wystarczająco szybko.

Odczyt jest szybki:
C/C++
//metoda zapisuje chunk na dysk
void diskToChunk( size_t id ) {
    MSG( "diskToChunk id=" + to_str( id ) );
    if( this->maxGB < 1000 ) {
        string name = this->cacheDir + to_str( id ) + ".chunk";
        FILE * file = fopen( name.c_str(), "rb" );
        char * mb_array = new char[ CHUNKSIZE ];
        //auto  csize    = sizeof(char);
        fread( mb_array, csize, CHUNKSIZE, file );
        fclose( file );
        this->chunk = this->cstr2vecbool( mb_array, CHUNKSIZE ); //patrz nizej
        delete[] mb_array;
    } else {
        MSG( "diskToChunk maxGB > 1000: TO-DO this fragment!!!" );
        throw new exception;
    }
    MSG( "diskToChunk END JOB" );
}

//pomocnik zamienia char* w vector<bool>
inline vector < bool > cstr2vecbool( char * array, size_t size ) {
    vector < bool > result( size * 8 );
    for( size_t i = 0; i < size; i++ )
         putCharToVector( result, i, array[ i ] );
   
    return result;
}

//zamienia znak char w 8 bitow, ktore pakuje do wektora
void putCharToVector( vector < bool > & vec, size_t pos, char c ) {
    //if (pos > vec.size()) return false;
    for( size_t i = 0; i < 8; i++ )
         vec[ pos + i ] =( c &( 1 << i ) ) != 0;
   
}


ale zapis na dysk kuleje:


C/C++
void chunkToDisk( long long index = - 1 ) {
    if( index < 0 )
         index = this->currentChunkID;
   
    if( this->maxGB < 1000 ) {
        MSG( "chunkToDisk, currentChunkID=" + to_str( index ) );
        string name = this->cacheDir + to_str( index ) + ".chunk";
        //char *mb_array = new char[CHUNKSIZE];
        char * mb_array = this->chunk2cstr();
        FILE * file = fopen( name.c_str(), "wb" );
        fwrite( mb_array, csize, CHUNKSIZE, file );
        fclose( file );
        delete[] mb_array;
        MSG( "chunkToDisk END JOB" );
    } else {
        MSG( "chunkToDisk if maxgb > 1000 to-do" );
        throw new exception();
    }
}

char * chunk2cstr() {
    cout << ">>>>> chunk2cstr size:" << this->chunk.size();
    cin.ignore();
    char * mb_array = new char[ this->chunk.size() ];
    //memset(mb_array, 0x0, this->chunk.size());   // uzywac przy starszych kompilatorach!!
    for( size_t i = 0; i < this->chunk.size(); i++ ) {
        //mb_array[i] = 0x0;                       // j.w.
        for( size_t j = 0; j < 8; j++ )
             mb_array[ i ] += this->chunk[ i + j ] << j; // imho tu kuleje
       
        //if (i % 10000000 == 0) MSG(to_str(i));
        //if (i >= this->chunk.size()) break;
    }
    return mb_array;
}

Co można zrobić, aby poprawić wydajność? Mam cholernie dużo danych do ziterowania. Hilfe Forumowicze :)
P-171765
» 2018-07-07 17:53:54
. Dane dzielę na chunki, obliczam który chcę zapisać/wczytać z dysku i trzymam dziada w polu typu vector<bool> chunk.
A std::vector<bool> używasz, bo..?

C/C++
char * mb_array = new char[ this->chunk.size() ];
//memset(mb_array, 0x0, this->chunk.size());   // uzywac przy starszych kompilatorach!!
Od kiedy to masz gwarancję, że zaalokowana pamięć jest w jakikolwiek sposób zainicjalizowana?

C/C++
throw new exception();
Zasadniczo, to akurat w C++ tak się nie pisze.
P-171766
Temat założony przez niniejszego użytkownika
» 2018-07-07 18:17:10
Nowe kompilatory wypełniają dane zerami, czytałem o tym kiedyś z oficjalnych źródeł C++. Nawet jeśli nie - poniżej w komentarzu jest memset. Ogólna faza testów poprawności/spójności danych będzie w dalszej fazie. Zresztą sprawdź sam na mniejszych niż używane przeze mnie rozmiary tablic - czy to będzie char, int, czy inny typ prosty - używając c++11/14/17 powinny być zera.

Sprawa wygląda tak, że mamy kod napisany w Javie, ale z pewnych przyczyn część algorytmu, nad którym pracujemy, wymaga zupełnie innych struktur danych i podejścia, dlatego padło na C++. Co do throw new exception, nie wiedziałem przyznaję szczerze, na razie nie jest to interesujący punkt z tego względu, że wszystkie ścieżki kodu gdzie cache z danymi z dysku przekracza 1000GB, tam trzeba będzie dopisać inne obsługi struktury plików, więc - nawet gdybym wiedział, że java-style nie wchodzi w grę, to i tak to trzeba będzie napisać od początku.

Wracając do mojego problemu - w wyniku analiz z konsolą i liczeniem czasu, wskazana instrukcja jest powolna. Nie bardzo wiem, jak to obejść, z Asemblerem niestety jestem na bakier totalnie. Używam chunk'ów z dysku po 10 MB (10*10^6, nie x1024^3). Docelowa maszyna, na której będzie leciał program jest dużo lepsza niż szrot, który używam, nie zmienia to postaci rzeczy, że danych do ziterowania jest w terabajtach...

C/C++
this->chunk = vector < bool >( CHUNKSIZE * 8 );
....

for( size_t i = 0; i < this->chunk.size(); i++ ) {
    //mb_array[i] = 0x0;
    for( size_t j = 0; j < 8; j++ )
    //if (this->chunk[i+j])
         mb_array[ i ] += this->chunk[ i + j ] << j; //#########
   
}
P-171767
» 2018-07-07 18:41:07
Nie odpowiedziałeś na pytanie. Dlaczego std::vector<bool>? Z punktu widzenia wydajności, to najgorszy możliwy wybór, bo to trade-off kosztem wydajności, a nie na rzecz wydajności. Zresztą, co ty w ogóle z nim robisz..?
C/C++
char * mb_array = new char[ this->chunk.size() ];
//memset(mb_array, 0x0, this->chunk.size());   // uzywac przy starszych kompilatorach!!
for( size_t i = 0; i < this->chunk.size(); i++ ) {
    //mb_array[i] = 0x0;                       // j.w.
    for( size_t j = 0; j < 8; j++ )
         mb_array[ i ] += this->chunk[ i + j ] << j; // imho tu kuleje
   
    //if (i % 10000000 == 0) MSG(to_str(i));
    //if (i >= this->chunk.size()) break;
}
Co to jest..? Mi to wygląda na typowe Javowe podejście. Przypominam, że w C++ masz bezpośredni dostęp do pamięci. Konwertujesz najpierw bajty na bity, a potem w drugą stronę. Po co?

Zresztą sprawdź sam na mniejszych niż używane przeze mnie rozmiary tablic - czy to będzie char, int, czy inny typ prosty - używając c++11/14/17 powinny być zera.
Dostałem krzaki. Ostatnio gdy sprawdzałem, VS 2017 to był nowy kompilator.
P-171768
Temat założony przez niniejszego użytkownika
» 2018-07-07 19:55:05
Potrzebuję ile wlezie przestrzeni dyskowej, którą traktuję jak ram dla tablicy/wektora bool. Robię pewne obliczenia przy użyciu nowych algorytmów, które w swoim czasie zostaną opublikowane. Pomysł jest taki, aby we wstępnej fazie na dysku utworzyć strukturę folderów, w każdym folderze max 1000 plików po 10 mb.

Mam funkcje selectCacheFile, która w zależności od indeksu long long (typedef Long) wybiera chunk z dysku i ładuje go do pola
this->chunk. Metody get/set pobierają/ustawiają w pamięci pole, a jeśli chunk jest w innym pliku, to selectCahceFile + saveChunk(size_t fileIndex) zapisuje aktualny chunk i ładuje inny na podstawie obliczonego indeksu. Całość zachowuje się jak wielka na 90% dysku tablica bool'i. Kombinujemy nowe algorytmy matematyczne, o których szczegółach na razie nie mogę mówić. Muszę mieć możliwość iterowania po plikach z boolami, aby imitować pamięć RAM.
P-171769
» 2018-07-07 20:02:43
Wywal std::vector<bool>.

PS: Twój kod w ogóle działa poprawnie..?
P-171770
Temat założony przez niniejszego użytkownika
» 2018-07-07 20:47:37
Zamieniłem wszystkie wystąpienia vector<bool> w gołą tablicę. Różnica jest ogromnie nieporównywalnie szalona. Eh, na cppreference jest wzmianka o wydajności. Jesteś wielki, dziękuję za pomoc :)

Skończę kod klasy-tablicy, wrzucę do wątku dla potomnych. Powinienem się jeszcze dziś uporać. Dzięki jeszcze raz za wszystkie wskazówki :)
P-171771
« 1 »
 Strona 1 z 1