Home

BenchmarkDotnet.linq AllocatedBytes Bug

AllocatedBytes was always null using the built-in benchmark tooling. The cause was the following line:
TotalAllocatedBytes += g.GetTotalAllocatedBytes(false) ?? 0;

With the type of Nullable<int> defaulting to null, the compound operator was resolving to
TotalAllocatedBytes = null + (g.GetTotalAllocatedBytes(false) ?? 0);
, thus always null

I updated the code in my instance to the following and it is now working as intended:

struct MemoryStats
{
    public long TotalOperations { get; private set; }
    public long? TotalAllocatedBytes { get; private set; }
    public long? BytesPerOperation => TotalOperations == 0 ? null : TotalAllocatedBytes / TotalOperations;

    public void Record(GcStats g)
    {
        TotalOperations += g.TotalOperations;
        var totalAllocatedBytes = g.GetTotalAllocatedBytes(false) ?? 0;
        if (TotalAllocatedBytes is null)
            TotalAllocatedBytes = totalAllocatedBytes;
        else
            TotalAllocatedBytes += totalAllocatedBytes;
    }
}

Comments

  • What was the code before you changed it?
    Mine doesn't define TotalAllocatedBytes as nullable so I don't see any issues with it.

    struct MemoryStats
    {
        public long TotalOperations { get; private set; }
        public long TotalAllocatedBytes { get; private set; }
        public long? BytesPerOperation => TotalOperations == 0 ? null : TotalAllocatedBytes / TotalOperations;
    
        public void Record(GcStats g)
        {
            TotalOperations += g.TotalOperations;
            TotalAllocatedBytes += g.GetTotalAllocatedBytes(false) ?? 0;
        }
    }
    
    
  • My version was long? to begin with. My LinqPad version is 8.6.1, which is reported as the latest. But I'm not sure how updates to the linq file are handled.

    I considered changing the type to non-nullable as the fix. But I didn't want to go through and find any potential side-effects. So it makes sense to me that Joe wrote it as long in another version.

  • That is the same LinqPad version that I am using.

    At the top of the script there is a comment that says that changes are merged in (and I have seen that happen)

    I've made a few changes to my copy of BenchmarkDotNet, so to make sure I hadn't changed MemoryStats, I
    compared my current query with the default embedded in Linqpad , using

    var benchmarkQuerySource = (string) Uncapsulate("LINQPad.Interop.BenchmarkHelper", "LINQPad.Runtime").BenchmarkQuerySource;
    
    var onDisk = System.IO.File.ReadAllText(System.IO.Path.Combine(Util.MyQueriesFolder, "BenchmarkDotNet.linq")) ;
    
    Util.Dif(benchmarkQuerySource, onDisk).Dump();
    
  • That is strange - I think TotalAllocatedBytes has always been non-nullable. At one stage there existed some other condition that could cause that figure to report incorrectly, but that was patched some time ago.

  • That's interesting. To my recollection I have never modified the file until making this post. The diff of my local versus embedded version has this difference in the reference section that might point to something:

    I archived my local and restored the assembly version. Thanks for all the help.

  • I should also mention that if you ever want to do a reset, you can delete the file and LINQPad will recreate it.

Sign In or Register to comment.