C# .NET IL字节码优化器

C# .NET IL字节码优化器,c#,.net,optimization,bytecode,il,C#,.net,Optimization,Bytecode,Il,我正在尝试用C#.NET和Mono编写用于游戏的优化代码。(是的,我有充分的理由使用C#而不是C++) 我注意到C#似乎没有正确地优化其操作符。运算符的运行速度是使用Vector4 math手动内联代码的两倍。 以下是我在.NET 4.5中运行9999999次的一些简单基准测试: // Test 1 for (uint i = 0; i != 9999999; ++i)// 230 MS { vector += vector2; vector2 -= vector; } // Test

我正在尝试用C#.NET和Mono编写用于游戏的优化代码。(是的,我有充分的理由使用C#而不是C++)

我注意到C#似乎没有正确地优化其操作符。运算符的运行速度是使用Vector4 math手动内联代码的两倍。 以下是我在.NET 4.5中运行9999999次的一些简单基准测试:

// Test 1
for (uint i = 0; i != 9999999; ++i)// 230 MS
{
  vector += vector2;
  vector2 -= vector;
}

// Test 2
for (uint i = 0; i != 9999999; ++i)// 185 MS
{
  vector = vector.Add(ref vector2);
  vector2 = vector2.Sub(ref vector);
}

// Test 3
for (uint i = 0; i != 9999999; ++i)// 116 MS
{
  vector.X += vector2.X;
  vector.Y += vector2.Y;
  vector.Z += vector2.Z;
  vector.W += vector2.W;
  vector2.X -= vector1.X;
  vector2.Y -= vector1.Y;
  vector2.Z -= vector1.Z;
  vector2.W -= vector1.W;
}

// EDIT Test 1 SOLVED ----------------------------------
// When the Operators are created like so, they actually perform the BEST!
// Sry MS for complaining :(...  Although SIMD support would be nice :)
struct Vector4
{
    public static Vector4 operator +(Vector4 p1, Vector4 p2)
{
    p1.X += p2.X;
    p1.Y += p2.Y;
    p1.Z += p2.Z;
    p1.W += p2.W;
    return p1;
}

public static Vector4 operator -(Vector4 p1, Vector4 p2)
{
    p1.X -= p2.X;
    p1.Y -= p2.Y;
    p1.Z -= p2.Z;
    p1.W -= p2.W;
    return p1;
}
}

for (uint i = 0; i != 9999999; ++i)// 75 MS
{
  vector += vector2;
  vector2 -= vector;
}
我想知道是否有任何.NET IL优化器工具?我已经找过了,但还真的找到什么了。或者更清楚地说,无论如何,优化我的C#代码或IL代码以提高性能

我真的希望操作员至少执行185ms。这对它也有意义


这里有一个指向im用于测试的应用程序的链接:

我找到了解决问题的方法。。。尽管我仍然想要任何关于.NET IL优化器的信息。另外,了解为什么使用操作符实际上比自己手动倾斜代码更快也很有趣

要使用.NET上的Vector4运算符获得最佳性能,请执行以下操作:

public static Vector4 operator +(Vector4 p1, Vector4 p2)
{
    p1.X += p2.X;
    p1.Y += p2.Y;
    p1.Z += p2.Z;
    p1.W += p2.W;
    return p1;
}

public static Vector4 operator -(Vector4 p1, Vector4 p2)
{
    p1.X -= p2.X;
    p1.Y -= p2.Y;
    p1.Z -= p2.Z;
    p1.W -= p2.W;
    return p1;
}
不要这样做:

public static Vector4 operator +(Vector4 p1, Vector4 p2)
{
    return new Vector4(p1.X+p2.X, p1.Y+p2.Y, p1.Z+p2.Z, p1.W+p2.W);
}
//ect...

您自己的答案和评论都强烈地暗示了为什么调用.Add比使用加法运算符更快

+
的语义是操作数保持不变。做1+2你不会期望1之后的值是3吧?因此,为了遵循最小惊喜规则,各种实现中的加法运算符都遵循这个语义

这也意味着vector4的加法操作符需要创建一个新的vector4对象。这个新对象的内存可能已经分配(例如堆栈),但这没有多大帮助,因为当它被分配给任何返回类型时,我们都必须复制该值

Add实例方法的语义不同于加法运算符。它变异其中一个实例,因此不必创建新对象


您发布的答案中加法运算符的语义与
add

在调试器下运行吗?@ReedCopsey No我在.NET 4.5 x86版本中构建。在AMD64X2处理器上运行。我编辑了你的Microsoft判断,因为它是非真实的,我对它过敏。请在堆栈溢出时保持中立。Test1和Test2正在创建额外的对象。我认为这就是他们速度较慢的原因,不是因为IL没有得到优化…顺便说一句,在.NET4.5上,你可以用来鼓励内联。为什么代码这么难看?一个简单的
返回新的Vector4(p1.X+p2.X,…)
可能同样快,但更好。您并没有真正创建值类型的实例。@CodesInChaos实际上这就是我所做的,速度太慢了。230毫秒对75毫秒。你会选哪一个?奇怪。看起来优化器的行为很愚蠢。没有理由认为这应该更快。我需要对此进行调查。@RuneFS值类型的局部变量大部分时间将存储在堆栈上(或在某些情况下存储在寄存器中)。@svick现在并没有真正改善情况,是吗?首先,我们将值推送到堆栈上,然后将其复制到指定的任何返回值上。创建一个新的
Vector4
会很耗时吗?它是一种值类型。你为什么要谈论V表查找?@code因为内存分配不是免费的,所以当你执行
newsomevaluetype
时,没有真正的内存分配。OP的
+=
代码与基于
的新矢量3(…)
的代码产生不同的机器代码,这没有真正的原因。@RuneFS我从你说的话中理解了发生了什么,这就是为什么IL优化器还可以帮助解决像这样的小问题。@CodeInChaos如何消除从堆栈到堆的结果副本?(或另一个stackframe)我看不出在不改变程序语义的情况下如何从机器代码中消除这一点