<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Florian Mätschke   -    .NET Strikes Back - HPC</title>
    <link>http://blogs.dotnet-braunschweig.de/Florian/</link>
    <description>C#, XNA, .NET Development &amp; Entertainment</description>
    <language>de-de</language>
    <copyright>Florian Mätschke</copyright>
    <lastBuildDate>Fri, 11 Sep 2009 19:05:33 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.0.7226.0</generator>
    <managingEditor>f.maetschke@dotnet-braunschweig.de</managingEditor>
    <webMaster>f.maetschke@dotnet-braunschweig.de</webMaster>
    <item>
      <trackback:ping>http://blogs.dotnet-braunschweig.de/Florian/Trackback.aspx?guid=18bc008d-7c8f-4fd6-accc-41e942b643fd</trackback:ping>
      <pingback:server>http://blogs.dotnet-braunschweig.de/Florian/pingback.aspx</pingback:server>
      <pingback:target>http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,18bc008d-7c8f-4fd6-accc-41e942b643fd.aspx</pingback:target>
      <dc:creator>Florian Mätschke</dc:creator>
      <wfw:comment>http://blogs.dotnet-braunschweig.de/Florian/CommentView,guid,18bc008d-7c8f-4fd6-accc-41e942b643fd.aspx</wfw:comment>
      <wfw:commentRss>http://blogs.dotnet-braunschweig.de/Florian/SyndicationService.asmx/GetEntryCommentsRss?guid=18bc008d-7c8f-4fd6-accc-41e942b643fd</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://blogs.dotnet-braunschweig.de/Florian/content/binary/WindowsLiveWriter/PerformanceOptimierunginCMehrdimensional_121BC/no_pressure_no_speed_2.jpg">
            <img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="No Pressure, No Speed!" border="0" alt="No Pressure, No Speed!" src="http://blogs.dotnet-braunschweig.de/Florian/content/binary/WindowsLiveWriter/PerformanceOptimierunginCMehrdimensional_121BC/no_pressure_no_speed_thumb.jpg" width="504" height="379" />
          </a>Die
Verwendung von mehrdimensionalen Arrays ist oftmals ein wesentlicher Bestandteil in
Programmen. Je nach Problemstellung und Größe der Arrays kann der Zugriff auf solche
die Laufzeit eines Programms negativ beeinflussen. 
</p>
        <p>
In C# gibt es grundsätzlich neben den eindimensionalen Arrays 2 Arten von mehrdimensionalen
Arrays. Diese unterscheiden sich nur in ihrer Notation:
</p>
        <ul>
          <li>
[,] – Multidimensionale Arrays 
</li>
          <li>
[][] – Jagged-Arrays 
</li>
        </ul>
        <p>
Bei multidimensionalen Arrays werden die Dimensionen durch ein Komma getrennt, bei
Jagged-Arrays durch die erneute Klammerung. Multidimensionale Arrays haben eine feste
Größe. Bei einem Jagged-Array kann die Größe variieren, da es ein Array von Arrays
ist. Das ist im Grunde genommen eigentlich schon alles was man darüber wissen sollte.
– Wie aber steht es jetzt mit den Geschwindigkeits-Unterschieden? Gibt es vielleicht
noch andere Möglichkeiten?
</p>
        <p>
Ja! Die gibt es definitiv. Bei einem Disput mit einem Kommilitonen über genau dieses
Thema hat dieser prompt einen Eintrag in seinem Blog dazu und dazugehörige Messergebnisse
veröffentlicht:
</p>
        <p>
 <a title="Manolo's HPC Blog" href="http://mshpc.spaces.live.com/blog/cns!25718992934D10D1!121.entry">Manolo's
HPC Blog</a></p>
        <p>
Er verwendet dort eine weitere, eher aus der Welt der C Programmierer bekannte Technik,
um mehrdimensionale Arrays zu realisieren. Es wird einfach ein eindimensionales Array
verwendet, das alle Elemente linear beinhaltet.
</p>
        <p>
Der Zugriff erfolgt über die Formel:
</p>
        <p>
          <em>position = Y * breite + X</em>
        </p>
        <p>
          <em>
          </em>
        </p>
        <p>
Als ich das Ergebnis das erste mal sah, konnte ich kaum glauben, dass dieses schneller
als ein Jagged-Array ist. Aber bei einer genaueren Untersuchung erklärt sich auch
warum. Darf man dem <a title="http://aspadvice.com/blogs/maniknet/archive/2008/04/18/C_2300_-und-ASP.Net-Performance-Optimierungen.aspx" href="http://aspadvice.com/blogs/maniknet/archive/2008/04/18/C_2300_-und-ASP.Net-Performance-Optimierungen.aspx" target="_blank">manik.net
– Blog</a> trauen:
</p>
        <blockquote>
          <p>
