<?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[SSE: Zugriff auf UNION &#x2F; Shuffle sehr langsam]]></title><description><![CDATA[<p>Hallo,</p>
<p>was SSE angeht, bin ich ein blutiger Anfänger. Mir geht es darum, die folgende Iteration zu beschleunigen, wobei a[] Parameter und &quot;o&quot; und &quot;n&quot; Vektoren sind:</p>
<pre><code class="language-csharp">for (i=0;i&lt;100000000;i++) {
n.x=a[1]+o.x*(a[2]+a[3]*o.x+a[4]*o.y+a[5]*o.z)+o.y*(a[6]+a[7]*o.y+a[8]*o.z)+o.z*(a[9]+a[10]*o.z);
n.y=a[11]+o.x*(a[12]+a[13]*o.x+a[14]*o.y+a[15]*o.z)+o.y*(a[16]+a[17]*o.y+a[18]*o.z)+o.z*(a[19]+a[20]*o.z);
n.z=a[21]+o.x*(a[22]+a[23]*o.x+a[24]*o.y+a[25]*o.z)+o.y*(a[26]+a[27]*o.y+a[28]*o.z)+o.z*(a[29]+a[30]*o.z);
o = n;
}
</code></pre>
<p>Das lässt sich ja wunderbar vektorisieren und sieht dann so aus:</p>
<pre><code class="language-csharp">// Variablendeklaration

union {
    __m128 m128[10];
    float  f[4][10];
} a;

union {
    __m128 m128;
    float  f[4];
} n;

for (i=0;i&lt;10;i++) {
    a.m128[i] = _mm_set_ps( 0.0, a[i+21], a[i+11], a[i+1] );  
}

__m128 block1;
__m128 block2;
__m128 block3;
__m128 tmp1;
__m128 tmp2;
__m128 tmp3;
__m128 tmp4;
__m128 ox;
__m128 oy;
__m128 oz; 

// Eigentliche Iteration

for (i=0;i&lt;100000000;i++) {
    tmp1 = _mm_mul_ps(a.m128[9], oz);
    tmp2 = _mm_add_ps(tmp1, a.m128[8]);

    block1 = _mm_mul_ps(tmp2, oz);
    tmp1 = _mm_mul_ps(a.m128[7], oz);
    tmp2 = _mm_mul_ps(a.m128[6], oy);      
    tmp3 = _mm_add_ps(tmp1, tmp2);
    tmp1 = _mm_add_ps(tmp3, a.m128[5]);
    block2 = _mm_mul_ps(tmp1, oy); 

    tmp1 = _mm_mul_ps(a.m128[4], oz);   
    tmp2 = _mm_mul_ps(a.m128[3], oy);  
    tmp3 = _mm_mul_ps(a.m128[2], ox);  
    tmp4 = _mm_add_ps(tmp1, tmp2);  
    tmp1 = _mm_add_ps(tmp3, tmp4); 
    tmp2 = _mm_add_ps(tmp1, a.m128[1]);
    block3 = _mm_mul_ps(tmp2, ox);

    tmp1 = _mm_add_ps(block1, block2);
    tmp2 = _mm_add_ps(tmp1, block3);
    n.m128 = _mm_add_ps(tmp2, a.m128[0]);

    // Hier der Problembereich: die Übertragung des Ergebnisses 
    // in die nächste Iterationsrunde. Der x-Wert von &quot;n&quot; muss in alle 4
    // Register von ox geschrieben werden.

    ox = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(0,0,0,0));
    oy = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(1,1,1,1));
    oz = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(2,2,2,2));
}
</code></pre>
<p>Für 100 Millionen Iterationen braucht die</p>
<p>-&gt; herkömmliche Variante : 1.907s<br />
-&gt; SSE/Vektorisierte Variante: 1.621s</p>
<p>Das ist zwar ein klein bisschen schneller, aber haut mich nicht wirklich vom Hocker. Stutzig geworden bin ich als ich in beiden Varianten einmal die Wertzuweisung am Ende weggelassen habe, also:</p>
<pre><code class="language-csharp">// o = n; (bei der herkömmlichen Variante)
</code></pre>
<p>und</p>
<pre><code class="language-csharp">// ox = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(0,0,0,0));
// oy = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(1,1,1,1));
// oz = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(2,2,2,2));
</code></pre>
<p>bei der SSE-Variante. Dann sieht das Ergebnis GANZ ANDERS AUS:</p>
<p>-&gt; herkömmliche Variante : 1.582s<br />
-&gt; SSE/Vektorisierte Variante: <strong>0.508s</strong></p>
<p>Dass die Iterationszeit abnimmt, war ja klar, aber dass SSE so viel schneller würde, hätte ich nicht gedacht. Im Umkehrschluss bedeutet dies, dass _mm_shuffle_ps wohl ziemlich langsam ist.</p>
<p>Mit _mm_set_ps1 geht es leider noch langsamer:</p>
<pre><code class="language-csharp">ox = _mm_set_ps1( n.f[0]); 
oy = _mm_set_ps1( n.f[1]); 
oz = _mm_set_ps1( n.f[2]);
</code></pre>
<p>Dann ist SSE langsamer als die herkömmliche Version.</p>
<p>Gibt es da noch einen Trick, den ich übersehen habe?</p>
<p>Danke für eure Hilfe!</p>
<p>Jens</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/201027/sse-zugriff-auf-union-shuffle-sehr-langsam</link><generator>RSS for Node</generator><lastBuildDate>Mon, 29 Jun 2026 06:13:49 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/201027.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 23 Dec 2007 12:01:30 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to SSE: Zugriff auf UNION &#x2F; Shuffle sehr langsam on Sun, 23 Dec 2007 12:01:30 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>was SSE angeht, bin ich ein blutiger Anfänger. Mir geht es darum, die folgende Iteration zu beschleunigen, wobei a[] Parameter und &quot;o&quot; und &quot;n&quot; Vektoren sind:</p>
<pre><code class="language-csharp">for (i=0;i&lt;100000000;i++) {
n.x=a[1]+o.x*(a[2]+a[3]*o.x+a[4]*o.y+a[5]*o.z)+o.y*(a[6]+a[7]*o.y+a[8]*o.z)+o.z*(a[9]+a[10]*o.z);
n.y=a[11]+o.x*(a[12]+a[13]*o.x+a[14]*o.y+a[15]*o.z)+o.y*(a[16]+a[17]*o.y+a[18]*o.z)+o.z*(a[19]+a[20]*o.z);
n.z=a[21]+o.x*(a[22]+a[23]*o.x+a[24]*o.y+a[25]*o.z)+o.y*(a[26]+a[27]*o.y+a[28]*o.z)+o.z*(a[29]+a[30]*o.z);
o = n;
}
</code></pre>
<p>Das lässt sich ja wunderbar vektorisieren und sieht dann so aus:</p>
<pre><code class="language-csharp">// Variablendeklaration

