Da ich mich auch schon eine weile damit beschäftige habe ich mal fix eine Beispiel-Implementierung für die Nutzung von Intrinsics gemacht.
Kurze vector-klasse:
|
C-/C++-Quelltext
|
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
|
#ifndef __VECTOR3_HPP___
#define __VECTOR3_HPP___
#include <xmmintrin.h>
template< typename TypeT >
class vector {
public:
vector(TypeT x_, TypeT y_, TypeT z_)
: x(x_)
, y(y_)
, z(z_) {}
TypeT dot(vector< TypeT > other) {
return x * other.x + y * other.y + z * other.z;
}
TypeT dot_sse(vector< TypeT > const& other) {
TypeT v1_sse_in[3] __attribute__((aligned(16))) = { x, y, z };
TypeT v2_sse_in[3] __attribute__((aligned(16))) = { other.x, other.y, other.z };
TypeT v_sse_out[3] __attribute__((aligned(16)));
__m128 a, b, c;
a = _mm_load_ps(v1_sse_in);
b = _mm_load_ps(v2_sse_in);
c = _mm_mul_ps(a, b);
_mm_store_ps(v_sse_out, c);
return v_sse_out[0] + v_sse_out[1] + v_sse_out[2];
}
TypeT x;
TypeT y;
TypeT z;
};
typedef vector< float > vector3f;
typedef vector< double > vector3d;
#endif // __VECTOR3_HPP___
|
Programm zum Testen (mit nanosekunden-genauer Zeitmessung):
|
C-/C++-Quelltext
|
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
|
#include <iostream>
#include <iomanip>
#include "vector3.hpp"
typedef unsigned long long tsc_t;
static inline tsc_t read_tsc() {
tsc_t tsc;
__asm__ __volatile__ ("rdtsc": "=A"(tsc));
return tsc;
}
int main(int argc, char* argv[]) {
vector3f v1(1.0f, 2.0f, 3.0f);
vector3f v2(4.0f, 5.0f, 6.0f);
float dot_product;
tsc_t start, end;
start = read_tsc();
dot_product = v1.dot(v2);
end = read_tsc();
std::cout << "ordinary version: " << dot_product
<< ", Time: " << std::setprecision(4)
<< (end - start) << "ns." << std::endl;
start = read_tsc();
dot_product = v1.dot_sse(v2);
end = read_tsc();
std::cout << "sse version: " << dot_product
<< ", Time: " << std::setprecision(4)
<< (end - start) << "ns." << std::endl;
return 0;
}
|
Ausgabe auf meine Rechner (CPU: Q6600, kompiliert mit g++ 4.3.3-dw2-tdm-1, flags: -msse -O0):
|
Quellcode
|
1
2
|
ordinary version: 32, Time: 1386ns.
sse version: 32, Time: 378ns.
|
und jetzt mit -O3:
|
Quellcode
|
1
2
|
ordinary version: 32, Time: 63ns.
sse version: 32, Time: 270ns.
|
Wie man sieht kann der Compiler eindeutig besser Optimieren als wenn man mit hardwarenahem SSE ran geht. SSE ist nur dann besser wenn man den Compiler, warum auch immer, nicht optimieren lässt. Denke SSE und Co. haben ihre Stärken auf anderer Ebene aber eben nicht beim optimieren des Punktprodukts eines Vektors
Gut Schuß
VuuRWerK
[edit]Mir viel noch folgendes ein: Vielleicht sollte man das ganze nochmal testen mit nicht-konstanten Werten, denke zwar das der Compiler dennoch besser optimiert aber man könnte ja mal schaun wie nach man mit SSE rankommt
Ich probier das dann mal sobald ich daheim bin.[/edit]