Skip to content

Instantly share code, notes, and snippets.

@Saduras
Last active September 24, 2017 13:21
Show Gist options
  • Save Saduras/2e262c10c173e7d0df0c67f143955c47 to your computer and use it in GitHub Desktop.
Save Saduras/2e262c10c173e7d0df0c67f143955c47 to your computer and use it in GitHub Desktop.
Reflection benchmark
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using TMPro;
using UnityEngine;
using Debug = UnityEngine.Debug;
public class ReflectionBenchmark : MonoBehaviour
{
TextMeshProUGUI label;
int n = 1000000;
class Animal
{
public string habitat;
public string biome;
public bool ambassador;
}
IEnumerator Start ()
{
label = GetComponent<TextMeshProUGUI>();
yield return new WaitForSeconds(1f);
Animal instance = new Animal
{
habitat = "",
ambassador = false,
biome = "",
};
string[] fieldNames = { "habitat", "ambassador", "biome"};
string result = $"n: {n}\n";
var watch = new Stopwatch();
watch.Start();
Normal(instance);
result += $"instance.field: {watch.ElapsedMilliseconds}ms\n";
watch.Restart();
SimpleReflection(fieldNames, instance);
result += $"Full refelction: {watch.ElapsedMilliseconds}ms\n";
watch.Restart();
CacheField(fieldNames, instance);
result += $"Cache GetField() in dict: {watch.ElapsedMilliseconds}ms\n";
watch.Restart();
CacheValue(fieldNames, instance);
result += $"Cache GetValue() in dict: {watch.ElapsedMilliseconds}ms\n";
watch.Restart();
CacheValueArray(fieldNames, instance);
result += $"Cache GetValue() in array: {watch.ElapsedMilliseconds}ms\n";
watch.Stop();
label.text = result;
}
void Normal(Animal instance)
{
int sumNormal = 0;
for (int i = 0; i < n; i++)
{
sumNormal += instance.habitat.ToString().Length;
sumNormal += instance.ambassador.ToString().Length;
sumNormal += instance.biome.ToString().Length;
}
Debug.Log("Control Sum " + sumNormal);
}
void SimpleReflection(string[] fieldNames, Animal instance)
{
int sumReflection = 0;
for (int i = 0; i < n; i++)
{
foreach (var fieldName in fieldNames)
{
var field = instance.GetType().GetField(fieldName);
sumReflection += field.GetValue(instance).ToString().Length;
}
}
Debug.Log("Control Sum " + sumReflection);
}
void CacheField(string[] fieldNames, Animal instance)
{
int sumCached = 0;
var dict = new Dictionary<string, FieldInfo>();
foreach (var fieldName in fieldNames)
dict[fieldName] = instance.GetType().GetField(fieldName);
for (int i = 0; i < n; i++)
{
foreach (var fieldName in fieldNames)
sumCached += dict[fieldName].GetValue(instance).ToString().Length;
}
Debug.Log("Control Sum " + sumCached);
}
void CacheValue(string[] fieldNames, Animal instance)
{
int sumCached = 0;
var dict = new Dictionary<string, object>();
foreach (var fieldName in fieldNames)
dict[fieldName] = instance.GetType().GetField(fieldName).GetValue(instance);
for (int i = 0; i < n; i++)
{
foreach (var fieldName in fieldNames)
sumCached += dict[fieldName].ToString().Length;
}
Debug.Log("Control Sum " + sumCached);
}
void CacheValueArray(string[] fieldNames, Animal instance)
{
int sumCached = 0;
var array = new KeyValuePair<string, object>[fieldNames.Length];
for (var i = 0; i < fieldNames.Length; i++)
array[i] = new KeyValuePair<string, object>(fieldNames[i],
instance.GetType().GetField(fieldNames[i]).GetValue(instance));
for (int i = 0; i < n; i++)
{
for (var j = 0; j < fieldNames.Length; j++)
sumCached += array[j].Value.ToString().Length;
}
Debug.Log("Control Sum " + sumCached);
}
}

Result on Samsung S6 edge (scripting backend Mono)

testcase time
instance.field 162ms
Full reflection 18516ms
Cache GetField() in dict 4729ms
Cache GetValue() in dict 736ms
Cache GetValue() in array 90ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment