What happens if your client complains that your application is running very slow!!! or in your load/stress testing you found that some functionalities are very slow in executing than expected. This is the time where you go for profiling the execution, to analyse the root cause of these issues.
So how we could develop a profiler, where we don’t have to wrap our normal code in a profiling code.
With the help of AOP (Aspect-Oriented Programming) we could do the profiling task without interrupting the actual code.
AOP is a programming paradigm in which secondary or supporting functions are isolated from the main program’s business logic
So in order bring the AOP functionality into this application, I am going to use a third party library PostSharp which I believe this is one of the best that is available in the market.
So, now we have got the basic things to start with and now let’s start coding….
Start a new solution in visual studio and add a new console application project to it. Then add the below references to the newly created project
Add reference to the Log4Net.dll, PostSharp.Laos.dll and PostSharp.Public.dll (Please read https://www.postsharp.net/documentation to get the basic installation procedure). Next, create a new attribute class called ProfileMethodAttribute – this class is responsible for doing the profiling work. Make sure that you have decorated this class with Serializable attribute
This class actually derives from OnMethodBoundaryAspect, it has got two methods OnEntry and OnExit which we needed. These method will be called before the start of a method execution and at the end of method execution respectively, when this attribute is decorated against a method.
When a call comes to OnEntry method, we will first log the execution call using the LoggerHelper, then start a clock using another helper class Profiler
///<summary> /// Helper class that wraps the timer based functionalities. ///</summary> internalstaticclassProfiler { ///<summary> /// Lock object. ///</summary> privatestaticreadonlyobject SyncLock = newobject();
///<summary> /// Variable that tracks the time. ///</summary> privatestaticreadonly Dictionary<int, Stack<long>> ProfilePool;
///<summary> /// Initializes static members of the <see cref="Profiler"/> class. ///</summary> staticProfiler() { ProfilePool = new Dictionary<int, Stack<long>>(); }
///<summary> /// Starts this timer. ///</summary> publicstaticvoidStart() { lock (SyncLock) { int currentThreadId = Thread.CurrentThread.ManagedThreadId; if (ProfilePool.ContainsKey(currentThreadId)) { ProfilePool[currentThreadId].Push( Environment.TickCount ); } else { var timerStack = new Stack<long>(); timerStack.Push(DateTime.UtcNow.Ticks); ProfilePool.Add(currentThreadId, timerStack); } } }
///<summary> /// Stops timer and calculate the execution time. ///</summary> ///<returns>Execution time in milli seconds</returns> publicstaticintStop() { lock (SyncLock) { long currentTicks = DateTime.UtcNow.Ticks; int currentThreadId = Thread.CurrentThread.ManagedThreadId;
if (ProfilePool.ContainsKey(currentThreadId)) { long ticks = ProfilePool[currentThreadId].Pop(); if (ProfilePool[currentThreadId].Count == 0) { ProfilePool.Remove(currentThreadId); }
var timeSpan = new TimeSpan(currentTicks - ticks);
return (int)timeSpan.TotalMilliseconds; } }
return0; } }
which stores the starting tick and calculate the time taken to execute when Stop is called.
Next step is to use this and see whether it is logged properly. In order enable profiling for a method, you just needs to decorate it with the ProfileMethod attribute. Like below