Skip to content

Commit

Permalink
Merge pull request #100 from AnnulusGames/optimization-collections
Browse files Browse the repository at this point in the history
Improve: optimize collections, add LinkedPool
  • Loading branch information
AnnulusGames committed Mar 16, 2024
2 parents 0f83da1 + d90a539 commit d7857eb
Show file tree
Hide file tree
Showing 17 changed files with 97 additions and 73 deletions.
8 changes: 8 additions & 0 deletions src/LitMotion/Assets/LitMotion/Runtime/Collections.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace LitMotion
namespace LitMotion.Collections
{
internal sealed class MinimumList<T>
/// <summary>
/// A list of minimal features. Note that it is NOT thread-safe and must NOT be marked readonly as it is a mutable struct.
/// </summary>
/// <typeparam name="T">Element type</typeparam>
[StructLayout(LayoutKind.Auto)]
public struct FastListCore<T>
{
public MinimumList(int initialCapacity = 16)
public FastListCore(int initialCapacity)
{
array = new T[initialCapacity];
tailIndex = 0;
}

public static readonly FastListCore<T> Empty = new(0);

T[] array;
int tailIndex;

Expand Down Expand Up @@ -51,26 +59,26 @@ public void EnsureCapacity(int capacity)
}
}

public T this[int index]
public readonly T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => array[index];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => array[index] = value;
}

public int Length
public readonly int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => tailIndex;
}

public Span<T> AsSpan() => array.AsSpan(0, tailIndex);
public readonly Span<T> AsSpan() => array.AsSpan(0, tailIndex);
public readonly T[] AsArray() => array;

