Intel、AMD的處理器都是在2011年才開始支援AVX指令集的,所以現在還有不少使用者的機器是不支援AVX的。AVX指令集,除了需要CPU硬體支援,還需要OS的支援,為什麼呢?因為OS在做context switch時,需要將AVX暫存器給save/restore好,要不就可能出現錯誤的執行結果。
微軟在其官方文件中公開宣稱,從Windows 7 SP1和Windows Server 2008 R2 SP1開始,才能支援AVX,但是根據實際的測試結果,在某些Windows XP物理機上,cpuid指令會一會兒返回支援AVX,一會兒返回不支援AVX,也就是不穩定。_xgetbv( )返回的結果也不穩定。
開源庫如OpenSSL、Chromium/CEF中都有隻利用cpuid指令檢測是否支援AVX的邏輯,導致進坑,在這種不穩定的XP上可能會崩掉。
要解決這個問題也很簡單,先判斷OS版本,在低於Windows 7 SP1、Windows Server 2008 R2 SP1的系統上,直接禁用AVX就行了;OS版本滿足AVX支援的要求的,再用cpuid、_xgetbv指令檢測。
對於
Chromium/CEF,只能修改它的程式碼重新編譯。要修改的檔案是:
chromium\src\v8\src\ia32\assembler-ia32.cc
chromium\src\v8\src\x64\assembler-x64.cc
要修改的函式:
bool OSHasAVXSupport() {
//此處省略一堆程式碼
//在此處加上OS版本判斷
// Check whether OS claims to support AVX.
uint64_t feature_mask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
return (feature_mask & 0x6) == 0x6;
}
} // namespace
void CpuFeatures::ProbeImpl(bool cross_compile) {
base::CPU cpu;
//此處省略一堆程式碼
if (cpu.has_avx() && FLAG_enable_avx && cpu.has_osxsave() &&
OSHasAVXSupport()) {
supported_ |= 1u << AVX;
}
對於OpenSSL,由於OpenSSL是優先使用呼叫者傳遞過來的環境變數OPENSSL_ia32cap的,所以在不方便直接修改OpenSSL的實現程式碼時,可以自己先做OS檢測,再做
cpuid、_xgetbv指令檢測,然後生成合適的
OPENSSL_ia32cap
環境變數傳遞給OpenSSL庫。當然,如果編譯OpenSSL時限定了只使用386指令,就無需擔心這個問題了。要正確限定OpenSSL只使用386指令,除了要在perl編譯指令碼命令列中加386引數外,還需要修改perl指令碼生成的ms\nt.mak或者
ms\ntdll.mak
檔案,在cl.exe的命令列中加上/arch:IA32引數才穩妥。
參考:
Enable Windows 7 Support for Intel AVX
Windows 7 and Windows Server 2008 R2 Service Pack 1 Bring AVX Support
OPENSSL_ia32cap
x86 Intrinsics List