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
|
||||
{
|
||||
using NamesValuesPair = Pair<string[], string[]>;
|
||||
using NamesValuesPair = Pair<string[], object[]>;
|
||||
|
||||
class SyncReport
|
||||
{
|
||||
@@ -35,10 +35,10 @@ namespace OpenRA.Network
|
||||
TypeInfo typeInfo;
|
||||
lock (typeInfoCache)
|
||||
typeInfo = typeInfoCache[type];
|
||||
var values = new string[typeInfo.Names.Length];
|
||||
var values = new object[typeInfo.Names.Length];
|
||||
var index = 0;
|
||||
|
||||
foreach (var func in typeInfo.MemberToStringFunctions)
|
||||
foreach (var func in typeInfo.SerializableCopyOfMemberFunctions)
|
||||
values[index++] = func(sync);
|
||||
|
||||
return Pair.New(typeInfo.Names, values);
|
||||
@@ -166,7 +166,7 @@ namespace OpenRA.Network
|
||||
static ParameterExpression syncParam = Expression.Parameter(typeof(ISync), "sync");
|
||||
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 TypeInfo(Type type)
|
||||
@@ -182,14 +182,25 @@ namespace OpenRA.Network
|
||||
"Invalid Property: " + prop.DeclaringType.FullName + "." + prop.Name);
|
||||
|
||||
var sync = Expression.Convert(syncParam, type);
|
||||
MemberToStringFunctions = fields
|
||||
.Select(fi => MemberToString(Expression.Field(sync, fi), fi.FieldType, fi.Name))
|
||||
.Concat(properties.Select(pi => MemberToString(Expression.Property(sync, pi), pi.PropertyType, pi.Name)))
|
||||
SerializableCopyOfMemberFunctions = fields
|
||||
.Select(fi => SerializableCopyOfMember(Expression.Field(sync, fi), fi.FieldType, fi.Name))
|
||||
.Concat(properties.Select(pi => SerializableCopyOfMember(Expression.Property(sync, pi), pi.PropertyType, 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)
|
||||
{
|
||||
// The lambda generated is shown below.
|
||||
@@ -197,10 +208,13 @@ namespace OpenRA.Network
|
||||
var toString = memberType.GetMethod("ToString", Type.EmptyTypes);
|
||||
Expression getString;
|
||||
if (memberType.IsValueType)
|
||||
{
|
||||
// (ISync sync) => { return ((TSync)sync).Foo.ToString(); }
|
||||
getString = Expression.Call(getMember, toString);
|
||||
}
|
||||
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 assignMemberVariable = Expression.Assign(memberVariable, getMember);
|
||||
var member = Expression.Block(new[] { memberVariable }, assignMemberVariable);
|
||||
|
||||
Reference in New Issue
Block a user