IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Problème avec une HashMap (STL/SGI)


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Février 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 11
    Par défaut Problème avec une HashMap (STL/SGI)
    Bonjour,

    Alors j'aimerais indexer dans une hashMap tout plein de k-mer de plusieurs millions de mots différents.
    J'utilise l'extension de la hashMap développée par SGI pour répondre à ce problème.
    Voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    ----> inclusion de l'extension SGI
     
    #include <ext/hash_map>
     
    using namespace std;
    namespace std { using namespace __gnu_cxx; }
     
    ----> utilisation du hasher proposé par SGI
    struct eqstr{
      bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1,s2)==0;
      }
    };
     
    -----> le block associé à la hash
     
    int main(int argc, char **argv)
    {
    // initialisation
     hash_map<const char*, int, hash<const char*>, eqstr> hash_kmer;
     ...
     ... 
     ullong cpt = 0;
     uint lg_kmer = k; // k une longueur fixe, plus petite que la taille du plus petit mot... 
     while (cpt < nb_mots) {
        tousLesMots.getline(mot_actuel, lg_mot+1);
        for (ullong i = 0 ; i < (lg_mot-lg_kmer) ; i++){
          facteur = (mot_actuel.substr(i,lg_kmer)).c_str();
          hash_kmer[facteur] ++ ;
        }
        cpt++;
      }
      ...
      ...
      return 0;
    }
    Le problème est que c'est très très lent !
    Par exemple, en prenant des mots de longueurs 75 et un k-mer de longueur 22, pour un nombre de mots de 45 millions, il faut 8 heures pour faire tourner le programme (sur une machine puissante).

    Au début, je pensais que c'était la gestion des collisions qui prenait beaucoup de temps. De ce fait, j'ai diminué la longueur de k pour avoir moins de collisions. Sauf que, pour le même exemple, mais avec un k de longueur 10 ça met 15 heures, donc deux fois plus de temps.

    Je pense que c'est mon implantation qui n'est pas bonne (ou peut-être le hasher que j'utilise). C'est pour cela que je me retourne vers vous car je ne suis pas plus compétant que ça dans les hashMap.
    PS : j'ai testé d'autres implantation de hash telles que google-sparse ou google-dense mais ça ne change rien.
    De plus dans ce comparatif, SGI n'est pas trop mal située :
    http://attractivechaos.awardspace.com/udb.html

    Qui aurait une idée de ce problème de lenteur ????

    Merci d'avance,

    Nicolas P

  2. #2
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Bonsoir,

    Peut-être pourrais tu nous mettre le code complet vu qu'il n'a pas l'air très long ? (avec la balise code). Et nous mettre un lien vers un exemple de base de mots pour qu'on puisse essayer nous-même et voir la cause de la lenteur.

    En attendant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // ----> utilisation du hasher proposé par SGI
    struct eqstr{
    bool operator()(const char* s1, const char* s2) const {
    return strcmp(s1,s2)==0;
    }
    };
    Pourquoi le commentaire parle de "l'utilisation du hasher", alors que la structure eqstr ne définit pas de fonction de hash, juste une fonction de comparaison !?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while (cpt < nb_mots) {
    tousLesMots.getline(mot_actuel, lg_mot+1);
    for (ullong i = 0 ; i < (lg_mot-lg_kmer) ; i++){
    facteur = (mot_actuel.substr(i,lg_kmer)).c_str();
    hash_kmer[facteur] ++ ;
    }
    humhum. Difficile de juger du code sans connaître la définition de tousLesMots, mot_actuel etc. mais ce bout de code a l’air très suspect quand même. On a l'impression que tu mets dans ta table de hash un pointeur vers un objet temporaire (mot_actuel.substr())

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Février 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 11
    Par défaut
    Oui en effet, je me suis trompé dans mon commentaire, ça c'est suelement l'equalKey que j'utilise. Je voulais juste dire que j'utilisais la fonction de hashage par défaut...

    Pour mon code, je vous l'envoie tel qu'il est. J'ai voulu couper pour simplifier un peu mais c'était pas une bonne idée finalement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
     
     
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <sys/time.h>
    #include <ext/hash_map>
    extern "C" {
    #include <time.h>
    }
     
    using namespace std;
    namespace std { using namespace __gnu_cxx; }
     
    #ifndef ullong
    #define ullong unsigned long long
    #endif
     
    ullong getChrono() {
      struct timeval time;
      time_t sec;
      suseconds_t usec;
     
      if (gettimeofday(&time,NULL) != -1) {
        sec = time.tv_sec;
        usec = time.tv_usec;
        return (ullong)sec*1000000+usec;
      }
      return 0;
    }
     
    struct eqstr{
      bool operator()(const char* s1, const char* s2) const {
        return strcmp(s1,s2)==0;
      }
    };
     
    int main(int argc, char **argv)
    {
      if (argc < 4){
        cerr << "Usage: " << argv[0] <<" read_file read_length threshold" << endl; 
        exit(1);
      }
      ullong start = getChrono();
     
      ifstream reads;
      reads.open(argv[1], ios::in);
      if (! reads.is_open()) {
        cerr << "Cannot open reads file: " << argv[1] << endl;
        exit(2);
      }
      reads.seekg (0, ios::end);
      ullong length = reads.tellg();
      int read_length = atoi(argv[2]);
      char *line = new char[read_length+1];
      reads.seekg (0, ios::beg);
      ullong nb_reads = length/(read_length+1);
      int threshold= atoi(argv[3]);
     
      hash_map<const char*, int, hash<const char*>, eqstr> hash_kmer;
     
      string read_string;
      const char *factor = new char[threshold+1];
      ullong current = 0;
     
      while (current < nb_reads) {
        reads.getline(line, read_length+1);
        read_string = line;
        for (ullong i = 0 ; i < (read_length-threshold) ; i++){
          factor = (read_string.substr(i,threshold)).c_str();
          hash_kmer[factor] ++ ;
        }
        current++;
      }  
      cout << "nb_factors indexed in hash_kmer: " << hash_kmer.size() << endl;
      cerr << "Creation of stl_hash_map: " << (getChrono()-start)/1000000. << " s" << endl;
      return 0;
    }

    Pour le lien avec un fichier de donnée :
    http://www.lirmm.fr/~nphilippe/test

    Merci encore

    Nicolas P

  4. #4
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 294
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    au cas où, ne sait-on jamais: êtes-vous bien certain de compiler avec les optimisations de compilation adéquates?

  5. #5
    screetch
    Invité(e)
    Par défaut
    c'est deja un miracle que ca marche.
    Comme dit plus haut:

    humhum. Difficile de juger du code sans connaître la définition de tousLesMots, mot_actuel etc. mais ce bout de code a l’air très suspect quand même. On a l'impression que tu mets dans ta table de hash un pointeur vers un objet temporaire (mot_actuel.substr())
    le gros avantage c'est que tu n'alloues presque pas de mémoire (en tous cas pas pour les chaines).
    Le gros inconvenient c'est que tu stockes probablement toute les chaines dans le meme bloc memoire (elles s'ecrasent les unes les autres). Toute les comparaisons de chaines etc etc sont probablement faussées.

    Sinon, tu pourrais afficher une sorte de barre de progres ou de ETA; ca pourrait aider a voir si il y a un probleme de complexité, ou bien si le programme s'arrete periodiquement...

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Février 2011
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 11
    Par défaut
    C'est possible que ce soit à cause de ça, mais j'suis septique.
    Au cas où, voila ma ligne de compilation :
    g++ -Wall -Wextra -ansi -g -O2 -funroll-loops buildSTLHash.cpp -o buildSTLHash

    En fait c'est vraiment très visuel ! Ça commence à patiner dans la semoule à partir d'un certain moment.
    Sur l'exemple que j'ai donné en lien, voici la trace de mon programme pour un k-mer de lg 22.

    Au début de l' exécution du programme, ça se comporte très normalement :

    10000 reads is included in stl_hash in 0.110646 s
    20000 reads is included in stl_hash in 0.214687 s
    30000 reads is included in stl_hash in 0.297762 s
    40000 reads is included in stl_hash in 0.423303 s
    50000 reads is included in stl_hash in 0.609714 s
    60000 reads is included in stl_hash in 0.771651 s
    70000 reads is included in stl_hash in 0.859677 s
    80000 reads is included in stl_hash in 0.976118 s
    90000 reads is included in stl_hash in 1.28819 s
    100000 reads is included in stl_hash in 1.40297 s
    110000 reads is included in stl_hash in 1.49794 s
    120000 reads is included in stl_hash in 1.59264 s
    130000 reads is included in stl_hash in 1.73249 s
    140000 reads is included in stl_hash in 1.85493 s
    150000 reads is included in stl_hash in 1.9604 s
    160000 reads is included in stl_hash in 2.07579 s
    170000 reads is included in stl_hash in 2.61795 s
    180000 reads is included in stl_hash in 2.74023 s
    190000 reads is included in stl_hash in 2.84681 s
    200000 reads is included in stl_hash in 3.01806 s
    210000 reads is included in stl_hash in 3.11888 s
    220000 reads is included in stl_hash in 3.21828 s
    230000 reads is included in stl_hash in 3.31929 s
    240000 reads is included in stl_hash in 3.42316 s
    250000 reads is included in stl_hash in 3.53848 s
    260000 reads is included in stl_hash in 3.65708 s
    270000 reads is included in stl_hash in 3.93243 s
    280000 reads is included in stl_hash in 4.05486 s
    290000 reads is included in stl_hash in 4.18682 s
    300000 reads is included in stl_hash in 4.29214 s
    310000 reads is included in stl_hash in 4.42333 s

    Soit 310 000 reads pour 4 secondes

    Et à partir d'un moment :

    17960000 reads is included in stl_hash in 1902.34 s
    17970000 reads is included in stl_hash in 1907.72 s
    17980000 reads is included in stl_hash in 1913.17 s
    17990000 reads is included in stl_hash in 1918.09 s
    18000000 reads is included in stl_hash in 1924.37 s
    18010000 reads is included in stl_hash in 1931.79 s
    18020000 reads is included in stl_hash in 1935.82 s
    18030000 reads is included in stl_hash in 1940.33 s
    18040000 reads is included in stl_hash in 1942.89 s
    18050000 reads is included in stl_hash in 1949.09 s
    18060000 reads is included in stl_hash in 1954.16 s

    Soit 100 000 reads pour 52 secondes. Et c'est de pire en pire...

    Peut-être qu'il y a de plus en plus de conflits à gérer ? Mais dans ce cas là, en réduisant la longueur du k-mer je devrais gagner de la vitesse, puisque j'ai moins de clés distinctes, non ?

    Je ne suis vraiment pas un spécialiste des hashMap, donc n'hésitez-pas à me donner toutes sortes de suggestions ou d'informations, ça ne me sera que bénéfique.

    Merci,

    Nicolas P

  7. #7
    screetch
    Invité(e)
    Par défaut
    il faut vraiment corriger ton problème de chaines temporaires qui sont ecrasées; imagines que maintenant toute tes comparaisons sont faussées, on est pas du tout dans le cas optimal pour un hash_map.

    Pour t'expliquer ce qui se passe, les clés sont effacées au fur et a mesure et probablement ecrasées par de nouvelles clés. Tu as un hash_map ou les clés sont donc presque surement changées après insertion, voire pire.

  8. #8
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 294
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par nphilippe1684 Voir le message
    Au cas où, voila ma ligne de compilation :
    g++ -Wall -Wextra -ansi -g -O2 -funroll-loops buildSTLHash.cpp -o buildSTLHash
    Je connais assez mal gcc, mais je pense qu'il est possible d'améliorer cela:
    -g c'est pour avoir les informations de debug. Pour optimiser, il faut donc l'enlever.
    sans doute qu'utiliser -O3 au lieu de -O2 sera également plus efficace

    Il faudrait également vérifier que vous utilisez une version récente de gcc (en effet, le -funroll-loops qui n'est pas documenté dans les dernières versions me porte à croire que vous en utilisez une ancienne).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. STL Problème avec une liste d'instances de class
    Par BruceBoc dans le forum SL & STL
    Réponses: 12
    Dernier message: 16/02/2007, 14h12
  2. [JBOSS] [Struts] Problème avec une application
    Par Tiercel dans le forum Wildfly/JBoss
    Réponses: 5
    Dernier message: 13/07/2004, 13h50
  3. Problème avec une instruction OUTER /Postgres
    Par Volcomix dans le forum Langage SQL
    Réponses: 14
    Dernier message: 21/04/2004, 16h56
  4. problème avec une requête imbriquée
    Par jaimepasteevy dans le forum Langage SQL
    Réponses: 13
    Dernier message: 05/12/2003, 10h29
  5. Problème avec une procédure stockée
    Par in dans le forum Langage SQL
    Réponses: 4
    Dernier message: 27/05/2003, 15h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo