Skip to content

Commit

Permalink
Merge pull request #323 from NoiseStudio/fix/322/entity-systems-after…
Browse files Browse the repository at this point in the history
…-waiting-for-dependency

Fix entity system after waiting for dependency is not executed as fast as possible
  • Loading branch information
Vixenka committed Aug 14, 2023
2 parents ff20beb + 8f2928a commit a5b3248
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 18 deletions.
22 changes: 22 additions & 0 deletions NoiseEngine.Tests/Collections/Concurrent/ConcurrentListTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,26 @@ public class ConcurrentListTest {
Assert.Equal(testList.OrderBy(x => x), list.OrderBy(x => x));
}

[Fact]
public void IterateDuringGrowing() {
ConcurrentList<int> list = new ConcurrentList<int>();
bool works = true;

Task[] tasks = Enumerable.Range(0, Environment.ProcessorCount * 4).Select(_ => Task.Run(() => {
int i = 0;
while (works) {
list.Remove(i);
list.Add(i++);
}
})).ToArray();

for (int i = 0; i < Environment.ProcessorCount * 16; i++) {
foreach (int element in list)
Assert.True(element >= 0);
}

works = false;
Task.WaitAll(tasks);
}

}
2 changes: 1 addition & 1 deletion NoiseEngine.Tests/Physics/PhysicsTestActivatorSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ internal partial class PhysicsTestActivatorSystem : EntitySystem {
scene.AddSystem(collisionResolveSystem, cycleTime);

RigidBodyInitializerSystem initalizer = new RigidBodyInitializerSystem();
scene.AddSystem(initalizer, cycleTime);
scene.AddSystem(initalizer, 500);
}