MSIL kann eindimensionale Arrays besser optimieren wie mehrdimensionale. 
<br />
Auf MSIL ebene sieht man den unterschied:
</p>
          <p>
int [,] secondarr = new int[1, 2]; 
<br />
secondarr[0, 0] = 40; 
<br /><br />
MSIL: 
<br />
IL_0029: ldc.i4.s 40 
<br />
IL_002b: call instance void int32[0...,0...]::Set(int32, int32,in32)
</p>
          <p>
Mit einem Jaggedarray sieht das ganze dann auf MSIL so aus: 
<br />
IL_001c: ldc.i4.s 40 
<br />
IL_001e: stelem.i4 
<br />
stelem = „store an element“
</p>
          <p>
Bei mehrdimensionalen Arrays wird der ganze „Generic Type“-Kram also betrieben was
einiges an Overhead erzeugt. 
</p>
        </blockquote>
        <p>
Daher ist es ratsam wann immer möglich ein lineares Array anstelle von einem Mehrdimensionalen
Array zu verwenden.
</p>
        <p>
Ich habe mir die ganze Sache aber in eigener Regie noch einmal angesehen. Als Ergebnis
habe ich es geschafft, eine noch schnellere Variante zu programmieren. Diese setzt
allerdings ein \unsafe bei den Compiler-Einstellungen voraus. 
</p>
        <p>
Anstelle auf die einzelnen Elemente des Arrays zuzugreifen, wird direkt auf einen
Pointer zugegriffen. – Eigentlich nichts besonderes, kann aber bei manch einer Berechnung
den ein oder anderen Performancegewinn bringen.
</p>
        <p>
Die Ergebnisse sehen dabei wie folgt aus:
</p>
        <blockquote>
          <p>
Result = 249500250000000 
<br />
1000times: Matrix A with [1000, 1000]  (matrix array): 11637ms 
<br />
Result = 249500250000000 
<br />
1000times: Matrix B with [1000][1000]  (jagged array): 6361ms 
<br />
Result = 249500250000000 
<br />
1000times: Matrix C with [1000* 1000]  (linear array): 5486ms 
<br />
Result = 249500250000000 
<br />
1000times: Matrix D with [1000* 1000]  (unsafe array): <strong>5175ms!!!</strong></p>
        </blockquote>
        <p>
Gegenüber dem [,] Array sind die beiden letzten Varianten ungefähr doppelt so schnell.
</p>
        <p>
          <strong>
            <font size="4">Also für die Zukunft merken:</font>
          </strong>
        </p>
        <ul>
          <ul>
          </ul>
          <li>
            <p>
              <strong>
                <font size="5">Keine [,]-Arrays verwenden!</font>
              </strong>
            </p>
          </li>
          <li>
            <p>
              <strong>
                <font size="5">[][]-Arrays können durch lineare Arrays ersetzt werden!</font>
              </strong>
            </p>
          </li>
        </ul>
        <p>
