traitement de fichiers texte très rapide (C ++)
j'ai écrit une application qui traite les données sur le GPU. Le Code fonctionne bien, mais j'ai le problème que la partie lecture du fichier d'entrée (~3 GO, texte) est le goulot d'étranglement de ma demande. (La lecture depuis le disque dur est rapide, mais le traitement ligne par ligne est lent).
J'ai lu une ligne avec getline() et copiez la ligne 1 à un vecteur, line2 à un vecteur et ignorer les lignes 3 et 4. Et ainsi de suite pour le reste de l'11 mio lignes.
J'ai essayé plusieurs approches pour obtenir le fichier au meilleur moment possible:
Méthode la plus rapide que j'ai trouvé est d'utiliser boost::iostreams::stream
D'autres ont été:
- Lire le fichier que gzip, afin de minimiser les IO, mais est plus lent que directement
en le lisant. - de copier le fichier ram en lecture(filepointer, chararray, longueur)
et le traiter avec une boucle de distinguer les lignes (plus lent que la boost)
Des suggestions pour le rendre plus rapide?
void readfastq(char *filename, int SRlength, uint32_t blocksize){
_filelength = 0; //total datasets (each 4 lines)
_SRlength = SRlength; //length of the 2. line
_blocksize = blocksize;
boost::iostreams::stream<boost::iostreams::file_source>ins(filename);
in = ins;
readNextBlock();
}
void readNextBlock() {
timeval start, end;
gettimeofday(&start, 0);
string name;
string seqtemp;
string garbage;
string phredtemp;
_seqs.empty();
_phred.empty();
_names.empty();
_filelength = 0;
//read only a part of the file i.e the first 4mio lines
while (std::getline(in, name) && _filelength<_blocksize) {
std::getline(in, seqtemp);
std::getline(in, garbage);
std::getline(in, phredtemp);
if (seqtemp.size() != _SRlength) {
if (seqtemp.size() != 0)
printf("Error on read in fastq: size is invalid\n");
} else {
_names.push_back(name);
for (int k = 0; k < _SRlength; k++) {
//handle special letters
if(seqtemp[k]== 'A') ...
else{
_seqs.push_back(5);
}
}
_filelength++;
}
}
EDIT:
La source, le fichier est téléchargeable sous https://docs.google.com/open?id=0B5bvyb427McSMjM2YWQwM2YtZGU2Mi00OGVmLThkODAtYzJhODIzYjNhYTY2
J'ai changé la fonction readfastq pour lire le fichier, à cause de quelques problèmes avec le pointeur. Donc, si vous appelez readfastq
la blocksize
(en ligne) doit être plus grand que le nombre de lignes à lire.
SOLUTION:
J'ai trouvé une solution, qui obtenir le temps pour lire dans le fichier de 60sec à 16 sec. J'ai enlevé l'intérieur de la boucle qui handeles les caractères spéciaux et de faire cela dans le GPU. Cela diminue la lecture dans le temps et seulement une augmentation minime de la GPU de temps de fonctionnement.
Merci pour vos suggestions.
void readfastq(char *filename, int SRlength) {
_filelength = 0;
_SRlength = SRlength;
size_t bytes_read, bytes_expected;
FILE *fp;
fp = fopen(filename, "r");
fseek(fp, 0L, SEEK_END); //go to the end of file
bytes_expected = ftell(fp); //get filesize
fseek(fp, 0L, SEEK_SET); //go to the begining of the file
fclose(fp);
if ((_seqarray = (char *) malloc(bytes_expected/2)) == NULL) //allocate space for file
err(EX_OSERR, "data malloc");
string name;
string seqtemp;
string garbage;
string phredtemp;
boost::iostreams::stream<boost::iostreams::file_source>file(filename);
while (std::getline(file, name)) {
std::getline(file, seqtemp);
std::getline(file, garbage);
std::getline(file, phredtemp);
if (seqtemp.size() != SRlength) {
if (seqtemp.size() != 0)
printf("Error on read in fastq: size is invalid\n");
} else {
_names.push_back(name);
strncpy( &(_seqarray[SRlength*_filelength]), seqtemp.c_str(), seqtemp.length()); //do not handle special letters here, do on GPU
_filelength++;
}
}
}
source d'informationauteur mic
Vous devez vous connecter pour publier un commentaire.
D'abord, au lieu de lire le fichier dans la mémoire vous pouvez travailler avec de mappages de fichier. Il vous suffit de créer votre programme comme 64-bit pour s'adapter à 3 GO d'espace d'adressage virtuel (pour application 32 bits seulement 2 GO est accessible dans le mode utilisateur). Ou sinon, vous pouvez map & le traitement de votre dossier par les parties.
Ensuite, il me semble que le goulot d'étranglement est "la copie d'une ligne à un vecteur". Traiter avec des vecteurs implique l'allocation dynamique de la mémoire (heap), qui, dans une critique de la boucle frappe la performance très au sérieux). Si c'est le cas - soit d'éviter l'utilisation de vecteurs, ou assurez-vous qu'ils sont déclarées en dehors de la boucle. Les aides de ce dernier, car lorsque vous réaffectez/clair vecteurs ils ne pas libérer de la mémoire.
Poster votre code (ou une partie de celui-ci) pour d'autres suggestions.
EDIT:
Il semble que tous vos goulots d'étranglement liés à la gestion de chaîne.
std::getline(in, seqtemp);
lecture dans unstd::string
traite de l'allocation dynamique de la mémoire._names.push_back(name);
C'est encore pire. D'abord lestd::string
est placé dans levector
par valeur. Moyens - la copie de la chaîne, d'où une autre dynamique d'allocation/libération qui se passe. En outre, lorsque finalement lesvector
est à l'intérieur réaffectées - tous les contenus des chaînes sont copiés à nouveau, avec toutes les conséquences.Je recommande d'utiliser ni de mise en forme standard de fichier fonctions d'e/S (Stdio/STL), ni
std::string
. Pour obtenir de meilleures performances, vous devez travailler avec des pointeurs vers des chaînes de caractères (plutôt que copié de chaînes de caractères), ce qui est possible si vous avez la carte la totalité du fichier. De Plus, vous aurez à mettre en œuvre l'analyse du fichier (division en lignes).Comme dans ce code:
si
_seqs
et_names
sontstd::vectors
et vous pouvez deviner la taille finale d'entre eux avant de traiter l'ensemble de 3 go de données, vous pouvez utiliserréserver
pour éviter la plupart de la mémoire de ré-allocation au cours de repousser les nouveaux éléments dans la boucle.Vous devez être conscient du fait que les vecteurs de produire efficacement une autre copie de pièces du dossier dans la mémoire principale. Donc, sauf si vous avez une mémoire principale suffisamment grande pour stocker le fichier texte, plus le vecteur et son contenu, vous aurez probablement jusqu'à la fin avec un certain nombre de défauts de page qui ont également une influence significative sur la vitesse de votre programme.
Des suggestions d'ordre général:
Puis si tout le reste échoue:
read(2)
) dans la page-alignés morceaux. Le faire de façon séquentielle, de sorte que le noyau de la lecture de l'avant joue à votre avantage.mmap(2)
-ing [parties de l'] fichier est une autre approche. Cela permet aussi d'éviter noyau userland copie.En fonction de la vitesse de vos disques, à l'aide d'un très rapide de l'algorithme de compression peut aider, comme fastlz (il y a au moins deux autres qui pourraient être plus efficace, mais sous la GPL, la licence peut être un problème).
Également, à l'aide de C++ structures de données et les fonctions de la voiture augmenter la vitesse que vous pouvez peut-être de parvenir à un meilleur compilateur-l'optimisation du temps. Va le C n'est pas toujours les fastes! Dans certaines mauvaises conditions, en utilisant char* vous devez analyser l'ensemble de la chaîne pour atteindre le \0 rendement désastreux performances.
Pour l'analyse de vos données, à l'aide de boost::spirit::qi est aussi probablement le plus optimisé approche http://alexott.blogspot.com/2010/01/boostspirit2-vs-atoi.html