使用JIT和GC的微基准测试语言(例如Java或C#)可能有点复杂,因此使用现有框架通常是个好主意-Java提供了出色的mhf或Caliper,可惜的是,据我所知,C#没有提供任何接近那些。乔恩·斯基特(Jon Skeet)在这里写下了这篇文章,我会盲目假设他会处理最重要的事情(乔恩知道他在该领域的工作;也是的,我实际上没有担心过)。我稍微调整了时间,因为预热后每次测试30秒对我的耐心来说太长了(应该做5秒)。
因此,首先得出的结果是Windows 7 x64下的.NET 4.5.1-数字表示它可以在5秒钟内运行的迭代,所以越高越好。
x64 JIT:
Standard 10,589.00 (1.00)
UnsafeStandard 10,612.00 (1.00)
Stackalloc 12,088.00 (1.14)
FixedStandard 10,715.00 (1.01)
GlobalAlloc 12,547.00 (1.18)
x86 JIT(是的,这仍然让人很难过):
Standard 14,787.00 (1.02)
UnsafeStandard 14,549.00 (1.00)
Stackalloc 15,830.00 (1.09)
FixedStandard 14,824.00 (1.02)
GlobalAlloc 18,744.00 (1.29)
这样最多可以实现14%的合理加速(并且大部分开销是由于必须运行GC,实际上将其视为最坏的情况)。不过x86的结果很有趣-尚不完全清楚发生了什么。
这是代码:
public static float Standard(int size) {
float[] samples = new float[size];
for (var ii = 0; ii < size; ii++) {
samples[ii] = 32768 + (ii != 0 ? samples[ii - 1] : 0);
}
return samples[size - 1];
}
public static unsafe float UnsafeStandard(int size) {
float[] samples = new float[size];
for (var ii = 0; ii < size; ii++) {
samples[ii] = 32768 + (ii != 0 ? samples[ii - 1] : 0);
}
return samples[size - 1];
}
public static unsafe float Stackalloc(int size) {
float* samples = stackalloc float[size];
for (var ii = 0; ii < size; ii++) {
samples[ii] = 32768 + (ii != 0 ? samples[ii - 1] : 0);
}
return samples[size - 1];
}
public static unsafe float FixedStandard(int size) {
float[] prev = new float[size];
fixed (float* samples = &prev[0]) {
for (var ii = 0; ii < size; ii++) {
samples[ii] = 32768 + (ii != 0 ? samples[ii - 1] : 0);
}
return samples[size - 1];
}
}
public static unsafe float GlobalAlloc(int size) {
var ptr = Marshal.AllocHGlobal(size * sizeof(float));
try {
float* samples = (float*)ptr;
for (var ii = 0; ii < size; ii++) {
samples[ii] = 32768 + (ii != 0 ? samples[ii - 1] : 0);
}
return samples[size - 1];
} finally {
Marshal.FreeHGlobal(ptr);
}
}
static void Main(string[] args) {
int inputSize = 100000;
var results = TestSuite.Create("Tests", inputSize, Standard(inputSize)).
Add(Standard).
Add(UnsafeStandard).
Add(Stackalloc).
Add(FixedStandard).
Add(GlobalAlloc).
RunTests();
results.Display(ResultColumns.NameAndIterations);
}