Bonjour,
J'ai écrit une méthode C++ pour multiplier deux quaternions (machins mathématiques servant à représenter des rotations dans l'espace 3D), bref, le code donne quelque chose comme ça:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 void CQuaternion::mult2(const CQuaternion & P) { float x = m_Q[3] * P.m_Q[0] + m_Q[0] * P.m_Q[3] + m_Q[1] * P.m_Q[2] - m_Q[2] * P.m_Q[1]; float y = m_Q[3] * P.m_Q[1] - m_Q[0] * P.m_Q[2] + m_Q[1] * P.m_Q[3] + m_Q[2] * P.m_Q[0]; float z = m_Q[3] * P.m_Q[2] + m_Q[0] * P.m_Q[1] - m_Q[1] * P.m_Q[0] + m_Q[2] * P.m_Q[3]; float w = m_Q[3] * P.m_Q[3] - m_Q[0] * P.m_Q[0] - m_Q[1] * P.m_Q[1] - m_Q[2] * P.m_Q[2]; m_Q[0] = x ; m_Q[1] = y ; m_Q[2] = z ; m_Q[3] = w ; }
Dans le but d'accélérer les calculs sur mon athlon xp 2200+, j'ai écrit un programme en assembleur, en utilisant nasm, que j'ai intégré dans mon programme C++
Le tout donne quelque chose comme ça:
Dans le code c++:
Et l'assembleur:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 extern "C" { // routine de multiplication en assembleur sse void mm_mult_quaternions ( CQuaternion &res, const CQuaternion &op1); } void CQuaternion::mult1(const CQuaternion & P) { mm_mult_quaternions(*this,P); }
Les deux donnent un bon résultat.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 segment .text global mm_mult_quaternions %define Q_quaternion ebp+8 %define P_quaternion ebp+12 mm_mult_quaternions: push ebp mov ebp,esp push eax push ebx mov eax,[Q_quaternion] mov ebx,[P_quaternion] movaps xmm0,[eax] ; (Q3,Q2,Q1,Q0) movaps xmm1,[ebx] ; (P3,P2,P1,P0) movaps xmm5,[sign] ; (-1,1,-1,1) movaps xmm4,xmm0 shufps xmm4,xmm4, 0xFF ; (Q3,Q3,Q3,Q3) mulps xmm4,xmm1 ; (Q3P3,Q3P2,Q3P1,Q3,P0) => res1 movaps xmm3,xmm0 shufps xmm3,xmm3,0 ; (Q0,Q0,Q0,Q0) shufps xmm1,xmm1,0x1B ; (P0,P1,P2,P3) mulps xmm3,xmm1 ; (P0Q0,P1Q0,P2Q0,P3Q0) xorps xmm3,xmm5 ; (-Q0P0,Q0P1,-Q0P2,Q0P3) addps xmm4,xmm3 ; res2 movaps xmm3,xmm0 shufps xmm3,xmm3,0x55 ; (Q1,Q1,Q1,Q1) shufps xmm1,xmm1,0xB1 ; (P1,P0,P3,P2) mulps xmm3,xmm1 ; (Q1P1,Q1P0,Q1P3,Q1P2) shufps xmm5,xmm5,0xD8 ; (-1,-1,1,1) xorps xmm3,xmm5 ; (-Q1P1,-Q1P0,Q1P3,Q1P2) addps xmm4,xmm3 ; => res3 shufps xmm0,xmm0, 0xAA ; (Q2,Q2,Q2,Q2) shufps xmm1,xmm1,0x1B ; (P2,P3,P0,P1) mulps xmm0,xmm1 ; (Q2P2,Q2P3,Q2P0,Q2P1) shufps xmm5,xmm5, 0xD2 ; (-1,1,1,-1) xorps xmm0,xmm5 ; (-Q2P2,Q2P3,Q2P0,-Q2P1) addps xmm4,xmm0 ; => res movaps [eax],xmm4 pop ebx pop eax mov esp,ebp pop ebp ret align 16 sign: dd 0x00000000 dd 0x80000000 dd 0x00000000 dd 0x80000000
L' ennui c'est que la fonction "mult2" donc en C++, est plus rapide que l'autre "mult1" en assembleur utilisant les instruction SSE du processeur.
Je fais faire 100000 multiplications et je compare le temps entre deux instructions "gettimeofday". La différence est de l'ordre par exemple:
4634 microsecondes pour mult1 (assembleur SSE)
3038 microsecondes pour mult2 (pur c++)
J'utilise gcc 4.1 sur LINUX-Debian etch
Si quelqu'un peut me dire qu'est-ce qui cloche ?
Merci d'avance.




Répondre avec citation








Partager