Den Quellcode zum verifizieren und selber Testen gibt es hier:
</p>
        <pre class="csharpcode">
          <span class="kwrd">using</span> System; <span class="kwrd">using</span> System.Collections.Generic; <span class="kwrd">using</span> System.Linq; <span class="kwrd">using</span> System.Text; <span class="kwrd">using</span> System.Diagnostics; <span class="kwrd">namespace</span> SpeedTest
{ <span class="kwrd">class</span> Program { <span class="kwrd">static</span><span class="kwrd">void</span> Main(<span class="kwrd">string</span>[]
args) { <span class="kwrd">int</span> n = 1000; Stopwatch swatch = <span class="kwrd">new</span> Stopwatch(); <span class="kwrd">double</span>[,]
A = <span class="kwrd">new</span><span class="kwrd">double</span>[n, n]; swatch.Start();
CalcMatrix(A,n); swatch.Stop(); Console.WriteLine(<span class="str">"{0}times:
Matrix A with [{0}, {0}] (matrix array): {1}ms"</span>, n, swatch.ElapsedMilliseconds);
swatch.Reset(); <span class="kwrd">double</span>[][] B = <span class="kwrd">new</span><span class="kwrd">double</span>[n][]; <span class="rem">//
init jagged arrays</span><span class="kwrd">for</span> (<span class="kwrd">int</span> i
= 0; i &lt; n; i++) { B[i] = <span class="kwrd">new</span><span class="kwrd">double</span>[n];
} swatch.Start(); CalcJagged(B, n); swatch.Stop(); Console.WriteLine(<span class="str">"{0}times:
Matrix B with [{0}][{0}] (jagged array): {1}ms"</span>, n, swatch.ElapsedMilliseconds);
swatch.Reset(); <span class="kwrd">double</span>[] C = <span class="kwrd">new</span><span class="kwrd">double</span>[n*
n]; swatch.Start(); CalcLinear(C, n); swatch.Stop(); Console.WriteLine(<span class="str">"{0}times:
Matrix C with [{0}* {0}] (linear array): {1}ms"</span>, n, swatch.ElapsedMilliseconds);
swatch.Reset(); <span class="kwrd">unsafe</span> { <span class="kwrd">double</span>[]
D = <span class="kwrd">new</span><span class="kwrd">double</span>[n * n]; swatch.Start(); <span class="kwrd">fixed</span>(<span class="kwrd">double</span>*
pD = D) CalcUnsafe(pD,n); swatch.Stop(); } Console.WriteLine(<span class="str">"{0}times:
Matrix D with [{0}* {0}] (unsafe array): {1}ms"</span>, n, swatch.ElapsedMilliseconds);
swatch.Reset(); Console.ReadKey(); } <span class="kwrd">private</span><span class="kwrd">static</span><span class="kwrd">void</span> CalcJagged(<span class="kwrd">double</span>[][]
B, <span class="kwrd">int</span> n) { <span class="kwrd">double</span> result = 0; <span class="kwrd">for</span> (<span class="kwrd">int</span> x
= 0; x &lt; n; x++) { <span class="kwrd">for</span> (<span class="kwrd">int</span> i
= 0; i &lt; n; i++) { <span class="kwrd">for</span> (<span class="kwrd">int</span> j
= 0; j &lt; n; j++) { B[i][j] = i * j; result += B[i][j]; } } } Console.WriteLine(<span class="str">"Result
= "</span> + result); } <span class="kwrd">private</span><span class="kwrd">static</span><span class="kwrd">void</span> CalcMatrix( <span class="kwrd">double</span>[,]
A, <span class="kwrd">int</span> n) { <span class="kwrd">double</span> result = 0; <span class="kwrd">for</span> (<span class="kwrd">int</span> x
= 0; x &lt; n; x++) { <span class="kwrd">for</span> (<span class="kwrd">int</span> i
= 0; i &lt; n; i++) { <span class="kwrd">for</span> (<span class="kwrd">int</span> j
= 0; j &lt; n; j++) { A[i, j] = i * j; result += A[i, j]; } } } Console.WriteLine(<span class="str">"Result
= "</span> + result); } <span class="kwrd">private</span><span class="kwrd">static</span><span class="kwrd">void</span> CalcLinear(<span class="kwrd">double</span>[]
C, <span class="kwrd">int</span> n) { <span class="kwrd">double</span> result = 0; <span class="kwrd">for</span> (<span class="kwrd">int</span> x
= 0; x &lt; n; x++) { <span class="kwrd">for</span> (<span class="kwrd">int</span> i
= 0; i &lt; n; i++) { <span class="kwrd">for</span> (<span class="kwrd">int</span> j
= 0; j &lt; n; j++) { C[i * n + j] = i * j; result += C[i * n + j]; } } } Console.WriteLine(<span class="str">"Result
= "</span> + result); } <span class="kwrd">unsafe</span><span class="kwrd">private</span><span class="kwrd">static</span><span class="kwrd">void</span> CalcUnsafe(<span class="kwrd">double</span>*
pD, <span class="kwrd">int</span> n) { <span class="kwrd">double</span> result = 0; <span class="kwrd">for</span> (<span class="kwrd">int</span> x
= 0; x &lt; n; x++) { <span class="kwrd">for</span> (<span class="kwrd">int</span> i
= 0; i &lt; n; i++) { <span class="kwrd">for</span> (<span class="kwrd">int</span> j
= 0; j &lt; n; j++) { *(pD + i * n + j) = i * j; result += *(pD + i * n + j); } }
} Console.WriteLine(<span class="str">"Result = "</span> + result); } }
}</pre>
        <img width="0" height="0" src="http://blogs.dotnet-braunschweig.de/Florian/aggbug.ashx?id=18bc008d-7c8f-4fd6-accc-41e942b643fd" />
      </body>
      <title>Performance Optimierung in C# &amp;ndash; Mehrdimensionale Arrays</title>
      <guid isPermaLink="false">http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,18bc008d-7c8f-4fd6-accc-41e942b643fd.aspx</guid>
      <link>http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,18bc008d-7c8f-4fd6-accc-41e942b643fd.aspx</link>
      <pubDate>Fri, 11 Sep 2009 19:05:33 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://blogs.dotnet-braunschweig.de/Florian/content/binary/WindowsLiveWriter/PerformanceOptimierunginCMehrdimensional_121BC/no_pressure_no_speed_2.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="No Pressure, No Speed!" border="0" alt="No Pressure, No Speed!" src="http://blogs.dotnet-braunschweig.de/Florian/content/binary/WindowsLiveWriter/PerformanceOptimierunginCMehrdimensional_121BC/no_pressure_no_speed_thumb.jpg" width="504" height="379" /&gt;&lt;/a&gt;Die
Verwendung von mehrdimensionalen Arrays ist oftmals ein wesentlicher Bestandteil in
Programmen. Je nach Problemstellung und Größe der Arrays kann der Zugriff auf solche
die Laufzeit eines Programms negativ beeinflussen. 
&lt;/p&gt;
&lt;p&gt;
In C# gibt es grundsätzlich neben den eindimensionalen Arrays 2 Arten von mehrdimensionalen
Arrays. Diese unterscheiden sich nur in ihrer Notation:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
[,] – Multidimensionale Arrays 
&lt;/li&gt;
&lt;li&gt;
[][] – Jagged-Arrays 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Bei multidimensionalen Arrays werden die Dimensionen durch ein Komma getrennt, bei
Jagged-Arrays durch die erneute Klammerung. Multidimensionale Arrays haben eine feste
Größe. Bei einem Jagged-Array kann die Größe variieren, da es ein Array von Arrays
ist. Das ist im Grunde genommen eigentlich schon alles was man darüber wissen sollte.
– Wie aber steht es jetzt mit den Geschwindigkeits-Unterschieden? Gibt es vielleicht
noch andere Möglichkeiten?
&lt;/p&gt;
&lt;p&gt;
Ja! Die gibt es definitiv. Bei einem Disput mit einem Kommilitonen über genau dieses
Thema hat dieser prompt einen Eintrag in seinem Blog dazu und dazugehörige Messergebnisse
veröffentlicht:
&lt;/p&gt;
&lt;p&gt;
&amp;#160;&lt;a title="Manolo&amp;#39;s HPC Blog" href="http://mshpc.spaces.live.com/blog/cns!25718992934D10D1!121.entry"&gt;Manolo's
HPC Blog&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
Er verwendet dort eine weitere, eher aus der Welt der C Programmierer bekannte Technik,
um mehrdimensionale Arrays zu realisieren. Es wird einfach ein eindimensionales Array
verwendet, das alle Elemente linear beinhaltet.
&lt;/p&gt;
&lt;p&gt;
Der Zugriff erfolgt über die Formel:
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;position = Y * breite + X&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;em&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
Als ich das Ergebnis das erste mal sah, konnte ich kaum glauben, dass dieses schneller
als ein Jagged-Array ist. Aber bei einer genaueren Untersuchung erklärt sich auch
warum. Darf man dem &lt;a title="http://aspadvice.com/blogs/maniknet/archive/2008/04/18/C_2300_-und-ASP.Net-Performance-Optimierungen.aspx" href="http://aspadvice.com/blogs/maniknet/archive/2008/04/18/C_2300_-und-ASP.Net-Performance-Optimierungen.aspx" target="_blank"&gt;manik.net
– Blog&lt;/a&gt; trauen:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
MSIL kann eindimensionale Arrays besser optimieren wie mehrdimensionale. 
&lt;br /&gt;
Auf MSIL ebene sieht man den unterschied:
&lt;/p&gt;
&lt;p&gt;
int [,] secondarr = new int[1, 2]; 
&lt;br /&gt;
secondarr[0, 0] = 40; 
&lt;br /&gt;
&lt;br /&gt;
MSIL: 
&lt;br /&gt;
IL_0029: ldc.i4.s 40 
&lt;br /&gt;
IL_002b: call instance void int32[0...,0...]::Set(int32, int32,in32)
&lt;/p&gt;
&lt;p&gt;
Mit einem Jaggedarray sieht das ganze dann auf MSIL so aus: 
&lt;br /&gt;
IL_001c: ldc.i4.s 40 
&lt;br /&gt;
IL_001e: stelem.i4 
&lt;br /&gt;
stelem = „store an element“
&lt;/p&gt;
&lt;p&gt;
Bei mehrdimensionalen Arrays wird der ganze „Generic Type“-Kram also betrieben was
einiges an Overhead erzeugt. 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Daher ist es ratsam wann immer möglich ein lineares Array anstelle von einem Mehrdimensionalen
Array zu verwenden.
&lt;/p&gt;
&lt;p&gt;
Ich habe mir die ganze Sache aber in eigener Regie noch einmal angesehen. Als Ergebnis
habe ich es geschafft, eine noch schnellere Variante zu programmieren. Diese setzt
allerdings ein \unsafe bei den Compiler-Einstellungen voraus. 
&lt;/p&gt;
&lt;p&gt;
Anstelle auf die einzelnen Elemente des Arrays zuzugreifen, wird direkt auf einen
Pointer zugegriffen. – Eigentlich nichts besonderes, kann aber bei manch einer Berechnung
den ein oder anderen Performancegewinn bringen.
&lt;/p&gt;
&lt;p&gt;
Die Ergebnisse sehen dabei wie folgt aus:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
Result = 249500250000000 
&lt;br /&gt;
1000times: Matrix A with [1000, 1000]&amp;#160; (matrix array): 11637ms 
&lt;br /&gt;
Result = 249500250000000 
&lt;br /&gt;
1000times: Matrix B with [1000][1000]&amp;#160; (jagged array): 6361ms 
&lt;br /&gt;
Result = 249500250000000 
&lt;br /&gt;
1000times: Matrix C with [1000* 1000]&amp;#160; (linear array): 5486ms 
&lt;br /&gt;
Result = 249500250000000 
&lt;br /&gt;
1000times: Matrix D with [1000* 1000]&amp;#160; (unsafe array): &lt;strong&gt;5175ms!!!&lt;/strong&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Gegenüber dem [,] Array sind die beiden letzten Varianten ungefähr doppelt so schnell.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;font size="4"&gt;Also für die Zukunft merken:&lt;/font&gt;&lt;/strong&gt; 
&lt;/p&gt;
&lt;ul&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;li&gt;
&lt;p&gt;
&lt;strong&gt;&lt;font size="5"&gt;Keine [,]-Arrays verwenden!&lt;/font&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;
&lt;strong&gt;&lt;font size="5"&gt;[][]-Arrays können durch lineare Arrays ersetzt werden!&lt;/font&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Den Quellcode zum verifizieren und selber Testen gibt es hier:
&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text; &lt;span class="kwrd"&gt;using&lt;/span&gt; System.Diagnostics; &lt;span class="kwrd"&gt;namespace&lt;/span&gt; SpeedTest
{ &lt;span class="kwrd"&gt;class&lt;/span&gt; Program { &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[]
args) { &lt;span class="kwrd"&gt;int&lt;/span&gt; n = 1000; Stopwatch swatch = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stopwatch(); &lt;span class="kwrd"&gt;double&lt;/span&gt;[,]
A = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt;[n, n]; swatch.Start();
CalcMatrix(A,n); swatch.Stop(); Console.WriteLine(&lt;span class="str"&gt;&amp;quot;{0}times:
Matrix A with [{0}, {0}] (matrix array): {1}ms&amp;quot;&lt;/span&gt;, n, swatch.ElapsedMilliseconds);
swatch.Reset(); &lt;span class="kwrd"&gt;double&lt;/span&gt;[][] B = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt;[n][]; &lt;span class="rem"&gt;//
init jagged arrays&lt;/span&gt; &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i
= 0; i &amp;lt; n; i++) { B[i] = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt;[n];
} swatch.Start(); CalcJagged(B, n); swatch.Stop(); Console.WriteLine(&lt;span class="str"&gt;&amp;quot;{0}times:
Matrix B with [{0}][{0}] (jagged array): {1}ms&amp;quot;&lt;/span&gt;, n, swatch.ElapsedMilliseconds);
swatch.Reset(); &lt;span class="kwrd"&gt;double&lt;/span&gt;[] C = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt;[n*
n]; swatch.Start(); CalcLinear(C, n); swatch.Stop(); Console.WriteLine(&lt;span class="str"&gt;&amp;quot;{0}times:
Matrix C with [{0}* {0}] (linear array): {1}ms&amp;quot;&lt;/span&gt;, n, swatch.ElapsedMilliseconds);
swatch.Reset(); &lt;span class="kwrd"&gt;unsafe&lt;/span&gt; { &lt;span class="kwrd"&gt;double&lt;/span&gt;[]
D = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt;[n * n]; swatch.Start(); &lt;span class="kwrd"&gt;fixed&lt;/span&gt;(&lt;span class="kwrd"&gt;double&lt;/span&gt;*
pD = D) CalcUnsafe(pD,n); swatch.Stop(); } Console.WriteLine(&lt;span class="str"&gt;&amp;quot;{0}times:
Matrix D with [{0}* {0}] (unsafe array): {1}ms&amp;quot;&lt;/span&gt;, n, swatch.ElapsedMilliseconds);
swatch.Reset(); Console.ReadKey(); } &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CalcJagged(&lt;span class="kwrd"&gt;double&lt;/span&gt;[][]
B, &lt;span class="kwrd"&gt;int&lt;/span&gt; n) { &lt;span class="kwrd"&gt;double&lt;/span&gt; result = 0; &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; x
= 0; x &amp;lt; n; x++) { &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i
= 0; i &amp;lt; n; i++) { &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j
= 0; j &amp;lt; n; j++) { B[i][j] = i * j; result += B[i][j]; } } } Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Result
= &amp;quot;&lt;/span&gt; + result); } &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CalcMatrix( &lt;span class="kwrd"&gt;double&lt;/span&gt;[,]
A, &lt;span class="kwrd"&gt;int&lt;/span&gt; n) { &lt;span class="kwrd"&gt;double&lt;/span&gt; result = 0; &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; x
= 0; x &amp;lt; n; x++) { &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i
= 0; i &amp;lt; n; i++) { &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j
= 0; j &amp;lt; n; j++) { A[i, j] = i * j; result += A[i, j]; } } } Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Result
= &amp;quot;&lt;/span&gt; + result); } &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CalcLinear(&lt;span class="kwrd"&gt;double&lt;/span&gt;[]
C, &lt;span class="kwrd"&gt;int&lt;/span&gt; n) { &lt;span class="kwrd"&gt;double&lt;/span&gt; result = 0; &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; x
= 0; x &amp;lt; n; x++) { &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i
= 0; i &amp;lt; n; i++) { &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j
= 0; j &amp;lt; n; j++) { C[i * n + j] = i * j; result += C[i * n + j]; } } } Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Result
= &amp;quot;&lt;/span&gt; + result); } &lt;span class="kwrd"&gt;unsafe&lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CalcUnsafe(&lt;span class="kwrd"&gt;double&lt;/span&gt;*
pD, &lt;span class="kwrd"&gt;int&lt;/span&gt; n) { &lt;span class="kwrd"&gt;double&lt;/span&gt; result = 0; &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; x
= 0; x &amp;lt; n; x++) { &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i
= 0; i &amp;lt; n; i++) { &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; j
= 0; j &amp;lt; n; j++) { *(pD + i * n + j) = i * j; result += *(pD + i * n + j); } }
} Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Result = &amp;quot;&lt;/span&gt; + result); } }
}&lt;/pre&gt;
&lt;img width="0" height="0" src="http://blogs.dotnet-braunschweig.de/Florian/aggbug.ashx?id=18bc008d-7c8f-4fd6-accc-41e942b643fd" /&gt;</description>
      <comments>http://blogs.dotnet-braunschweig.de/Florian/CommentView,guid,18bc008d-7c8f-4fd6-accc-41e942b643fd.aspx</comments>
      <category>.NET</category>
      <category>C#</category>
      <category>HPC</category>
    </item>
    <item>
      <trackback:ping>http://blogs.dotnet-braunschweig.de/Florian/Trackback.aspx?guid=fa03aa3b-733d-4c8d-908c-2409d999fe04</trackback:ping>
      <pingback:server>http://blogs.dotnet-braunschweig.de/Florian/pingback.aspx</pingback:server>
      <pingback:target>http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,fa03aa3b-733d-4c8d-908c-2409d999fe04.aspx</pingback:target>
      <dc:creator>Florian Mätschke</dc:creator>
      <wfw:comment>http://blogs.dotnet-braunschweig.de/Florian/CommentView,guid,fa03aa3b-733d-4c8d-908c-2409d999fe04.aspx</wfw:comment>
      <wfw:commentRss>http://blogs.dotnet-braunschweig.de/Florian/SyndicationService.asmx/GetEntryCommentsRss?guid=fa03aa3b-733d-4c8d-908c-2409d999fe04</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Ich hatte gestern bereits mit einem kleinen Problem zu kämpfen, welches sich aber