[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
void CheckIndex(int index)
readonly void CheckIndex(int index)
{
if (index < 0 || index > tailIndex) throw new IndexOutOfRangeException();
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace LitMotion.Collections
{
/// <summary>
/// An object pool node consisting of a linked list
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ILinkedPoolNode<T> where T : class
{
ref T NextNode { get; }
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
using System.Runtime.InteropServices;
using System.Threading;

namespace LitMotion
namespace LitMotion.Collections
{
// This implementation is based on UniTask's TaskPool<T>
// Reference: https://github.com/Cysharp/UniTask/blob/64792b672d35e43b3412fc74861f8bdbf41e3a6f/src/UniTask/Assets/Plugins/UniTask/Runtime/TaskPool.cs

/// <summary>
/// Thread-safe linked list object pool
/// </summary>
/// <typeparam name="T"></typeparam>
[StructLayout(LayoutKind.Auto)]
internal struct MotionTaskSourcePool<T> where T : class, IMotionTaskSourcePoolNode<T>
public struct LinkedPool<T> where T : class, ILinkedPoolNode<T>
{
static readonly int MaxPoolSize = int.MaxValue;

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Runtime.CompilerServices;
using UnityEngine;
using TMPro;
using LitMotion.Collections;

#if UNITY_EDITOR
using UnityEditor;
#endif
Expand Down Expand Up @@ -173,7 +175,7 @@ public TextMeshProMotionAnimator()

TMP_Text target;
internal CharInfo[] charInfoArray;
internal MinimumList<MotionHandle> motionHandleList = new();
internal FastListCore<MotionHandle> motionHandleList = new(16);

TextMeshProMotionAnimator nextNode;

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System.Runtime.CompilerServices;
using UnityEngine;
using LitMotion.Collections;

namespace LitMotion
{
[DisallowMultipleComponent]
[AddComponentMenu("")]
internal sealed class MotionHandleLinker : MonoBehaviour
{
readonly MinimumList<MotionHandle> handleList = new(8);
FastListCore<MotionHandle> handleList = new(8);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Register(MotionHandle handle)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System.Runtime.CompilerServices;
using LitMotion.Collections;

namespace LitMotion
{
internal static class MotionStorageManager
{
static readonly MinimumList<IMotionStorage> storageList = new();
static FastListCore<IMotionStorage> storageList = new(16);

public static int CurrentStorageId { get; private set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
using System;
using System.Threading;
using UnityEngine;
using LitMotion.Collections;

namespace LitMotion
{
internal sealed class AwaitableMotionConfiguredSource : IMotionTaskSourcePoolNode<AwaitableMotionConfiguredSource>
internal sealed class AwaitableMotionConfiguredSource : ILinkedPoolNode<AwaitableMotionConfiguredSource>
{
static MotionTaskSourcePool<AwaitableMotionConfiguredSource> pool;
static LinkedPool<AwaitableMotionConfiguredSource> pool;

AwaitableMotionConfiguredSource nextNode;
public ref AwaitableMotionConfiguredSource NextNode => ref nextNode;
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System;
using System.Threading;
using System.Threading.Tasks.Sources;
using LitMotion.Collections;

namespace LitMotion
{
internal sealed class ValueTaskMotionConfiguredSource : IValueTaskSource, IMotionTaskSourcePoolNode<ValueTaskMotionConfiguredSource>
internal sealed class ValueTaskMotionConfiguredSource : IValueTaskSource, ILinkedPoolNode<ValueTaskMotionConfiguredSource>
{
static MotionTaskSourcePool<ValueTaskMotionConfiguredSource> pool;
static LinkedPool<ValueTaskMotionConfiguredSource> pool;

ValueTaskMotionConfiguredSource nextNode;
public ref ValueTaskMotionConfiguredSource NextNode => ref nextNode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using LitMotion.Collections;

namespace LitMotion
{
Expand Down Expand Up @@ -27,7 +28,7 @@ public static MotionStorage<TValue, TOptions, TAdapter> GetOrCreate()
}
}

static readonly MinimumList<IUpdateRunner> updateRunners = new();
static FastListCore<IUpdateRunner> updateRunners = new(16);

/// <summary>
/// ManualMotionDispatcher time. It increases every time Update is called.
Expand Down
54 changes: 34 additions & 20 deletions src/LitMotion/Assets/LitMotion/Runtime/MotionDispatcher.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Runtime.CompilerServices;
using UnityEngine;
using LitMotion.Collections;

#if UNITY_EDITOR
using UnityEditor;
#endif
Expand Down Expand Up @@ -104,29 +106,41 @@ public static (UpdateRunner<TValue, TOptions, TAdapter> runner, bool isCreated)
}
}

static readonly MinimumList<IUpdateRunner> initializationRunners = new();
static readonly MinimumList<IUpdateRunner> earlyUpdateRunners = new();
static readonly MinimumList<IUpdateRunner> fixedUpdateRunners = new();
static readonly MinimumList<IUpdateRunner> preUpdateRunners = new();
static readonly MinimumList<IUpdateRunner> updateRunners = new();
static readonly MinimumList<IUpdateRunner> preLateUpdateRunners = new();
static readonly MinimumList<IUpdateRunner> postLateUpdateRunners = new();
static readonly MinimumList<IUpdateRunner> timeUpdateRunners = new();
static FastListCore<IUpdateRunner> initializationRunners = new(16);
static FastListCore<IUpdateRunner> earlyUpdateRunners = new(16);
static FastListCore<IUpdateRunner> fixedUpdateRunners = new(16);
static FastListCore<IUpdateRunner> preUpdateRunners = new(16);
static FastListCore<IUpdateRunner> updateRunners = new(16);
static FastListCore<IUpdateRunner> preLateUpdateRunners = new(16);
static FastListCore<IUpdateRunner> postLateUpdateRunners = new(16);
static FastListCore<IUpdateRunner> timeUpdateRunners = new(16);

internal static FastListCore<IUpdateRunner> EmptyList = new(0);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static MinimumList<IUpdateRunner> GetRunnerList(PlayerLoopTiming playerLoopTiming)
static ref FastListCore<IUpdateRunner> GetRunnerList(PlayerLoopTiming playerLoopTiming)
{
return playerLoopTiming switch
// FastListCore<T> must be passed as ref
switch (playerLoopTiming)
{
PlayerLoopTiming.Initialization => initializationRunners,
PlayerLoopTiming.EarlyUpdate => earlyUpdateRunners,
PlayerLoopTiming.FixedUpdate => fixedUpdateRunners,
PlayerLoopTiming.PreUpdate => preUpdateRunners,
PlayerLoopTiming.Update => updateRunners,
PlayerLoopTiming.PreLateUpdate => preLateUpdateRunners,
PlayerLoopTiming.PostLateUpdate => postLateUpdateRunners,
PlayerLoopTiming.TimeUpdate => timeUpdateRunners,
_ => null
default:
return ref EmptyList;
case PlayerLoopTiming.Initialization:
return ref initializationRunners;
case PlayerLoopTiming.EarlyUpdate:
return ref earlyUpdateRunners;
case PlayerLoopTiming.FixedUpdate:
return ref fixedUpdateRunners;
case PlayerLoopTiming.PreUpdate:
return ref preUpdateRunners;
case PlayerLoopTiming.Update:
return ref updateRunners;
case PlayerLoopTiming.PreLateUpdate:
return ref preLateUpdateRunners;
case PlayerLoopTiming.PostLateUpdate:
return ref postLateUpdateRunners;
case PlayerLoopTiming.TimeUpdate:
return ref timeUpdateRunners;
};
}

Expand Down Expand Up @@ -259,7 +273,7 @@ public static void InitUpdateRunner()
}
}

static readonly MinimumList<IUpdateRunner> updateRunners = new();
static FastListCore<IUpdateRunner> updateRunners = new(16);

public static MotionHandle Schedule<TValue, TOptions, TAdapter>(in MotionData<TValue, TOptions> data, in MotionCallbackData callbackData)
where TValue : unmanaged
Expand Down

0 comments on commit d7857eb

Please sign in to comment.