OCaml 多核心 - 2020 年 7 月

歡迎來到 2020 年 7 月的 Multicore OCaml 報告!此更新連同先前的更新,由 @shakthimaan、@kayceesrk 和我共同編撰。無論在上游 OCaml 還是我們的多核心樹中,都有許多進展。

多核心 OCaml

透過領域執行上下文實現執行緒相容性

簡而言之:一旦 #381 合併,dune 將可與多核心 OCaml 搭配運作。

如同我上個月指出的,沒有一個與傳統 OCaml 向後相容的 Thread 模組,是生態系統相容性的一大阻礙。乍看之下,這可能會讓人有些困惑 — 為什麼多核心 OCaml 需要非平行執行緒支援?答案就在多核心 OCaml 中的並發和並行之間的關係。並發是我們如何分割多個計算,使其在重疊的時間段內執行,而並行是我們如何同時在不同的核心上執行它們以獲得更高的效能。許多套件(最值得注意的是 Dune)目前使用 Thread 模組來方便地取得並發性,同時編寫直線程式碼而不使用 monad 抽象。這些用途不需要平行性,但是若要不使用基於執行緒的並發,則很難重寫。

因此,多核心 OCaml 也需要提供一個效能相當好的 Thread 版本的方法。我們嘗試的第一個解決方案(由 @jhw 開始,並由 @engil 在 #342 中繼續)將 Thread 對應到多核心領域,但由於我們的並發上下文(Thread 實例)數量可能遠大於可用的 CPU 數量(Domain 實例),因此在大量執行緒的情況下擴展性不佳。這導致了一場腦力激盪(#357),以找出適用於像 Dune 或 XenServer 堆疊 等大量使用執行緒的應用程式的解決方案。

我們的解決方案引入了一個我們稱之為 #381 中的領域執行上下文的概念,它允許我們將多個系統執行緒對應到 OCaml 領域。一旦該 PR 經過審查並合併到多核心 OCaml 分支中,它將解鎖更多生態系統套件,因為 Dune 建置系統將在未修改的情況下編譯。此後,廣泛 opam 測試的最後一個「重大」障礙是 ocaml-migrate-parsetree,它需要一個小修補程式來支援多核心 OCaml 樹中存在的 effect 關鍵字語法。

領域本機儲存

領域本機儲存 (DLS) (#372) 是一種將 OCaml 值私下附加到領域的簡單方法。在 LU 分解基準測試 的 PR 中展示了使用 DLS 時加速的一個好例子。在這種情況下,基準測試需要大量的隨機數,並且在領域本機平行初始化它們是一個勝利。

另一個例子是演算法的平行實作(最初由 @per_kristian_lehre 在 #336 中提出),它在 #151 中加速良好(對於那些想要檢查基準的人,#155 中有一個循序版本,您可以查看 Sandmark 的網頁介面)。

使用多核心 OCaml 進行平行程式設計(文件)

已提供一份關於使用多核心 OCaml 進行平行程式設計的教學課程。它提供了多核心 OCaml 的簡介,並解釋了 DomainsDomainslibChannels 的概念。還用範例說明了使用 perfEventlog 分析 OCaml 程式碼。

此草稿已在 Reddit 以及 HackerNews 上分享,因此您可以在那裡找到更多關於它的討論。

Coq 基準測試

用於 OCaml 的 Sandmark 基準測試套件已成功更新為使用 dune.2.6.0 並為多核心 OCaml 4.10.0 建置。透過此重大升級,我們也已能夠包含 Coq 及其相依性。我們正在努力將更多回歸 Coq 基準測試新增到測試套件中。

上游 OCaml

上游 OCaml 樹在 4.12.0dev 樹中出現了一連串的活動,並進行了變更以準備用於多核心 OCaml。最大的一個是(引述 @xavierleroy 的話)在 ocaml/ocaml#9728 中的傳說中的無頁面壓縮器。這是繼上個月的工作 (#9698) 之後,當編譯器使用 "no-naked-pointers" 選項建置時,消除頁面表的使用,並為平行多核心 OCaml 執行階段整合到未來版本的 OCaml 中鋪平了道路。

我們希望納入 OCaml 4.12 的其他變更之一是標記和清除時垃圾收集器顏色的使用對齊。 #9756 變更使上游執行階段使用我們在 將平行性改裝到 OCaml ICFP 論文中描述的相同方案,並提供了一些額外的改進,您可以在 PR 審閱註解中閱讀。

如果您對完整的變更集感到好奇,您可以看到迄今為止在上游已關閉的所有 多核心先決條件問題。

詳細更新

與先前的更新一樣,多核心 OCaml 更新會先列出,然後是 Sandmark 基準測試專案的增強功能。最後會提及上游 OCaml 正在進行和已完成的更新,以供您參考。

多核心 OCaml

進行中

  • ocaml-multicore/ocaml-multicore#342 使用 Domain 實作執行緒程式庫

    這是一個正在進行的工作,以重新定位 @jhwoodyatt 的 Domain 執行緒程式庫實作。

  • ocaml-multicore/ocaml-multicore#357 使用 pthreads 實作系統執行緒

    在此實作中引入了領域執行上下文 (DEC),作為使用 pthreads 實作系統執行緒的並發抽象。

  • ocaml-multicore/ocaml-multicore#374 在次要收集時強制主要切片

    領域中被封鎖的執行緒在透過 handle_interrupt 服務次要收集器時可能不會推進主要 GC,因此我們需要進行次要收集以排程主要收集切片。

已完成

領域本機狀態

在並行次要 GC 中移除殘留物

  • ocaml-multicore/ocaml-multicore#370 移除 Cloadmut 和 lloadmut

    此修補程式已清理 CloadmutIloadmut 的實作和使用。這簡化了程式碼,並使其更接近於庫存 OCaml。

  • ocaml-multicore/ocaml-multicore#371 領域中斷清理

    runtime/domain.c 中,已移除 struct interruptor* sender。領域 RPC 函式已在 domain.h 中分組在一起,並應用了一致的定義命名。

程式碼清理

雜項

  • ocaml-multicore/ocaml-multicore#366 新增事件以記錄閒置領域

    新增了 domain/idle_waitdomain/send_interrupt 事件,以追蹤閒置的網域。以下顯示具有此效果的事件日誌螢幕截圖。

PR 366 Image |690x298

  • ocaml-multicore/ocaml-multicore#369 將 caml_urge_major_slice 分割成 caml_request_minor_gc 和 caml_request_major_slice

    caml_urge_major_slices 被分割成 caml_request_minor_gccaml_request_major_slice。這減少了次要垃圾回收的總次數,如下圖所示。

PR 369 Image |690x203

  • ocaml-multicore/ocaml-multicore#373 修復當目前目錄名稱包含空格時的 opam pin 指令

    使用 opam pin-k path 命令列引數來處理包含空白字元的目錄名稱。

  • ocaml-multicore/ocaml-multicore#375 僅在需要時鎖定全域可用列表以採用池

    當沒有需要採用的全域池時,會移除配置上的鎖定獲取和釋放。

  • ocaml-multicore/ocaml-multicore#377 將 Travis CI 中運行的環境變數分組

    OCAMLRUNPARAM 參數被定義為環境變數的一部分,並使用 USE_RUNTIME=d 指令。

  • ocaml/dune#3608 上游 Multicore dune 啟動程式修補程式

    此修補程式用於使用次要編譯器方法建置 dune,以解決 ocaml/dune#3548 的問題。

效能評測

進行中

  • ocaml-bench/sandmark#107 新增 Coq 效能評測

    Sandmark 升級為使用 Multicore OCaml 4.10.0 的 dune.2.6.0,使得我們能夠安裝 Coq 及其相依性。我們目前正努力為 Sandmark 新增更多的 Coq 回歸效能評測。

  • ocaml-bench/sandmark#122 程式碼大小的測量

    基準測試的程式碼大小是 flambda 分支所需的一項測量,我們正在研究是否將其添加到 Sandmark 基準測試運行中。

  • ocaml-bench/sandmark#142 [RFC] 使用者應如何設定 Sandmark 執行?

    我們正在收集使用者回饋和關於如何設定 Sandmark 基準測試的建議。請在此討論中分享您的想法和評論。

  • ocaml-bench/sandmark#150 可運作的 Coq 檔案

    在 Sandmark 中新增更多用於效能評測的 Coq 檔案。

已完成

Dune 2.6.0 升級

  • ocaml-bench/sandmark#131 更新解壓縮效能評測

    @dinosaure 更新了解壓縮效能評測,以使用 dune.2.6.0 的最新 decompress.1.1.0。

  • ocaml-bench/sandmark#132 更新相依性套件以使用 dune.2.6.0 和 Multicore OCaml 4.10.0

    Sandmark 現在已更新為使用 dune.2.6.0 和 Multicore OCaml 4.10.0,並升級了 30 多個相依性套件。您可以使用以下指令測試它:

    $ opam install dune.2.6.0
    $ make ocaml-versions/4.10.0+multicore.bench
    

Coq 效能評測

持續整合

  • ocaml-bench/sandmark#136 在 .drone.yml 中使用 BUILD_ONLY

    已更新 .drone.yml 檔案,以使用 BUILD_ONLY 環境變數來僅安裝相依性,而不執行 CI 的基準測試。

  • ocaml-bench/sandmark#147 新增對關聯基準測試標籤的支援

    引入了 macro_benchrun_in_ci 標籤來與基準測試關聯。標記為 run_in_ci 的基準測試將作為 Sandmark CI 的一部分執行。

雜項

  • ocaml-bench/sandmark#124 在 Makefile 中新增使用者可設定的 paramwrapper

    現在可以將 --cpu-list 指定為 PARAMWRAPPER 環境變數,以執行平行基準測試。

  • ocaml-bench/sandmark#134 在 README 中包含更多資訊

    已更新 README 以包含文件,以反映 Sandmark 的最新變更。

  • ocaml-bench/sandmark#141 使用其他選項豐富變體

    現在 ocaml-versions/* 檔案使用 JSON 檔案格式,可讓您指定 ocaml-base-compiler 來源 URL、configure 選項和 OCAMLRUNPARAMS。以下提供範例:

    {
      "url" : "https://github.com/ocaml-multicore/ocaml-multicore/archive/parallel_minor_gc.tar.gz",
      "configure" : "-q",
      "runparams" : "v=0x400"
    }
    
  • ocaml-bench/sandmark#146 將主幹從 4.11.0 更新至 4.12.0

    Sandmark 現在使用最新的 OCaml 4.12.0 作為 ocaml-versions/ 中的主幹。

  • ocaml-bench/sandmark#148 安裝 python3-pip 和 intervaltree 以進行乾淨的 CI 建置

    已更新 .drone.yml 檔案以安裝 python3-pipintervaltree 軟體套件,以避免呼叫 Makefile 時發生錯誤。

OCaml

進行中

  • ocaml/ocaml#9722 再次針對 EINTR 的信號

    此修補程式提供新的實作來解決鎖定和信號處理問題。

  • ocaml/ocaml#9756 垃圾收集器顏色變更

    此 PR 移除垃圾收集器 (GC) 顏色配置中的灰色,以便與 Multicore OCaml 主要收集器一起使用。

已完成

  • ocaml/dune#3576 在 OCaml 4.12.0 中,空的封存檔不再產生 .a 檔案

    永遠不會為空的程式庫產生原生封存檔,這修正了與 OCaml 4.12.0 處理空封存檔時的相容性問題。

  • ocaml/ocaml#9541 為儀器化運行時間新增手冊頁

    根據審查意見更新了 manual/manual/cmds/instrumented-runtime.etex 文件,並已合併到 stock OCaml 中。

  • ocaml/ocaml#9728 簡化了不含分頁表的壓縮

    使用自我描述的閉包表示法來簡化壓縮器,並擺脫分頁表。

我們要感謝社群中所有 OCaml 開發人員和使用者,感謝他們對 multicore OCaml 專案的持續支援、程式碼審查、文件和貢獻。

縮寫

  • CI:持續整合
  • DEC:網域執行環境
  • GC:垃圾收集器
  • OPAM:OCaml 套件管理器
  • PR:提取請求
  • RFC:請求評論
  • RPC:遠端程序呼叫