recht leicht beheben lässt.
</p>
        <p>
Nachdem man eine neue Compute-Node hinzugefügt hat, und einen <strong>Framework-Test</strong> ausgeführt
hat, kam es zu folgenden Fehler:
</p>
        <p>
 
</p>
        <p>
          <strong>Exception thrown while executing RunDiagnostic: Could not load file or assembly
'file:///C:\Program Files\Microsoft HPC Pack 2008 R2\Bin\CCPPSH.dll' or one of its
dependencies. The system cannot find the file specified.</strong>
        </p>
        <p>
          <strong>System.IO.FileNotFoundException</strong>
        </p>
        <p>
          <strong>
          </strong>
        </p>
        <p>
Ein einfaches Nach-Kopieren der Dateien genügt leider nicht. Um sich Abhilfe zu schaffen
empfehle ich folgende Methode:
</p>
        <p>
Als erstes sollte man die betroffene Node offline nehmen, im Cluster Manager also
“Take Offline” mit einem Rechtsklick auf die Node auswählen.
</p>
        <p>
Danach kopiert (z.B. per Remote Desktop und Kopieren/Einfügen)  ihr das HPC Pack
2008 R2 auf die betroffene Node. Dafür habe ich mir einen Ordner “C:\Install” angelegt.
</p>
        <p>
