Replace TraitContainer.AllEnumerator with ApplyToAll.
As proposed in the past in #13577. Replace TraitContainer.All() that uses the custom AllEnumerator with TraitContainer.ApplyToAllX() that takes an action as argument. The AllEnumerator.Current function show up in profiling reports since it is used each tick multiple times for multiple traits. The function is 'heavy' because it creates TraitPair<T>'s temporary objects for each actor trait combination. In the past about 20k ITick trait pairs were present during an average multi player game. Using an Apply function that takes an action avoid the need to create these temporary objects. To be able to still use 'DoTimed' somewhat efficiently the measurement was moved to inside the trait container method. Results in a 25% performance improvement in accessing all traits of a certain type. Apply function could be used for other TraitContainer functions as well for further improvements. Test result for calling on a dummy trait on 20k actors a 1000 times: 1315 ms traitcontainer.AllEnumerator (current) 989 ms traitcontainer.Apply (this commit)
This commit is contained in:
@@ -11,8 +11,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using OpenRA.Primitives;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
@@ -122,6 +124,16 @@ namespace OpenRA
|
||||
t.Value.RemoveActor(a.ActorID);
|
||||
}
|
||||
|
||||
public void ApplyToActorsWithTrait<T>(Action<Actor, T> action)
|
||||
{
|
||||
InnerGet<T>().ApplyToAll(action);
|
||||
}
|
||||
|
||||
public void ApplyToActorsWithTraitTimed<T>(Action<Actor, T> action, string text)
|
||||
{
|
||||
InnerGet<T>().ApplyToAllTimed(action, text);
|
||||
}
|
||||
|
||||
interface ITraitContainer
|
||||
{
|
||||
void Add(Actor actor, object trait);
|
||||
@@ -277,6 +289,32 @@ namespace OpenRA
|
||||
actors.RemoveRange(startIndex, count);
|
||||
traits.RemoveRange(startIndex, count);
|
||||
}
|
||||
|
||||
public void ApplyToAll(Action<Actor, T> action)
|
||||
{
|
||||
for (var i = 0; i < actors.Count; i++)
|
||||
action(actors[i], traits[i]);
|
||||
}
|
||||
|
||||
public void ApplyToAllTimed(Action<Actor, T> action, string text)
|
||||
{
|
||||
var longTickThresholdInStopwatchTicks = PerfTimer.LongTickThresholdInStopwatchTicks;
|
||||
var start = Stopwatch.GetTimestamp();
|
||||
for (var i = 0; i < actors.Count; i++)
|
||||
{
|
||||
var actor = actors[i];
|
||||
var trait = traits[i];
|
||||
action(actor, trait);
|
||||
var current = Stopwatch.GetTimestamp();
|
||||
if (current - start > longTickThresholdInStopwatchTicks)
|
||||
{
|
||||
PerfTimer.LogLongTick(start, current, text, trait);
|
||||
start = Stopwatch.GetTimestamp();
|
||||
}
|
||||
else
|
||||
start = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ namespace OpenRA
|
||||
foreach (var a in actors.Values)
|
||||
a.Tick();
|
||||
|
||||
ActorsWithTrait<ITick>().DoTimed(x => x.Trait.Tick(x.Actor), "Trait");
|
||||
ApplyToActorsWithTraitTimed<ITick>((Actor actor, ITick trait) => trait.Tick(actor), "Trait");
|
||||
|
||||
effects.DoTimed(e => e.Tick(this), "Effect");
|
||||
}
|
||||
@@ -477,7 +477,7 @@ namespace OpenRA
|
||||
// For things that want to update their render state once per tick, ignoring pause state
|
||||
public void TickRender(WorldRenderer wr)
|
||||
{
|
||||
ActorsWithTrait<ITickRender>().DoTimed(x => x.Trait.TickRender(wr, x.Actor), "Render");
|
||||
ApplyToActorsWithTraitTimed<ITickRender>((Actor actor, ITickRender trait) => trait.TickRender(wr, actor), "Render");
|
||||
ScreenMap.TickRender();
|
||||
}
|
||||
|
||||
@@ -536,6 +536,11 @@ namespace OpenRA
|
||||
return TraitDict.ActorsWithTrait<T>();
|
||||
}
|
||||
|
||||
public void ApplyToActorsWithTraitTimed<T>(Action<Actor, T> action, string text)
|
||||
{
|
||||
TraitDict.ApplyToActorsWithTraitTimed<T>(action, text);
|
||||
}
|
||||
|
||||
public IEnumerable<Actor> ActorsHavingTrait<T>()
|
||||
{
|
||||
return TraitDict.ActorsHavingTrait<T>();
|
||||
|
||||
Reference in New Issue
Block a user