Welcome to AspAdvice Sign in | Join | Help

manik.net

alles über c# / microsoft asp.net und viel, viel mehr
Performance Timing mit ‚using’ und delegates mit „Conditional“ Methoden

Letztens musste ich die (zeitliche) Performance einer sehr CPU/IO lästigen Operation verbessern.
Da die Operation in diverse kleinere Vorgänge unterteilt war musste ich die Vorgänge ermitteln, welche am meisten Zeit in Anspruch nahmen und das meiste Optimierungspotential hatten. Dafür hab ich eine Klasse entworfen die mit dem „using“-Mechanismus die Dauer einer Operation ermittelt. Dabei bin ich auch darauf gestoßen, dass der C# Compiler Methoden die das „Conditional“ Attribut haben nicht delegates zuweisen kann.

Also, nun zu der Klasse:

public class PerformanceTiming : IDisposable
{
 public delegate void LogPerformance(string value);
 
 private DateTime _startTime;
 private string _name;
 private LogPerformance _logPerformanceMethod;
 
 private const string _startMessage = "PerformanceTiming={0}: Start={1}";
 private const string _endMessage = "PerformanceTiming={0}: End={1} Duration={2}msec";
 
 public PerformanceTiming(string name)
 {
  // cannot directly use Debug.WriteLine(string) as it has the "Conditional" attribute.
  //  _logPerformanceMethod = System.Diagnostics.Debug.WriteLine(value);
  // have to use wrapper function
  _logPerformanceMethod = DebugWriteLineWrapper;
  _name = name;
  _startTime = DateTime.Now;
 
  _logPerformanceMethod(string.Format(_startMessage, _name, _startTime.ToLongTimeString()));
 }
 
 public PerformanceTiming(string name, LogPerformance logPerformanceMethod)
 {
  _logPerformanceMethod = logPerformanceMethod;
  _name = name;
  _startTime = DateTime.Now;
 
  _logPerformanceMethod(string.Format(_startMessage, _name, _startTime.ToLongTimeString()));
 }
 public void DebugWriteLineWrapper(string value)
 {
  System.Diagnostics.Debug.WriteLine(value);
 }
 
 #region IDisposable Members
 public void Dispose()
 {
  _logPerformanceMethod(string.Format(_endMessage, _name, DateTime.Now.ToLongTimeString(), (DateTime.Now - _startTime).TotalMilliseconds));
 }
#endregion
}


Mehr oder weniger simple, ja, aber es ist eigentlich auch die Idee bzw. die Anwendung der Klasse was die Sache so sinnvoll macht.

using (PerformanceTiming performanceTiming = new PerformanceTiming("HeavyWork"))

      System.Threading.Thread.Sleep(2000);

}

Damit wird der folgende Output in den Debugoutput stream geschrieben:

PerformanceTiming=HeavyWork: Start=13:12:16
PerformanceTiming=HeavyWork: End=13:12:18 Duration=1999,6672msec

Es wird also die Start-/Endzeit der Operation ausgegeben, plus die Dauer in Millisekunden.
Die Ausgabe kann natürlich ohne Probleme angepasst werden.
Man kann auch eine Methode an das PerformanceTiming Objekt übergeben, welcher dann die Ausgabestrings übergeben werden, so z.B.
Console.Writeline.

using (PerformanceTiming performanceTiming = new PerformanceTiming("HeavyWork", Console.WriteLine))

      System.Threading.Thread.Sleep(2000);
}

Man könnte  natürlich auch jede andere Funktion die nur einen (string) Parameter hat übergeben, z.B. StreamWriter.WriteLine um Direkt in eine Datei zu loggen.

Conditional Methoden und delegates, wie macht man das? Man schreibt einfach eine Wrapper funktion die nicht das [Conditional("DEBUG")] Attribut besitzt.

So wird aus:

_logPerformanceMethod = System.Diagnostics.Debug.WriteLine;

Das:

_logPerformanceMethod = DebugWriteLineWrapper; 
public void DebugWriteLineWrapper(string value) 

            System.Diagnostics.Debug.WriteLine(value); 
}

So, das war nun mein erster mehr oder weniger Sinnvoller Blogeintrag :-)

EDIT: Wie postet man eigentlich code-snippets hier?

EDIT2: I now know the answer thanks to my friend Brendan from Orcs, Goblins and .NET, I will blog about it in a few days.

Sponsor
Posted: Friday, December 21, 2007 1:18 PM by manik

Comments

No Comments

Leave a Comment

(required) 

(required) 

(optional)

(required) 

Enter the code you see below

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS