簡體   English   中英

根據支持的說明選擇要使用的裝配實現

[英]Choose assembly implementation to use based on supported instructions

我正在開發一個C庫,它編譯/鏈接到.a文件,用戶可以靜態鏈接到他們的代碼。 庫的性能非常重要,因此我在x86-64匯編中編寫性能關鍵的例程來優化性能。

對於某些例程,如果使用BMI2指令,我可以獲得明顯更好的性能,而不是堅持使用“標准”x86-64指令集。 麻煩的是,BMI2最近剛推出,我的一些用戶使用不支持這些指令的處理器。

所以,我寫了兩次優化例程,一次使用BMI2指令,一次不使用它們。 在我目前的設置中,我將分發兩個版本的.a文件:一個需要支持BMI2指令的“快速”版本,以及一個不需要支持BMI2指令的“慢”版本。

我問是否有辦法通過分發單個.a文件來簡化這一過程,該文件將根據最終應用程序運行的CPU是否支持BMI2指令動態選擇正確的實現。

與StackOverflow上的類似問題不同,這里有兩個特點:

  • 選擇功能的技術需要在關鍵路徑中具有特別低的開銷。 在匯編優化之后,所討論的例程在~10 ns內運行,因此即使單個if語句也可能很重要。
  • 需要“動態”選擇的功能在開始時選擇一次,然后在程序的持續時間內保持固定。 我希望這將提供比這個問題中建議的更快的解決方案: 在運行時選擇方法實現

我到目前為止提出的最快解決方案是執行以下操作:

  1. 使用cpuid指令檢查CPU是否支持BMI2指令。
  2. 根據結果​​設置全局變量truefalse
  3. 在每個函數調用上對此全局變量的值進行分支。

我對這種方法不滿意,因為它有兩個缺點:

  • 我不知道如何自動運行cpuid並在程序開頭設置一個全局變量,因為我正在分發一個.a文件並且無法控制最終二進制文件中的main函數。 如果它提供了更好的解決方案,我很高興在這里使用C ++,只要最終的庫仍然可以與C程序鏈接和調用。
  • 這會在每次函數調用時產生開銷,理想情況下,唯一的開銷是在程序啟動時。

有沒有比我上面詳述的更有效的解決方案?

x264使用init函數(在調用其他任何東西之前需要調用庫的用戶,或類似的東西)來根據CPUID結果設置函數指針的結構。 包括考慮到pshufb在一些支持它的早期CPU上pshufb緩慢。

如果你的功能依賴於pdep / pext ,你可能想要檢測AMD與英特爾,因為AMD的pdep / pext非常慢,並且可能不值得在Ryzen上使用,即使它可用。 (有關說明表,請參閱https://agner.org/optimize/ 。)


函數指針的開銷相當低,與調用共享庫或DLL中的函數大致相同。 call [rel funcptr]而不是call func (在編譯器生成的asm中調用您的函數)。

CPU依賴代碼:如何避免函數指針? 在C中展示了一個非常簡單的例子,並且正在尋找避免它的方法。 通過動態鏈接,您可以在動態鏈接時進行CPU檢測,因此動態鏈接間接也成為您的CPU調度間接(就像glibc選擇優化的memcpy實現一樣)。

但是對於.a靜態鏈接,只需創建靜態初始化為基線版本的函數指針,並且您的CPU初始化函數(希望在任何函數指針被解除引用之前運行)將其重寫為指向最佳版本的當前的CPU。

如果您使用的是gcc,則可以讓編譯器自動實現所有樣板代碼。 關於函數多版本化的gcc手冊頁

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM