【发布时间】:2015-05-12 15:28:44
【问题描述】:
Net 4.6 RC x64 的速度是 x86(发布版)的两倍:
考虑这段代码:
class SpectralNorm
{
public static void Main(String[] args)
{
int n = 5500;
if (args.Length > 0) n = Int32.Parse(args[0]);
var spec = new SpectralNorm();
var watch = Stopwatch.StartNew();
var res = spec.Approximate(n);
Console.WriteLine("{0:f9} -- {1}", res, watch.Elapsed.TotalMilliseconds);
}
double Approximate(int n)
{
// create unit vector
double[] u = new double[n];
for (int i = 0; i < n; i++) u[i] = 1;
// 20 steps of the power method
double[] v = new double[n];
for (int i = 0; i < n; i++) v[i] = 0;
for (int i = 0; i < 10; i++)
{
MultiplyAtAv(n, u, v);
MultiplyAtAv(n, v, u);
}
// B=AtA A multiplied by A transposed
// v.Bv /(v.v) eigenvalue of v
double vBv = 0, vv = 0;
for (int i = 0; i < n; i++)
{
vBv += u[i] * v[i];
vv += v[i] * v[i];
}
return Math.Sqrt(vBv / vv);
}
/* return element i,j of infinite matrix A */
double A(int i, int j)
{
return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1);
}
/* multiply vector v by matrix A */
void MultiplyAv(int n, double[] v, double[] Av)
{
for (int i = 0; i < n; i++)
{
Av[i] = 0;
for (int j = 0; j < n; j++) Av[i] += A(i, j) * v[j];
}
}
/* multiply vector v by matrix A transposed */
void MultiplyAtv(int n, double[] v, double[] Atv)
{
for (int i = 0; i < n; i++)
{
Atv[i] = 0;
for (int j = 0; j < n; j++) Atv[i] += A(j, i) * v[j];
}
}
/* multiply vector v by matrix A and then by matrix A transposed */
void MultiplyAtAv(int n, double[] v, double[] AtAv)
{
double[] u = new double[n];
MultiplyAv(n, v, u);
MultiplyAtv(n, u, AtAv);
}
}
在我的机器上,x86 发布版本需要 4.5 秒才能完成,而 x64 需要 9.5 秒。 x64 是否需要任何特定的标志/设置?
更新
事实证明,RyuJIT 在这个问题上起了作用。
如果在 app.config 中启用了useLegacyJit,结果会有所不同,这一次 x64 更快。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
</startup>
<runtime>
<useLegacyJit enabled="1" />
</runtime>
</configuration>
更新
现已将该问题报告给 CLR 团队coreclr, issue 993
【问题讨论】:
-
我不熟悉光谱规范,这是需要考虑的大量代码。你能给我们总结一下这是在做什么——成百上千的大型浮点双精度矩阵的矩阵运算,其中也有平方根和除法?你能在这两个方面都分析一下吗,你能看看生成的汇编程序是否有任何明显的悲观情绪吗?
-
您是否正在运行发布版本,而不是在调试器中运行它?
-
值得在
for循环中运行几次并忽略前几次迭代,因为 JIT 编译器需要第一次发挥它的魔力。 -
.NET 4.6 有一个全新的 x64 抖动(项目 RyuJIT),你不会得到与以前的 .NET 版本可比的结果。报告严重性能下降的最佳方法是使用 connect.microsoft.com,快点,而 4.6 仍处于测试阶段。
-
事实上 4.6 是 rc 而不是 beta。这是关于 microsoft connect 的报告:“connect.microsoft.com/VisualStudio/feedback/details/1294384”。
标签: c# .net visual-studio-2015 ryujit