Skip to content

Instantly share code, notes, and snippets.

@thomaslevesque
Last active July 6, 2021 01:48
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save thomaslevesque/6f653d8b3a82b1d038e1 to your computer and use it in GitHub Desktop.
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)
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