Skip to content

Instantly share code, notes, and snippets.

@hez2010
Created December 14, 2025 09:55
Show Gist options
  • Select an option

  • Save hez2010/289c0b6242d1aca0d6171caa97a2bcd8 to your computer and use it in GitHub Desktop.

Select an option

Save hez2010/289c0b6242d1aca0d6171caa97a2bcd8 to your computer and use it in GitHub Desktop.
benchmarks.cs
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public class Benchmarks
{
private static unsafe void* Malloc(nuint size, nuint alignment)
{
return NativeMemory.AlignedAlloc(size, alignment);
}
private static unsafe void Free(void* pointer)
{
NativeMemory.AlignedFree(pointer);
}
private interface IJob
{
void Run();
}
// Fibonacci
public struct FibonacciNET : IJob
{
public uint number;
public uint result;
public void Run()
{
result = Fibonacci(number);
}
private uint Fibonacci(uint number)
{
if (number <= 1)
return 1;
return Fibonacci(number - 1) + Fibonacci(number - 2);
}
}
// Mandelbrot
public struct MandelbrotNET : IJob
{
public uint width;
public uint height;
public uint iterations;
public float result;
public void Run()
{
result = Mandelbrot(width, height, iterations);
}
private float Mandelbrot(uint width, uint height, uint iterations)
{
float data = 0.0f;
for (uint i = 0; i < iterations; i++)
{
float
left = -2.1f,
right = 1.0f,
top = -1.3f,
bottom = 1.3f,
deltaX = (right - left) / width,
deltaY = (bottom - top) / height,
coordinateX = left;
for (uint x = 0; x < width; x++)
{
float coordinateY = top;
for (uint y = 0; y < height; y++)
{
float workX = 0;
float workY = 0;
int counter = 0;
while (counter < 255 && MathF.Sqrt((workX * workX) + (workY * workY)) < 2.0f)
{
counter++;
float newX = (workX * workX) - (workY * workY) + coordinateX;
workY = 2 * workX * workY + coordinateY;
workX = newX;
}
data = workX + workY;
coordinateY += deltaY;
}
coordinateX += deltaX;
}
}
return data;
}
}
// NBody
private struct NBody
{
public double x, y, z, vx, vy, vz, mass;
}
public unsafe struct NBodyNET : IJob
{
public uint advancements;
public double result;
public void Run()
{
result = NBody(advancements);
}
private double NBody(uint advancements)
{
NBody* sun = stackalloc NBody[5];
NBody* end = sun + 4;
InitializeBodies(sun, end);
Energy(sun, end);
while (--advancements > 0)
{
Advance(sun, end, 0.01);
}
Energy(sun, end);
return sun[0].x + sun[0].y;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void InitializeBodies(NBody* sun, NBody* end)
{
const double pi = 3.141592653589793;
const double solarMass = 4 * pi * pi;
const double daysPerYear = 365.24;
unchecked
{
sun[1] = new NBody
{ // Jupiter
x = 4.84143144246472090e+00,
y = -1.16032004402742839e+00,
z = -1.03622044471123109e-01,
vx = 1.66007664274403694e-03 * daysPerYear,
vy = 7.69901118419740425e-03 * daysPerYear,
vz = -6.90460016972063023e-05 * daysPerYear,
mass = 9.54791938424326609e-04 * solarMass
};
sun[2] = new NBody
{ // Saturn
x = 8.34336671824457987e+00,
y = 4.12479856412430479e+00,
z = -4.03523417114321381e-01,
vx = -2.76742510726862411e-03 * daysPerYear,
vy = 4.99852801234917238e-03 * daysPerYear,
vz = 2.30417297573763929e-05 * daysPerYear,
mass = 2.85885980666130812e-04 * solarMass
};
sun[3] = new NBody
{ // Uranus
x = 1.28943695621391310e+01,
y = -1.51111514016986312e+01,
z = -2.23307578892655734e-01,
vx = 2.96460137564761618e-03 * daysPerYear,
vy = 2.37847173959480950e-03 * daysPerYear,
vz = -2.96589568540237556e-05 * daysPerYear,
mass = 4.36624404335156298e-05 * solarMass
};
sun[4] = new NBody
{ // Neptune
x = 1.53796971148509165e+01,
y = -2.59193146099879641e+01,
z = 1.79258772950371181e-01,
vx = 2.68067772490389322e-03 * daysPerYear,
vy = 1.62824170038242295e-03 * daysPerYear,
vz = -9.51592254519715870e-05 * daysPerYear,
mass = 5.15138902046611451e-05 * solarMass
};
double vx = 0, vy = 0, vz = 0;
for (NBody* planet = sun + 1; planet <= end; ++planet)
{
double mass = planet->mass;
vx += planet->vx * mass;
vy += planet->vy * mass;
vz += planet->vz * mass;
}
sun->mass = solarMass;
sun->vx = vx / -solarMass;
sun->vy = vy / -solarMass;
sun->vz = vz / -solarMass;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Energy(NBody* sun, NBody* end)
{
unchecked
{
double e = 0.0;
for (NBody* bi = sun; bi <= end; ++bi)
{
double
imass = bi->mass,
ix = bi->x,
iy = bi->y,
iz = bi->z,
ivx = bi->vx,
ivy = bi->vy,
ivz = bi->vz;
e += 0.5 * imass * (ivx * ivx + ivy * ivy + ivz * ivz);
for (NBody* bj = bi + 1; bj <= end; ++bj)
{
double
jmass = bj->mass,
dx = ix - bj->x,
dy = iy - bj->y,
dz = iz - bj->z;
e -= imass * jmass / Math.Sqrt(dx * dx + dy * dy + dz * dz);
}
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double GetD2(double dx, double dy, double dz)
{
double d2 = dx * dx + dy * dy + dz * dz;
return d2 * Math.Sqrt(d2);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Advance(NBody* sun, NBody* end, double distance)
{
unchecked
{
for (NBody* bi = sun; bi < end; ++bi)
{
double
ix = bi->x,
iy = bi->y,
iz = bi->z,
ivx = bi->vx,
ivy = bi->vy,
ivz = bi->vz,
imass = bi->mass;
for (NBody* bj = bi + 1; bj <= end; ++bj)
{
double
dx = bj->x - ix,
dy = bj->y - iy,
dz = bj->z - iz,
jmass = bj->mass,
mag = distance / GetD2(dx, dy, dz);
bj->vx = bj->vx - dx * imass * mag;
bj->vy = bj->vy - dy * imass * mag;
bj->vz = bj->vz - dz * imass * mag;
ivx = ivx + dx * jmass * mag;
ivy = ivy + dy * jmass * mag;
ivz = ivz + dz * jmass * mag;
}
bi->vx = ivx;
bi->vy = ivy;
bi->vz = ivz;
bi->x = ix + ivx * distance;
bi->y = iy + ivy * distance;
bi->z = iz + ivz * distance;
}
end->x = end->x + end->vx * distance;
end->y = end->y + end->vy * distance;
end->z = end->z + end->vz * distance;
}
}
}
// Sieve of Eratosthenes
[InlineArray(1024)]
struct Flag { private byte Elem; }
public unsafe struct SieveOfEratosthenesNET : IJob
{
public uint iterations;
public uint result;
public void Run()
{
result = SieveOfEratosthenes(iterations);
}
private uint SieveOfEratosthenes(uint iterations)
{
const int size = 1024;
var flags = new Flag();
int a, b, c, prime;
uint count = 0;
for (a = 1; a <= iterations; a++)
{
count = 0;
for (b = 0; b < size; b++)
{
flags[b] = 1; // True
}
for (b = 0; b < size; b++)
{
if (flags[b] == 1)
{
prime = b + b + 3;
c = b + prime;
while (c < size)
{
flags[c] = 0; // False
c += prime;
}
count++;
}
}
}
return count;
}
}
// Pixar Raytracer
private struct Vector3 { public float X, Y, Z; }
public enum PixarRayHit
{
None = 0,
Letter = 1,
Wall = 2,
Sun = 3
}
[InlineArray(2)]
struct Curves { private Vector3 Elem; }
[InlineArray(60)]
struct Letters { private byte Elem; }
public unsafe struct PixarRaytracerNET : IJob
{
public uint width;
public uint height;
public uint samples;
public float result;
public void Run()
{
result = PixarRaytracer(width, height, samples);
}
private uint marsagliaZ, marsagliaW;
private float PixarRaytracer(uint width, uint height, uint samples)
{
marsagliaZ = 666;
marsagliaW = 999;
Vector3 position = new Vector3 { X = -22.0f, Y = 5.0f, Z = 25.0f };
Vector3 goal = new Vector3 { X = -3.0f, Y = 4.0f, Z = 0.0f };
goal = Add(Inverse(goal), MultiplyFloat(position, -1.0f));
Vector3 left = new Vector3 { X = goal.Z, Y = 0, Z = goal.X };
left = MultiplyFloat(Inverse(left), 1.0f / width);
Vector3 up = Cross(goal, left);
Vector3 color = default(Vector3);
Vector3 adjust = default(Vector3);
for (uint y = height; y > 0; y--)
{
for (uint x = width; x > 0; x--)
{
for (uint p = samples; p > 0; p--)
{
color = Add(color, Trace(position, Add(Inverse(MultiplyFloat(Add(goal, left), x - width / 2 + Random())), MultiplyFloat(up, y - height / 2 + Random()))));
}
color = MultiplyFloat(color, (1.0f / samples) + 14.0f / 241.0f);
adjust = AddFloat(color, 1.0f);
color = new Vector3
{
X = color.X / adjust.X,
Y = color.Y / adjust.Y,
Z = color.Z / adjust.Z
};
color = MultiplyFloat(color, 255.0f);
}
}
return color.X + color.Y + color.Z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector3 Multiply(Vector3 left, Vector3 right)
{
left.X *= right.X;
left.Y *= right.Y;
left.Z *= right.Z;
return left;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector3 MultiplyFloat(Vector3 vector, float value)
{
vector.X *= value;
vector.Y *= value;
vector.Z *= value;
return vector;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float Modulus(Vector3 left, Vector3 right)
{
return left.X * right.X + left.Y * right.Y + left.Z * right.Z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float ModulusSelf(Vector3 vector)
{
return vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector3 Inverse(Vector3 vector)
{
return MultiplyFloat(vector, 1 / MathF.Sqrt(ModulusSelf(vector)));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector3 Add(Vector3 left, Vector3 right)
{
left.X += right.X;
left.Y += right.Y;
left.Z += right.Z;
return left;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector3 AddFloat(Vector3 vector, float value)
{
vector.X += value;
vector.Y += value;
vector.Z += value;
return vector;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector3 Cross(Vector3 to, Vector3 from)
{
Vector3 vector = default(Vector3);
vector.X = to.Y * from.Z - to.Z * from.Y;
vector.Y = to.Z * from.X - to.X * from.Z;
vector.Z = to.X * from.Y - to.Y * from.X;
return vector;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float Min(float left, float right)
{
return left < right ? left : right;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float BoxTest(Vector3 position, Vector3 lowerLeft, Vector3 upperRight)
{
lowerLeft = MultiplyFloat(Add(position, lowerLeft), -1);
upperRight = MultiplyFloat(Add(upperRight, position), -1);
return -Min(Min(Min(lowerLeft.X, upperRight.X), Min(lowerLeft.Y, upperRight.Y)), Min(lowerLeft.Z, upperRight.Z));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float Random()
{
marsagliaZ = 36969 * (marsagliaZ & 65535) + (marsagliaZ >> 16);
marsagliaW = 18000 * (marsagliaW & 65535) + (marsagliaW >> 16);
return ((marsagliaZ << 16) + marsagliaW) * 2.0f / 10000000000.0f;
}
private float Sample(Vector3 position, int* hitType)
{
const int size = 60;
float distance = 1e9f;
Vector3 f = position;
var letters = new Letters();
// P // I // X // A // R
letters[0] = 53; letters[12] = 65; letters[24] = 73; letters[32] = 85; letters[44] = 97; letters[56] = 99;
letters[1] = 79; letters[13] = 79; letters[25] = 79; letters[33] = 79; letters[45] = 79; letters[57] = 87;
letters[2] = 53; letters[14] = 69; letters[26] = 81; letters[34] = 89; letters[46] = 97; letters[58] = 105;
letters[3] = 95; letters[15] = 79; letters[27] = 95; letters[35] = 95; letters[47] = 95; letters[59] = 79;
letters[4] = 53; letters[16] = 67; letters[28] = 73; letters[36] = 89; letters[48] = 97;
letters[5] = 87; letters[17] = 79; letters[29] = 95; letters[37] = 95; letters[49] = 87;
letters[6] = 57; letters[18] = 67; letters[30] = 81; letters[38] = 93; letters[50] = 101;
letters[7] = 87; letters[19] = 95; letters[31] = 79; letters[39] = 79; letters[51] = 87;
letters[8] = 53; letters[20] = 65; letters[40] = 87; letters[52] = 97;
letters[9] = 95; letters[21] = 95; letters[41] = 87; letters[53] = 95;
letters[10] = 57; letters[22] = 69; letters[42] = 91; letters[54] = 101;
letters[11] = 95; letters[23] = 95; letters[43] = 87; letters[55] = 95;
f.Z = 0.0f;
for (int i = 0; i < size; i += 4)
{
Vector3 begin = MultiplyFloat(new Vector3 { X = letters[i] - 79.0f, Y = letters[i + 1] - 79.0f, Z = 0.0f }, 0.5f);
Vector3 e = Add(MultiplyFloat(new Vector3 { X = letters[i + 2] - 79.0f, Y = letters[i + 3] - 79.0f, Z = 0.0f }, 0.5f), MultiplyFloat(begin, -1.0f));
Vector3 o = MultiplyFloat(Add(f, MultiplyFloat(Add(begin, e), Min(-Min(Modulus(MultiplyFloat(Add(begin, f), -1.0f), e) / ModulusSelf(e), 0.0f), 1.0f))), -1.0f);
distance = Min(distance, ModulusSelf(o));
}
distance = MathF.Sqrt(distance);
var curves = new Curves();
curves[0] = new Vector3 { X = -11.0f, Y = 6.0f, Z = 0.0f };
curves[1] = new Vector3 { X = 11.0f, Y = 6.0f, Z = 0.0f };
for (int i = 1; i >= 0; i--)
{
Vector3 o = Add(f, MultiplyFloat(curves[i], -1.0f));
float m = 0.0f;
if (o.X > 0.0f)
{
m = MathF.Abs(MathF.Sqrt(ModulusSelf(o)) - 2.0f);
}
else
{
if (o.Y > 0.0f)
o.Y += -2.0f;
else
o.Y += 2.0f;
o.Y += MathF.Sqrt(ModulusSelf(o));
}
distance = Min(distance, m);
}
distance = MathF.Pow(MathF.Pow(distance, 8.0f) + MathF.Pow(position.Z, 8.0f), 0.125f) - 0.5f;
*hitType = (int)PixarRayHit.Letter;
float roomDistance = Min(-Min(BoxTest(position, new Vector3 { X = -30.0f, Y = -0.5f, Z = -30.0f }, new Vector3 { X = 30.0f, Y = 18.0f, Z = 30.0f }), BoxTest(position, new Vector3 { X = -25.0f, Y = -17.5f, Z = -25.0f }, new Vector3 { X = 25.0f, Y = 20.0f, Z = 25.0f })), BoxTest(new Vector3 { X = MathF.Abs(position.X) % 8, Y = position.Y, Z = position.Z }, new Vector3 { X = 1.5f, Y = 18.5f, Z = -25.0f }, new Vector3 { X = 6.5f, Y = 20.0f, Z = 25.0f }));
if (roomDistance < distance)
{
distance = roomDistance;
*hitType = (int)PixarRayHit.Wall;
}
float sun = 19.9f - position.Y;
if (sun < distance)
{
distance = sun;
*hitType = (int)PixarRayHit.Sun;
}
return distance;
}
private int RayMarching(Vector3 origin, Vector3 direction, Vector3* hitPosition, Vector3* hitNormal)
{
int hitType = (int)PixarRayHit.None;
int noHitCount = 0;
float distance = 0.0f;
for (float i = 0; i < 100; i += distance)
{
*hitPosition = MultiplyFloat(Add(origin, direction), i);
distance = Sample(*hitPosition, &hitType);
if (distance < 0.01f || ++noHitCount > 99)
{
*hitNormal = Inverse(new Vector3 { X = Sample(Add(*hitPosition, new Vector3 { X = 0.01f, Y = 0.0f, Z = 0.0f }), &noHitCount) - distance, Y = Sample(Add(*hitPosition, new Vector3 { X = 0.0f, Y = 0.01f, Z = 0.0f }), &noHitCount) - distance, Z = Sample(Add(*hitPosition, new Vector3 { X = 0.0f, Y = 0.0f, Z = 0.01f }), &noHitCount) - distance });
return hitType;
}
}
return (int)PixarRayHit.None;
}
private Vector3 Trace(Vector3 origin, Vector3 direction)
{
Vector3
sampledPosition = new Vector3 { X = 1.0f, Y = 1.0f, Z = 1.0f },
normal = new Vector3 { X = 1.0f, Y = 1.0f, Z = 1.0f },
color = new Vector3 { X = 1.0f, Y = 1.0f, Z = 1.0f },
attenuation = new Vector3 { X = 1.0f, Y = 1.0f, Z = 1.0f },
lightDirection = Inverse(new Vector3 { X = 0.6f, Y = 0.6f, Z = 1.0f });
for (int bounce = 3; bounce > 0; bounce--)
{
PixarRayHit hitType = (PixarRayHit)RayMarching(origin, direction, &sampledPosition, &normal);
switch (hitType)
{
case PixarRayHit.None:
break;
case PixarRayHit.Letter:
{
direction = MultiplyFloat(Add(direction, normal), Modulus(normal, direction) * -2.0f);
origin = MultiplyFloat(Add(sampledPosition, direction), 0.1f);
attenuation = MultiplyFloat(attenuation, 0.2f);
break;
}
case PixarRayHit.Wall:
{
float
incidence = Modulus(normal, lightDirection),
p = 6.283185f * Random(),
c = Random(),
s = MathF.Sqrt(1.0f - c),
g = normal.Z < 0 ? -1.0f : 1.0f,
u = -1.0f / (g + normal.Z),
v = normal.X * normal.Y * u;
direction = Add(Add(new Vector3 { X = v, Y = g + normal.Y * normal.Y * u, Z = -normal.Y * (MathF.Cos(p) * s) }, new Vector3 { X = 1.0f + g * normal.X * normal.X * u, Y = g * v, Z = -g * normal.X }), MultiplyFloat(normal, MathF.Sqrt(c)));
origin = MultiplyFloat(Add(sampledPosition, direction), 0.1f);
attenuation = MultiplyFloat(attenuation, 0.2f);
if (incidence > 0 && RayMarching(MultiplyFloat(Add(sampledPosition, normal), 0.1f), lightDirection, &sampledPosition, &normal) == (int)PixarRayHit.Sun)
color = MultiplyFloat(Multiply(Add(color, attenuation), new Vector3 { X = 500.0f, Y = 400.0f, Z = 100.0f }), incidence);
break;
}
case PixarRayHit.Sun:
{
color = Multiply(Add(color, attenuation), new Vector3 { X = 50.0f, Y = 80.0f, Z = 100.0f });
goto escape;
}
}
}
escape:
return color;
}
}
// Fireflies Flocking
private struct Boid
{
public Vector3 position, velocity, acceleration;
}
public unsafe struct FirefliesFlockingNET : IJob
{
public uint boids;
public uint lifetime;
public float result;
public void Run()
{
result = FirefliesFlocking(boids, lifetime);
}
private uint parkMiller;
private float maxSpeed;
private float maxForce;
private float separationDistance;
private float neighbourDistance;
private float FirefliesFlocking(uint boids, uint lifetime)
{
parkMiller = 666;
maxSpeed = 1.0f;
maxForce = 0.03f;
separationDistance = 15.0f;
neighbourDistance = 30.0f;
Boid* fireflies = (Boid*)Malloc((nuint)(boids * sizeof(Boid)), 16);
for (uint i = 0; i < boids; ++i)
{
fireflies[i].position = new Vector3 { X = Random(), Y = Random(), Z = Random() };
fireflies[i].velocity = new Vector3 { X = Random(), Y = Random(), Z = Random() };
fireflies[i].acceleration = new Vector3 { X = 0.0f, Y = 0.0f, Z = 0.0f };
}
for (uint i = 0; i < lifetime; ++i)
{
// Update
for (uint boid = 0; boid < boids; ++boid)
{
Add(&fireflies[boid].velocity, &fireflies[boid].acceleration);
float speed = Length(&fireflies[boid].velocity);
if (speed > maxSpeed)
{
Divide(&fireflies[boid].velocity, speed);
Multiply(&fireflies[boid].velocity, maxSpeed);
}
Add(&fireflies[boid].position, &fireflies[boid].velocity);
Multiply(&fireflies[boid].acceleration, maxSpeed);
}
// Separation
for (uint boid = 0; boid < boids; ++boid)
{
Vector3 separation = default(Vector3);
int count = 0;
for (uint target = 0; target < boids; ++target)
{
Vector3 position = fireflies[boid].position;
Subtract(&position, &fireflies[target].position);
float distance = Length(&position);
if (distance > 0.0f && distance < separationDistance)
{
Normalize(&position);
Divide(&position, distance);
separation = position;
count++;
}
}
if (count > 0)
{
Divide(&separation, (float)count);
Normalize(&separation);
Multiply(&separation, maxSpeed);
Subtract(&separation, &fireflies[boid].velocity);
float force = Length(&separation);
if (force > maxForce)
{
Divide(&separation, force);
Multiply(&separation, maxForce);
}
Multiply(&separation, 1.5f);
Add(&fireflies[boid].acceleration, &separation);
}
}
// Cohesion
for (uint boid = 0; boid < boids; ++boid)
{
Vector3 cohesion = default(Vector3);
int count = 0;
for (uint target = 0; target < boids; ++target)
{
Vector3 position = fireflies[boid].position;
Subtract(&position, &fireflies[target].position);
float distance = Length(&position);
if (distance > 0.0f && distance < neighbourDistance)
{
cohesion = fireflies[boid].position;
count++;
}
}
if (count > 0)
{
Divide(&cohesion, (float)count);
Subtract(&cohesion, &fireflies[boid].position);
Normalize(&cohesion);
Multiply(&cohesion, maxSpeed);
Subtract(&cohesion, &fireflies[boid].velocity);
float force = Length(&cohesion);
if (force > maxForce)
{
Divide(&cohesion, force);
Multiply(&cohesion, maxForce);
}
Add(&fireflies[boid].acceleration, &cohesion);
}
}
}
Free(fireflies);
return (float)parkMiller;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Add(Vector3* left, Vector3* right)
{
left->X += right->X;
left->Y += right->Y;
left->Z += right->Z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Subtract(Vector3* left, Vector3* right)
{
left->X -= right->X;
left->Y -= right->Y;
left->Z -= right->Z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Divide(Vector3* vector, float value)
{
vector->X /= value;
vector->Y /= value;
vector->Z /= value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Multiply(Vector3* vector, float value)
{
vector->X *= value;
vector->Y *= value;
vector->Z *= value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Normalize(Vector3* vector)
{
float length = MathF.Sqrt(vector->X * vector->X + vector->Y * vector->Y + vector->Z * vector->Z);
vector->X /= length;
vector->Y /= length;
vector->Z /= length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float Length(Vector3* vector)
{
return MathF.Sqrt(vector->X * vector->X + vector->Y * vector->Y + vector->Z * vector->Z);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float Random()
{
parkMiller = (uint)(((ulong)parkMiller * 48271u) % 0x7fffffff);
return parkMiller / 10000000.0f;
}
}
// Polynomials
[InlineArray(100)]
struct Poly { private float Elem; }
public unsafe struct PolynomialsNET : IJob
{
public uint iterations;
public float result;
public void Run()
{
result = Polynomials(iterations);
}
private float Polynomials(uint iterations)
{
const float x = 0.2f;
float pu = 0.0f;
var poly = new Poly();;
for (uint i = 0; i < iterations; i++)
{
float mu = 10.0f;
float s;
int j;
for (j = 0; j < 100; j++)
{
poly[j] = mu = (mu + 2.0f) / 2.0f;
}
s = 0.0f;
for (j = 0; j < 100; j++)
{
s = x * s + poly[j];
}
pu += s;
}
return pu;
}
}
// Particle Kinematics
private struct Particle
{
public float x, y, z, vx, vy, vz;
}
public unsafe struct ParticleKinematicsNET : IJob
{
public uint quantity;
public uint iterations;
public float result;
public void Run()
{
result = ParticleKinematics(quantity, iterations);
}
private float ParticleKinematics(uint quantity, uint iterations)
{
Particle* particles = (Particle*)Malloc((nuint)(quantity * sizeof(Particle)), 16);
for (uint i = 0; i < quantity; ++i)
{
particles[i].x = (float)i;
particles[i].y = (float)(i + 1);
particles[i].z = (float)(i + 2);
particles[i].vx = 1.0f;
particles[i].vy = 2.0f;
particles[i].vz = 3.0f;
}
for (uint a = 0; a < iterations; ++a)
{
for (uint b = 0, c = quantity; b < c; ++b)
{
Particle* p = &particles[b];
p->x += p->vx;
p->y += p->vy;
p->z += p->vz;
}
}
Particle particle = new Particle { x = particles[0].x, y = particles[0].y, z = particles[0].z };
Free(particles);
return particle.x + particle.y + particle.z;
}
}
// Arcfour
public unsafe struct ArcfourNET : IJob
{
public uint iterations;
public int result;
public void Run()
{
result = Arcfour(iterations);
}
private int Arcfour(uint iterations)
{
const int keyLength = 5;
const int streamLength = 10;
byte* state = (byte*)Malloc(256, 8);
byte* buffer = (byte*)Malloc(64, 8);
byte* key = stackalloc byte[5];
byte* stream = stackalloc byte[10];
key[0] = 0xDB;
key[1] = 0xB7;
key[2] = 0x60;
key[3] = 0xD4;
key[4] = 0x56;
stream[0] = 0xEB;
stream[1] = 0x9F;
stream[2] = 0x77;
stream[3] = 0x81;
stream[4] = 0xB7;
stream[5] = 0x34;
stream[6] = 0xCA;
stream[7] = 0x72;
stream[8] = 0xA7;
stream[9] = 0x19;
int idx = 0;
for (uint i = 0; i < iterations; i++)
{
idx = KeySetup(state, key, keyLength);
idx = GenerateStream(state, buffer, streamLength);
}
Free(state);
Free(buffer);
return idx;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int KeySetup(byte* state, byte* key, int length)
{
int i, j;
byte t;
for (i = 0; i < 256; ++i)
{
state[i] = (byte)i;
}
for (i = 0, j = 0; i < 256; ++i)
{
j = (j + state[i] + key[i % length]) % 256;
t = state[i];
state[i] = state[j];
state[j] = t;
}
return i;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GenerateStream(byte* state, byte* buffer, int length)
{
int i, j;
int idx;
byte t;
for (idx = 0, i = 0, j = 0; idx < length; ++idx)
{
i = (i + 1) % 256;
j = (j + state[i]) % 256;
t = state[i];
state[i] = state[j];
state[j] = t;
buffer[idx] = state[(state[i] + state[j]) % 256];
}
return i;
}
}
// Seahash
public unsafe struct SeahashNET : IJob
{
public uint iterations;
public ulong result;
public void Run()
{
result = Seahash(iterations);
}
private ulong Seahash(uint iterations)
{
const int bufferLength = 1024 * 128;
byte* buffer = (byte*)Malloc(bufferLength, 8);
for (int i = 0; i < bufferLength; i++)
{
buffer[i] = (byte)(i % 256);
}
ulong hash = 0;
for (uint i = 0; i < iterations; i++)
{
hash = Compute(buffer, bufferLength, 0x16F11FE89B0D677C, 0xB480A793D8E6C86C, 0x6FE2E5AAF078EBC9, 0x14F994A4C5259381);
}
Free(buffer);
return hash;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ulong Read(byte* pointer)
{
return *(ulong*)pointer;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ulong Diffuse(ulong value)
{
value *= 0x6EED0E9DA4D94A4F;
value ^= ((value >> 32) >> (int)(value >> 60));
value *= 0x6EED0E9DA4D94A4F;
return value;
}
private ulong Compute(byte* buffer, ulong length, ulong a, ulong b, ulong c, ulong d)
{
const uint blockSize = 32;
ulong end = length & ~(blockSize - 1);
for (uint i = 0; i < end; i += blockSize)
{
a ^= Read(buffer + i);
b ^= Read(buffer + i + 8);
c ^= Read(buffer + i + 16);
d ^= Read(buffer + i + 24);
a = Diffuse(a);
b = Diffuse(b);
c = Diffuse(c);
d = Diffuse(d);
}
ulong excessive = length - end;
byte* bufferEnd = buffer + end;
if (excessive > 0)
{
a ^= Read(bufferEnd);
if (excessive > 8)
{
b ^= Read(bufferEnd);
if (excessive > 16)
{
c ^= Read(bufferEnd);
if (excessive > 24)
{
d ^= Read(bufferEnd);
d = Diffuse(d);
}
c = Diffuse(c);
}
b = Diffuse(b);
}
a = Diffuse(a);
}
a ^= b;
c ^= d;
a ^= c;
a ^= length;
return Diffuse(a);
}
}
// Radix
[InlineArray(10)]
struct Bucket { private int Elem; }
public unsafe struct RadixNET : IJob
{
public uint iterations;
public int result;
public void Run()
{
result = Radix(iterations);
}
private uint classicRandom;
private int Radix(uint iterations)
{
classicRandom = 7525;
const int arrayLength = 128;
int* array = (int*)Malloc(arrayLength * sizeof(int), 16);
for (uint a = 0; a < iterations; a++)
{
for (int b = 0; b < arrayLength; b++)
{
array[b] = Random();
}
Sort(array, arrayLength);
}
int head = array[0];
Free(array);
return head;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int Random()
{
classicRandom = (6253729 * classicRandom + 4396403);
return (int)(classicRandom % 32767);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int FindLargest(int* array, int length)
{
int i;
int largest = -1;
for (i = 0; i < length; i++)
{
if (array[i] > largest)
largest = array[i];
}
return largest;
}
private void Sort(int* array, int length)
{
int i;
int* semiSorted = stackalloc int[length];
int significantDigit = 1;
int largest = FindLargest(array, length);
while (largest / significantDigit > 0)
{
var bucket = new Bucket();
for (i = 0; i < length; i++)
{
bucket[(array[i] / significantDigit) % 10]++;
}
for (i = 1; i < 10; i++)
{
bucket[i] += bucket[i - 1];
}
for (i = length - 1; i >= 0; i--)
{
semiSorted[--bucket[(array[i] / significantDigit) % 10]] = array[i];
}
for (i = 0; i < length; i++)
{
array[i] = semiSorted[i];
}
significantDigit *= 10;
}
}
}
[STAThread, MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void Main()
{
var stopwatch = new System.Diagnostics.Stopwatch();
double time = 0;
// Options
bool
fibonacciEnabled = true,
mandelbrotEnabled = true,
nbodyEnabled = true,
sieveOfEratosthenesEnabled = true,
pixarRaytracerEnabled = true,
firefliesFlockingEnabled = true,
polynomialsEnabled = true,
particleKinematicsEnabled = true,
arcfourEnabled = true,
seahashEnabled = true,
radixEnabled = true;
uint
fibonacciNumber = 46,
mandelbrotIterations = 8,
nbodyAdvancements = 100000000,
sieveOfEratosthenesIterations = 1000000,
pixarRaytracerSamples = 16,
firefliesFlockingLifetime = 1000,
polynomialsIterations = 10000000,
particleKinematicsIterations = 10000000,
arcfourIterations = 10000000,
seahashIterations = 1000000,
radixIterations = 1000000;
// Benchmarks
if (fibonacciEnabled)
{
var benchmark = new FibonacciNET
{
number = fibonacciNumber
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Fibonacci: " + time + " ms");
}
if (mandelbrotEnabled)
{
var benchmark = new MandelbrotNET
{
width = 1920,
height = 1080,
iterations = mandelbrotIterations
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Mandelbrot: " + time + " ms");
}
if (nbodyEnabled)
{
var benchmark = new NBodyNET
{
advancements = nbodyAdvancements
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("NBody: " + time + " ms");
}
if (sieveOfEratosthenesEnabled)
{
var benchmark = new SieveOfEratosthenesNET
{
iterations = sieveOfEratosthenesIterations
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Sieve of Eratosthenes: " + time + " ms");
}
if (pixarRaytracerEnabled)
{
var benchmark = new PixarRaytracerNET
{
width = 720,
height = 480,
samples = pixarRaytracerSamples
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Pixar Raytracer: " + time + " ms");
}
if (firefliesFlockingEnabled)
{
var benchmark = new FirefliesFlockingNET
{
boids = 1000,
lifetime = firefliesFlockingLifetime
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Fireflies Flocking: " + time + " ms");
}
if (polynomialsEnabled)
{
var benchmark = new PolynomialsNET
{
iterations = polynomialsIterations
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Polynomials: " + time + " ms");
}
if (particleKinematicsEnabled)
{
var benchmark = new ParticleKinematicsNET
{
quantity = 1000,
iterations = particleKinematicsIterations
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Particle Kinematics: " + time + " ms");
}
if (arcfourEnabled)
{
var benchmark = new ArcfourNET
{
iterations = arcfourIterations
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Arcfour: " + time + " ms");
}
if (seahashEnabled)
{
var benchmark = new SeahashNET
{
iterations = seahashIterations
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Seahash: " + time + " ms");
}
if (radixEnabled)
{
var benchmark = new RadixNET
{
iterations = radixIterations
};
stopwatch.Stop();
benchmark.Run();
stopwatch.Restart();
benchmark.Run();
time = stopwatch.ElapsedMilliseconds;
Console.WriteLine("Radix: " + time + " ms");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment