|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#17 |
|
Messages: n/a
Hébergeur: |
In article <481dd692$0$933$ba4acef3@news.orange.fr>,
Sylvain SF <sylvain@boiteaspam.info> wrote: >Fabien LE LEZ wrote on 04/05/2008 17:08: >> On Sun, 04 May 2008 11:14:49 +0200, Ploc <ploc@clop.invalid>: >> >>> char *lc=(char*)malloc(100 * sizeof(lc)); >>> [...] >>> fscanf(f, "%s %g %g %g", lc, &x, &y, &z); >> >> Comme indiqué précédemment, si jamais la longueur de la chaîne >> "labelXXX" est supérieure à 100, boum ! > >fscanf_s(f, "%s %g %g %g", lc, 100, &x, &y, &z); > >est supporté par gcc, non ? Non. gcc est un compilateur. La bibliotheque standard (et ses extensions) n'en font pas partie. |
|
|
|
#18 |
|
Messages: n/a
Hébergeur: |
On Sun, 04 May 2008 17:30:31 +0200, "Sylvain SF"
<sylvain@boiteaspam.info>: >est supporté par gcc, non ? Mais du coup, ce n'est plus du C. Et si j'ai bien saisi, l'OP a besoin de la portabilité. (Par ailleurs, même si on accepte ce code, il faudra refaire le test de performance.) |
|
|
|
#19 |
|
Messages: n/a
Hébergeur: |
On Sun, 04 May 2008 11:14:43 +0200, Ploc <ploc@clop.invalid>:
>Le bout de code que j'ai écrit est juste là pour des questions de test >que j'ai codé pour essayer d'expliquer les différences de rapidité entre >deux versions d'un programme réel. Mais la, ca n'a plus grand chose à >voir avec l'existant. Ben justement, le code en C et le code en C++ ne font pas la même chose. Difficile donc de les comparer. >Ce n'est pas très génant pour nous de garder le code existant en C. Si le code existant fonctionne bien (ce qui n'est pas le cas du code C que tu as fourni ici), effectivement, le changer ne sert pas à grand-chose. |
|
|
|
#20 |
|
Messages: n/a
Hébergeur: |
>Après quelques essais, j'ai bien l'impression que parser soi-même les
>données apporte un gain de performances assez confortable. Ça se confirme. Et je me suis aperçu que mmap() ne change pas grand-chose. Le code que j'avais proposé, avec une fonction main() plus standard (cf ci-dessous), donne d'aussi bons résultats. Manifestement, au moins dans gcc, scanf est effroyablement lent, et >> encore plus. Seule autre modification : dans la série "cachez ce char const* que je ne saurais voir", j'ai uniformisé pour n'utiliser que std::string, même dans Source. Voici donc un programme en C++ standard, certes un peu long, mais qui est très largement plus rapide que ton code en C (et, a fortiori, que ton code en C++). #include <string> class Source { public: typedef std::string::const_iterator const_iterator; bool Fini() const { return ptr == Fin(); } void Avancer() { ++ptr; } char Get() const { return *ptr; } const_iterator Ptr() const { return ptr; } const_iterator Fin() const { return src.end(); } Source (std::string const& src_) : src (src_), ptr (src_.begin()) {} private: std::string const& src; const_iterator ptr; }; struct Destination { std::string label; float a, b, c; }; void RechercheDebutLigne (Source& src) { bool fin_ligne_trouvee= false; while (!src.Fini()) { if (src.Get()=='\n') { fin_ligne_trouvee= true; } else if (fin_ligne_trouvee) { return; } src.Avancer(); } } bool Lire (float& dest, Source& src) { dest= 0; bool negatif= false; float decimale= 0.1; bool info_rencontree= false; bool virgule_rencontree= false; while (!src.Fini()) { if (src.Get() == '\n') { break; } if (src.Get() == '-') { if (info_rencontree) { return false; // mal formé } negatif= true; } else if (src.Get() == '.') { if (virgule_rencontree) { return false; // mal formé } virgule_rencontree= true; info_rencontree= true; } else if (src.Get() >= '0' && src.Get() <= '9') { if (virgule_rencontree) { dest+= decimale * (src.Get()-'0'); decimale /= 10; } else { dest*= 10; dest+= src.Get()-'0'; } info_rencontree= true; } else if (info_rencontree) { break; } src.Avancer(); } if (negatif) { dest= -dest; } return info_rencontree; } bool Lire (std::string& dest, Source& src) { Source::const_iterator debut= src.Fin(); while (!src.Fini()) { if (src.Get() == '\n') { break; } if (src.Get() == ' ' || src.Get() == '\t') { if (debut != src.Fin()) { break; } } else if (debut == src.Fin()) { debut= src.Ptr(); } src.Avancer(); } if (debut == src.Fin()) { return false; } else { dest.assign (debut, src.Ptr()); return true; } } bool Lire (Destination& dest, Source& src) { bool ok= Lire (dest.label, src) && Lire (dest.a, src) && Lire (dest.b, src) && Lire (dest.c, src); RechercheDebutLigne (src); return ok; } #include <iostream> #include <fstream> int main() { using namespace std; char const nom_src[]= "data.txt"; ifstream ifs (nom_src); string ligne; unsigned int num_ligne= 0; while (std::getline (ifs, ligne, '\n')) { ++num_ligne; Destination d; Source s (ligne); if (!Lire (d, s)) { // erreur } } cerr << num_ligne << " lignes lues" << endl; } |
|
|
|
#21 |
|
Messages: n/a
Hébergeur: |
Fabien LE LEZ wrote on 04/05/2008 17:40:
> >> [fscanf_s] est supporté par gcc, non ? > > Mais du coup, ce n'est plus du C. qui, quoi ? > Et si j'ai bien saisi, l'OP a besoin de la portabilité. ces _s sont supportés par VC 14+ (second compilo listé par le PO) de nombreux posts (web) sur le net laissaient penser que gcc (et ses libraries usuelles !...) les supportaient aussi. > si on accepte ce code, il faudra refaire le test de performance. dans l'absolu oui, je commentais seulement le rique de BO. (ça n'impliquait pas que ce serait a priori moins ou plus rapide). Sylvain. |
|
|
|
#22 |
|
Messages: n/a
Hébergeur: |
Fabien LE LEZ wrote:
> On Sat, 03 May 2008 21:46:32 +0200, Ploc <ploc@clop.invalid>: > >> En passant de C (à base de fscanf) à c++ avec ifstream (voir le code en >> bas), je passe de 1min 40s en C à 3min 10s en c++. > > Après quelques essais, j'ai bien l'impression que parser soi-même les > données apporte un gain de performances assez confortable. > > Soit donc un > > struct Destination > { > std::string label; > float a, b, c; > }; > > que je remplis par lecture d'une ligne dans le fichier, puis que je > jette sans rien en faire. Recommencer jusqu'à épuisement du fichier. > En cas d'erreur de format, on considère que la ligne est déficiente, > et on passe à la suivante. > > J'ai fait les tests sur un AMD Athlon64 double coeur, 2,4 GHz, avec > 2 Go de RAM. Debian 64 bits, g++ 4.1.2, optimisation "-O3". > > Commençons par un fichier de 953 Mo. > real 0m24.446s > user 0m11.129s > sys 0m0.412s > > 953.674 Mo une deuxième fois : > real 0m13.218s > user 0m11.277s > sys 0m0.372s > > La deuxième fois, le fichier était déjà en cache, ce qui semble > confirmer que la ligne "user" représente bien le temps que le > processeur met à convertir les données. > > Un fichier un peu plus gros (3814 Mo) confirme une vitesse de > traitement d'environ 85 Mo/s : > real 2m34.111s > user 0m45.239s > sys 0m3.844s > > Si maintenant je mets en commentaire la ligne 134 (i.e. je supprime > l'appel à std::string::assign()), j'obtiens, pour mon fichier de > 3814 Mo : > > real 2m5.296s > user 0m17.713s > sys 0m3.844s > > soit 2,5 fois moins. La recopie de la chaîne de caractères "labelXXX" > est donc, de loin, ce qui prend le plus de temps. > > C'est bon à savoir : si jamais tu n'as besoin de ce texte que de temps > en temps, tu peux te contenter de conserver les pointeurs sur le début > et la fin de la chaîne (la fonction mmap() garantit que la mémoire > pointée sera toujours accessible). Et si ce texte est juste là pour > faire joli, et ne sert à rien, tu peux carrément ne pas conserver sa > valeur. > > > > > < snip code de test > > > J'ai finalement pu tester ce programme. Tel quel il est assez proche en durée de la version c. En sortant la ligne 'Destination d' de la boucle, on fait même mieux (on teste toujours le temps d'I/O, pour l'utilisation des valeurs extraites, on verra plus tard). Par contre, le mmap passera jamais sous visual studio. La remarque sur l'extraction des labels est très interressante. Malheureusement, j'en ai besion assez vite. Dommage. |
|
|
|
#23 |
|
Messages: n/a
Hébergeur: |
On Sun, 04 May 2008 19:18:40 +0200, Ploc <ploc@clop.invalid>:
>Tel quel il est assez proche en durée de la version c. Bizarre. J'ai une différence d'un facteur 4 ou 5. (Sauf en l'absence d'optimisation ("-Ox")) >Par contre, le mmap passera jamais sous visual studio. Il y a l'équivalent presque exact sous Windows. De toute façon je t'ai donné une autre version, en C++ standard. |
|
|
|
#24 |
|
Messages: n/a
Hébergeur: |
On Sun, 04 May 2008 19:18:40 +0200, Ploc <ploc@clop.invalid>:
>La remarque sur l'extraction des labels est très interressante. Qu'est-ce que tu dois en faire exactement, de ces labels ? |
|
![]() |
| Outils de la discussion | |
|
|