[Delphi] Concaténation de chaines et performances... {long}
Dernière réponse : dans Programmation
Je rencontre actuellement dans un des progs que je fais des pbs de performances...
Avec un coup de profiler, j'ai vu que ce qui prenait du temps etait une fonction (faite maison) bien particuliere dans laquelle je dois concaténer tout un tas de chaines et renvoyer le resultat (plusieurs dizaine de Ko) a la fonction appelante...
la boucle principale de la fonction consiste a ajouter au result la valeur de differentes variables plus un saut de ligne (CRLF)...
Bien evidemment, le code est un peu plus complexe, mais en simplifiant a l'extreme, ca donne qqchose comme ca:
j'en ai déduit (peut-etre a tort) que ce qui prenait du temps etait la reservation/assignement de la memoire pour les chaines temporaires...
j'ai donc essayé de voir dans un prog. a part les alternatives possibles:
utilisation de l'operateur +
en une fois: (nom de code: concat)
en 2 fois (nom de code: concat2)
utilisation de la fonction format (nom de code: format)
assignement de la memoire par bloc de 8k et copie des chaines caracteres par caracteres (nom de code: array)
assignement de la memoire par bloc de 8k et copie des chaines via system.move() (nom de code: move)
j'ai donc fait un petit prog pour tester cela et j'ai mesuré le temps pris pour chaques options...
Le source est dispo ici
voila les resultats que j'obtiens sur un PIV 2.4Ghz, les resultats sont en millisecondes :
il est clair que le format n'est pas la solution (on s'en doutait un peu des le debut). on le vire des tests suivant...
le array et le move sont rapides, ca ne m'etonne pas...
par contre je ne comprends pas les differences entre le concat et concat2
concat est au tas (on le vire des prochains tests), move commence a ralentir
array semble un poil plus performant que concat2
move est au tas, array est toujours plus performant que concat2
donc au final, on obtiens un classement avec
1. array (copie car. par car.)
2. concat2 (operateur +, une ligne par variable a concatener)
3. move (copie direct en memoire)
4. concat (operateur +, tout sur une ligne)
5. format
il y a plusieurs choses que je ne comprends pas dans ses resultats (si cette tendance est confirmée par d'autres):
- pourquoi concat rame par rapport a concat2 ? ca ne devrait etre pas la meme chose au final pour le compilateur ?
- pourquoi array est plus performant que move ? je pensais que ca aurait donné les memes resultats ou que move aurait eté plus rapide ?
si qq'un a des des reponses a me donner , je suis preneur !
merci
JY.
Avec un coup de profiler, j'ai vu que ce qui prenait du temps etait une fonction (faite maison) bien particuliere dans laquelle je dois concaténer tout un tas de chaines et renvoyer le resultat (plusieurs dizaine de Ko) a la fonction appelante...
la boucle principale de la fonction consiste a ajouter au result la valeur de differentes variables plus un saut de ligne (CRLF)...
Bien evidemment, le code est un peu plus complexe, mais en simplifiant a l'extreme, ca donne qqchose comme ca:
for i:= 0 to count-1 do result := result + #13#10 + chaine[i] ;
j'en ai déduit (peut-etre a tort) que ce qui prenait du temps etait la reservation/assignement de la memoire pour les chaines temporaires...
j'ai donc essayé de voir dans un prog. a part les alternatives possibles:
en une fois: (nom de code: concat)
for i:= 0 to count-1 do result := result + #13#10 + chaine[i] ;
en 2 fois (nom de code: concat2)
for i:= 0 to count-1 do begin result := result + #13#10; result := result + chaine[i]; end;
for i:= 0 to count-1 do result := format('%s'#13#10'%s', [result,chaine[i]]);
aryPos := 0; setlength(aryResult,8000); FillChar(aryResult[aryPos], 8000, #0); for i:= 0 to count-1 do begin sItem := chaine[i]; for aryIndex := 1 to length(sItem) do begin aryResult[aryPos] := sItem[aryIndex]; inc(aryPos); end; end;
aryPos := 0; setlength(aryResult,8000); FillChar(aryResult[aryPos], 8000, #0); for i:= 0 to count-1 do begin sItem := chaine[i]; System.Move(sItem[1], aryResult[aryPos],length(sItem)); aryPos := aryPos + length(sItem); end;
j'ai donc fait un petit prog pour tester cela et j'ai mesuré le temps pris pour chaques options...
Le source est dispo ici
voila les resultats que j'obtiens sur un PIV 2.4Ghz, les resultats sont en millisecondes :
------------------------------------------------------------- Test avec 1000 boucles ------------------------------------------------------------- concat : 31 concat2: 0 format : 47 array : 0 move : 0 ------------------------------------------------------------- Test avec 5000 boucles ------------------------------------------------------------- concat : 672 concat2: 0 format : 1609 array : 0 move : 0 ------------------------------------------------------------- Test avec 10000 boucles ------------------------------------------------------------- concat : 2766 concat2: 0 format : 6765 array : 0 move : 16
il est clair que le format n'est pas la solution (on s'en doutait un peu des le debut). on le vire des tests suivant...
le array et le move sont rapides, ca ne m'etonne pas...
par contre je ne comprends pas les differences entre le concat et concat2
------------------------------------------------------------- Test avec 25000 boucles ------------------------------------------------------------- concat : 19297 concat2: 16 format : ca va ramer... on passe ce test...! array : 0 move : 94
concat est au tas (on le vire des prochains tests), move commence a ralentir
array semble un poil plus performant que concat2
------------------------------------------------------------- Test avec 50000 boucles ------------------------------------------------------------- concat : ca va ramer... on passe ce test...! concat2: 31 format : ca va ramer... on passe ce test...! array : 16 move : 297 ------------------------------------------------------------- Test avec 75000 boucles ------------------------------------------------------------- concat : ca va ramer... on passe ce test...! concat2: 47 format : ca va ramer... on passe ce test...! array : 31 move : 515 ------------------------------------------------------------- Test avec 100000 boucles ------------------------------------------------------------- concat : ca va ramer... on passe ce test...! concat2: 63 format : ca va ramer... on passe ce test...! array : 46 move : 1016 ------------------------------------------------------------- Test avec 500000 boucles ------------------------------------------------------------- concat : ca va ramer... on passe ce test...! concat2: 312 format: ca va ramer... on passe ce test...! array : 282 move : 24328
move est au tas, array est toujours plus performant que concat2
donc au final, on obtiens un classement avec
1. array (copie car. par car.)
2. concat2 (operateur +, une ligne par variable a concatener)
3. move (copie direct en memoire)
4. concat (operateur +, tout sur une ligne)
5. format
il y a plusieurs choses que je ne comprends pas dans ses resultats (si cette tendance est confirmée par d'autres):
- pourquoi concat rame par rapport a concat2 ? ca ne devrait etre pas la meme chose au final pour le compilateur ?
- pourquoi array est plus performant que move ? je pensais que ca aurait donné les memes resultats ou que move aurait eté plus rapide ?
si qq'un a des des reponses a me donner , je suis preneur !
merci
JY.
Autres pages sur : delphi concatenation chaines performances long
Lassé par la pub ? Créez un compte
Pour comparer avec un 2500+ Barton
Compilé avec Delphi 5 , tu es en 6 je crois.
-------------------------------------------------------------
Test avec 25000 boucles
-------------------------------------------------------------
concat : 19385
concat2: 10
format : ca va ramer... on passe ce test...!
array : 10
move : 60
-------------------------------------------------------------
Test avec 50000 boucles
-------------------------------------------------------------
concat : ca va ramer... on passe ce test...!
concat2: 20
format : ca va ramer... on passe ce test...!
array : 20
move : 245
Demain si je trouve un moment(au boulot
) je compile Avec D6 au boulot et j'essaie de comprendre.
Compilé avec Delphi 5 , tu es en 6 je crois.
-------------------------------------------------------------
Test avec 25000 boucles
-------------------------------------------------------------
concat : 19385
concat2: 10
format : ca va ramer... on passe ce test...!
array : 10
move : 60
-------------------------------------------------------------
Test avec 50000 boucles
-------------------------------------------------------------
concat : ca va ramer... on passe ce test...!
concat2: 20
format : ca va ramer... on passe ce test...!
array : 20
move : 245
Demain si je trouve un moment(au boulot
) je compile Avec D6 au boulot et j'essaie de comprendre.
mârci
il y a qq infos en plus sur le topic h.fr: http://forum.hardware.fr/forum2.php3?post=38378&cat=10
il y a qq infos en plus sur le topic h.fr: http://forum.hardware.fr/forum2.php3?post=38378&cat=10
Lassé par la pub ? Créez un compte
le crosspost spa bien