generated from pancake-llc/package
-
Notifications
You must be signed in to change notification settings - Fork 12
Benchmark
yenmoc edited this page Jan 16, 2024
·
9 revisions
public class Mover : MonoBehaviour
{
float _speed;
void Awake()
{
_speed = Random.Range(1.0f, 1.1f);
}
void Update()
{
moveUpAndDown();
}
void moveUpAndDown()
{
var currPos = transform.position;
transform.position = new Vector3(currPos.x, Mathf.PingPong(Time.time * _speed, 10f), currPos.z);
}
}
public class ManagedMover : MonoBehaviour
{
float _speed;
void Awake()
{
_speed = Random.Range(1.0f, 1.1f);
}
void OnEnable()
{
// Registers the script into the UpdateManager
UpdateManager.Add(this);
}
public void UpdateManager_Update()
{
moveUpAndDown();
}
void moveUpAndDown()
{
var currPos = transform.position;
transform.position = new Vector3(currPos.x, Mathf.PingPong(Time.time * _speed, 10f), currPos.z);
}
void OnDisable()
{
// Unregisters the script from the UpdateManager
UpdateManager.Remove(this);
}
}
public static class UpdateManager
{
public static Stopwatch SW { get; private set; } = new Stopwatch();
public static Action StopWatchStoppedCallback;
static HashSet<ManagedMover> _updateables = new HashSet<ManagedMover>();
/// <summary>
/// Adds a <see cref="Mover"/> to the list of updateables
/// </summary>
/// <param name="obj">The object that will be added</param>
public static void Add(ManagedMover mover)
{
_updateables.Add(mover);
}
/// <summary>
/// Removes a <see cref="Mover"/> from the list of updateables
/// </summary>
/// <param name="obj">The object that will be removed</param>
public static void Remove(ManagedMover mover)
{
_updateables.Remove(mover);
}
class UpdateManagerInnerMonoBehaviour : MonoBehaviour
{
void Update()
{
SW.Restart();
foreach (var mover in _updateables)
{
mover.UpdateManager_Update();
}
SW.Stop();
StopWatchStoppedCallback?.Invoke();
}
}
#region Static constructor and field for inner MonoBehaviour
static UpdateManager()
{
var gameObject = new GameObject();
_innerMonoBehaviour = gameObject.AddComponent<UpdateManagerInnerMonoBehaviour>();
#if UNITY_EDITOR
gameObject.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
_innerMonoBehaviour.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
#endif
}
static UpdateManagerInnerMonoBehaviour _innerMonoBehaviour;
#endregion
}
public class Spawner : MonoBehaviour
{
/// <summary>
/// Use this flags to change updating logic from manual to Unity
/// </summary>
public static bool UseUpdateManager { get; set; } = false;
/// <summary>
/// The prefab type that this script spawns
/// </summary>
[SerializeField] GameObject _objectToSpawn;
void Start() { SpawnObjects(100); }
/// <summary>
/// Will spawn count * count - 1 objects in the scene
/// </summary>
public void SpawnObjects(int count)
{
for (int i = 0; i < count * 2; i = i + 2)
{
for (int j = 0; j < count * 2; j = j + 2)
{
if (i == 2 && j == 2) continue;
var go = Instantiate(_objectToSpawn, new Vector3(i, 0f, j), Quaternion.identity, transform);
if (UseUpdateManager) go.AddComponent<ManagedMover>();
else go.AddComponent<Mover>();
}
}
}
}
public class UpdateBenchmark
{
private const float WARMUP_TIME = 5f;
private const float EXECUTION_TIME = 60f;
[UnityTest, Performance]
public IEnumerator UpdateManager_Benchmark()
{
Spawner.UseUpdateManager = true;
SceneManager.LoadScene("Update Manager");
var sampleGroup = new SampleGroup("Update Time", SampleUnit.Millisecond);
// Wait a frame for scene load
yield return null;
// Small idling before measurement starts
yield return new WaitForSecondsRealtime(WARMUP_TIME);
UpdateManager.StopWatchStoppedCallback += () => Measure.Custom(sampleGroup, UpdateManager.SW.Elapsed.TotalMilliseconds);
yield return new WaitForSecondsRealtime(EXECUTION_TIME);
UpdateManager.StopWatchStoppedCallback = null;
}
[UnityTest, Performance]
public IEnumerator TraditionalUpdate_Benchmark()
{
Spawner.UseUpdateManager = false;
SceneManager.LoadScene("Update Manager");
var sampleGroup = new SampleGroup("Update Time", SampleUnit.Millisecond);
// Wait a frame for scene load
yield return null;
// Add the helper monos
var go = new GameObject("Temp mono holder");
go.AddComponent<UpdateBenchmarkHelperJustBefore>();
go.AddComponent<UpdateBenchmarkHelperJustAfter>();
// Small idling before measurement starts
yield return new WaitForSecondsRealtime(WARMUP_TIME);
UpdateBenchmarkHelperJustAfter.StopWatchStoppedCallback += () => Measure.Custom(sampleGroup, UpdateBenchmarkHelperJustAfter.SW.Elapsed.TotalMilliseconds);
yield return new WaitForSecondsRealtime(EXECUTION_TIME);
UpdateBenchmarkHelperJustAfter.StopWatchStoppedCallback = null;
}
}
Vector3[] input = new Vector3[1000];
... // init vector input to test
Vector3[] DefaultVectorMultiplication()
{
Vector3[] results = new Vector3[1000];
for (int i = 0; i < 1000; i++)
{
results[i] = input[i] * 5f;
}
return results;
}
Vector3[] input = new Vector3[1000];
... // init vector input to test
Vector3[] DefaultVectorMultiplication()
{
Vector3[] results = new Vector3[1000];
for (int i = 0; i < 1000; i++)
{
Vector3 curr = input[i];
Vector3 result;
result.x = curr.x * 5f;
result.y = curr.y * 5f;
result.z = curr.z * 5f;
results[i] = result;
}
return results;
}