Dann startet ihr im Unterordner “C:\Install\HPC Pack 2008 R2 CTP\HPCPack\setup” die
MSI-Installation “ cpp_x64.msi mit [Rechsklick –&gt; Install]. Den Installations-Dialogen
folgend wird darauf das HPC Pack wieder deinstalliert.
</p>
        <p>
Dieser Schritt ist nötig, um eine Neuinstallation zu beginnen. Dies tun wir mit der
setup.exe im übergeordneten Ordner.
</p>
        <p>
Bei der Installation wählt ihr “Join an existing HPC cluster by creating a new compute
node”.
</p>
        <p>
Danach gebt ihr noch den hostname eurer Head-Node ein. In meinem Fall ist dies “MSHPC”. 
</p>
        <p>
Die Client Tools habe ich ebenfalls mit installiert. 
</p>
        <p>
Je nach gewählter Topologie kann man sich entscheiden, Microsoft Update zu nutzen.
In meinem Fall hab ich es deaktiviert, weil das Cluster-Netzwerk von der Außenwelt
getrennt ist.
</p>
        <p>
Nun kann die Node wieder online geschaltet werden, und siehe da, alle Tests sollten
erfolgreich verlaufen.
</p>
        <img width="0" height="0" src="http://blogs.dotnet-braunschweig.de/Florian/aggbug.ashx?id=fa03aa3b-733d-4c8d-908c-2409d999fe04" />
      </body>
      <title>Windows HPC Server 2008 R2 &amp;ndash; Compute-Node Fehler beim Framework-Test</title>
      <guid isPermaLink="false">http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,fa03aa3b-733d-4c8d-908c-2409d999fe04.aspx</guid>
      <link>http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,fa03aa3b-733d-4c8d-908c-2409d999fe04.aspx</link>
      <pubDate>Fri, 03 Jul 2009 11:46:27 GMT</pubDate>
      <description>&lt;p&gt;
