【发布时间】:2017-11-04 19:11:49
【问题描述】:
我注意到包装单个浮点数的结构比直接使用浮点数要慢得多,大约只有一半的性能。
using System;
using System.Diagnostics;
struct Vector1 {
public float X;
public Vector1(float x) {
X = x;
}
public static Vector1 operator +(Vector1 a, Vector1 b) {
a.X = a.X + b.X;
return a;
}
}
但是,在添加额外的“额外”字段后,似乎会发生一些神奇的事情,并且性能再次变得更加合理:
struct Vector1Magic {
public float X;
private bool magic;
public Vector1Magic(float x) {
X = x;
magic = true;
}
public static Vector1Magic operator +(Vector1Magic a, Vector1Magic b) {
a.X = a.X + b.X;
return a;
}
}
我用来对这些进行基准测试的代码如下:
class Program {
static void Main(string[] args) {
int iterationCount = 1000000000;
var sw = new Stopwatch();
sw.Start();
var total = 0.0f;
for (int i = 0; i < iterationCount; i++) {
var v = (float) i;
total = total + v;
}
sw.Stop();
Console.WriteLine("Float time was {0} for {1} iterations.", sw.Elapsed, iterationCount);
Console.WriteLine("total = {0}", total);
sw.Reset();
sw.Start();
var totalV = new Vector1(0.0f);
for (int i = 0; i < iterationCount; i++) {
var v = new Vector1(i);
totalV += v;
}
sw.Stop();
Console.WriteLine("Vector1 time was {0} for {1} iterations.", sw.Elapsed, iterationCount);
Console.WriteLine("totalV = {0}", totalV);
sw.Reset();
sw.Start();
var totalVm = new Vector1Magic(0.0f);
for (int i = 0; i < iterationCount; i++) {
var vm = new Vector1Magic(i);
totalVm += vm;
}
sw.Stop();
Console.WriteLine("Vector1Magic time was {0} for {1} iterations.", sw.Elapsed, iterationCount);
Console.WriteLine("totalVm = {0}", totalVm);
Console.Read();
}
}
与基准测试结果:
Float time was 00:00:02.2444910 for 1000000000 iterations.
Vector1 time was 00:00:04.4490656 for 1000000000 iterations.
Vector1Magic time was 00:00:02.2262701 for 1000000000 iterations.
编译器/环境设置: 操作系统:Windows 10 64 位 工具链:VS2017 框架:.Net 4.6.2 目标:任何 CPU 首选 32 位
如果将 64 位设置为目标,我们的结果更可预测,但明显比我们在 32 位目标上看到的 Vector1Magic 差:
Float time was 00:00:00.6800014 for 1000000000 iterations.
Vector1 time was 00:00:04.4572642 for 1000000000 iterations.
Vector1Magic time was 00:00:05.7806399 for 1000000000 iterations.
对于真正的巫师,我在此处包含了 IL 转储:https://pastebin.com/sz2QLGEx
进一步调查表明,这似乎是特定于 Windows 运行时的,因为单声道编译器产生相同的 IL。
在单声道运行时,与原始浮点数相比,两种结构变体的性能大约慢 2 倍。这与我们在 .Net 上看到的性能有很大不同。
这是怎么回事?
*请注意,这个问题最初包含一个有缺陷的基准测试过程(感谢 Max Payne 指出这一点),并且已经更新以更准确地反映时间安排。
【问题讨论】:
-
我猜这是由于结构包装现在具有更好的内存对齐。
-
您应该添加一个预热迭代以排除来自 JIT 或其他一次性处理的可能干扰。
-
如果我切换到 64 位,我的“魔术”向量的性能会更差。
-
我之前加入了一个热身期 - 这对这次测试没有显着影响。
-
我希望有人能解决这个问题。 Vector1Magic 会更快,这太违反直觉了。