私は、単一のフロートをラップする構造体が、フロートを直接使用するよりもパフォーマンスの約半分で大幅に遅いことに気付きました。structに余分なフィールドを追加すると、パフォーマンスが大幅に向上するのはなぜですか?
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.
コンパイラ/環境設定: OS:Windowsの10 64ビット ツールチェーン:VS2017 フレームワーク:.NET 4.6.2 ターゲット:64ビットがターゲットとして設定されている場合は、任意のCPUは、我々の結果を32ビット
を好みますより予測可能ですが、我々は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
を詳細な調査では、モノラルコンパイラは同じILを生成するので、これはWindowsランタイムに固有のようです。
モノラルランタイムでは、両方の構造体バリアントが、生の浮動小数点に比べて約2倍遅い性能を持ちます。これは、.Netで見られるパフォーマンスとはかなり異なっています。
ここでは何が起こっていますか?
*この質問には当初は欠陥のあるベンチマークプロセスが含まれていました(これを指摘してくれたマックスペイン氏に感謝します)。タイミングをより正確に反映するように更新されました。
イムを、これは今より良いメモリ配置を持つ梱包構造体によるものである推測:
は、7年前anseredたようです。 –
JITまたは他のワンタイム処理からの干渉を排除するためにウォーミングアップ反復を追加する必要があります。 – PetSerAl
64ビットに切り替えると、「マジック」ベクタのパフォーマンスが低下します。 – Adrian