This was a fun project!
At a previous job we worked a lot with C# and we had some pretty bad performance issues in some places. So I took on the job of building a “performance recorder” to help find where the issues were.
The approach I took for this was quite interesting though by using AOP (Aspect Oriented Programming). Essentially injecting code at build-time on any classes or functions we added the [PerformanceLogging] annotation to. This made it extremely easy to track performance on any code we wanted!
I achieved this with a lot of help from the AspectInjector library 🙌
When we add the annotation, the function gets wrapped at build-time by our custom code that can then measure how long that function takes to run. If we turn off the recorder the code still gets wrapped, but the code just calls the wrapped method directly, with a minimal hit to performance.
The actual code used to measure performance isn’t much more than a timer. It wraps the function and measures how long it takes to run.
After that, the execution time gets added to a list of results that allow showing the data. I also made sure to support multiple runs of the same function and nesting, so if you saw a function take 10s, you could see how much of that time was taken up by functions called by that function (as long as they were also annotated). We could also see how many times each function was called - also very handy!
Over time I added some more features to the library, such as measuring execution times for lambdas, result filtering, and custom formatters. But the core of the project stayed the same.
Here is an example of what the output looks like:
+-
+- ApplicationImpl.RunApplication count: 1 sum: 1.85 avg: 1.85 max: 1.85 min: 1.85
+- WorkerImpl.RunOperationB count: 1 sum: 1.13 avg: 1.13 max: 1.13 min: 1.13
| +- WorkerImpl.RunPrivateOperationB2 count: 1 sum: 0.41 avg: 0.41 max: 0.41 min: 0.41
| | +- WorkerImpl.RunPrivateOperationB21 count: 1 sum: 0.00 avg: 0.00 max: 0.00 min: 0.00
+- ApplicationImpl.Worker count: 11 sum: 0.16 avg: 0.01 max: 0.14 min: 0.00
+- WorkerImpl..ctor count: 11 sum: 0.00 avg: 0.00 max: 0.00 min: 0.00
I no longer use this or work on it, but the code is available if you want to use it!
The documentation is also available.