Merge pull request #10657 from RoosterDragon/sync-perf
Improve sync performance
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 = a.Actor.ActorID,
|
ActorID = actor.ActorID,
|
||||||
Type = a.Actor.Info.Name,
|
Type = actor.Info.Name,
|
||||||
Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName,
|
Owner = (actor.Owner == null) ? "null" : actor.Owner.PlayerName,
|
||||||
Trait = a.Trait.GetType().Name,
|
Trait = syncHash.Trait.GetType().Name,
|
||||||
Hash = sync,
|
Hash = syncHash.Hash,
|
||||||
NamesValues = DumpSyncTrait(a.Trait)
|
NamesValues = DumpSyncTrait(syncHash.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,24 +26,29 @@ 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 },
|
||||||
{ typeof(CVec), ((Func<CVec, int>)HashCVec).Method },
|
{ typeof(CVec), ((Func<CVec, int>)HashCVec).Method },
|
||||||
{ typeof(WDist), ((Func<WDist, int>)Hash).Method },
|
{ typeof(WDist), ((Func<WDist, int>)HashUsingHashCode).Method },
|
||||||
{ typeof(WPos), ((Func<WPos, int>)Hash).Method },
|
{ typeof(WPos), ((Func<WPos, int>)HashUsingHashCode).Method },
|
||||||
{ typeof(WVec), ((Func<WVec, int>)Hash).Method },
|
{ typeof(WVec), ((Func<WVec, int>)HashUsingHashCode).Method },
|
||||||
{ typeof(WAngle), ((Func<WAngle, int>)Hash).Method },
|
{ typeof(WAngle), ((Func<WAngle, int>)HashUsingHashCode).Method },
|
||||||
{ typeof(WRot), ((Func<WRot, int>)Hash).Method },
|
{ typeof(WRot), ((Func<WRot, int>)HashUsingHashCode).Method },
|
||||||
{ typeof(TypeDictionary), ((Func<TypeDictionary, int>)HashTDict).Method },
|
|
||||||
{ typeof(Actor), ((Func<Actor, int>)HashActor).Method },
|
{ typeof(Actor), ((Func<Actor, int>)HashActor).Method },
|
||||||
{ typeof(Player), ((Func<Player, int>)HashPlayer).Method },
|
{ typeof(Player), ((Func<Player, int>)HashPlayer).Method },
|
||||||
{ typeof(Target), ((Func<Target, int>)HashTarget).Method },
|
{ typeof(Target), ((Func<Target, int>)HashTarget).Method },
|
||||||
@@ -51,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();
|
||||||
@@ -62,15 +67,13 @@ namespace OpenRA
|
|||||||
il.Emit(OpCodes.Ldc_I4, 0x555);
|
il.Emit(OpCodes.Ldc_I4, 0x555);
|
||||||
il.MarkLabel(l);
|
il.MarkLabel(l);
|
||||||
}
|
}
|
||||||
else if (type.HasAttribute<SyncAttribute>())
|
|
||||||
il.EmitCall(OpCodes.Call, ((Func<object, int>)CalculateSyncHash).Method, null);
|
|
||||||
else if (type != typeof(int))
|
else if (type != typeof(int))
|
||||||
throw new NotImplementedException("SyncAttribute on member of unhashable type: {0}".F(type.FullName));
|
throw new NotImplementedException("SyncAttribute on member of unhashable type: {0}".F(type.FullName));
|
||||||
|
|
||||||
il.Emit(OpCodes.Xor);
|
il.Emit(OpCodes.Xor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Func<object, int> GenerateHashFunc(Type t)
|
static Func<object, int> GenerateHashFunc(Type t)
|
||||||
{
|
{
|
||||||
var d = new DynamicMethod("hash_{0}".F(t.Name), typeof(int), new Type[] { typeof(object) }, t);
|
var d = new DynamicMethod("hash_{0}".F(t.Name), typeof(int), new Type[] { typeof(object) }, t);
|
||||||
var il = d.GetILGenerator();
|
var il = d.GetILGenerator();
|
||||||
@@ -116,14 +119,6 @@ namespace OpenRA
|
|||||||
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
return ((i2.X * 5) ^ (i2.Y * 3)) / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int HashTDict(TypeDictionary d)
|
|
||||||
{
|
|
||||||
var ret = 0;
|
|
||||||
foreach (var o in d)
|
|
||||||
ret += CalculateSyncHash(o);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int HashActor(Actor a)
|
public static int HashActor(Actor a)
|
||||||
{
|
{
|
||||||
if (a != null)
|
if (a != null)
|
||||||
@@ -152,7 +147,7 @@ namespace OpenRA
|
|||||||
return (int)(t.FrozenActor.Actor.ActorID << 16) * 0x567;
|
return (int)(t.FrozenActor.Actor.ActorID << 16) * 0x567;
|
||||||
|
|
||||||
case TargetType.Terrain:
|
case TargetType.Terrain:
|
||||||
return Hash(t.CenterPosition);
|
return HashUsingHashCode(t.CenterPosition);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
case TargetType.Invalid:
|
case TargetType.Invalid:
|
||||||
@@ -160,7 +155,7 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int Hash<T>(T t)
|
public static int HashUsingHashCode<T>(T t)
|
||||||
{
|
{
|
||||||
return t.GetHashCode();
|
return t.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
var hash = 0;
|
var hash = 0;
|
||||||
foreach (var objective in objectives)
|
foreach (var objective in objectives)
|
||||||
hash ^= Sync.Hash(objective.State);
|
hash ^= Sync.HashUsingHashCode(objective.State);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user