Ich hatte gestern bereits mit einem kleinen Problem zu kämpfen, welches sich aber
recht leicht beheben lässt.
&lt;/p&gt;
&lt;p&gt;
Nachdem man eine neue Compute-Node hinzugefügt hat, und einen &lt;strong&gt;Framework-Test&lt;/strong&gt; ausgeführt
hat, kam es zu folgenden Fehler:
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Exception thrown while executing RunDiagnostic: Could not load file or assembly
'file:///C:\Program Files\Microsoft HPC Pack 2008 R2\Bin\CCPPSH.dll' or one of its
dependencies. The system cannot find the file specified.&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;System.IO.FileNotFoundException&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
Ein einfaches Nach-Kopieren der Dateien genügt leider nicht. Um sich Abhilfe zu schaffen
empfehle ich folgende Methode:
&lt;/p&gt;
&lt;p&gt;
Als erstes sollte man die betroffene Node offline nehmen, im Cluster Manager also
“Take Offline” mit einem Rechtsklick auf die Node auswählen.
&lt;/p&gt;
&lt;p&gt;
Danach kopiert (z.B. per Remote Desktop und Kopieren/Einfügen)&amp;#160; ihr das HPC Pack
2008 R2 auf die betroffene Node. Dafür habe ich mir einen Ordner “C:\Install” angelegt.
&lt;/p&gt;
&lt;p&gt;
Dann startet ihr im Unterordner “C:\Install\HPC Pack 2008 R2 CTP\HPCPack\setup” die
MSI-Installation “ cpp_x64.msi mit [Rechsklick –&amp;gt; Install]. Den Installations-Dialogen
folgend wird darauf das HPC Pack wieder deinstalliert.
&lt;/p&gt;
&lt;p&gt;
Dieser Schritt ist nötig, um eine Neuinstallation zu beginnen. Dies tun wir mit der
setup.exe im übergeordneten Ordner.
&lt;/p&gt;
&lt;p&gt;
Bei der Installation wählt ihr “Join an existing HPC cluster by creating a new compute
node”.
&lt;/p&gt;
&lt;p&gt;
Danach gebt ihr noch den hostname eurer Head-Node ein. In meinem Fall ist dies “MSHPC”. 
&lt;/p&gt;
&lt;p&gt;
Die Client Tools habe ich ebenfalls mit installiert. 
&lt;/p&gt;
&lt;p&gt;
Je nach gewählter Topologie kann man sich entscheiden, Microsoft Update zu nutzen.
In meinem Fall hab ich es deaktiviert, weil das Cluster-Netzwerk von der Außenwelt
getrennt ist.
&lt;/p&gt;
&lt;p&gt;
Nun kann die Node wieder online geschaltet werden, und siehe da, alle Tests sollten
erfolgreich verlaufen.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blogs.dotnet-braunschweig.de/Florian/aggbug.ashx?id=fa03aa3b-733d-4c8d-908c-2409d999fe04" /&gt;</description>
      <comments>http://blogs.dotnet-braunschweig.de/Florian/CommentView,guid,fa03aa3b-733d-4c8d-908c-2409d999fe04.aspx</comments>
      <category>HPC</category>
    </item>
    <item>
      <trackback:ping>http://blogs.dotnet-braunschweig.de/Florian/Trackback.aspx?guid=d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4</trackback:ping>
      <pingback:server>http://blogs.dotnet-braunschweig.de/Florian/pingback.aspx</pingback:server>
      <pingback:target>http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4.aspx</pingback:target>
      <dc:creator>Florian Mätschke</dc:creator>
      <wfw:comment>http://blogs.dotnet-braunschweig.de/Florian/CommentView,guid,d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4.aspx</wfw:comment>
      <wfw:commentRss>http://blogs.dotnet-braunschweig.de/Florian/SyndicationService.asmx/GetEntryCommentsRss?guid=d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Gestern habe ich mich mal an den neuen Windows HPC Server 2008 R2 als CTP Version
