SIMD 的意思是 Single Instruction Multiple Data。顧名思義,一個指令可以處理多個數據。
.NET Framework 4.6 推出的 Nuget 程序包 System.Numerics.Vectors 裡面的 Vector`1 類型是有硬件加速功能的。這個硬件加速功能就是指即時編譯的時候根據硬件環境選用一些 SIMD 的指令讓程序運行更快。
這個硬件加速功能的威力可以用下面的方式得到驗證。
用單線程的程序重復 10000000H 個單精度浮點數的加法。加法的每一個輸入都是引用類型,輸出也必須獲取值的引用。
VB 2017 程序:
動態獲取當前硬件支持一組算多少個單精度浮點數的加法,然後分組計算。Release x64 編譯,優化代碼(反編譯驗證沒有優化掉循環),取消整數溢出檢查(為了跟 c# 執行時間一樣)。
VB
Imports System.Numerics
Module Program
Sub Main()
Const TotalDataSize = &H1000_0000
Dim watch As New Stopwatch
Dim groupSize = Vector(Of Single).Count
Dim groupCount = TotalDataSize / groupSize
Console.WriteLine($"每組數據的大小:{groupSize} (1:不優化,4:SSE2 優化,8:AVX2 優化)
一共要處理 {groupCount} 次數據以完成測試。")
Console.WriteLine("計時開始!")
watch.Start()
Dim groupA(groupSize - 1), groupB(groupSize - 1) As Single
Dim vecA As New Vector(Of Single)(groupA), vecB As New Vector(Of Single)(groupB), vecResult As Vector(Of Single)
For i = 1 To groupCount
vecResult = vecA + vecB
Next
watch.Stop()
Console.WriteLine($"計時結束。用時:{watch.ElapsedMilliseconds} 毫秒。")
Console.ReadKey()
End Sub
End Module
VC++ 2017程序:
用循環 0x10000000 次的 for 循環,Release x64 編譯,禁止優化(開優化不管循環多少次都是 0 毫秒,肯定是把循環優化掉了)。
C++
#include "stdafx.h"
#include <iostream>
#include "NotOptimizedNativeCodes.h"
const int TotalDataSize = 0x10000000;
#pragma unmanaged
void NativeTest()
{
float groupA[1] = { 0 }, groupB[1] = { 0 }, *groupResult;
for (size_t i = 0; i < TotalDataSize; i++)
{
float result = groupA[0] + groupB[0];
groupResult = &result;
}
}
#pragma managed
using namespace System;
using namespace System::Diagnostics;
int NotOptimizedNativeCodes::Program::main(array<System::String ^> ^args)
{
auto watch = gcnew Stopwatch();
std::cout << "每組數據的大小:" << 1 << "(1:不優化,4:SSE2 優化,8:AVX2 優化)" << std::endl <<
"一共要處理" << TotalDataSize << " 次數據以完成測試。" << std::endl;
Console::WriteLine(L"計時開始!");
watch->Start();
NativeTest();
watch->Stop();
std::cout << "計時結束。用時:" << watch->ElapsedMilliseconds << " 毫秒。" << std::endl;
Console::ReadKey();
return 0;
}
int main(array<System::String ^> ^args)
{
NotOptimizedNativeCodes::Program::main(args);
}
執行結果(CPU 是 i5 6400,有 AVX2 指令集)
使用 i7 3632QM (沒有 AVX2 但是有 SSE2)