DotNet simple and effective profiling

There is one thing all programmers experience at one point or another, performance issues… One might use simple break points to get a coarse idea of the problem locations or when things get really frustrating a stopwatch with several measurement points.
But even that gets frustrating when there are lots of problem areas and it soon turns into a cumbersome practice which we all loathe.

But nothing beats some good old fashioned scripting to create a more elegant solution:

    public class SimpleProfiler : IDisposable
    {
        private readonly Stopwatch _stopWatch = new Stopwatch();
        private readonly int _measurementFormatLength;
        private readonly bool _printFinalResult;
        public SimpleProfiler(string title = null, int measurementFormatLength = 30, bool printFinalResult = true)
        {
            _measurementFormatLength = measurementFormatLength;
            _printFinalResult = printFinalResult;
            if (title != null)
            {
                Debug.WriteLine(title);
            }
            _stopWatch.Start();
        }
        public void Restart()
        {
            _stopWatch.Restart();
        }
        public void Dispose()
        {
            _stopWatch.Stop();
            if (_printFinalResult)
            {
                Debug.WriteLine("Elapsed {0} ms", _stopWatch.ElapsedMilliseconds);
            }
        }

        public void AddMeasurement(string comment = "")
        {
            Debug.WriteLine(" {0} {1} ms", comment.PadRight(_measurementFormatLength).Substring(0, _measurementFormatLength), _stopWatch.ElapsedMilliseconds);
        }
    }

Simple invoke:

            using (new SimpleProfiler())
            {
                WebClient webClient = new WebClient();
                webClient.DownloadString("http://www.black-mail.nl/");
            }

More complex invoke:

            using (SimpleProfiler profiler = new SimpleProfiler("Download test", 15, false))
            {
                WebClient webClient = new WebClient();
                webClient.DownloadString("http://www.black-mail.nl/");
                profiler.AddMeasurement("http test");
                profiler.Restart();
                webClient.DownloadString("https://www.black-mail.nl/");
                profiler.AddMeasurement("https test");
            }

Next up the extension method, sometimes it’s better to itterate a function a “few” times in order to get a better idea:

    public static class ExtensionMethods
    {
        public static Int64 Profile(this T input, Action action, int iterations = 1)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < iterations; i++)
            {
                action(input);
            }
            stopwatch.Stop();

            return stopwatch.ElapsedMilliseconds;
        }

        public static Int64 Profile(this Action action, int iterations = 1)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < iterations; i++)
            {
                action();
            }
            stopwatch.Stop();

            return stopwatch.ElapsedMilliseconds;
        }
    }

Simple invoke:

            Action action = LongCalculation;
            Debug.WriteLine(action.Profile().ToString(CultureInfo.InvariantCulture));

More complex invoke:

            Action action = LongCalculation;
            Debug.WriteLine(action.Profile(x => x.Invoke("Some input")).ToString(CultureInfo.InvariantCulture));

Although it won't provide you with some of the nice graphs, heatmaps or other goodies some external applications might offer, it will save a lot of time and annoyance.

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.