herangewagt.
</p>
        <p>
Dafür hergehalten hat ein kleiner Test-Cluster, den ich von meiner Uni dafür bereitgestellt
bekommen habe.
</p>
        <p>
Es handelt sich dabei um 3 Supermicro Nodes, mit jeweils 2x2 Cores (Amd Opteron) Prozessoren.
</p>
        <p>
Die Headnode verfügt über 32GB Ram, die Compute-Nodes jeweils 8.
</p>
        <p>
Zur Zeit habe ich also nur 2 Compute-Nodes, es können aber ohne Probleme weitere nachgezogen
werden.
</p>
        <p>
Im Rahmen meiner Seminararbeit werde ich einen Block-orientierten Gauss-Algorithmus
mit MPI/MPI.NET entwickeln, einmal in C und einmal in C#, und die Performance-Unterschiede
auf Linux, Windows, Managed und Unmanaged miteinander vergleichen.
</p>
        <p>
Auf was für Hürden ich eventuell mit der CTP des Windows HPC Server 2008 R2 treffe,
werde ich euch in der nächsten Zeit hier in meinem Blog mal berichten.
</p>
        <img width="0" height="0" src="http://blogs.dotnet-braunschweig.de/Florian/aggbug.ashx?id=d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4" />
      </body>
      <title>Windows HPC Server 2008 R2</title>
      <guid isPermaLink="false">http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4.aspx</guid>
      <link>http://blogs.dotnet-braunschweig.de/Florian/PermaLink,guid,d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4.aspx</link>
      <pubDate>Fri, 03 Jul 2009 10:00:52 GMT</pubDate>
      <description>&lt;p&gt;
