{"id":722,"date":"2020-10-31T13:39:12","date_gmt":"2020-10-31T12:39:12","guid":{"rendered":"https:\/\/www.steffen-liersch.de\/content\/de\/?p=722"},"modified":"2025-03-02T11:29:36","modified_gmt":"2025-03-02T10:29:36","slug":"liersch-profiling","status":"publish","type":"post","link":"https:\/\/www.steffen-liersch.de\/content\/de\/2020\/10\/liersch-profiling\/","title":{"rendered":"Liersch.Profiling &#8211; .NET-Bibliothek zur Performanceanalyse"},"content":{"rendered":"<p>Die .NET-Bibliothek <code>Liersch.Profiling<\/code> umfasst Funktionen zur Messung der Ausf\u00fchrungszeit von Funktionen. Es werden alle wichtigen .NET-Plattformen unterst\u00fctzt (ab .NET Framework 4.0, ab .NET Core 2.0 und ab .NET Standard 2.0). Alle wesentlichen \u00c4nderungen sind in der Datei <a href=\"https:\/\/github.com\/steffen-liersch\/Liersch.Profiling\/blob\/main\/CHANGELOG.md\">CHANGELOG.md<\/a> protokolliert.<\/p>\n<h2>Zeitmessung<\/h2>\n<p>Die Funktion <code>MeasurePerformance<\/code> der Klasse <code>MeasuringTools<\/code> ermittelt die Performance der angegebenen Funktionen. F\u00fcr jede Funktion wird ein <code>MeasuringData<\/code>-Objekt geliefert. Darin sind die Anzahl der Aufrufe und die daf\u00fcr ben\u00f6tigte Zeit gespeichert. Die Zeitmessung erfolgt auf Basis der Klasse <code>Stopwatch<\/code>. Die Genauigkeit ist abh\u00e4ngig von der eingesetzten Hardware. Bei dieser Art der Messung wird das Ergebnis stets von den zur selben Zeit laufenden Prozessen und deren Threads beeinflusst.<\/p>\n<pre><code class=\"language-cs\">Action a1=() =&gt; Thread.Sleep(10);\nAction a2=() =&gt; Thread.Sleep(20);\nMeasuringData[] md=MeasuringTools.MeasurePerformance(a1, a2);\nConsole.WriteLine(&quot;Thread.Sleep(10) =&gt; &quot;+md[0].Format());\nConsole.WriteLine(&quot;Thread.Sleep(20) =&gt; &quot;+md[1].Format());<\/code><\/pre>\n<h2>Messung der CPU-Zeit<\/h2>\n<p>Alternativ kann die Funktion <code>MeasureProcessorTime<\/code> genutzt werden, um die w\u00e4hrend der Messung vom Prozess ben\u00f6tigte Prozessorzeit zu ermitteln. Die Beeinflussung durch andere, zur Zeit der Messung laufende Prozesse sollte wesentlich geringer sein, als beim <code>Stopwatch<\/code>-basierten Ansatz.<\/p>\n<p><code>MeasureProcessorTime<\/code> kann nicht die Zeit messen, die f\u00fcr das Warten auf bestimmte Ereignisse ben\u00f6tigt wird (z. B. <code>EventWaitHandle.Wait<\/code> oder <code>Thread.Sleep<\/code>), da f\u00fcr diese Art des Wartens keine CPU-Zeit ben\u00f6tigt wird.<\/p>\n<h2>Automatisierte Messungen<\/h2>\n<p>Wenn mehrere Testfunktionen vorhanden sind, k\u00f6nnen diese automatisiert aufgerufen werden. Testfunktionen m\u00fcssen mit dem Attribut <code>MeasuringAttribute<\/code> markiert sein und <code>MeasuringData<\/code>-Objekte zur\u00fcckgeben.<\/p>\n<pre><code class=\"language-cs\">static class Tests\n{\n  [Measuring(1, &quot;SleepTicks(1) vs. SleepTicks(2)&quot;)]\n  public static MeasuringData[] TestSleepTicks()\n  {\n    Action a1=() =&gt; Functions.SleepTicks(1);\n    Action a2=() =&gt; Functions.SleepTicks(2);\n    return MeasuringTools.MeasurePerformance(a1, a2);\n  }\n\n  [Measuring(2, &quot;SleepMilliseconds(1) vs. SleepMilliseconds(2)&quot;)]\n  public static MeasuringData[] TestSleepMilliseconds()\n  {\n    Action a1=() =&gt; Functions.SleepMilliseconds(1);\n    Action a2=() =&gt; Functions.SleepMilliseconds(2);\n    return MeasuringTools.MeasurePerformance(a1, a2);\n  }\n\n  [Measuring(3, &quot;Thread.Sleep(10) vs. Thread.Sleep(20)&quot;)]\n  public static MeasuringData[] TestThreadSleep()\n  {\n    Action a1=() =&gt; Thread.Sleep(10);\n    Action a2=() =&gt; Thread.Sleep(20);\n    return MeasuringTools.MeasurePerformance(a1, a2);\n  }\n}<\/code><\/pre>\n<p>Der automatisierte Aufruf aller Testmethoden erfolgt mit Hilfe der Funktion <code>RunTests<\/code> der Klasse <code>MeasuringTools<\/code>. Die Beschreibungstexte und Messergebnisse werden auf der Konsole ausgegeben. Wenn eine Klasse nur statische Testfunktionen enth\u00e4lt oder \u00fcber einen Standardkonstruktor verf\u00fcgt, reicht es aus, den Typ anstelle einer Instanz zu \u00fcbergeben.<\/p>\n<pre><code class=\"language-cs\">MeasuringTools.RunTests(typeof(Tests));<\/code><\/pre>\n<h2>Genauigkeit der Messung<\/h2>\n<p>Unabh\u00e4ngig von der Messmethode gibt es verschiedene Faktoren, die eine Messung beeintr\u00e4chtigen. Funktionen, die viele Objekte erzeugen, werden beispielsweise von einer unter Umst\u00e4nden stattfindenden Garbage Collection beeinflusst. Deshalb wird vor jeder Messung eine Garbage Collection erzwungen, um eine einigerma\u00dfen vergleichbare Startsituation herzustellen. Andere Threads, die auf demselben Prozessorkern aktiv sind, k\u00f6nnen das Messergebnis ebenfalls verf\u00e4lschen.<\/p>\n<h2>Wertformatierung<\/h2>\n<p>Die Klasse <code>Formatter<\/code> enth\u00e4lt Funktionen f\u00fcr die Formatierung von einheitenbehafteten Werten. Die Funktionen sind auch unabh\u00e4ngig von den eigentlichen Messfunktionen nutzbar. Die aktuelle Implementierung der Formatierungsfunktionen arbeitet generell kulturunabh\u00e4ngige (siehe <code>CultureInfo.InvariantCulture<\/code>).<\/p>\n<pre><code class=\"language-cs\">Console.WriteLine(&quot;Duration: &quot;+Formatter.FormatSeconds(md.Duration.TotalSeconds, 1));\nConsole.WriteLine(&quot;Score: &quot;+Formatter.FormatDecimal(md.Score, 1, &quot;Hz&quot;));<\/code><\/pre>\n<h2>Copyright<\/h2>\n<p>Copyright \u00a9 2020-2021 Steffen Liersch<br \/>\n<a href=\"https:\/\/www.steffen-liersch.de\/\">https:\/\/www.steffen-liersch.de\/<\/a><\/p>\n<h2>Verweise<\/h2>\n<p>Der Quellcode wird auf GitHub gepflegt:<br \/>\n<a href=\"https:\/\/github.com\/steffen-liersch\/Liersch.Profiling\">https:\/\/github.com\/steffen-liersch\/Liersch.Profiling<\/a><\/p>\n<p>Pakete k\u00f6nnen \u00fcber NuGet heruntergeladen werden:<br \/>\n<a href=\"https:\/\/www.nuget.org\/packages\/Liersch.Profiling\">https:\/\/www.nuget.org\/packages\/Liersch.Profiling<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Die .NET-Bibliothek Liersch.Profiling umfasst Funktionen zur Messung der Ausf\u00fchrungszeit von Funktionen. Es werden alle wichtigen .NET-Plattformen unterst\u00fctzt (ab .NET Framework 4.5, ab .NET Core 2.0 und ab .NET Standard 2.0).<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[21,25,36,31],"class_list":["post-722","post","type-post","status-publish","format-standard","hentry","category-net","tag-net","tag-cs","tag-open-source","tag-products"],"_links":{"self":[{"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/posts\/722","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/comments?post=722"}],"version-history":[{"count":9,"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/posts\/722\/revisions"}],"predecessor-version":[{"id":836,"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/posts\/722\/revisions\/836"}],"wp:attachment":[{"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/media?parent=722"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/categories?post=722"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.steffen-liersch.de\/content\/de\/wp-json\/wp\/v2\/tags?post=722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}