Skip to content

Instantly share code, notes, and snippets.

@msx752
Last active June 30, 2024 22:08
Show Gist options
  • Save msx752/185b08bc689109ce37d9cd226aee3daa to your computer and use it in GitHub Desktop.
Save msx752/185b08bc689109ce37d9cd226aee3daa to your computer and use it in GitHub Desktop.
experimental c# atomiclock
using BenchmarkDotNet.Attributes;
namespace Extendlocked
{
public class AtomicBenchmark
{
#region Increment
[Benchmark]
public void IncrementByte()
{
byte counter = 0;
InterlockedEx.Increment(ref counter);
}
[Benchmark]
public void IncrementInt()
{
int counter = 0;
InterlockedEx.Increment(ref counter);
}
[Benchmark]
public void IncrementLong()
{
long counter = 0;
InterlockedEx.Increment(ref counter);
}
[Benchmark]
public void IncrementSByte()
{
sbyte counter = 0;
InterlockedEx.Increment(ref counter);
}
[Benchmark]
public void IncrementShort()
{
short counter = 0;
InterlockedEx.Increment(ref counter);
}
[Benchmark]
public void IncrementUInt()
{
uint counter = 0;
InterlockedEx.Increment(ref counter);
}
[Benchmark]
public void IncrementULong()
{
ulong counter = 0;
InterlockedEx.Increment(ref counter);
}
[Benchmark]
public void IncrementUShort()
{
ushort counter = 0;
InterlockedEx.Increment(ref counter);
}
#endregion Increment
#region Decrement
[Benchmark]
public void DecrementByte()
{
byte counter = 1;
InterlockedEx.Decrement(ref counter);
}
[Benchmark]
public void DecrementInt()
{
int counter = 1;
InterlockedEx.Decrement(ref counter);
}
[Benchmark]
public void DecrementLong()
{
long counter = 1;
InterlockedEx.Decrement(ref counter);
}
[Benchmark]
public void DecrementSByte()
{
sbyte counter = 1;
InterlockedEx.Decrement(ref counter);
}
[Benchmark]
public void DecrementShort()
{
short counter = 1;
InterlockedEx.Decrement(ref counter);
}
[Benchmark]
public void DecrementUInt()
{
uint counter = 1;
InterlockedEx.Decrement(ref counter);
}
[Benchmark]
public void DecrementULong()
{
ulong counter = 1;
InterlockedEx.Decrement(ref counter);
}
[Benchmark]
public void DecrementUShort()
{
ushort counter = 1;
InterlockedEx.Decrement(ref counter);
}
#endregion Decrement
#region Read
[Benchmark]
public void ReadByte()
{
byte counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadDouble()
{
double counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadFloat()
{
float counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadInt()
{
int counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadLong()
{
long counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadSByte()
{
sbyte counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadShort()
{
short counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadUInt()
{
uint counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadULong()
{
ulong counter = 1;
InterlockedEx.Read(ref counter);
}
[Benchmark]
public void ReadUShort()
{
ushort counter = 1;
InterlockedEx.Read(ref counter);
}
#endregion Read
#region Write
[Benchmark]
public void WriteByte()
{
byte counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteDouble()
{
double counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteFloat()
{
float counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteInt()
{
int counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteLong()
{
long counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteSByte()
{
sbyte counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteShort()
{
short counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteUInt()
{
uint counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteULong()
{
ulong counter = 1;
InterlockedEx.Write(ref counter, 3);
}
[Benchmark]
public void WriteUShort()
{
ushort counter = 1;
InterlockedEx.Write(ref counter, 3);
}
#endregion Write
}
}
using System;
using System.Threading;
namespace Extendlocked
{
public static class InterlockedEx
{
#region Exchange
public static T Exchange<T>(ref T obj, Func<T, T> func)
{
if (func == null)
throw new NullReferenceException(nameof(func));
Thread.MemoryBarrier();
obj = func(obj);
return obj;
}
#endregion Exchange
#region CompareExchange
public static T CompareExchange<T>(ref T obj, T val, T compared)
{
return CompareExchange<T>(ref obj, (oldv) => val, compared);
}
#endregion CompareExchange
#region Decrement 2
public static ulong Decrement(ref ulong obj, int decrementBy)
{
ulong result = 0;
for (int i = 0; i < decrementBy; i++)
result = Interlocked.Decrement(ref obj);
return result;
}
public static long Decrement(ref long obj, int decrementBy)
{
long result = 0;
for (int i = 0; i < decrementBy; i++)
result = Interlocked.Decrement(ref obj);
return result;
}
public static uint Decrement(ref uint obj, int decrementBy)
{
uint result = 0;
for (int i = 0; i < decrementBy; i++)
result = Interlocked.Decrement(ref obj);
return result;
}
public static int Decrement(ref int obj, int decrementBy)
{
int result = 0;
for (int i = 0; i < decrementBy; i++)
result = Interlocked.Decrement(ref obj);
return result;
}
public static sbyte Decrement(ref sbyte obj, byte decrementBy)
{
return _InternalDecrementBy(ref obj, decrementBy);
}
public static byte Decrement(ref byte obj, byte decrementBy)
{
return _InternalDecrementBy(ref obj, decrementBy);
}
public static ushort Decrement(ref ushort obj, ushort decrementBy)
{
return _InternalDecrementBy(ref obj, decrementBy);
}
public static short Decrement(ref short obj, short decrementBy)
{
return _InternalDecrementBy(ref obj, decrementBy);
}
#endregion Decrement 2
#region Decrement 1
public static ulong Decrement(ref ulong obj)
{
return Decrement(ref obj, 1);
}
public static long Decrement(ref long obj)
{
return Decrement(ref obj, 1);
}
public static uint Decrement(ref uint obj)
{
return Decrement(ref obj, 1);
}
public static int Decrement(ref int obj)
{
return Decrement(ref obj, 1);
}
public static sbyte Decrement(ref sbyte obj)
{
return Decrement(ref obj, 1);
}
public static byte Decrement(ref byte obj)
{
return Decrement(ref obj, 1);
}
public static ushort Decrement(ref ushort obj)
{
return Decrement(ref obj, 1);
}
public static short Decrement(ref short obj)
{
return Decrement(ref obj, 1);
}
#endregion Decrement 1
#region Increment 2
public static ulong Increment(ref ulong obj, int incrementBy)
{
ulong result = 0;
for (int i = 0; i < incrementBy; i++)
result = Interlocked.Increment(ref obj);
return result;
}
public static long Increment(ref long obj, int incrementBy)
{
long result = 0;
for (int i = 0; i < incrementBy; i++)
result = Interlocked.Increment(ref obj);
return result;
}
public static uint Increment(ref uint obj, int incrementBy)
{
uint result = 0;
for (int i = 0; i < incrementBy; i++)
result = Interlocked.Increment(ref obj);
return result;
}
public static int Increment(ref int obj, int incrementBy)
{
int result = 0;
for (int i = 0; i < incrementBy; i++)
result = Interlocked.Increment(ref obj);
return result;
}
public static sbyte Increment(ref sbyte obj, sbyte incrementBy)
{
return _InternalIncrementBy(ref obj, incrementBy);
}
public static byte Increment(ref byte obj, byte incrementBy)
{
return _InternalIncrementBy(ref obj, incrementBy);
}
public static ushort Increment(ref ushort obj, int incrementBy)
{
return _InternalIncrementBy(ref obj, incrementBy);
}
public static short Increment(ref short obj, int incrementBy)
{
return _InternalIncrementBy(ref obj, incrementBy);
}
#endregion Increment 2
#region Increment 1
public static ulong Increment(ref ulong obj)
{
return Increment(ref obj, 1);
}
public static long Increment(ref long obj)
{
return Increment(ref obj, 1);
}
public static uint Increment(ref uint obj)
{
return Increment(ref obj, 1);
}
public static int Increment(ref int obj)
{
return Increment(ref obj, 1);
}
public static sbyte Increment(ref sbyte obj)
{
return Increment(ref obj, 1);
}
public static byte Increment(ref byte obj)
{
return Increment(ref obj, 1);
}
public static ushort Increment(ref ushort obj)
{
return Increment(ref obj, 1);
}
public static short Increment(ref short obj)
{
return Increment(ref obj, 1);
}
#endregion Increment 1
#region Read
public static object Read(ref object obj)
{
return Interlocked.CompareExchange(ref obj, 0, 0);
}
public static double Read(ref double obj)
{
return Interlocked.CompareExchange(ref obj, 0, 0);
}
public static float Read(ref float obj)
{
return Interlocked.CompareExchange(ref obj, 0, 0);
}
public static IntPtr Read(ref IntPtr obj)
{
return Interlocked.CompareExchange(ref obj, IntPtr.Zero, IntPtr.Zero);
}
public static uint Read(ref uint obj)
{
return Interlocked.CompareExchange(ref obj, 0, 0);
}
public static ulong Read(ref ulong obj)
{
return Interlocked.CompareExchange(ref obj, 0, 0);
}
public static int Read(ref int obj)
{
return Interlocked.CompareExchange(ref obj, 0, 0);
}
public static long Read(ref long obj)
{
return Interlocked.CompareExchange(ref obj, 0, 0);
}
public static byte Read(ref byte obj)
{
return Read<byte>(ref obj);
}
public static sbyte Read(ref sbyte obj)
{
return Read<sbyte>(ref obj);
}
public static ushort Read(ref ushort obj)
{
return Read<ushort>(ref obj);
}
public static short Read(ref short obj)
{
return Read<short>(ref obj);
}
public static bool Read(ref bool obj)
{
return Read<bool>(ref obj);
}
#endregion Read
#region Write
public static void Write(ref ulong obj, ulong val)
{
Interlocked.Exchange(ref obj, val);
}
public static void Write(ref long obj, long val)
{
Interlocked.Exchange(ref obj, val);
}
public static void Write(ref uint obj, uint val)
{
Interlocked.Exchange(ref obj, val);
}
public static void Write(ref int obj, int val)
{
Interlocked.Exchange(ref obj, val);
}
public static void Write(ref IntPtr obj, IntPtr val)
{
Interlocked.Exchange(ref obj, val);
}
public static void Write(ref double obj, double val)
{
Write<double>(ref obj, val);
}
public static void Write(ref float obj, float val)
{
Write<float>(ref obj, val);
}
public static void Write(ref byte obj, byte val)
{
Write<byte>(ref obj, val);
}
public static void Write(ref sbyte obj, sbyte val)
{
Write<sbyte>(ref obj, val);
}
public static void Write(ref ushort obj, ushort val)
{
Write<ushort>(ref obj, val);
}
public static void Write(ref short obj, short val)
{
Write<short>(ref obj, val);
}
public static void Write(ref bool obj, bool val)
{
Write<bool>(ref obj, val);
}
public static void Write(ref object obj, object val)
{
Write<object>(ref obj, val);
}
#endregion Write
#region Generic Methods
public static T CompareExchange<T>(ref T obj, Func<T, T> func, T compared)
{
if (obj == null)
throw new NullReferenceException(nameof(obj));
Thread.MemoryBarrier();
T returnVal = obj;
if (returnVal.Equals(compared))
obj = Exchange<T>(ref obj, func);
return returnVal;
}
public static T Read<T>(ref T obj)
{
Thread.MemoryBarrier();
T returnVal = obj;
return returnVal;
}
public static T Write<T>(ref T obj, T value)
{
Thread.MemoryBarrier();
obj = value;
return obj;
}
#endregion Generic Methods
#region Internal IncrementDecrement
private static T _Internal_IncrementDecrement<T>(ref T obj, int decision, int val) where T : unmanaged
{
if (decision != 1 && decision != -1)
throw new ArgumentException("decision must be -1 or 1 to do increment, decrement");
Thread.MemoryBarrier();
if (typeof(T) == typeof(byte))
return (T)(object)(byte)(Interlocked.Add(ref Unsafe.As<T, int>(ref obj), decision * val));
if (typeof(T) == typeof(sbyte))
return (T)(object)(sbyte)(Interlocked.Add(ref Unsafe.As<T, int>(ref obj), decision * val));
if (typeof(T) == typeof(short))
return (T)(object)(short)(Interlocked.Add(ref Unsafe.As<T, int>(ref obj), decision * val));
if (typeof(T) == typeof(ushort))
return (T)(object)(ushort)(Interlocked.Add(ref Unsafe.As<T, int>(ref obj), decision * val));
throw new ArgumentException($"Unsupported type: {typeof(T).Name}");
}
private static T _InternalDecrementBy<T>(ref T obj, int decrementBy) where T : unmanaged
{
return _Internal_IncrementDecrement(ref obj, -1, decrementBy);
}
private static T _InternalIncrementBy<T>(ref T obj, int incrementBy) where T : unmanaged
{
return _Internal_IncrementDecrement(ref obj, 1, incrementBy);
}
#endregion Internal IncrementDecrement
}
}
namespace Extendlocked
{
using Extendlocked;
using System;
using BenchmarkDotNet.Running;
internal class Program
{
private static void Main(string[] args)
{
var summary = BenchmarkRunner.Run(typeof(Program).Assembly);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment