› Foros › PC › Software libre
e-Minguez escribió:"Creo", que el precompilador lo que hace es p[i] -> *(p+i), asique teoricamente no deberia haber diferencias o_O
e-Minguez escribió:"Creo", que el precompilador lo que hace es p[i] -> *(p+i), asique teoricamente no deberia haber diferencias o_O
A ver si algun guru de la programación en C nos aclara... x)
Salu2!
$ diff detectSphere.cc detectSphere2.cc
49,51c49,51
< for (int i=0;i<uMLE.numel();i++) *(uMLEC + i)=uMLE(i);
< for (int i=0;i<u.numel();i++) *(uC + i)=u(i);
< for (int i=0;i<constell.numel();i++) *(constellC + i)=constell(i);
---
> for (int i=0;i<uMLE.numel();i++) uMLEC[i]=uMLE(i);
> for (int i=0;i<u.numel();i++) uC[i]=u(i);
> for (int i=0;i<constell.numel();i++) constellC[i]=constell(i);
64,65c64,65
< for (int i=0;i<distances.numel();i++) distances(i)=*(distancesD + i);
< for (int i=0;i<symbols.numel();i++) symbols(i)=*(symbolsD + i);
---
> for (int i=0;i<distances.numel();i++) distances(i)=distancesD[i];
> for (int i=0;i<symbols.numel();i++) symbols(i)=symbolsD[i];
98c98
< *(distancesD + distancesInd + j) = INFINITY;
---
> distancesD[distancesInd + j] = INFINITY;
122c122
< sumatC += *(uC + uInd + j) * *(diffCandC + j);
---
> sumatC += uC[uInd + j] * diffCandC[j];
127,129c127,129
< *(diffCandC + antenna) = *(constellC + i) - *(uMLEC + uMLEInd + antenna);
< double uii = (*(uC + uInd + antenna)).real();
< Complex resultC = *(diffCandC + antenna) + sumatC / uii;
---
> diffCandC[antenna] = constellC[i] - uMLEC[uMLEInd + antenna];
> double uii = (uC[uInd + antenna]).real();
> Complex resultC = diffCandC[antenna] + sumatC / uii;
133c133
< *(candidateVector + antenna) = i;
---
> candidateVector[antenna] = i;
141c141
< double worstDistance = *(distancesD + distancesInd);
---
> double worstDistance = distancesD[distancesInd];
145c145
< if (*(distancesD + distancesInd + j) > worstDistance)
---
> if (distancesD[distancesInd + j] > worstDistance)
147c147
< worstDistance = *(distancesD + distancesInd + j);
---
> worstDistance = distancesD[distancesInd + j];
154c154
< *(distancesD + distancesInd + worstCand) = distance;
---
> distancesD[distancesInd + worstCand] = distance;
157c157
< *(symbolsD + symbolsInd + j) = *(candidateVector + j);
---
> symbolsD[symbolsInd + j] = candidateVector[j];
franjva@tay64 ~/octave/detection $ rm *.o
franjva@tay64 ~/octave/detection $ rm *.oct
franjva@tay64 ~/octave/detection $ CXXFLAGS="-O0" mkoctfile detectSphere.cc
franjva@tay64 ~/octave/detection $ CXXFLAGS="-O0" mkoctfile detectSphere2.cc
franjva@tay64 ~/octave/detection $ cmp detectSphere.o detectSphere2.o
detectSphere.o detectSphere2.o differ: byte 41, line 1
int 5["array"];
[ $ ~/prueba-punteros ] cat arrays.c
#include <stdio.h>
int main (int argc, char **argv)
{
int arr[10];
int i;
for ( i = 0 ; i < 10 ; i++ )
arr[i] = i;
for ( i = 0 ; i < 10 ; i++ )
printf("%d\n",arr[i]);
return 0;
}
[ $ ~/prueba-punteros ] cat punteros.c
#include <stdio.h>
int main (int argc, char **argv)
{
int arr[10];
int i;
for ( i = 0 ; i < 10 ; i++ )
*(arr+i) = i;
for ( i = 0 ; i < 10 ; i++ )
printf("%d\n",*(arr+i));
return 0;
}
[ $ ~/prueba-punteros ] for i in *.c ; do gcc -S -o ${i/.c/.s} ${i} ; done
[ $ ~/prueba-punteros ] diff -u arrays.s punteros.s
--- arrays.s 2005-10-09 00:14:23.000000000 +0200
+++ punteros.s 2005-10-09 00:14:23.000000000 +0200
@@ -1,4 +1,4 @@
- .file "arrays.c"
+ .file "punteros.c"
.section .rodata
.LC0:
.string "%d\n"
[ $ ~/prueba-punteros ] for i in *.c ; do gcc -O3 -S -o ${i/.c/.s} ${i} ; done
[ $ ~/prueba-punteros ] diff -u arrays.s punteros.s
--- arrays.s 2005-10-09 00:19:24.000000000 +0200
+++ punteros.s 2005-10-09 00:19:24.000000000 +0200
@@ -1,4 +1,4 @@
- .file "arrays.c"
+ .file "punteros.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d\n"
franjva@tay64 ~/octave/detection $ CXXFLAGS="-S -O0" mkoctfile -c detectSphere.cc
franjva@tay64 ~/octave/detection $ CXXFLAGS="-S -O0" mkoctfile -c detectSphere2.cc
franjva@tay64 ~/octave/detection $ diff detectSphere.o detectSphere2.o
1c1
< .file "detectSphere.cc"
---
> .file "detectSphere2.cc"
2335,2337c2335
< movq distancesInd@GOTPCREL(%rip), %rax
< movl (%rax), %eax
< movslq %eax,%rdx
---
> movq distancesInd@GOTPCREL(%rip), %rdx
2338a2337
> addl (%rdx), %eax
2340d2338
< leaq (%rdx,%rax), %rax
2435,2436d2432
< movl -32(%rbp), %eax
< movslq %eax,%rdx
2437a2434
> addl -32(%rbp), %eax
2439d2435
< leaq (%rdx,%rax), %rax
2471,2473c2467
< movq uMLEInd@GOTPCREL(%rip), %rax
< movl (%rax), %eax
< movslq %eax,%rdx
---
> movq uMLEInd@GOTPCREL(%rip), %rdx
2474a2469
> addl (%rdx), %eax
2476d2470
< leaq (%rdx,%rax), %rax
2500,2501d2493
< movl -32(%rbp), %eax
< movslq %eax,%rdx
2502a2495
> addl -32(%rbp), %eax
2504d2496
< leaq (%rdx,%rax), %rax
2562a2555
> movq candidateVector@GOTPCREL(%rip), %rcx
2564,2566c2557
< cltq
< leaq 0(,%rax,4), %rcx
< movq candidateVector@GOTPCREL(%rip), %rdx
---
> movslq %eax,%rdx
2568c2559
< movl %eax, (%rcx,%rdx)
---
> movl %eax, (%rcx,%rdx,4)
2603,2605c2594
< movq distancesInd@GOTPCREL(%rip), %rax
< movl (%rax), %eax
< movslq %eax,%rdx
---
> movq distancesInd@GOTPCREL(%rip), %rdx
2606a2596
> addl (%rdx), %eax
2608d2597
< leaq (%rdx,%rax), %rax
2618,2620c2607
< movq distancesInd@GOTPCREL(%rip), %rax
< movl (%rax), %eax
< movslq %eax,%rdx
---
> movq distancesInd@GOTPCREL(%rip), %rdx
2621a2609
> addl (%rdx), %eax
2623d2610
< leaq (%rdx,%rax), %rax
2642,2644c2629
< movq distancesInd@GOTPCREL(%rip), %rax
< movl (%rax), %eax
< movslq %eax,%rdx
---
> movq distancesInd@GOTPCREL(%rip), %rdx
2645a2631
> addl (%rdx), %eax
2647d2632
< leaq (%rdx,%rax), %rax
2667,2668d2651
< movl -180(%rbp), %eax
< movslq %eax,%rdx
2669a2653
> addl -180(%rbp), %eax
2671,2672c2655
< leaq (%rdx,%rax), %rax
< leaq 0(,%rax,8), %rcx
---
> leaq 0(,%rax,8), %rsi
2674c2657,2658
< movq (%rax), %rsi
---
> movq (%rax), %rcx
> movq candidateVector@GOTPCREL(%rip), %rdx
2677,2680c2661,2662
< leaq 0(,%rax,4), %rdx
< movq candidateVector@GOTPCREL(%rip), %rax
< cvtsi2sd (%rdx,%rax), %xmm2
< movsd %xmm2, (%rcx,%rsi)
---
> cvtsi2sd (%rdx,%rax,4), %xmm2
> movsd %xmm2, (%rsi,%rcx)
Ferdy escribió:¿ Has comprobado que te pasa lo mismo con código C ? Yo no se apenas C++ como para hacer una prueba simple. Como ves en mi caso ha generado lo mismo con -O3 que sin optimizaciones.
Mañana lo pruebo en un alpha... ahora me voy al sobre.
Saludos.Ferdy
franjva@tay64 ~/octave/detection $ CXXFLAGS="-S -O0" mkoctfile -c detectSphere.cc
franjva@tay64 ~/octave/detection $ CXXFLAGS="-S -O0" mkoctfile -c detectSphere2.cc
franjva@tay64 ~/octave/detection $ diff detectSphere.o detectSphere2.o
1c1
< .file "detectSphere.cc"
---
> .file "detectSphere2.cc"
2888,2890c2888,2889
< movl 16(%ebp), %eax
< leal 0(,%eax,4), %ecx
< movl candidateVector@GOT(%ebx), %edx
---
> movl candidateVector@GOT(%ebx), %ecx
> movl 16(%ebp), %edx
2892c2891
< movl %eax, (%ecx,%edx)
---
> movl %eax, (%ecx,%edx,4)
2990c2989
< leal 0(,%eax,8), %ecx
---
> leal 0(,%eax,8), %esi
2992c2991,2992
< movl (%eax), %esi
---
> movl (%eax), %ecx
> movl candidateVector@GOT(%ebx), %edx
2994,2997c2994,2995
< leal 0(,%eax,4), %edx
< movl candidateVector@GOT(%ebx), %eax
< fildl (%edx,%eax)
< fstpl (%ecx,%esi)
---
> fildl (%edx,%eax,4)
> fstpl (%esi,%ecx)
detectSphere: ans = 10.024
detectSphere2: ans = 10.022
detectSphere: ans = 6.7558
detectSphere2: ans = 7.5135
[ $ ~/prueba-punteros ] for i in *.c ; do alpha-unknown-linux-gnu-gcc -O2 -mieee -S -o ${i/.c/.s} ${i} ; done
[ $ ~/prueba-punteros ] for i in *.c ; do alpha-unknown-linux-gnu-gcc -O2 -mieee -c -o ${i/.c/.o} ${i} ; done
[ $ ~/prueba-punteros ] sha1sum *.o *.s
e5ee7b263db3826451abd6eb0f239319bb683232 arrays.o
e5ee7b263db3826451abd6eb0f239319bb683232 punteros.o
c0da51261acf27fed18790236cd0c14d6307c562 arrays.s
c0da51261acf27fed18790236cd0c14d6307c562 punteros.s
main()
{
int i, j, k, *p;
i = *(p + j + k);
}
main()
{
int i, j, k, *p;
i = p[j + k];
}
franjva@tay64 ~/prueba2 $ gcc -S p1.c
franjva@tay64 ~/prueba2 $ gcc -S p2.c
franjva@tay64 ~/prueba2 $ diff p1.s p2.s
1c1
< .file "p1.c"
---
> .file "p2.c"
11,12d10
< movl -8(%rbp), %eax
< movslq %eax,%rdx
13a12
> addl -8(%rbp), %eax
15d13
< leaq (%rdx,%rax), %rax
franjva@tay64 ~/prueba2 $ gcc -m32 -S p1.c
franjva@tay64 ~/prueba2 $ gcc -m32 -S p2.c
franjva@tay64 ~/prueba2 $ diff p1.s p2.s
1c1
< .file "p1.c"
---
> .file "p2.c"
main:
.LFB2:
pushq %rbp
.LCFI0:
movq %rsp, %rbp
.LCFI1:
movl -8(%rbp), %eax
movslq %eax,%rdx
movl -12(%rbp), %eax
cltq
leaq (%rdx,%rax), %rax
leaq 0(,%rax,4), %rdx
movq -24(%rbp), %rax
movl (%rdx,%rax), %eax
movl %eax, -4(%rbp)
leave
ret
main:
.LFB2:
pushq %rbp
.LCFI0:
movq %rsp, %rbp
.LCFI1:
movl -12(%rbp), %eax
addl -8(%rbp), %eax
cltq
leaq 0(,%rax,4), %rdx
movq -24(%rbp), %rax
movl (%rdx,%rax), %eax
movl %eax, -4(%rbp)
leave
ret
jyck escribió:" Al evaluar p[i],C la convierte inmediatamente a *(p+i); las dos formas son equivalentes......En resumen, cualquier expresión de array en índice es equivalente a una expresión escrita como un puntero y desplazamiento."
jyck escribió:Supongo que esto no saca de todas las dudas, pero si que aclara un poco el tema, supongo (que es mucho suponer) que el 10% de velocidad de diferencia se pierde en el cambio de uno a otro, aunque no creo, ya que el cambio lo haría en tiempo de compilacion....
main()
{
int i, j, k, *p;
i = *(p + (j + k));
}
Ferdy escribió:¿ Y este código en amd64 qué genera ?main()
{
int i, j, k, *p;
i = *(p + (j + k));
}
Puede que esté haciendo internamente una conversión int->pointer. Hacerla en x86 no da problemas; pero al hacerla en amd64 necesita 'algo más' (que no se muy bien lo que es); de ahí podría venir que haya más código.
Es una simple especulación ya que no conozco asm de x86.
Parece un "bug" en la implementacion del direccionamiento de memoria de gcc para amd64 más bien
Ferdy escribió:Mmmm me lo temía... ¿ en x86_64 no segfaultea ?
--- asociativa.s 2005-10-09 20:37:36.000000000 +0200
+++ asociativa-2.s 2005-10-09 20:38:03.000000000 +0200
@@ -21,7 +21,8 @@
stl $1,16($15)
ldl $2,36($15)
ldl $1,40($15)
- addq $2,$1,$1
+ addl $2,$1,$1
+ addl $31,$1,$1
s4addq $1,0,$2
ldq $1,48($15)
addq $2,$1,$1
addq $2,$1,$1
addl $2,$1,$1
addl $31,$1,$1
Josemilla escribió:Como dijo alguien en este foro: Mira que sois frikis.
No en serio, me gusta leer posts tan técnicos.
Saludos.
movl -8(%rbp), %eax -> mueve lo apuntado por rbp-8 a eax (32 bit). Seguramente sea j (ó k).
movslq %eax,%rdx -> mueve eax a rdx, extendiéndolo (con signo) a 64 bits
movl -12(%rbp), %eax -> mueve lo apuntado por rbp-12 a eax (32 bit). Seguramente k (ó j).
cltq -> extiende eax a rax, pasando a ser de 64 bits.
leaq (%rdx,%rax), %rax -> suma rdx y rax (j + k, ambos 64bit) y lo deja en rax
movl -12(%rbp), %eax -> mete en eax j
addl -8(%rbp), %eax -> le suma k y lo deja en eax (en 32 bits)
cltq -> pasa eax a 64 bits (rax)
el_Salmon escribió:Rebuscando un poco en San Google me he encontrado un articulo interesante que puede ayudarnos:
"x86-64 Machine-Level Programming" Randal E. Bryant
Narf escribió:Y sigo preguntándome cómo es más rápido lo segundo que lo primero. Maravillas de la arquitectura de ordenadores XD.
1 movl -12(%rbp), %eax -> mete en eax j
2 addl -8(%rbp), %eax -> le suma k y lo deja en eax (en 32 bits)
3 cltq -> pasa eax a 64 bits (rax)
1movl -8(%rbp), %eax -> mueve lo apuntado por rbp-8 a eax (32 bit). Seguramente sea j (ó k).
2movslq %eax,%rdx -> mueve eax a rdx, extendiéndolo (con signo) a 64 bits
3movl -12(%rbp), %eax -> mueve lo apuntado por rbp-12 a eax (32 bit). Seguramente k (ó j).
4 cltq -> extiende eax a rax, pasando a ser de 64 bits.
5leaq (%rdx,%rax), %rax -> suma rdx y rax (j + k, ambos 64bit) y lo deja en rax
e-Minguez escribió:Veamos ;)
Si en teoria lo que hace el precompilador es pasar p[i] a *(p+i)... no hay alguna manera de "parar" al compilador para ver el codigo antes de compilar (justo despues de que pase el precompilador)?
Harl escribió:En cualquier caso se pueden ejecutar simulataneamente y
aunque sean más intrucciones, perederan menos ciclos
(cosa de los chips superescalares)
Y no tiene por que afectar que las dos usen rax para eso esta
el renombrado de registros
Harl escribió:PD:
los athlon64 tienen otros 8 registros de proposito general
(16 en total)
Narf escribió:Sí, podría ser posible ejecutar en paralelo los 2 grupos de instrucciones que dices. Pero difícilmente podría ser más rápido que el caso anterior. Igual de rápido, posible; más rápido, bastante difícil
Harl escribió:Puede que sean instrucciones más rápidas.
Ten en cuenta que eso se pasa a microcodigo dentro de la CPU
y puede que ela add se implmente por instrucciones más complejas
que el leaq
Sin saber como esl pipe o el microcodigo del Athlon
es dificl saberlo
Tambien observa que el add que usa el primer codigo
lee de memoria (eso es muy complejo)
y que en el segundo ejemplo se suman dos registros
direactamente.
Las lecturas de memoria es lo que más ciclos pierde
y en el segundo ejemplo esos ciclos perdidos
se enmascaran con las otras instrucciones
¿pero se esta ejecutando más rápido?¿no?
franjva@tay64 ~/prueba2 $ diff -U 10 p1.c p2.c
--- p1.c 2005-10-10 20:14:12.000000000 +0200
+++ p2.c 2005-10-10 20:14:01.000000000 +0200
@@ -1,6 +1,6 @@
main()
{
int i, j=2, k=5, p[10];
long int ind;
- for (ind=10e8; ind--; ) i = *(p + j + k);
+ for (ind=10e8; ind--; ) i = p[j + k];
}
franjva@tay64 ~/prueba2 $ gcc -S p1.c
franjva@tay64 ~/prueba2 $ gcc -S p2.c
franjva@tay64 ~/prueba2 $ diff p1.s p2.s
1c1
< .file "p1.c"
---
> .file "p2.c"
19,20d18
< movl -8(%rbp), %eax
< movslq %eax,%rdx
21a20
> addl -8(%rbp), %eax
23d21
< leaq (%rdx,%rax), %rax
franjva@tay64 ~/prueba2 $ gcc -o p1 p1.c
franjva@tay64 ~/prueba2 $ gcc -o p2 p2.c
franjva@tay64 ~/prueba2 $ time ./p1
real 0m3.710s
user 0m3.640s
sys 0m0.064s
franjva@tay64 ~/prueba2 $ time ./p1
real 0m3.711s
user 0m3.656s
sys 0m0.040s
franjva@tay64 ~/prueba2 $ time ./p1
real 0m3.710s
user 0m3.652s
sys 0m0.048s
franjva@tay64 ~/prueba2 $ time ./p2
real 0m3.248s
user 0m3.196s
sys 0m0.040s
franjva@tay64 ~/prueba2 $ time ./p2
real 0m3.248s
user 0m3.196s
sys 0m0.044s
franjva@tay64 ~/prueba2 $ time ./p2
real 0m3.250s
user 0m3.196s
sys 0m0.044s
--- punteros.s 2005-10-10 15:32:37 -0400
+++ arrays.s 2005-10-10 15:32:37 -0400
@@ -32,7 +32,8 @@
$L5:
ldl $2,20($15)
ldl $1,24($15)
- addq $2,$1,$1
+ addl $2,$1,$1
+ addl $31,$1,$1
s4addq $1,0,$1
lda $2,16($15)
addq $1,$2,$1
ferdy@gendcc02 ~ $ time ./punteros
real 0m28.346s
user 0m28.336s
sys 0m0.007s
ferdy@gendcc02 ~ $ time ./punteros
real 0m28.348s
user 0m28.327s
sys 0m0.021s
ferdy@gendcc02 ~ $ time ./punteros
real 0m28.348s
user 0m28.329s
sys 0m0.018s
ferdy@gendcc02 ~ $ time ./arrays
real 0m32.119s
user 0m32.104s
sys 0m0.014s
ferdy@gendcc02 ~ $ time ./arrays
real 0m32.116s
user 0m32.102s
sys 0m0.014s
ferdy@gendcc02 ~ $ time ./arrays
real 0m32.120s
user 0m32.102s
sys 0m0.017s
ferdy@gendcc02 ~/punteros-test $ vim arrays.s
ferdy@gendcc02 ~/punteros-test $ gcc -o arrays-noaddl-31-1-1 arrays.s
ferdy@gendcc02 ~/punteros-test $ time ./arrays-noaddl-31-1-1
real 0m28.348s
user 0m28.333s
sys 0m0.013s
ferdy@gendcc02 ~/punteros-test $ time ./arrays-noaddl-31-1-1
real 0m28.348s
user 0m28.331s
sys 0m0.016s
ferdy@gendcc02 ~/punteros-test $ time ./arrays-noaddl-31-1-1
real 0m28.347s
user 0m28.331s
sys 0m0.014s
22:17 <@ferdy> do you have any idea on why p[i+j] is different from *(p+i+j) ?
22:17 <@ferdy> I thought the compiler did the p[i] -> *(p+i) change...
22:19 <@kloeri> that would probably depend of locality of p, i and j, number of free registers,
whether gcc thinks it's worth pushing all those registers when calling functions
etc.
22:19 <@ferdy> rather unpredictably then...
22:19 <@kloeri> there's a lot more to optimizers than (usually) meets the eye
22:20 <@ferdy> it generates the same code on x86 (with easy and complex code)... but seems to
generate different code on 64bit platforms...
22:21 <@ferdy> thanks anyway :)
22:21 <@kloeri> depends a lot on number of registers, various penalties etc.
22:22 <@ferdy> I see...
22:22 <@kloeri> so it makes a lot of sense that it doesn't behave equally on different archs
22:23 <@ferdy> mind If I paste this to someone that was also trying to find out why ?
22:23 <@kloeri> not at all
22:23 <@ferdy> thanks million