union {
    __m128 m128[10];
    float  f[4][10];
} a;

union {
    __m128 m128;
    float  f[4];
} n;

for (i=0;i&lt;10;i++) {
    a.m128[i] = _mm_set_ps( 0.0, a[i+21], a[i+11], a[i+1] );  
}

__m128 block1;
__m128 block2;
__m128 block3;
__m128 tmp1;
__m128 tmp2;
__m128 tmp3;
__m128 tmp4;
__m128 ox;
__m128 oy;
__m128 oz; 

// Eigentliche Iteration

for (i=0;i&lt;100000000;i++) {
    tmp1 = _mm_mul_ps(a.m128[9], oz);
    tmp2 = _mm_add_ps(tmp1, a.m128[8]);

    block1 = _mm_mul_ps(tmp2, oz);
    tmp1 = _mm_mul_ps(a.m128[7], oz);
    tmp2 = _mm_mul_ps(a.m128[6], oy);      
    tmp3 = _mm_add_ps(tmp1, tmp2);
    tmp1 = _mm_add_ps(tmp3, a.m128[5]);
    block2 = _mm_mul_ps(tmp1, oy); 

    tmp1 = _mm_mul_ps(a.m128[4], oz);   
    tmp2 = _mm_mul_ps(a.m128[3], oy);  
    tmp3 = _mm_mul_ps(a.m128[2], ox);  
    tmp4 = _mm_add_ps(tmp1, tmp2);  
    tmp1 = _mm_add_ps(tmp3, tmp4); 
    tmp2 = _mm_add_ps(tmp1, a.m128[1]);
    block3 = _mm_mul_ps(tmp2, ox);

    tmp1 = _mm_add_ps(block1, block2);
    tmp2 = _mm_add_ps(tmp1, block3);
    n.m128 = _mm_add_ps(tmp2, a.m128[0]);

    // Hier der Problembereich: die Übertragung des Ergebnisses 
    // in die nächste Iterationsrunde. Der x-Wert von &quot;n&quot; muss in alle 4
    // Register von ox geschrieben werden.

    ox = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(0,0,0,0));
    oy = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(1,1,1,1));
    oz = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(2,2,2,2));
}
</code></pre>
<p>Für 100 Millionen Iterationen braucht die</p>
<p>-&gt; herkömmliche Variante : 1.907s<br />
-&gt; SSE/Vektorisierte Variante: 1.621s</p>
<p>Das ist zwar ein klein bisschen schneller, aber haut mich nicht wirklich vom Hocker. Stutzig geworden bin ich als ich in beiden Varianten einmal die Wertzuweisung am Ende weggelassen habe, also:</p>
<pre><code class="language-csharp">// o = n; (bei der herkömmlichen Variante)
</code></pre>
<p>und</p>
<pre><code class="language-csharp">// ox = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(0,0,0,0));
// oy = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(1,1,1,1));
// oz = _mm_shuffle_ps( n.m128, n.m128, _MM_SHUFFLE(2,2,2,2));
</code></pre>
<p>bei der SSE-Variante. Dann sieht das Ergebnis GANZ ANDERS AUS:</p>
<p>-&gt; herkömmliche Variante : 1.582s<br />
-&gt; SSE/Vektorisierte Variante: <strong>0.508s</strong></p>
<p>Dass die Iterationszeit abnimmt, war ja klar, aber dass SSE so viel schneller würde, hätte ich nicht gedacht. Im Umkehrschluss bedeutet dies, dass _mm_shuffle_ps wohl ziemlich langsam ist.</p>
<p>Mit _mm_set_ps1 geht es leider noch langsamer:</p>
<pre><code class="language-csharp">ox = _mm_set_ps1( n.f[0]); 
oy = _mm_set_ps1( n.f[1]); 
oz = _mm_set_ps1( n.f[2]);
</code></pre>
<p>Dann ist SSE langsamer als die herkömmliche Version.</p>
<p>Gibt es da noch einen Trick, den ich übersehen habe?</p>
<p>Danke für eure Hilfe!</p>
<p>Jens</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1425135</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1425135</guid><dc:creator><![CDATA[Jens Friese]]></dc:creator><pubDate>Sun, 23 Dec 2007 12:01:30 GMT</pubDate></item><item><title><![CDATA[Reply to SSE: Zugriff auf UNION &#x2F; Shuffle sehr langsam on Sun, 23 Dec 2007 13:14:58 GMT]]></title><description><![CDATA[<p>Dieser Thread wurde von Moderator/in <a href="http://www.c-plusplus.net/forum/profile-var-mode-is-viewprofile-and-u-is-403.html" rel="nofollow">HumeSikkins</a> aus dem Forum <a href="http://www.c-plusplus.net/forum/viewforum-var-f-is-15.html" rel="nofollow">C++</a> in das Forum <a href="http://www.c-plusplus.net/forum/viewforum-var-f-is-8.html" rel="nofollow">Rund um die Programmierung</a> verschoben.</p>
<p>Im Zweifelsfall bitte auch folgende Hinweise beachten:<br />
<a href="http://www.c-plusplus.net/forum/viewtopic-var-t-is-39405.html" rel="nofollow">C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?</a></p>
<p><em>Dieses Posting wurde automatisch erzeugt.</em></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1425169</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1425169</guid><dc:creator><![CDATA[C++ Forumbot]]></dc:creator><pubDate>Sun, 23 Dec 2007 13:14:58 GMT</pubDate></item><item><title><![CDATA[Reply to SSE: Zugriff auf UNION &#x2F; Shuffle sehr langsam on Mon, 24 Dec 2007 14:13:26 GMT]]></title><description><![CDATA[<p>Hierzu kann man Verschiedenes sagen, allerdings würde ich für die Diskussion vollständigen (d.h. per c&amp;p unmittelbar compilierbaren) Code bevorzugen. Zudem wäre die Kenntnis des verwendeten Compilers und des Prozessors (um die Zeitangabe bewerten zu können) hilfreich.</p>
<p>Möglicherweise ist dieses Thema im Assemblerforum am besten aufgehoben.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1425634</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1425634</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 24 Dec 2007 14:13:26 GMT</pubDate></item></channel></rss>