我对.net中有效的低级算法感兴趣.我想让我们选择在C#而不是C++中编写更多的代码,但是一个绊脚石就是.net中的边界检查,它发生在循环和随机访问数组时.
激励示例是计算两个数组中相应元素的乘积之和的函数(这是两个向量的点积).
static void SumProduct(double[] X, double[] Y)
{
double sum = 0;
int length = X.Length;
if (length != Y.Length)
throw new ArgumentException("X and Y must be same size");
for (int i = 0; i < length; i++) // Check X.Length instead? See below
sum += X[i] * Y[i];
}
Run Code Online (Sandbox Code Playgroud)
从我所知道的,并且不知道足够的IL或x86来检查,编译器将不会优化X 和的 边界检查Y.我错了和/或有没有办法编写我的代码以允许编译器帮助我?
更多详情
有许多效率论据支持和反对使用特定语言,尤其是最好专注于"大O"算法成本而不是比例常数,而更高级别的语言可以帮助您实现这一目标.关于.net中边界检查的主题,我发现的最好的文章是MSDN上的CLR中的数组边界检查消除(也在关于启用优化的重要性的堆栈溢出答案中引用).
这可以追溯到2009年,所以我想知道从那时起事情是否发生了重大变化.此外,文章揭示了一些真正的微妙之处,这些微妙之处本来就让我感到高兴,因此仅此一点,我欢迎一些专家建议.
例如,似乎在上面的代码中,我最好i< X.Length不要写作而不是i < length.此外,我还天真地假设对于具有单个数组的算法,编写foreach循环将更好地向编译器声明您的意图并为其提供优化边界检查的最佳机会.
根据MSDN文章,SumForBAD下面,我认为肯定会优化,不会.虽然SumFor可以直接优化,SumForEach …
我使用英特尔®架构代码分析器(IACA)发现了一些意想不到的东西(对我而言).
以下指令使用[base+index]寻址
addps xmm1, xmmword ptr [rsi+rax*1]
Run Code Online (Sandbox Code Playgroud)
根据IACA没有微熔丝.但是,如果我用[base+offset]这样的
addps xmm1, xmmword ptr [rsi]
Run Code Online (Sandbox Code Playgroud)
IACA报告它确实融合了.
英特尔优化参考手册的第2-11节给出了以下"可以由所有解码器处理的微融合微操作"的示例
FADD DOUBLE PTR [RDI + RSI*8]
Run Code Online (Sandbox Code Playgroud)
和Agner Fog的优化装配手册也给出了使用[base+index]寻址的微操作融合的例子.例如,请参见第12.2节"Core2上的相同示例".那么正确的答案是什么?
我正在评估我的项目的网络+渲染工作负载。
程序连续运行一个主循环:
while (true) {
doSomething()
drawSomething()
doSomething2()
sendSomething()
}
Run Code Online (Sandbox Code Playgroud)
主循环每秒运行 60 多次。
我想查看性能故障,每个程序需要多少时间。
我担心的是,如果我打印每个程序的每个入口和出口的时间间隔,
这会导致巨大的性能开销。
我很好奇什么是衡量性能的惯用方法。
日志打印是否足够好?