Skip to content

Instantly share code, notes, and snippets.

@vgrudenic
Created May 13, 2017 18:33
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save vgrudenic/545c338b99a90a971ca5c53da523f23f to your computer and use it in GitHub Desktop.
Comparison of struct and class arrays in C#
using System;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Structs_vs_classes_array_test
{
// code slightly modified from the Jackson Dunstan's article
// How to Write Faster Code Than 90% of Programmers
// http://jacksondunstan.com/articles/3860
class Program
{
static void Main(string[] args)
{
#if DEBUG
Console.WriteLine("Release build might give better results");
#endif
if (System.Diagnostics.Debugger.IsAttached)
Console.WriteLine("Run with Ctrl+F5 to Start without debugging");
new TestScript().Start();
Console.WriteLine("Done.");
Console.Read();
}
}
class TestScript
{
public void Start()
{
const int count = 10 * 1000 * 1000;
ProjectileStruct[] projectileStructs = new ProjectileStruct[count];
ProjectileClass[] projectileClasses = new ProjectileClass[count];
Console.WriteLine("Creating arrays...");
int[] indices = Enumerable.Range(0, count).ToArray();
for (int i = 0; i < count; ++i)
{
projectileClasses[i] = ProjectileClass.Create();
projectileStructs[i] = ProjectileStruct.Create();
}
Console.WriteLine("Shuffling arrays...");
Shuffle(projectileStructs);
Shuffle(projectileClasses);
Console.WriteLine("---");
Console.WriteLine("Unshuffled indices test:");
RunTest(count, projectileStructs, projectileClasses, indices);
Shuffle(indices);
Console.WriteLine("---");
Console.WriteLine("Shuffled indices test:");
RunTest(count, projectileStructs, projectileClasses, indices);
}
private static void RunTest(int count, ProjectileStruct[] projectileStructs, ProjectileClass[] projectileClasses, int[] indices)
{
for (int k = 0; k < 3; k++)
{
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < count; ++i)
{
UpdateProjectile(ref projectileStructs[indices[i]], 0.5f);
}
sw.Stop();
var structTime = sw.Elapsed.TotalMilliseconds;
sw.Restart();
for (int i = 0; i < count; ++i)
{
UpdateProjectile(projectileClasses[indices[i]], 0.5f);
}
sw.Stop();
var classTime = sw.Elapsed.TotalMilliseconds;
Console.WriteLine(
"Struct {0:0.0}ms vs Class {1:0.0}ms ({2:0.0}x slower)",
structTime,
classTime, (double)classTime / structTime
);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void UpdateProjectile(ref ProjectileStruct projectile, float time)
{
projectile.Position += projectile.Velocity * time;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void UpdateProjectile(ProjectileClass projectile, float time)
{
projectile.Position += projectile.Velocity * time;
}
public static void Shuffle<T>(T[] list)
{
for (int n = list.Length; n > 1;)
{
n--;
int k = TestRandom.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
static Random TestRandom = new Random();
struct Vector3
{
public float x, y, z;
public static Vector3 operator *(Vector3 v, float f)
{
v.x *= f;
v.y *= f;
v.z *= f;
return v;
}
public static Vector3 operator +(Vector3 v, Vector3 b)
{
v.x += b.x;
v.y += b.y;
v.z += b.z;
return v;
}
}
struct ProjectileStruct
{
public Vector3 Position;
public Vector3 Velocity;
public static ProjectileStruct Create()
{
var projectile = new ProjectileStruct();
projectile.Position.x = (float)TestRandom.NextDouble();
projectile.Position.y = (float)TestRandom.NextDouble();
projectile.Position.z = (float)TestRandom.NextDouble();
projectile.Velocity.x = (float)TestRandom.NextDouble();
projectile.Velocity.y = (float)TestRandom.NextDouble();
projectile.Velocity.z = (float)TestRandom.NextDouble();
return projectile;
}
}
sealed class ProjectileClass
{
public Vector3 Position;
public Vector3 Velocity;
public static ProjectileClass Create()
{
var projectile = new ProjectileClass();
projectile.Position.x = (float)TestRandom.NextDouble();
projectile.Position.y = (float)TestRandom.NextDouble();
projectile.Position.z = (float)TestRandom.NextDouble();
projectile.Velocity.x = (float)TestRandom.NextDouble();
projectile.Velocity.y = (float)TestRandom.NextDouble();
projectile.Velocity.z = (float)TestRandom.NextDouble();
return projectile;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment