[EXPERTS]optimisation du c/asm

Résolu
MrdJack Messages postés 146 Date d'inscription jeudi 22 avril 2004 Statut Membre Dernière intervention 8 mars 2008 - 8 mai 2006 à 22:14
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019 - 8 mai 2006 à 23:05
Bonsoir,

je suis en train de me renseigner sur le c et l'asm niveau vitesse d'execution.

en detail je me demande comment créer un code en c pour que sont
listing asm soit le plus optimisé et un probleme de compréhension est
alors survenu :

je me suis basé sur la fonction strlen() de la stl. j'ai édité son
fichier asm (strlen.asm) afin de voir comment c'est organisé en asm.

dans ce fichier il y a aussi un code en c equivalent. mais apres avoir
essayé ce code alternatif, je me suis rendu compte qu'il etait moins
rapide que celui en assembleur.

en poussant mes recherches, j'ai regardé le listing du code asm de la
fonction strlen écrite en c (l'alternative) et à ma grande surprise, le
listing asm de cette fonction est plus court en nombre de ligne que le
code asm du fichier strlen.asm ( sans compter la sauvegarde des
registres et tout qui doit etre équivalente)

le truc dingue c'est que cette fonction qui est plus lente que celle codée en asm prend moins de ligne.



voilà les deux résultats :

CODESEG

public strlen

strlen proc

.FPO ( 0, 1, 0, 0, 0, 0 )

string equ [esp + 4]

mov
ecx,string
; ecx -> string

test
ecx,3
; test if string is aligned on 32 bits

je short main_loop

str_misaligned:

; simple byte loop until string is aligned

mov al,byte ptr [ecx]

inc ecx

test al,al

je short byte_3

test ecx,3

jne short str_misaligned

add
eax,dword ptr 0 ; 5
byte nop to align label below

align
16
; should be redundant

main_loop:

mov
eax,dword ptr [ecx] ; read 4 bytes

mov edx,7efefeffh

add edx,eax

xor eax,-1

xor eax,edx

add ecx,4

test eax,81010100h

je short main_loop

; found zero byte in the loop

mov eax,[ecx - 4]

test
al,al
; is it byte 0

je short byte_0

test
ah,ah
; is it byte 1

je short byte_1

test
eax,00ff0000h
; is it byte 2

je short byte_2

test
eax,0ff000000h ;
is it byte 3

je short byte_3

jmp
short main_loop ; taken
if bits 24-30 are clear and bit


; 31 is set

byte_3:

lea eax,[ecx - 1]

mov ecx,string

sub eax,ecx

ret

byte_2:

lea eax,[ecx - 2]

mov ecx,string

sub eax,ecx

ret

byte_1:

lea eax,[ecx - 3]

mov ecx,string

sub eax,ecx

ret

byte_0:

lea eax,[ecx - 4]

mov ecx,string

sub eax,ecx

ret

strlen endp

end



puis :


; 18 : {

00000 55 push ebp

00001 8b ec mov ebp, esp

00003 83 ec 44
sub esp, 68
; 00000044H

00006 53 push ebx

00007 56 push esi

00008 57 push edi

00009 8d 7d bc lea edi, DWORD PTR [ebp-68]

0000c b9 11 00 00 00
mov ecx, 17
; 00000011H

00011 b8 cc cc cc cc
mov eax, -858993460
; ccccccccH

00016 f3 ab rep stosd

; 19 : int length = 0;

00018 c7 45 fc 00 00

00 00 mov DWORD PTR _length$[ebp], 0

$L1269:

; 20 :

; 21 : while( *str++ )

0001f 8b 45 08 mov eax, DWORD PTR _str$[ebp]

00022 0f be 08 movsx ecx, BYTE PTR [eax]

00025 8b 55 08 mov edx, DWORD PTR _str$[ebp]

00028 83 c2 01 add edx, 1

0002b 89 55 08 mov DWORD PTR _str$[ebp], edx

0002e 85 c9 test ecx, ecx

00030 74 0b je SHORT $L1270

; 22 : ++length;

00032 8b 45 fc mov eax, DWORD PTR _length$[ebp]

00035 83 c0 01 add eax, 1

00038 89 45 fc mov DWORD PTR _length$[ebp], eax

0003b eb e2 jmp SHORT $L1269

$L1270:

; 23 :

; 24 : return( length );

0003d 8b 45 fc mov eax, DWORD PTR _length$[ebp]

; 25 : }

00040 5f pop edi

00041 5e pop esi

00042 5b pop ebx

00043 8b e5 mov esp, ebp

00045 5d pop ebp

00046 c3 ret 0



donc je piges pas pourquoi la premiere fonction est plus rapide mais
plus grande alors que la deuxieme es tplus lente et plus petite

je sais deja que chaque compilo peut donner un code différent mais mon
probleme de comprehension est basé sur la relation ligne de code par
rapport à la vitesse ( je m'avance un peu mais peut etre parce que la
premiere fonction prend 4B par 4B mais ca reste une supposition)



merci de m'éclairer sur le sujet.



PS je suis assez doué en c et un peu en asm (disont que je connais
l'assembleur utilisé sur les automates programmables de telemecanique
et de siemens. je connais les bases pour un programme com ou exe sous
dos mis à part les interruptions qui sans une refférence me donne un
mal de cranne ! le reste est assez similaire)

4 réponses

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
8 mai 2006 à 22:37
C'est clair, le plus court en code n'est pas le meilleur en performance.
Exemple: Je déroule la boucle 3 fois donc je n'effectue qu'un saut de code (jnz short Llen1) sur 3.
La func du haut aspire par passe de 4 octets dès que la chaine est alignée sur 4, il y a donc code de 'tant que non aligné' avant.

Essaie ceci, devrait aller pas mal non plus.

#ifndef BNINLINE
#ifdef __cplusplus
#define BNINLINE inline
#else
#define BNINLINE __inline
#endif /* __cplusplus */
#endif

BNINLINE DWORD bnstrlen(char *psz)
{
__asm {
mov eax, psz
Llen1:
mov dl, [eax]
inc eax
test dl, dl
jz short LlenOut
mov dl, [eax]
inc eax
test dl, dl
jz short LlenOut
mov dl, [eax]
inc eax
test dl, dl
jnz short Llen1
LlenOut:
dec eax
sub eax, psz
}
}

ciao...
BruNews, MVP VC++
3
MuPuF Messages postés 536 Date d'inscription mercredi 27 avril 2005 Statut Membre Dernière intervention 22 août 2008
8 mai 2006 à 22:27
bah, tu devrais savoir que certaines commandes demandent plusieurs cycles pros, enfin il me semble
Enfin c'est la seule explication possible
Un connaisseur dans le coin ????
0
MrdJack Messages postés 146 Date d'inscription jeudi 22 avril 2004 Statut Membre Dernière intervention 8 mars 2008 2
8 mai 2006 à 22:59
en effet je comprends mieux le systeme, et surtout que je vais me
mettre direct à l'asm car on voit bien qu'en c c'est impossible à
réaliser !!!

je crois bien que au final, mon code sera plus composé d'assembleur que de c visiblement



une petite question : dans la ligne de code mov dl, [eax] les crochets signifie bien que l'on va chercher la valeur de la zone mémoire pointée par eax n'est-ce pas ?



sinon merci encore pour votre aide

@+
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
8 mai 2006 à 23:05
exact pour mov mais ce n'est pas toujours le cas.

lea edx, [eax+eax*4]
ici pas d'accès mémoire mais simple opération arythmétique: edx = eax*5

ciao...
BruNews, MVP VC++
0
Rejoignez-nous