Improving Moving Average implementation in conjunction with BenchmarkDotNet

Improving Moving Average implementation in conjunction with BenchmarkDotNet

Arjun Krishna

2 minute read

Last night I read an article about someone working on moving average calculation. I remembered I had done a similar exercise few years ago. I put it into BenchmarkDotNet and then wanted to try ArrayPool and ReadOnlySpan features in C# to improve its performance. I do not do much open-source stuff, so feel free to improve it and let me know where I have gone wrong. BenchmarkConsoleTest .

Github Repo

The code is available on github : BenchmarkConsoleTest

Moving Average Sample Implementation

        [Benchmark]
        public double[] MovingAverageDeltaSum()
        {

            var currentFrameSize = 0;
            double cumulativeSum = 0;
            ReadOnlySpan<double> dataSpan = Data.AsSpan();
            var samePool = ArrayPool<double>.Shared;
            var dataList = samePool.Rent(Data.Length);
            var result = new double[Data.Length];
            for (int dataItemIndexCounter = 0; dataItemIndexCounter < dataSpan.Length; dataItemIndexCounter++)
            {
                var indexForDataItemToBeRemoved = dataItemIndexCounter - FrameSize;

                if (indexForDataItemToBeRemoved >= 0)
                {
                    cumulativeSum -= dataSpan[indexForDataItemToBeRemoved];
                    currentFrameSize--;
                }

                if (dataItemIndexCounter < dataSpan.Length)
                {
                    //if (double.IsInfinity(cumulativeSum+dataSpan[dataItemIndexCounter])) throw new Exception("overflow error");
                    cumulativeSum += dataSpan[dataItemIndexCounter];
                    //if (double.IsInfinity(cumulativeSum)) throw new Exception("overflow error");
                    currentFrameSize++;
                }

                dataList[dataItemIndexCounter] = (cumulativeSum / (currentFrameSize * 1.0d));
            }
            
            Array.Copy(dataList, result, Data.Length);
            samePool.Return(dataList);

            return result;
        }

BenchmarkDotNet Result

I need to improve the setup of BenchmarkDotNet to output graphs etc. Will do so in the future. I also need to make sure I’ve configured BenchmarkDotNet correctly as some results looked too good to be true, when I changed params to test it. I also noticed that for very large doubles where it may overflow, it could give spurious results. I actually tested that by using float and making it overflow, but same would hold true for double. So this is work in progress whenever I find time at night or weekends.

BenchmarkDotNet result

Things Remaining To Be Tried in The Future

I wanted to make one version work with ComputeSharp and the nuget package was giving me an issue with the visual studio target with winRT. Will try it later sometime.

Need to learn how to use sharplab.io to understand a little bit more about how all these tools come together to improve most used parts of your code.