private void OnUpdateEntity() {
Expand Down
6 changes: 5 additions & 1 deletion NoiseEngine/Collections/Concurrent/ConcurrentList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Xml.Linq;

namespace NoiseEngine.Collections.Concurrent;

Expand Down Expand Up @@ -117,8 +118,11 @@ public class ConcurrentList<T> : ICollection<T>, IReadOnlyCollection<T>, ICollec
/// from <see cref="ConcurrentList{T}"/>. The <see cref="Array"/> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
public void CopyTo(T[] array, int arrayIndex) {
foreach (T element in this)
foreach (T element in this) {
if (arrayIndex >= array.Length)
break;
array[arrayIndex++] = element;
}
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions NoiseEngine/Collections/Concurrent/ConcurrentListSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ namespace NoiseEngine.Collections.Concurrent;

internal class ConcurrentListSegment<T> : IEnumerable<T> {

private readonly ConcurrentListSegmentValue<T>[] items;
internal readonly ConcurrentListSegmentValue<T>[] items;

private ConcurrentListSegment<T>? previous;

private int nextIndex;
internal int nextIndex;
private int count;

public int Capacity => items.Length;
Expand Down
15 changes: 6 additions & 9 deletions NoiseEngine/Jobs/EntityScheduleWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ internal class EntityScheduleWorker : IDisposable {
enqueueThreadLocker.WaitOne();

long executionTime = DateTime.UtcNow.Ticks;
EntitySystem[] sortedSystems =
systems.OrderByDescending(x => executionTime - x.lastExecutionTime).ToArray();
EntitySystem[] sortedSystems = systems.OrderBy(x => x.lastExecutionTime + x.cycleTimeWithDelta).ToArray();

if (sortedSystems.Length == 0)
continue;
Expand All @@ -110,14 +109,12 @@ internal class EntityScheduleWorker : IDisposable {
foreach (EntitySystem system in sortedSystems) {
double executionTimeDifference = executionTime - system.lastExecutionTime;
if (system.cycleTimeWithDelta >= executionTimeDifference)
break;

if (!system.TryOrderWork())
continue;

packages.Enqueue(new SchedulePackage(true, system, null, 0, 0));
SignalExecutorThreads();
if (!system.TryOrderWork(true))
continue;

EnqueueCycleBegin(system);
needToWait = false;
}

Expand Down Expand Up @@ -156,8 +153,8 @@ internal class EntityScheduleWorker : IDisposable {

EntityLocker locker = executionData.Chunk!.GetLocker();
if (
executionData.System.ComponentWriteAccess ? !locker.TryEnterWriteLock(1) :
!locker.TryEnterReadLock(1)
executionData.System.ComponentWriteAccess ? !locker.TryEnterWriteLock(0) :
!locker.TryEnterReadLock(0)
) {
packages.Enqueue(executionData);
continue;
Expand Down
34 changes: 29 additions & 5 deletions NoiseEngine/Jobs/EntitySystemT0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ protected struct NoiseEngineInternal_DoNotUse {
private readonly object scheduleLocker = new object();
private readonly object enabledLocker = new object();
private readonly Dictionary<EntitySystem, uint> dependencies = new Dictionary<EntitySystem, uint>();
private readonly ConcurrentQueue<EntitySystem> waitingForExecution = new ConcurrentQueue<EntitySystem>();

private EntityWorld? world;
private uint ongoingWork;
Expand Down Expand Up @@ -323,7 +324,7 @@ protected struct NoiseEngineInternal_DoNotUse {
/// <returns><see langword="true"/> when cycle was enqueued; otherwise <see langword="false"/>.</returns>
public bool TryExecute() {
EntitySchedule? schedule = Schedule;
if (schedule is null || !TryOrderWork())
if (schedule is null || !TryOrderWork(false))
return false;
schedule.Worker.EnqueueCycleBegin(this);
return true;
Expand All @@ -335,7 +336,7 @@ protected struct NoiseEngineInternal_DoNotUse {
/// <returns><see langword="true"/> when cycle was executed; otherwise <see langword="false"/>.</returns>
public bool TryExecuteAndWait() {
EntitySchedule? schedule = Schedule;
if (schedule is null || !TryOrderWork())
if (schedule is null || !TryOrderWork(false))
return false;
schedule.Worker.EnqueuePackages(this);
Wait();
Expand Down Expand Up @@ -463,13 +464,18 @@ protected struct NoiseEngineInternal_DoNotUse {
long executionTime = DateTime.UtcNow.Ticks;

long difference = executionTime - lastExecutionTime;
Debug.Assert(difference >= 0);

DeltaTime = difference / (double)TimeSpan.TicksPerSecond;
DeltaTimeF = (float)DeltaTime;

double? cycleTime = CycleTime;
if (cycleTime.HasValue) {
long cycleTimeInTicks = (long)(cycleTime.Value * TimeSpan.TicksPerMillisecond);
cycleTimeWithDelta = cycleTimeInTicks - (difference - cycleTimeInTicks);
if (difference <= cycleTimeInTicks)
cycleTimeWithDelta = cycleTimeInTicks;
else
cycleTimeWithDelta = cycleTimeInTicks - (difference - cycleTimeInTicks);
}

lastExecutionTime = executionTime;
Expand Down Expand Up @@ -520,6 +526,17 @@ protected struct NoiseEngineInternal_DoNotUse {
workResetEvent.Set();
}

if (!waitingForExecution.IsEmpty) {
long executionTime = DateTime.UtcNow.Ticks;
while (waitingForExecution.TryDequeue(out EntitySystem? system)) {
double executionTimeDifference = executionTime - system.lastExecutionTime;
if (system.cycleTimeWithDelta >= executionTimeDifference)
continue;

system.TryExecute();
}
}

if (!enabled) {
lock (enabledLocker) {
OnStop();
Expand All @@ -528,12 +545,15 @@ protected struct NoiseEngineInternal_DoNotUse {
}
}

internal bool TryOrderWork() {
internal bool TryOrderWork(bool invokedFromSchedule) {
if (!Enabled || IsDisposed || isWorking.Exchange(true))
return false;

foreach (EntitySystem system in Dependencies) {
if (system.cycleCount == dependencies[system]) {
if (invokedFromSchedule)
system.AddSystemToWaitingForExecution(this);

lock (workLocker) {
isWorking = false;
workResetEvent.Set();
Expand All @@ -546,6 +566,10 @@ protected struct NoiseEngineInternal_DoNotUse {
return true;
}

internal void AddSystemToWaitingForExecution(EntitySystem system) {
waitingForExecution.Enqueue(system);
}

/// <summary>
/// This method is executed when this system is initializing.
/// </summary>
Expand Down Expand Up @@ -583,7 +607,7 @@ protected struct NoiseEngineInternal_DoNotUse {
}

private void WaitWhenCanExecuteAndOrderWork() {
while (!TryOrderWork()) {
while (!TryOrderWork(false)) {
AssertCouldExecute();
Wait();
}
Expand Down

0 comments on commit a5b3248

Please sign in to comment.