Gestern habe ich mich mal an den neuen Windows HPC Server 2008 R2 als CTP Version
herangewagt.
&lt;/p&gt;
&lt;p&gt;
Dafür hergehalten hat ein kleiner Test-Cluster, den ich von meiner Uni dafür bereitgestellt
bekommen habe.
&lt;/p&gt;
&lt;p&gt;
Es handelt sich dabei um 3 Supermicro Nodes, mit jeweils 2x2 Cores (Amd Opteron) Prozessoren.
&lt;/p&gt;
&lt;p&gt;
Die Headnode verfügt über 32GB Ram, die Compute-Nodes jeweils 8.
&lt;/p&gt;
&lt;p&gt;
Zur Zeit habe ich also nur 2 Compute-Nodes, es können aber ohne Probleme weitere nachgezogen
werden.
&lt;/p&gt;
&lt;p&gt;
Im Rahmen meiner Seminararbeit werde ich einen Block-orientierten Gauss-Algorithmus
mit MPI/MPI.NET entwickeln, einmal in C und einmal in C#, und die Performance-Unterschiede
auf Linux, Windows, Managed und Unmanaged miteinander vergleichen.
&lt;/p&gt;
&lt;p&gt;
Auf was für Hürden ich eventuell mit der CTP des Windows HPC Server 2008 R2 treffe,
werde ich euch in der nächsten Zeit hier in meinem Blog mal berichten.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://blogs.dotnet-braunschweig.de/Florian/aggbug.ashx?id=d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4" /&gt;</description>
      <comments>http://blogs.dotnet-braunschweig.de/Florian/CommentView,guid,d2c25a2c-92c1-49c3-86b9-0f6716aaf2c4.aspx</comments>
      <category>HPC</category>
    </item>
  </channel>
</rss>