OCaml 多核 - 2021年6月
欢迎阅读 2021 年 6 月的 多核 OCaml 月度报告!本月更新以及上个月更新由 @avsm、@ctk21、@kayceesrk 和 @shakthimaan 共同整理。
我们的总体目标仍然按计划进行,将在夏季生成 OCaml 5.0 多核域限定并行处理的预览树。
4.12.0+domains 的生态系统兼容性
在5 月份的更新中,我提到我们的重点现在是调整生态系统以更好地与多核协同工作,我很高兴地报告说,这方面进展非常顺利。
-
4.12.0+domains 多核编译器变体已合并到主线 opam-repo中,因此您现在可以直接
opam switch 4.12.0+domains
。base-domains
包也可用于将您的 opam 项目标记为需要Domains
模块,因此您现在甚至可以将您早期支持多核的库发布到主线 opam 存储库。 -
OCaml 标准库已针对多个域的并行使用进行了安全化(wiki,issue,修复);特别是
Format
和Random
模块。当在多个域中运行现有 OCaml 代码时,这些模块是我们发现的主要不兼容性来源。
-
Domain
模块的接口已精简,去除了critical_section
、wait
、notify
,这使得运行时大大简化。GC C-API 接口现已实现,这意味着 Jane Street 的Base
、Core
和Async
现在可以在4.12+domains
上编译而无需修改;例如,opam install patdiff
在4.12+domains
切换上开箱即用! -
Domainslib 0.3.0 已发布,其中包含多项改进,包括用于任务分配的工作窃取双端队列。通过使用原语和 O(1) 查找,域局部变量读取的性能也得到了提升。关于
多核 OCaml 中的并行编程
的章节已更新以反映 Domainslib 的最新进展。
这意味着大型应用程序堆栈现在应该能够很好地使用 4.12.0+domains 进行编译(例如 Tezos 节点和 patdiff 会使用 opam 中许多依赖树)。如果您发现任何不兼容性,请在存储库中报告。
4.12.0+domains+effects
我们的大部分精力都集中在使仅域树(用于 OCaml 5.0)快速运行上,但我们也在推进基于直接风格效果的 IO 堆栈。
- Linux Io_uring 的
uring
绑定现在可在 opam-repository 上使用,因此您也可以在顺序 OCaml 上试用它。一个不错的迷你项目是为现有的 Async 或 Lwt 引擎添加 uring 后端,如果有人想尝试进行实质性贡献的话。 - 现在,
eio
库 已经相当可用,可以用于文件系统和网络。我们已向 OCaml 研讨会提交了一个演讲,将更详细地介绍其内部结构,因此,如果被接受,请在接下来的几个月里继续关注。这里的主要变化是性能改进,HTTP 堆栈与(例如)rust-hyper
相当具有竞争力。
我们很快也会有一个此树的变体,它将移除自定义效果语法并将纤维(运行时部分)实现为 Obj
函数。这将进一步提高生态系统兼容性,并允许我们构建内部使用纤维来提供并发性的直接风格 OCaml 库,而无需在它们的接口中公开任何效果的使用。
基准测试和性能
我们始终渴望获得更多能利用多核功能的基准测试;如果您想尝试多核并帮助编写基准测试,可以在wiki上找到一些建议。我们有一个私有服务器,它运行一个带有 Jupyter 笔记本的 Sandmark 每晚基准测试管道,我们可以向提交基准测试的任何人提供访问权限。我们继续测试 Sandmark 与current-bench的集成,以便更好地与 GitHub PR 集成。
与往常一样,首先列出多核 OCaml 的正在进行和已完成的任务,然后是生态系统及其相关库的更新。然后会提到 Sandmark 基准测试和每晚构建工作。最后,为了方便您参考,提供了上游 OCaml 安全点 PR 的状态。
多核 OCaml
正在进行
-
ocaml-multicore/ocaml-multicore#573 将主干安全点 PR 反向移植到多核
将来自 ocaml/ocaml 的安全点 PR 反向移植到多核 OCaml 的工作正在进行中。
-
ocaml-multicore/ocaml-multicore#584 现代化信号处理
一个将多核 OCaml 信号实现更接近上游 OCaml 的补丁。
-
ocaml-multicore/ocaml-multicore#598 不要将信号传递给已阻止它们的线程
一个不将信号传递给处于阻塞状态的线程的草稿 PR。需要处理不带 systhreads 的情况。
-
ocaml-multicore/ocaml-multicore#600 在头文件中公开更多 GC 变量
caml_young_start
、caml_young_limit
和caml_minor_heap_wsz
变量已在运行时定义。 -
ocaml-multicore/ocaml-multicore#601 域更好的参与者
来自 STW 信号的迭代
0(Max_domains)
和来自域创建的迭代0(n_running_domains)
现已移除。 -
ocaml-multicore/ocaml-multicore#603 Systhreads 滴答线程
将滴答线程移植到多核 OCaml 的初始草稿 PR。
已完成
增强功能
-
ocaml-multicore/ocaml-multicore#552 添加一个
force_instrumented_runtime
选项到配置configure
脚本现在接受一个新的--enable-force-instrumented-runtime
选项,以方便在链接器调用中使用检测运行时以获取事件日志。 -
ocaml-multicore/ocaml-multicore#558 重构
Domain.{spawn/join}
以不使用临界区已移除
Domain.{spawn/join}
中的临界区以及Domain.wait
的使用。 -
ocaml-multicore/ocaml-multicore#561 简化
Domain.Sync
:移除wait
、notify
、critical_section
Domain.Sync
中的一个重大更改,移除了critical_section
、notify
、wait
、wait_for
和wait_until
。这是为了消除运行时中域间消息传递的需求。 -
ocaml-multicore/ocaml-multicore#576 在运行时包含 Git 哈希
现在在运行时打印 Git 哈希,如下所示
$ ./boot/ocamlrun -version The OCaml runtime, version 4.12.0+multicore Built with git hash 'ae3fb4bb6' on branch 'runtime_version' with tag '<tag unavailable>'
-
ocaml-multicore/ocaml-multicore#579 用于获取 DLS 根的原语
已实现一个用于获取 DLS 的新原语,它现在是
amd64
上的单个mov
指令。
上游
-
ocaml-multicore/ocaml-multicore#555 运行时:
CAML_TRACE_VERSION
现在设置为多核特定值定义了
CAML_TRACE_VERSION
以区分多核 OCaml 和运行时的主干。 -
ocaml-multicore/ocaml-multicore#581 将我们的内联使用移动到
Caml_inline
我们现在对运行时中的所有 C 内联使用
Caml_inline
,以与上游 OCaml 保持一致。 -
ocaml-multicore/ocaml-multicore#589 重新引入
adjust_gc_speed
主干中的
caml_adjust_gc_speed
函数已重新引入到多核 OCaml 运行时。 -
ocaml-multicore/ocaml-multicore#590 运行时:在 gc_ctrl 中存根
caml_stat_*
接口在 gc_ctrl.h 中创建
caml_stat_*
存根函数,以引入一个与 GC stat 实用程序兼容的层,这些实用程序在主干中可用。
修复
-
ocaml-multicore/ocaml-multicore#562 从 DLABs 导入对次要堆分配代码的修复
用于次要堆分配的乘法因子 2 已移除,并且来自 config.h 的
Minor_heap_max
限制不再转换为多核 OCaml 的字节大小。 -
ocaml-multicore/ocaml-multicore#593 修复与短暂对象相关的两个问题
一个简化终止期间短暂对象传递的补丁。
-
ocaml-multicore/ocaml-multicore#594 修复终结器传递问题
使用
caml_finish_major_cycle
导致主要 GC 阶段Phase_sweep_and_mark_main
正确地传递终结器。 -
ocaml-multicore/ocaml-multicore#596 systhreads:在初始化线程描述符后执行
st_thread_id
线程 ID 甚至在初始化线程描述符之前就已设置,此 PR 修复了顺序。
-
ocaml-multicore/ocaml-multicore#604 修复
caml_scan_global_young_roots
中未受保护的caml_skiplist_empty
此 PR 引入了
caml_iterate_global_roots
函数并修复了全局根的锁定错误。
清理
-
ocaml-multicore/ocaml-multicore#567 简化一些 minor_gc 代码
not_alone
变量已通过简化 minor_gc.c 代码进行清理。 -
ocaml-multicore/ocaml-multicore#580 移除结构体 domain
caml_domain_state
现在是域信息的唯一来源,移除了struct domain
。struct dom_internal
不再泄漏到运行时。 -
ocaml-multicore/ocaml-multicore#583 移除中断队列
在接收中断时锁定 `struct_interruptor` 和使用 `struct interrupt` 的操作已移除,简化了域的实现。
杂项
-
ocaml-multicore/ocaml-multicore#582 使 Random、Hashtbl 和 Filename 中的全局状态成为域本地状态
现在 `Random`、`Hashtbl` 和 `Filename` 中的默认状态设置为域本地状态。
-
ocaml-multicore/ocaml-multicore#586 使 Format 中的状态成为域本地状态
现在 `Format` 中的默认状态设置为域本地状态。
-
ocaml-multicore/ocaml-multicore#595 实现 `caml_alloc_dependent_memory` 和 `caml_free_dependent_memory`
依赖内存是指依赖于 GC(和终结器)进行释放的堆内存块。`caml_alloc_dependent_memory` 和 `caml_free_dependent_memory` 已添加到 runtime/memory.c 中。
生态系统
正在进行
-
ocaml-multicore/eventlog-tools#3 使用 ocaml/setup-ocaml@v2
更新了 `.github/workflows/main.yml` 以构建 ocaml/setup-ocaml@v2。
-
ocaml-multicore/parallel-programming-in-multicore-ocaml#7 添加关于域本地存储的部分
README.md 文件现在包含了关于域本地存储的部分。
-
ocaml-multicore/eio#26 Grand Central Dispatch 后端
Eio 的 Grand Central Dispatch (GCD) 后端实现正在开发中。
-
ocaml-multicore/domainslib#34 修复 `parallel_for_reduce` 中的初始值计算
一个修复 `parallel_for_reduce` 中初始值的补丁,因为它被计算了多次。
-
ocaml-multicore/domainslib#36 切换到默认的 `Random` 模块
该库已更新为使用默认的 `Random` 模块,因为它将状态存储在域本地存储中,可以从多个域调用。Sandmark 结果如下所示。
-
ocaml-multicore/multicore-opam#56 Base-effects 严格依赖于 4.12
关于在 `base-effects.base/opam` 中使用 OCaml 4.12.0 严格下限的问题。
-
ocsigen/lwt#860 Lwt_domain:一个与多核并行性的接口
Lwt_domain
模块已移植到 domainslib 任务池,用于使用多核 OCaml 的域在 CPU 内核上执行计算。以下是在配备 24 个隔离内核的英特尔至强金牌 5120 处理器上获得的一些基准测试结果。
已完成
Ocaml-Uring
ocaml-uring
存储库包含了 OCaml 的 `io_uring` 绑定。
-
ocaml-multicore/ocaml-uring#21 添加 accept 调用
accept
调用已添加到 uring,并包含了 `unix` 库作为依赖项。 -
ocaml-multicore/ocaml-uring#22 添加对取消的支持
添加了一个 `cancel` 方法来请求取消作业。排队操作和测试也已更新。
-
ocaml-multicore/ocaml-uring#24 整理强制转换
Int_val
已更改为 `Long_val`,以消除在 64 位平台上对符号扩展指令的需求。 -
ocaml-multicore/ocaml-uring#25 修复 test_cancel
添加了一个带有 `queue_depth` 参数的 `with_uring` 函数来处理取消测试。
-
ocaml-multicore/ocaml-uring#26 添加 `openat2`
openat2
方法已添加,可访问所有 Linux 打开和解析标志。 -
ocaml-multicore/ocaml-uring#27 微调 C 标记以提高性能
CFLAGS 已更新以提高性能。对于 noop 基准测试,观察到以下结果。
Before: noop 10000 │ 1174227.1170 ns/run│ After: noop 10000 │ 920622.5802 ns/run│
-
ocaml-multicore/ocaml-uring#28 不要允许在正在使用时释放环
在创建时将环添加到全局集中,并在退出时清理。此外,在分配插槽之前会检查无效的取消请求。
-
ocaml-multicore/ocaml-uring#29 将 iovec 替换为 cstruct 并清理 C 存根
readv
和 `writev` 现在接受 Cstruct 列表,允许访问 bigarray 的子范围,并与多个缓冲区一起使用。OOM 错误的处理也得到了改进。 -
ocaml-multicore/ocaml-uring#30 修复 API 中剩余的 TODO
read
和 `write` 方法分别重命名为 `read_fixed` 和 `write_fixed`。`Region.to_cstruct` 已添加作为创建子 bigarray 的替代方法。如果用户请求更大的大小块,则现在会引发异常。 -
ocaml-multicore/ocaml-uring#31 在等待时使用 `caml_enter_blocking_section`
在等待时使用 `caml_enter_blocking_section` 和 `caml_leave_blocking_section`,这允许其他线程执行,并且在多核 OCaml 的情况下 GC 可以运行。
-
ocaml-multicore/ocaml-uring#32 使用来自 OCaml 的 C 标记编译 uring
在构建 uring 时使用 OCaml C 标记,并删除未使用的 dune 文件。
-
ocaml-multicore/ocaml-uring#33 准备发布
CHANGES.md、README.md、dune-project 和 uring.opam 文件已更新以准备发布。
-
ocaml-multicore/ocaml-uring#34 将 `liburing` 转换为子树
我们现在使用子树而不是子模块,以便可以将 ocaml-uring 提交到 opam 存储库。
多核 OCaml 中的并行编程
-
ocaml-multicore/parallel-programming-in-multicore-ocaml#5 将 `num_domains` 更改为 `num_additional_domains`
文档和代码示例已更新为现在使用 `num_additional_domains` 而不是 `num_domains`。
-
ocaml-multicore/parallel-programming-in-multicore-ocaml#6 更新编译器版本的最新信息
README.md 中的编译器版本已更新为使用 4.12 及其变体。
-
ocaml-multicore/parallel-programming-in-multicore-ocaml#8 鼓励人们使用默认的 chunk_size 设置
建议在使用 `parallel_for` 时使用默认的 `chunk_size`,尤其是在域数量变大时。
-
ocaml-multicore/parallel-programming-in-multicore-ocaml#9 事件日志部分更新
由于多核 OCaml 包含来自 trunk 的 CTF 跟踪支持,因此 `eventlog-tools` 库现在可以用于解析跟踪文件。相关信息已更新到 README.md 文件中。
Eio
eio
库为多核 OCaml 提供了一个基于效果的并行 IO 堆栈。
新增功能
-
ocaml-multicore/eio#41 添加 eio.mli 文件
一个包含 `Generic`、`Flow`、`Network` 和 `Stdenv` 模块的 `lib_eio/eio.mli` 文件已添加到存储库中。
-
ocaml-multicore/eio#45 添加基本域管理器
此 PR 允许您在另一个域上运行 CPU 密集型任务,并向 `traceln` 添加了一个互斥锁以避免输出重叠。
-
ocaml-multicore/eio#46 添加 Eio.Time 并允许取消休眠
使用 `psq` 而不是 `bheap` 库来允许取消。`Eio.Time` 模块已添加到 `lib_eio/eio.ml` 中。
-
ocaml-multicore/eio#53 添加 `Switch.sub_opt`
添加了一个新的 `Switch.sub_opt` 实现以允许使用新的开关运行函数。此外,`Switch.sub` 已修改,因此它不是命名参数。
-
ocaml-multicore/eio#54 初始文件系统抽象
添加了一个 `Dir` 模块以允许文件系统抽象以及创建文件和目录的功能。在 Linux 上,它使用 `openat2` 和 `RESOLVE_BENEATH`。
-
ocaml-multicore/eio#56 添加 `with_open_in`、`with_open_out` 和 `with_open_dir` 辅助函数
Eio.Dir
模块现在包含 `with_open_in`、`with_open_out` 和 `with_open_dir` 辅助函数。 -
ocaml-multicore/eio#58 添加 `Eio_linux.{readv, writev}`
Eio_linux.{readv, writev}
函数已添加到 `lib_eio_linux/eio_linux.ml` 中,它使用新的 OCaml-Uring API。 -
ocaml-multicore/eio#59 添加 `Eio_linux.noop` 和一个简单的基准测试
添加了一个 `Eio_linux.noop` 实现用于基准测试 Uring 调度。
-
ocaml-multicore/eio#61 添加通用 Enter 效果以简化调度程序
引入了 `Enter` 效果以简化调度程序操作,这对 noop 基准测试没有太大影响,如下所示。
改进
-
ocaml-multicore/eio#38 将 Flow.write 重命名为 Flow.copy
代码和文档已更新为将 `Flow.write` 重命名为 `Flow.copy` 以提高清晰度。
-
ocaml-multicore/eio#36 使用 uring 进行 accept
enqueue_accept
函数现在使用 `Uring.accept` 以及 `effect Accept`。 -
优化了 `Eunix.free` 并使用 `Uring.peek` 处理已完成的事件以获得更好的性能结果。
-
ocaml-multicore/eio#48 简化 `Suspend` 操作
通过用来自 Eio 的代码替换旧的 `Await` 和 `Yield` 效果来简化 `Suspend` 效果。
-
ocaml-multicore/eio#52 将 Linux 支持拆分到 `eio_linux` 库中
eunix
现在具有不同后端共享的公共代码,而 `eio_linux` 提供了 Linux io-uring 后端。测试和文档已更新以反映此更改。 -
ocaml-multicore/eio#57 使用回溯重新引发异常
添加了在开关捕获异常时存储回溯引用的支持。当您稍后想要重新引发异常时,这很有用。
-
ocaml-multicore/eio#60 简化完成的处理
此 PR 在 `type io_job` 中添加了 `Job` 和 `Job_no_cancel`,以及其他 `Log.debug` 消息。
清理
-
ocaml-multicore/eio#42 将 fibreslib 合并到 eio 中
Fibreslib
代码现在已与 `eio` 合并。您现在需要打开 `Eio.Std` 而不是打开 `Fibreslib`。 -
ocaml-multicore/eio#47 清理网络 API
网络 API 已更新,其中包含一些更改,例如将 `bind` 重命名为 `listen`,用我们自己的类型替换 `Unix.shutdown_command` 在 Eio API 中,以及用自定义类型替换 `Unix.sockaddr`。
-
ocaml-multicore/eio#49 删除 `Eio.Private.Waiters` 和 `Eio.Private.Switch`
Eio.Private.Waiters
和 `Eio.Private.Switch` 模块已删除,等待现在使用 Eio 库处理。 -
ocaml-multicore/eio#55 一些 API 和 README 的清理
此 PR 包含多个清理和文档更改。README.md 已修改为使用
Eio.Flow.shutdown
代替Eio.Flow.close
,并添加了一个时间部分。Eio.Network
模块已更改为Eio.Net
。Time.now
和Time.sleep_until
方法已添加到lib_eio/eio.ml
中。
文档
-
ocaml-multicore/eio#43 添加关于确定性的设计说明
README.md 文档已更新,并添加了一些关于确定性的设计说明。
-
ocaml-multicore/eio#50 README 改进
更新了 README.md 并添加了
doc/prelude.ml
用于 MDX。
处理取消
-
ocaml-multicore/eio#39 允许取消 accept 操作
此 PR 现在支持取消服务器的 accept 和读取操作。
-
ocaml-multicore/eio#40 支持取消剩余的 Uring 操作
现在支持取消
connect
、wait_readable
和await_writable
Uring 操作的请求。 -
ocaml-multicore/eio#44 修复读取取消测试
ENOENT
值已正确修正为使用-2,并且更新了取消读取请求的文档。 -
ocaml-multicore/eio#51 从取消操作中获取
EALREADY
不是错误在
lib_eunix/eunix.ml
中处理EALREADY
情况,其中操作在进行中时被取消。
其他
-
ocaml-multicore/eventlog-tools#2 添加一个 pausetimes 工具
一个名为
eventlog_pausetimes
的工具已添加到eventlog-tools
中,它接收事件日志文件的目录并计算平均值、最大暂停时间以及高达第 99.9 个百分位的分布。例如ocaml-eventlog-pausetimes /home/engil/dev/ocaml-multicore/trace3/caml-426094-* name { "name": "name", "mean_latency": 718617, "max_latency": 33839379, "distr_latency": [191,250,707,16886,55829,105386,249272,552640,1325621,13312993,26227671] }
-
ocaml-multicore/kcas#9 使用
cpu_relax
进行回退Domain.Sync.{critical_section, wait_for}
现在已被Domain.Sync.cpu_relax
替换,这与无锁实现相匹配。 -
ocaml-multicore/retro-httpaf-bench#10 添加 Eio 基准测试
Eio 基准测试现已添加到 retro-httpaf-bench GitHub 存储库中。
-
ocaml-multicore/retro-httpaf-bench#11 在 CI 构建中进行递归检出
build_image.yml
工作流程已更新,以对 CI 构建的子模块执行递归检出。 -
domainslib#29 使用 Chase Lev 双端队列进行任务窃取
用于跨域调度任务的任务窃取 Chase Lev 双端队列现已合并,并在具有 128 个 CPU 内核的机器上显示出有希望的结果。
-
ocaml-multicore/multicore-opam#55 添加 domainslib 的 0.3.0 版本
domainslib.0.3.0
的 opam 文件已添加到 multicore-opam 存储库中。
基准测试
正在进行
-
ocaml-bench/sandmark-nightly#1 无法更改比较输入值
在
parallel_nightly.ipynb
笔记本中,下拉选项中的Timestamp
和Variant
字段在重新计算整个工作簿时会被重置。
-
ocaml-bench/sandmark#230 使用 dune.2.8.1 构建 4.13.0+trunk 版本
ocaml-migrate-parsetree.2.2.0
和ppxlib.0.22.2
包现在可用于 4.13.0+trunk,我们目前正在将 Sandmark 中的 Irmin Layers 基准测试从使用 Irmin 2.4 移植到 2.6。 -
ocaml-bench/sandmark#231 在 nightly 笔记本中查看一组基准测试的结果
使用 Sandmark Jupyter 笔记本时,过滤基准测试列表的功能请求。
-
ocaml-bench/sandmark#233 更新 pausetimes_multicore 以适应最新的 Multicore 更改
暂停时间现在已针对 4.12.0 上游和 4.12.0 Multicore 分支更新,以使用新的通用跟踪格式 (CTF)。下面说明了顺序和并行暂停时间结果的生成图表
-
ocaml-bench/sandmark#235 更新选定的基准测试集作为基线基准测试
用于比较的基线基准测试应该只来自用户在 Jupyter 笔记本中选择的基准测试。
-
ocaml-bench/sandmark#236 在 sandmark_nightly 中实现暂停时间支持
需要在 Sandmark nightly Jupyter 笔记本中实现顺序和并行暂停时间图结果。结果类似于OCaml 并行化改造,ICFP 2020 论文中产生的图 10 和图 12。
-
ocaml-bench/sandmark#237 在更大的机器上运行 sandmark_nightly
Sandmark nightly 顺序和并行基准测试运行的测试已在 24 核机器上完成,我们希望将其部署在 64 核以上的机器上,以受益于 Domainslib 的最新改进。
-
ocaml-bench/sandmark#241 切换到默认的 Random 模块
关于是否切换到对顺序 Minilight、全局根微基准测试和进化算法使用
Random.State
的讨论正在进行中。
已完成
-
ocaml-bench/sandmark#232
num_domains
->num_additional_domains
基准测试已更新为现在使用
num_additional_domains
,以与 Domainslib 中的命名保持一致。 -
ocaml-bench/sandmark#239 将 grammatrix 移植到任务池
Multicore Grammatrix 基准测试现已移植为使用 Domainslib 任务池。时间和加速图如下所示
OCaml
正在进行
-
此 PR 目前正在针对 ARM64 和 PowerPC 架构进行测试和评估,特别是应用于
Ipoll
指令的分支松弛。
感谢社区中所有 OCaml 用户、开发者和贡献者对项目的持续支持。请注意安全!