Generate sync reports faster by delaying ToString calls until it is written to disk.
Values for the report are generated by calling ToString on members, we avoid calling this on value types for performance. By instead just copying the value we can delay calling ToString until later and avoid spending time and memory creating strings that usually go unused.
This commit is contained in:
@@ -17,7 +17,7 @@ using OpenRA.Primitives;
|
|||||||
|
|
||||||
namespace OpenRA.Network
|
namespace OpenRA.Network
|
||||||
{
|
{
|
||||||
using NamesValuesPair = Pair<string[], string[]>;
|
using NamesValuesPair = Pair<string[], object[]>;
|
||||||
|
|
||||||
class SyncReport
|
class SyncReport
|
||||||
{
|
{
|
||||||
@@ -35,10 +35,10 @@ namespace OpenRA.Network
|
|||||||
TypeInfo typeInfo;
|
TypeInfo typeInfo;
|
||||||
lock (typeInfoCache)
|
lock (typeInfoCache)
|
||||||
typeInfo = typeInfoCache[type];
|
typeInfo = typeInfoCache[type];
|
||||||
var values = new string[typeInfo.Names.Length];
|
var values = new object[typeInfo.Names.Length];
|
||||||
var index = 0;
|
var index = 0;
|
||||||
|
|
||||||
foreach (var func in typeInfo.MemberToStringFunctions)
|
foreach (var func in typeInfo.SerializableCopyOfMemberFunctions)
|
||||||
values[index++] = func(sync);
|
values[index++] = func(sync);
|
||||||
|
|
||||||
return Pair.New(typeInfo.Names, values);
|
return Pair.New(typeInfo.Names, values);
|
||||||
@@ -166,7 +166,7 @@ namespace OpenRA.Network
|
|||||||
static ParameterExpression syncParam = Expression.Parameter(typeof(ISync), "sync");
|
static ParameterExpression syncParam = Expression.Parameter(typeof(ISync), "sync");
|
||||||
static ConstantExpression nullString = Expression.Constant(null, typeof(string));
|
static ConstantExpression nullString = Expression.Constant(null, typeof(string));
|
||||||
|
|
||||||
public readonly Func<ISync, string>[] MemberToStringFunctions;
|
public readonly Func<ISync, object>[] SerializableCopyOfMemberFunctions;
|
||||||
public readonly string[] Names;
|
public readonly string[] Names;
|
||||||
|
|
||||||
public TypeInfo(Type type)
|
public TypeInfo(Type type)
|
||||||
@@ -182,14 +182,25 @@ namespace OpenRA.Network
|
|||||||
"Invalid Property: " + prop.DeclaringType.FullName + "." + prop.Name);
|
"Invalid Property: " + prop.DeclaringType.FullName + "." + prop.Name);
|
||||||
|
|
||||||
var sync = Expression.Convert(syncParam, type);
|
var sync = Expression.Convert(syncParam, type);
|
||||||
MemberToStringFunctions = fields
|
SerializableCopyOfMemberFunctions = fields
|
||||||
.Select(fi => MemberToString(Expression.Field(sync, fi), fi.FieldType, fi.Name))
|
.Select(fi => SerializableCopyOfMember(Expression.Field(sync, fi), fi.FieldType, fi.Name))
|
||||||
.Concat(properties.Select(pi => MemberToString(Expression.Property(sync, pi), pi.PropertyType, pi.Name)))
|
.Concat(properties.Select(pi => SerializableCopyOfMember(Expression.Property(sync, pi), pi.PropertyType, pi.Name)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
Names = fields.Select(fi => fi.Name).Concat(properties.Select(pi => pi.Name)).ToArray();
|
Names = fields.Select(fi => fi.Name).Concat(properties.Select(pi => pi.Name)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Func<ISync, object> SerializableCopyOfMember(MemberExpression getMember, Type memberType, string name)
|
||||||
|
{
|
||||||
|
if (memberType.IsValueType)
|
||||||
|
{
|
||||||
|
// We can get a copy just by accessing the member since it is a value type.
|
||||||
|
var boxedCopy = Expression.Convert(getMember, typeof(object));
|
||||||
|
return Expression.Lambda<Func<ISync, object>>(boxedCopy, name, new[] { syncParam }).Compile();
|
||||||
|
}
|
||||||
|
return MemberToString(getMember, memberType, name);
|
||||||
|
}
|
||||||
|
|
||||||
static Func<ISync, string> MemberToString(MemberExpression getMember, Type memberType, string name)
|
static Func<ISync, string> MemberToString(MemberExpression getMember, Type memberType, string name)
|
||||||
{
|
{
|
||||||
// The lambda generated is shown below.
|
// The lambda generated is shown below.
|
||||||
@@ -197,10 +208,13 @@ namespace OpenRA.Network
|
|||||||
var toString = memberType.GetMethod("ToString", Type.EmptyTypes);
|
var toString = memberType.GetMethod("ToString", Type.EmptyTypes);
|
||||||
Expression getString;
|
Expression getString;
|
||||||
if (memberType.IsValueType)
|
if (memberType.IsValueType)
|
||||||
|
{
|
||||||
|
// (ISync sync) => { return ((TSync)sync).Foo.ToString(); }
|
||||||
getString = Expression.Call(getMember, toString);
|
getString = Expression.Call(getMember, toString);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// (ISync sync) => { var foo = ((TSync)sync).Foo; return foo == null ? null : foo.ToString()); }
|
// (ISync sync) => { var foo = ((TSync)sync).Foo; return foo == null ? null : foo.ToString(); }
|
||||||
var memberVariable = Expression.Variable(memberType, getMember.Member.Name);
|
var memberVariable = Expression.Variable(memberType, getMember.Member.Name);
|
||||||
var assignMemberVariable = Expression.Assign(memberVariable, getMember);
|
var assignMemberVariable = Expression.Assign(memberVariable, getMember);
|
||||||
var member = Expression.Block(new[] { memberVariable }, assignMemberVariable);
|
var member = Expression.Block(new[] { memberVariable }, assignMemberVariable);
|
||||||
|
|||||||
Reference in New Issue
Block a user