Cache sync hash functions per actor for faster sync calculations.
Caching the result of the function lookup allows the actor to calculate all the sync hashes for its syncable traits faster as it does not need to repeat the lookup each time.
This commit is contained in:
@@ -24,6 +24,13 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
public sealed class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>, IDisposable
|
public sealed class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>, IDisposable
|
||||||
{
|
{
|
||||||
|
internal struct SyncHash
|
||||||
|
{
|
||||||
|
public readonly ISync Trait;
|
||||||
|
public readonly int Hash;
|
||||||
|
public SyncHash(ISync trait, int hash) { Trait = trait; Hash = hash; }
|
||||||
|
}
|
||||||
|
|
||||||
public readonly ActorInfo Info;
|
public readonly ActorInfo Info;
|
||||||
|
|
||||||
public readonly World World;
|
public readonly World World;
|
||||||
@@ -62,6 +69,8 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal IEnumerable<SyncHash> SyncHashes { get; private set; }
|
||||||
|
|
||||||
readonly IFacing facing;
|
readonly IFacing facing;
|
||||||
readonly IHealth health;
|
readonly IHealth health;
|
||||||
readonly IRenderModifier[] renderModifiers;
|
readonly IRenderModifier[] renderModifiers;
|
||||||
@@ -112,6 +121,12 @@ namespace OpenRA
|
|||||||
visibilityModifiers = TraitsImplementing<IVisibilityModifier>().ToArray();
|
visibilityModifiers = TraitsImplementing<IVisibilityModifier>().ToArray();
|
||||||
defaultVisibility = Trait<IDefaultVisibility>();
|
defaultVisibility = Trait<IDefaultVisibility>();
|
||||||
Targetables = TraitsImplementing<ITargetable>().ToArray();
|
Targetables = TraitsImplementing<ITargetable>().ToArray();
|
||||||
|
|
||||||
|
SyncHashes =
|
||||||
|
TraitsImplementing<ISync>()
|
||||||
|
.Select(sync => Pair.New(sync, Sync.GetHashFunction(sync)))
|
||||||
|
.ToArray()
|
||||||
|
.Select(pair => new SyncHash(pair.First, pair.Second(pair.First)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle DetermineBounds()
|
Rectangle DetermineBounds()
|
||||||
|
|||||||
@@ -63,31 +63,29 @@ namespace OpenRA.Network
|
|||||||
report.SyncedRandom = orderManager.World.SharedRandom.Last;
|
report.SyncedRandom = orderManager.World.SharedRandom.Last;
|
||||||
report.TotalCount = orderManager.World.SharedRandom.TotalCount;
|
report.TotalCount = orderManager.World.SharedRandom.TotalCount;
|
||||||
report.Traits.Clear();
|
report.Traits.Clear();
|
||||||
foreach (var a in orderManager.World.ActorsWithTrait<ISync>())
|
foreach (var actor in orderManager.World.ActorsHavingTrait<ISync>())
|
||||||
{
|
foreach (var syncHash in actor.SyncHashes)
|
||||||
var sync = Sync.CalculateSyncHash(a.Trait);
|
if (syncHash.Hash != 0)
|
||||||
if (sync != 0)
|
report.Traits.Add(new TraitReport()
|
||||||
report.Traits.Add(new TraitReport()
|
{
|
||||||
{
|
ActorID = actor.ActorID,
|
||||||
ActorID = a.Actor.ActorID,
|
Type = actor.Info.Name,
|
||||||
Type = a.Actor.Info.Name,
|
Owner = (actor.Owner == null) ? "null" : actor.Owner.PlayerName,
|
||||||
Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName,
|
Trait = syncHash.Trait.GetType().Name,
|
||||||
Trait = a.Trait.GetType().Name,
|
Hash = syncHash.Hash,
|
||||||
Hash = sync,
|
NamesValues = DumpSyncTrait(syncHash.Trait)
|
||||||
NamesValues = DumpSyncTrait(a.Trait)
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var e in orderManager.World.Effects)
|
foreach (var e in orderManager.World.Effects)
|
||||||
{
|
{
|
||||||
var sync = e as ISync;
|
var sync = e as ISync;
|
||||||
if (sync != null)
|
if (sync != null)
|
||||||
{
|
{
|
||||||
var hash = Sync.CalculateSyncHash(sync);
|
var hash = Sync.Hash(sync);
|
||||||
if (hash != 0)
|
if (hash != 0)
|
||||||
report.Effects.Add(new EffectReport()
|
report.Effects.Add(new EffectReport()
|
||||||
{
|
{
|
||||||
Name = sync.ToString().Split('.').Last(),
|
Name = sync.GetType().Name,
|
||||||
Hash = hash,
|
Hash = hash,
|
||||||
NamesValues = DumpSyncTrait(sync)
|
NamesValues = DumpSyncTrait(sync)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,14 +26,20 @@ namespace OpenRA
|
|||||||
|
|
||||||
public static class Sync
|
public static class Sync
|
||||||
{
|
{
|
||||||
static Cache<Type, Func<object, int>> hashFuncCache = new Cache<Type, Func<object, int>>(t => GenerateHashFunc(t));
|
static readonly ConcurrentCache<Type, Func<object, int>> HashFunctions =
|
||||||
|
new ConcurrentCache<Type, Func<object, int>>(GenerateHashFunc);
|
||||||
|
|
||||||
public static int CalculateSyncHash(object obj)
|
internal static Func<object, int> GetHashFunction(ISync sync)
|
||||||
{
|
{
|
||||||
return hashFuncCache[obj.GetType()](obj);
|
return HashFunctions[sync.GetType()];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Dictionary<Type, MethodInfo> hashFunctions = new Dictionary<Type, MethodInfo>()
|
internal static int Hash(ISync sync)
|
||||||
|
{
|
||||||
|
return GetHashFunction(sync)(sync);
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly Dictionary<Type, MethodInfo> CustomHashFunctions = new Dictionary<Type, MethodInfo>()
|
||||||
{
|
{
|
||||||
{ typeof(int2), ((Func<int2, int>)HashInt2).Method },
|
{ typeof(int2), ((Func<int2, int>)HashInt2).Method },
|
||||||
{ typeof(CPos), ((Func<CPos, int>)HashCPos).Method },
|
{ typeof(CPos), ((Func<CPos, int>)HashCPos).Method },
|
||||||
@@ -50,8 +56,8 @@ namespace OpenRA
|
|||||||
|
|
||||||
static void EmitSyncOpcodes(Type type, ILGenerator il)
|
static void EmitSyncOpcodes(Type type, ILGenerator il)
|
||||||
{
|
{
|
||||||
if (hashFunctions.ContainsKey(type))
|
if (CustomHashFunctions.ContainsKey(type))
|
||||||
il.EmitCall(OpCodes.Call, hashFunctions[type], null);
|
il.EmitCall(OpCodes.Call, CustomHashFunctions[type], null);
|
||||||
else if (type == typeof(bool))
|
else if (type == typeof(bool))
|
||||||
{
|
{
|
||||||
var l = il.DefineLabel();
|
var l = il.DefineLabel();
|
||||||
|
|||||||
@@ -341,18 +341,19 @@ namespace OpenRA
|
|||||||
|
|
||||||
// hash all the actors
|
// hash all the actors
|
||||||
foreach (var a in Actors)
|
foreach (var a in Actors)
|
||||||
ret += n++ * (int)(1 + a.ActorID) * Sync.CalculateSyncHash(a);
|
ret += n++ * (int)(1 + a.ActorID) * Sync.HashActor(a);
|
||||||
|
|
||||||
// hash all the traits that tick
|
// hash all the traits that tick
|
||||||
foreach (var x in ActorsWithTrait<ISync>())
|
foreach (var actor in ActorsHavingTrait<ISync>())
|
||||||
ret += n++ * (int)(1 + x.Actor.ActorID) * Sync.CalculateSyncHash(x.Trait);
|
foreach (var syncHash in actor.SyncHashes)
|
||||||
|
ret += n++ * (int)(1 + actor.ActorID) * syncHash.Hash;
|
||||||
|
|
||||||
// TODO: don't go over all effects
|
// TODO: don't go over all effects
|
||||||
foreach (var e in Effects)
|
foreach (var e in Effects)
|
||||||
{
|
{
|
||||||
var sync = e as ISync;
|
var sync = e as ISync;
|
||||||
if (sync != null)
|
if (sync != null)
|
||||||
ret += n++ * Sync.CalculateSyncHash(sync);
|
ret += n++ * Sync.Hash(sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash the shared rng
|
// Hash the shared rng
|
||||||
|
|||||||
Reference in New Issue
Block a user