Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Micro Benchmarks and Hot Paths

DZone's Guide to

Micro Benchmarks and Hot Paths

Here are some cool benchmarks of a piece of complex code. We'll look at memory allocation, and discover which pointer is most advantageous.

Free Resource

RavenDB vs MongoDB: Which is Better? This White Paper compares the two leading NoSQL Document Databases on 9 features to find out which is the best solution for your next project.  

I’m doing some work to refactor a complex piece of code, and I have a piece of memory that is allocated, then accessed via a struct pointer. This piece of code gets called a lot, so I wondered about the tradeoff of holding a pointer that is already casted to the right struct pointer vs the cost of another pointer in the object.

Note, those are objects that are created a lot, and used a lot. Those are not the kind of things that you would usually need to worry about. Because I wasn’t sure, I decided to test this out. And I used BenchmarkDotNet to do so:

public struct FooHeader
{
    public long PageNumber;
    public int Size;
}

[BenchmarkTask(platform: BenchmarkPlatform.X86,
           jitVersion: BenchmarkJitVersion.LegacyJit)]
[BenchmarkTask(platform: BenchmarkPlatform.X64,
               jitVersion: BenchmarkJitVersion.LegacyJit)]
[BenchmarkTask(platform: BenchmarkPlatform.X64,
               jitVersion: BenchmarkJitVersion.RyuJit)]
public unsafe class ToCastOrNotToCast
{
    byte* p;
    FooHeader* h;
    public ToCastOrNotToCast()
    {
        p = (byte*)Marshal.AllocHGlobal(1024);
        h = (FooHeader*)p;
    }

    [Benchmark]
    public void NoCast()
    {
        h->PageNumber++;
    }

    [Benchmark]
    public void Cast()
    {
        ((FooHeader*)p)->PageNumber++;
    }

    [Benchmark]
    public void DirectCastArray()
    {
        ((long*)p)[0]++;
    }


    [Benchmark]
    public void DirectCastPtr()
    {
        (*(long*)p)++;
    }
}

The last two tests are pretty much just to have something to compare to, because if needed, I would just calculate memory offsets manually, but I doubt that those would be needed.

The one downside of BenchmarkDotNet is that it takes a very long time to actually run those tests. I’ll save you the suspense, here are the results:

image

I was expected the NoCast method to be faster, to be honest. But the Cast method is consistently (very slightly) the fastest one. Which is surprising.

Here is the generated IL:

image

And the differences in assembly code are:

image

Note that I’m not 100% sure about the assembly code. I got it from the disassembly windows in VS, and it is possible that it changed what is actually going on.

So I’m not really sure why this would be difference, and it is really is a small difference. But it is there.

Do you pay to use your database? What if your database paid you? Learn more with RavenDB.

Topics:
performance ,benchmarking ,memory ,java

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}