簡體   English   中英

如何使用 GHC 在近機器級別可靠地影響生成的代碼?

[英]How to reliably influence generated code at near machine level using GHC?

雖然這聽起來像是一個理論問題,但假設我決定投資並構建一個用 Haskell 編寫的關鍵任務應用程序。 一年后,我發現我絕對需要提高一些非常細小的瓶頸的性能,這將需要優化接近原始機器能力的內存訪問。

一些假設:

  • 它不是實時系統 - 偶爾的延遲峰值是可以容忍的(來自中斷、線程調度異常、偶爾的 GC 等)
  • 這不是一個數字問題——數據布局和緩存友好的訪問模式是最重要的(避免指針追逐,減少條件跳轉等)
  • 代碼可能與特定的 GHC 版本相關聯(但沒有分叉)
  • 性能目標需要對預先分配的堆外數組進行就地修改,同時考慮對齊(C 字符串、位打包字段等)
  • 數據在數組中是靜態有界的,如果需要,很少分配

GHC 提供什么機制來執行這種優化? 可靠地說,我的意思是,如果源代碼更改導致代碼不再執行,則可以在源代碼中更正,而無需在程序集中重寫。

  • 是否已經可以使用 GHC 特定的擴展和庫?
  • 自定義 FFI 是否有助於避免 C 調用約定開銷?
  • 特殊用途的編譯器插件可以通過受限制的源 DSL 來完成嗎?
  • 來自“高級”程序集(LLVM?)的源代碼生成器可以成為解決方案嗎?

聽起來您正在尋找未裝箱的數組。 haskell-land 中的“未裝箱”意味着“沒有運行時堆表示”。 您通常可以通過查看核心表示(這是一種非常類似 haskell 的語言,這是編譯的第一階段)來了解代碼的某些部分是否被編譯為未裝箱循環(不執行分配的循環) . 例如,您可能會在核心輸出中看到Int# ,這意味着一個沒有堆表示的整數(它將在寄存器中)。

在優化haskell 代碼時,我們會定期查看核心,並期望能夠通過更改源代碼(例如添加嚴格注釋,或擺弄一個可以內聯的函數)來操縱或糾正性能回歸。 這並不總是很有趣,但會相當穩定,尤其是在您固定編譯器版本時。

回到未裝箱數組:GHC 在 GHC.Prim 中公開了許多低級 primop,特別是聽起來您想要可變的未裝箱數組 ( MutableByteArray )。 primitive包將這些 primops 暴露在一個稍微更安全、更友好的 API 后面,是您應該使用的(取決於是否編寫自己的庫)。

還有許多其他實現未裝箱數組的庫,例如vector ,它們構建在MutableByteArray ,但關鍵是該結構上的操作不會產生垃圾,並且可能會編譯成非常可預測的機器指令。

如果您正在執行數字工作並希望使用特定指令或直接在匯編中實現某些循環,您可能還想查看 此技術

GHC 還有一個非常強大的 FFI,你可以研究如何用 C 和互操作編寫你的程序的一部分; 為此,haskell 在其他結構中支持固定數組。

如果你需要更多的控制權,那么 haskell 可能是錯誤的語言。 從您的描述中無法判斷您的問題是否屬於這種情況(您的要求似乎自相矛盾:您需要能夠編寫仔細的緩存調整算法,但任意 GC 暫停都可以嗎?)。

最后一個注意事項:您不能依賴 GHC 的本機代碼生成器來執行任何低級強度降低優化,例如 GCC 執行的(GHC 的 NCG 可能永遠不會知道有關位操作黑客、自動向量化等) . 相反,您可以嘗試使用 LLVM 后端,但不能保證您是否在程序中看到加速。

暫無
暫無

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

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