<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Vektorisierung]]></title><description><![CDATA[<p>Ich wollte ein wenig mit SSE2 spielen und hab dabei ein paar Versuche gestartet.</p>
<p>2 Double-Vektoren b und c sollen addiert werden und das Ergebnis soll in den Vektor c geschrieben werden.</p>
<p>Ich habe verschiedene Array-Größen getestet , wobei ich mich hier mal auf<br />
N = 10000000 beziehe.</p>
<p>Ich habe das ganze 100 mal durchgeführt und die Gesamtausführungszeit gemessen.</p>
<p>Einmal mit SSE2, einmal ohne.</p>
<p>Compiler gcc 4.7, -O0 als Optimierung.</p>
<p>Zeit wurde mit clock_gettime(CLOCK_MONOTONIC, ...) gemessen.</p>
<p>Leider unterscheidet sich die Gesamtausführungszeit für die 100 Additionen fast nicht. Sowohl mit als auch ohne SSE erhalte ich 4 Sekunden und ein paar zerquetschte. Hier der Code. Das einzige, das fehlt ist die Timer-Klasse, die nur die clock_gettime-Methode kapselt.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;vector&gt;
using namespace std;

#include &quot;Timer.h&quot;

#include &lt;emmintrin.h&gt;

void add_vector(double *a, double *b, double *c, const unsigned int&amp; N)
{
	__m128d *av, *bv, *cv;
	av = (__m128d *) a; // assume 16-byte aligned
	bv = (__m128d *) b; // assume 16-byte aligned
	cv = (__m128d *) c; // assume 16-byte aligned
	for (unsigned int i = 0; i &lt; N / 2; i++)
		av[i] = _mm_add_pd(bv[i], cv[i]);
}

void add(double *a, double *b, double *c, const unsigned int&amp; N)
{
	for (unsigned int i = 0; i &lt; N; i++)
		a[i] = b[i] + c[i];
}

int main()
{
	Timer timer;

	const unsigned int N = 10000000;
	double *a, *b, *c;
	a = (double*) malloc(N * sizeof(double));
	b = (double*) malloc(N * sizeof(double));
	c = (double*) malloc(N * sizeof(double));

	for (unsigned int i = 0; i &lt; N; i++)
	{
		c[i] = b[i] = i;
	}

	const unsigned int iterations = 100;

	timer.start();
	for (unsigned int i = 0; i &lt; iterations; i++)
	{
// entweder erste oder zweite Variante, nie beide in einem Programmlauf
		add_vector(a, b, c, N);      
		add(a,b,c,N);
	}
	timer.stop();

	cout &lt;&lt; a[N-1] &lt;&lt; endl;

	timer.printStoppedTime();

	return 0;
}
</code></pre>
<p>Einmal echte Ausgaben:<br />
Ohne Vektorisierung: 4:432148737 (Sec:nanosec)<br />
Mit Vektorisierung : 4:103451164</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/310309/vektorisierung</link><generator>RSS for Node</generator><lastBuildDate>Tue, 04 Aug 2026 19:22:06 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/310309.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 08 Nov 2012 13:39:19 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Vektorisierung on Thu, 08 Nov 2012 13:39:19 GMT]]></title><description><![CDATA[<p>Ich wollte ein wenig mit SSE2 spielen und hab dabei ein paar Versuche gestartet.</p>
<p>2 Double-Vektoren b und c sollen addiert werden und das Ergebnis soll in den Vektor c geschrieben werden.</p>
<p>Ich habe verschiedene Array-Größen getestet , wobei ich mich hier mal auf<br />
N = 10000000 beziehe.</p>
<p>Ich habe das ganze 100 mal durchgeführt und die Gesamtausführungszeit gemessen.</p>
<p>Einmal mit SSE2, einmal ohne.</p>
<p>Compiler gcc 4.7, -O0 als Optimierung.</p>
<p>Zeit wurde mit clock_gettime(CLOCK_MONOTONIC, ...) gemessen.</p>
<p>Leider unterscheidet sich die Gesamtausführungszeit für die 100 Additionen fast nicht. Sowohl mit als auch ohne SSE erhalte ich 4 Sekunden und ein paar zerquetschte. Hier der Code. Das einzige, das fehlt ist die Timer-Klasse, die nur die clock_gettime-Methode kapselt.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;vector&gt;
using namespace std;

#include &quot;Timer.h&quot;

#include &lt;emmintrin.h&gt;

void add_vector(double *a, double *b, double *c, const unsigned int&amp; N)
{
	__m128d *av, *bv, *cv;
	av = (__m128d *) a; // assume 16-byte aligned
	bv = (__m128d *) b; // assume 16-byte aligned
	cv = (__m128d *) c; // assume 16-byte aligned
	for (unsigned int i = 0; i &lt; N / 2; i++)
		av[i] = _mm_add_pd(bv[i], cv[i]);
}

void add(double *a, double *b, double *c, const unsigned int&amp; N)
{
	for (unsigned int i = 0; i &lt; N; i++)
		a[i] = b[i] + c[i];
}

int main()
{
	Timer timer;

	const unsigned int N = 10000000;
	double *a, *b, *c;
	a = (double*) malloc(N * sizeof(double));
	b = (double*) malloc(N * sizeof(double));
	c = (double*) malloc(N * sizeof(double));

	for (unsigned int i = 0; i &lt; N; i++)
	{
		c[i] = b[i] = i;
	}

	const unsigned int iterations = 100;

	timer.start();
	for (unsigned int i = 0; i &lt; iterations; i++)
	{
// entweder erste oder zweite Variante, nie beide in einem Programmlauf
		add_vector(a, b, c, N);      
		add(a,b,c,N);
	}
	timer.stop();

	cout &lt;&lt; a[N-1] &lt;&lt; endl;

	timer.printStoppedTime();

	return 0;
}
</code></pre>
<p>Einmal echte Ausgaben:<br />
Ohne Vektorisierung: 4:432148737 (Sec:nanosec)<br />
Mit Vektorisierung : 4:103451164</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2268948</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2268948</guid><dc:creator><![CDATA[shisha]]></dc:creator><pubDate>Thu, 08 Nov 2012 13:39:19 GMT</pubDate></item><item><title><![CDATA[Reply to Vektorisierung on Thu, 08 Nov 2012 14:03:10 GMT]]></title><description><![CDATA[<p>Ganz vergessen hinzuschreiben, was ich eigentlich will^^</p>
<p>Warum sind die gemessenen Zeiten so ähnlich?</p>
<p>Liegt hier ein fehler in der Benutzung vor?<br />
Ist das Beispiel zu einfach?</p>
<p>Werden vlt doch an irgendeiner Stelle trotz -O0 Optimierungen vorgenommen?<br />
Eventuell &quot;merkt&quot; das Programm ja dass es 100 mal das selbe ausführt oder so...</p>
<p>Sind die Laufzeiten realistisch?<br />
Vielleicht ist ja auch nur meine Timer-Klasse nicht ok?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2268955</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2268955</guid><dc:creator><![CDATA[shisha]]></dc:creator><pubDate>Thu, 08 Nov 2012 14:03:10 GMT</pubDate></item><item><title><![CDATA[Reply to Vektorisierung on Thu, 08 Nov 2012 14:06:37 GMT]]></title><description><![CDATA[<p>Sind denn fast 10% mehr Speed nicht genug? Du machst schließlich fast nix mit den Daten. Das heißt, die meiste Zeit wird dein Programm bloß Daten aus dem Speicher in die CPU-Register schaufeln, ob es die normalen Register sind oder die SSE-Register: Der Unterschied ist bloß ob die CPU dann ein oder zwei Schritte pro Datenpaar braucht, aber für jedes Datenpaar werden einige CPU-Schritte zum Umherschaufeln draufgehen.</p>
<p>Im übrigen kann ich die Zahlen bestätigen (i7, GCC 4.8, Zeit gemessen mit Linux time Kommando):<br />
O0: 5.6 s vs 4.2 s (bei mir also ein bisschen krasser, kann am System liegen)<br />
O3: 2.8 s vs 2.7 s<br />
O3, native: 2.7 s vs 2.7 s<br />
O3, native, lto: 2.7 s vs 2.7 s</p>
<p>Und noch ein alter Spruch: Niemanden interessiert es, wie schnell oder langsam unoptimierter Code läuft.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2268957</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2268957</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Thu, 08 Nov 2012 14:06:37 GMT</pubDate></item><item><title><![CDATA[Reply to Vektorisierung on Thu, 08 Nov 2012 14:29:27 GMT]]></title><description><![CDATA[<p>shisha schrieb:</p>
<blockquote>
<p>Leider unterscheidet sich die Gesamtausführungszeit für die 100 Additionen fast nicht.</p>
</blockquote>
<p>Schau dir doch mal an, was für ein Assemblercode da generiert wird.</p>
<p>Ich denke aber, dass die CPU hier gar nicht der Flaschenhals ist, sondern der Speicher. Du läufst zwar schön linear durch drei Speicherbereiche, berechnest aber nur sehr wenig. Eine Floatingpoint-Addition ist heute glaub'ich relativ billig. Das würde bedeuten: Die Berechnungen kosten zwar weniger Taktzyklen, aber nun wartet die CPU auf die neuen Daten aus dem Speicher und hat kaum etwas zu tun.</p>
<p>Deswegen lohnt sich std::valarray ja auch nicht wirklich, auch wenn es SSE-optimiert implementiert wurde. valarray kann gegen etwas ähnliches was per Expression-Templates implementiert wurde, heutzutage nicht mehr richtig gegen anstinken -- performancetechnisch.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2268961</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2268961</guid><dc:creator><![CDATA[krümelkacker]]></dc:creator><pubDate>Thu, 08 Nov 2012 14:29:27 GMT</pubDate></item><item><title><![CDATA[Reply to Vektorisierung on Thu, 08 Nov 2012 14:42:00 GMT]]></title><description><![CDATA[<p>Mein Compiler (Vs2012) erzeugt auch fuer die Funktion 'add' SSE2-Intruktionen. Hinzu kommt loop unrolling.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2268972</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2268972</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Thu, 08 Nov 2012 14:42:00 GMT</pubDate></item><item><title><![CDATA[Reply to Vektorisierung on Thu, 08 Nov 2012 15:58:38 GMT]]></title><description><![CDATA[<p>knivil schrieb:</p>
<blockquote>
<p>Mein Compiler (Vs2012) erzeugt auch fuer die Funktion 'add' SSE2-Intruktionen. Hinzu kommt loop unrolling.</p>
</blockquote>
<p>Auch in unoptimiertem Code? <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f62e.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--face_with_open_mouth"
      title=":open_mouth:"
      alt="😮"
    /> Das finde ich aber arg aggressiv. Wie soll man denn bei loop unrolling noch vernünftig debuggen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2269004</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2269004</guid><dc:creator><![CDATA[SeppJ]]></dc:creator><pubDate>Thu, 08 Nov 2012 15:58:38 GMT</pubDate></item><item><title><![CDATA[Reply to Vektorisierung on Fri, 09 Nov 2012 10:19:27 GMT]]></title><description><![CDATA[<p>knivil schrieb:</p>
<blockquote>
<p>Mein Compiler (Vs2012) erzeugt auch fuer die Funktion 'add' SSE2-Intruktionen. Hinzu kommt loop unrolling.</p>
</blockquote>
<p>Aber nur, wenn das in den Optionen so eingestellt ist. Aber selbst wenn ich die Erzeugung von SSE2 Instruktionen ausschalte kommen dieselben Zeiten raus. Das ist komplett memory-bound. Schneller wird es nur, wenn ich die Benchmark-Schleife (die über die Iterationen läuft) mit parallel_for (aus ppl.h) laufen lasse. Aber das optimiert den Benchmark und nicht den gebenchmarkten Algorithmus. Ein parallel_for in add() bringt hingegen nichts.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2269206</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2269206</guid><dc:creator><![CDATA[VS]]></dc:creator><pubDate>Fri, 09 Nov 2012 10:19:27 GMT</pubDate></item><item><title><![CDATA[Reply to Vektorisierung on Fri, 09 Nov 2012 12:05:44 GMT]]></title><description><![CDATA[<blockquote>
<p>parallel_for</p>
</blockquote>
<p>Das ist komplett am Thema vorbei.</p>
<blockquote>
<p>Wie soll man denn bei loop unrolling noch vernünftig debuggen?</p>
</blockquote>
<p>Wenn du deinen Breakpoint setzt, dann siehst du fuer gewoehnlich nur den Cpp-Code. Bei Loopunrolling haettest du dann eben 3 Breakpoints im Asm-Code. Aber so genau habe ich das nicht analysiert. Es ist halt ein kleiner ... nicht aussagekraeftiger Benchmark, da wollte ich nicht zuviel Zeit investieren.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2269258</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2269258</guid><dc:creator><![CDATA[knivil]]></dc:creator><pubDate>Fri, 09 Nov 2012 12:05:44 GMT</pubDate></item></channel></rss>