Last active
August 6, 2024 01:25
-
-
Save thomaslevesque/6f653d8b3a82b1d038e1 to your computer and use it in GitHub Desktop.
Benchmark of memset implementations in C# using a loop or the initblk CLR instruction (run in LinqPad)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
var array = new byte[10000000]; | |
var initBlk = new InitblkMemoryHelper(); | |
var loop = new LoopMemoryHelper(); | |
// First run for JIT warmup and type initialization | |
initBlk.Memset(array, 0, array.Length, 42); | |
loop.Memset(array, 0, array.Length, 42); | |
int iterations = 1000; | |
Test("InitBlk", initBlk, array, iterations); | |
Test("Loop", loop, array, iterations); | |
} | |
void Test(string name, IMemoryHelper helper, byte[] array, int iterations) | |
{ | |
Stopwatch sw = Stopwatch.StartNew(); | |
for (int i = 0; i < iterations; i++) | |
{ | |
helper.Memset(array, 0, array.Length, 42); | |
} | |
sw.Stop(); | |
sw.Elapsed.Dump(name); | |
} | |
interface IMemoryHelper | |
{ | |
void Memset(byte[] array, int start, int count, byte value); | |
} | |
class LoopMemoryHelper : IMemoryHelper | |
{ | |
public void Memset(byte[] array, int start, int count, byte value) | |
{ | |
int upper = start + count; | |
for (int i = start; i < upper; i++) | |
{ | |
array[i] = value; | |
} | |
} | |
} | |
class InitblkMemoryHelper : IMemoryHelper | |
{ | |
private delegate void MemorySetter(IntPtr array, byte value, int count); | |
private static readonly MemorySetter _memset; | |
static InitblkMemoryHelper() | |
{ | |
_memset = CreateMemset(); | |
} | |
private static MemorySetter CreateMemset() | |
{ | |
var m = new DynamicMethod( | |
"memset", | |
MethodAttributes.Public | MethodAttributes.Static, | |
CallingConventions.Standard, | |
typeof(void), | |
new[] { typeof(IntPtr), typeof(byte), typeof(int) }, | |
typeof(InitblkMemoryHelper), | |
false); | |
var il = m.GetILGenerator(); | |
il.Emit(OpCodes.Ldarg_0); // address | |
il.Emit(OpCodes.Ldarg_1); // initialization value | |
il.Emit(OpCodes.Ldarg_2); // number of bytes | |
il.Emit(OpCodes.Initblk); | |
il.Emit(OpCodes.Ret); | |
return (MemorySetter)m.CreateDelegate(typeof(MemorySetter)); | |
} | |
public void Memset(byte[] array, int start, int count, byte value) | |
{ | |
GCHandle h = default(GCHandle); | |
try | |
{ | |
h = GCHandle.Alloc(array, GCHandleType.Pinned); | |
IntPtr addr = h.AddrOfPinnedObject() + start; | |
_memset(addr, value, count); | |
} | |
finally | |
{ | |
if (h.IsAllocated) | |
h.Free(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment