OCaml 多核 - 2021年9月
欢迎阅读 2021 年 9 月的 Multicore OCaml 月度报告!本月的更新以及 之前的更新 由我 @ctk21、@kayceesrk 和 @shakthimaan 共同整理。团队在过去几个月里一直在努力完成 最后几个功能,以实现与标准 OCaml 的功能奇偶校验。我们还与 OCaml 核心团队密切合作,制定了将 Multicore OCaml 上游到标准 OCaml 的时间线,现在已经达成一致意见:
OCaml 5.0 将通过域支持共享内存并行,以及通过效果处理器支持直接风格并发(无语法支持).
- 该 域机制 允许 OCaml 程序员通过利用现代处理器上可用的多个内核进行并行处理来加速 OCaml 代码。
- 效果处理器允许 OCaml 程序员编写 高性能的直接风格并发程序,无需像今天使用 Lwt 和 Async 库那样使用单子并发。效果处理器还可以作为构建其他非局部控制流抽象的有用抽象,例如 生成器、轻量级线程等。OCaml 将是 首批支持效果处理器的工业级语言之一。
新代码将必须经过对上游 OCaml 贡献的通常严格审查流程,但我们预计将在未来几个月内推进审查流程。
回顾:什么是效果处理器?
以下是摘录自 "将效果处理器改造到 OCaml 上"
效果处理器为用户定义的效果提供了模块化基础。关键思想是将效果操作的定义与其解释分离,解释由效果的处理器给出。例如
effect In_line : in_channel -> string
声明一个名为
In_line
的效果,它以类型为in_channel
的输入通道作为参数,执行时返回一个string
值。计算可以在不知道In_line
效果如何实现的情况下执行In_line
效果。此计算可能包含在以不同方式处理In_line
的不同处理器中。例如,In_line
可以通过对输入通道执行阻塞读取或通过将其卸载到 libuv 等事件循环来异步执行读取来实现,而无需更改计算。由于将效果操作与其实现分离,因此效果处理器能够实现模块化编程的新方法。效果处理器是异常处理器的泛化,其中,除了要处理的效果之外,处理器还提供了执行点的分界延续。此延续可用于稍后恢复挂起的计算。这使得可以组合地表达非局部控制流机制,例如可恢复异常、轻量级线程、协程、生成器和异步 I/O。
OCaml 中的效果处理器的实现是一次性的——也就是说,延续只能恢复一次,如果未使用则必须显式地终止。此限制使在存在可变数据结构的情况下更容易推理控制流,并且还允许实现高性能。
您可以在 完整论文 中阅读更多关于 OCaml 中效果处理器的信息。
为什么 OCaml 5.0 中没有对效果处理器提供语法支持?
Multicore OCaml 中当前的效果处理器无法确保 效果安全性。也就是说,编译器不会确保程序执行的所有效果都被处理。相反,未处理的效果会导致运行时异常。由于我们计划在未来扩展 OCaml 以支持 效果系统,因此 OCaml 5.0 不会提供用于使用效果处理器进行编程的语法支持。相反,我们通过标准库中的函数公开相同的功能,为效果系统落地时保留语法决策。基于函数的效果处理器与 Multicore OCaml 中当前的语法版本一样具有表现力。例如,以下内容的无语法版本:
effect E : string
let comp () =
print_string "0 ";
print_string (perform E);
print_string "3 "
let main () =
try
comp ()
with effect E k ->
print_string "1 ";
continue k "2 ";
print_string “4 "
将是
type _ eff += E : string eff
let comp () =
print_string "0 ";
print_string (perform E);
print_string "3 "
let main () =
try_with comp ()
{ effc = fun e ->
match e with
| E -> Some (fun k ->
print_string "1 ";
continue k "2 ";
print_string “4 “)
| e -> None }
可以想象编写一个 ppx 扩展,使程序员能够编写接近早期版本的代码。
我今天应该使用哪个 opam 切换?
4.12+domains
opam 切换具有所有将进入 OCaml 5.0 的功能,包括作为函数的效果处理器。这些函数所在的精确模块可能会在 5.0 版中发生更改,但基本形式应该保持不变。
4.12+domains+effects
opam 切换将被保留,但语法不会上游。此切换主要用于尝试学术文献中 OCaml 效果处理器的示例。
要了解有关使用此效果系统进行编程的更多信息,请参阅 eio 库和 最近的这次演讲。在接下来的几周内,eio
库将移植到 4.12+domains
以使用基于函数的效果处理器,以便它可以用于 OCaml 5.0。
关于 2021 年 9 月的更新
已合并了许多增强功能,以提高 stdlib 的线程安全性,改进测试套件覆盖率,以及通常的错误修复。生态系统项目的文档已更新,以提高可读性、语法和一致性。Sandmark-nightly 网络服务目前正在 Docker 化,以便部署以可视化和分析基准测试结果。Sandmark 2.0-beta 分支也已发布,其中包含 2.0 功能,可供测试和反馈。
我们要感谢以下人员的贡献
- @lingmar(Linnea Ingmar)报告了 4.12.0+domains 中
caml_shared_try_alloc
处的段错误。 - @dhil(Daniel Hillerström)提供了一个补丁来从编译器源代码中删除
drop_continuation
。 - @nilsbecker(Nils Becker)报告了在使用 Task.pool 管理时使用 14 个内核发生的崩溃。
- @cjen1(Chris Jensen)观察并使用 ulimit 修复了在尝试 Eio 自述文件示例时出现的
Unix.ENOMEM
错误。 - @anuragsoni(Anurag Soni)为
retro-httpaf-bench
贡献了一个异步 HTTP 基准测试。
与往常一样,Multicore OCaml 更新首先列出,然后是生态系统工具和库的更新。最后列出 Sandmark-nightly 的正在进行的工作和 Sandmark 基准测试任务,以供参考。
Multicore OCaml
正在进行
线程安全
-
ocaml-multicore/ocaml-multicore#632
Str
模块多域安全性该 PR#635 使
lib-str
域安全,以便与 Multicore OCaml 并发工作。 -
ocaml-multicore/ocaml-multicore#636 用于线程安全可变性的库构建锁
关于为简单、可变状态库创建两个线程安全模块的可能性进行公开讨论。
段错误
-
ocaml-multicore/ocaml-multicore#639 GC 中的段错误
正在调查由 @lingmar(Linnea Ingmar)报告的 4.12.0+domains 中
caml_shared_try_alloc
引起的段错误。 -
ocaml-multicore/ocaml-multicore#646 Coq 在构建期间发生段错误
当使用 Multicore OCaml 运行时,Coq 证明助手会导致段错误,并且已提供了一个新的 tarball 供测试。
测试套件
-
ocaml-multicore/ocaml-multicore#640 Windows 的 GitHub Actions
GitHub Actions 已更新,可在 Windows 上运行 Multicore OCaml 测试套件。
-
ocaml-multicore/ocaml-multicore#641 使多核测试套件运行程序与标准 OCaml 保持一致
需要审查 Multicore 禁用的测试,以查看是否可以重新启用它们,以及像 trunk 一样并行运行它们。
杂项
-
ocaml-multicore/ocaml-multicore#637
caml_page_table_lookup
在 ocaml-multicore 中不可用ancien
包使用Is_in_heap_or_young
宏,该宏在内部使用caml_page_table_lookup
,而caml_page_table_lookup
尚未在 Multicore OCaml 中实现。 -
ocaml-multicore/ocaml-multicore#653 删除
drop_continuation
由 @dhil(Daniel Hillerström)贡献的 PR,用于删除
drop_continuation
,因为clone_continuation
也已删除。
已完成
上游
-
ocaml-multicore/ocaml-multicore#631 不要从
caml_alloc
C 函数中的信号引发异步异常一个 PR,防止异步异常从信号处理程序中抛出,并避免从 C 中的
caml_alloc_*
调用轮询挂起的信号。 -
ocaml-multicore/ocaml-multicore#638 为标准库添加一些单射性注解
为了使用多核 OCaml 编译
stdcompat
,单射性注解已从 4.12.0 版本回退到stdlib
。 -
ocaml-multicore/ocaml-multicore#642 删除页面表功能的残余部分
多核 OCaml 中未使用页面表,并且已删除相应的宏和函数定义。
-
ocaml-multicore/ocaml-multicore#643
Core_kernel
字节报告已关闭分配的字节数报告出现偏差,因为
young_ptr
和young_end
被定义为char *
。更改它们为value *
的 PR 现已合并。 -
ocaml-multicore/ocaml-multicore#652 将
young_start/end/ptr
指针更改为指向 value多核 OCaml 中
young_start
、young_end
和young_ptr
的使用已更新为value *
而不是char *
,以与主干保持一致。
回退
-
ocaml-multicore/ocaml-multicore#573 将主干安全点 PR 回退到多核
安全点实现现已回退到多核 OCaml。
-
ocaml-multicore/ocaml-multicore#644 小改动
一个补丁,用
caml_modify
替换已弃用的宏Modify
,并在runtime/caml/alloc.h
中添加对caml_alloc_float_array
的引用。 -
ocaml-multicore/ocaml-multicore#649 整合主干的所有 EINTR 修复
来自 ocaml/ocaml#9722 的 EINTR 基于信号的修复已并入多核 OCaml。
线程安全
-
ocaml-multicore/ocaml-multicore#630 使信号对多核安全
多核 OCaml 中的信号实现已进行了大修,具有清晰且正确的语义。
-
ocaml-multicore/ocaml-multicore#635 使
lib-str
域安全该 PR 将
str
中全局变量的使用迁移到线程局部存储。还添加了一个并行执行str
计算的测试用例。
效果处理器
-
ocaml-multicore/ocaml-multicore#650 添加将效果处理器公开为函数所需的原语
包含促进
4.12+domains
更新的原语,以继续与来自4.12+domains+effects
的更改一起工作。 -
ocaml-multicore/ocaml-multicore#651 将深层和浅层处理器公开为函数
该 PR 将深层和浅层处理器作为 Obj 模块中的函数公开。它还删除了克隆延续的功能。
其他
-
ocaml-multicore/ocaml-multicore#633 使用
no-flat-float-arrays
构建 4.12.0+domains 出现错误链接器错误已在 PR#644 中修复。
-
ocaml-multicore/ocaml-multicore#647 改进多核的问题模板
多核 OCaml 错误报告模板已改进,包括“描述问题”、“重现步骤”、“多核 OCaml 构建版本”、“您是否尝试在打开调试运行时和堆验证的情况下运行它?”和“回溯”等部分。
生态系统
正在进行
-
ocaml-multicore/domainslib#43
Task.pool
管理中可能存在错误@nilsbecker (Nils Becker) 报告称,在使用 14 个核心时,Task.pool 管理出现段错误。
-
ocaml-multicore/multicore-opam#59 修复 ocaml-multicore/ocaml-multicore#514 之后出现的 batteries 问题
更新
batteries.3.3.0+multicore
opam 文件,为batteries-included
使用正确的 src URL。 -
ocaml-multicore/multicore-opam#60 多核 domains+effects 语言服务器无法与 VS Code 一起使用
在使用多核 domains+effects 语言服务器时,VS Code 会显示“Request textDocument/hover failed”错误。
-
ocaml-multicore/eio#81 是否可以实现 IO 优先级?
关于 IO 优先级和为共识系统调度纤程的查询。
已完成
构建
-
ocaml-multicore/eventlog-tools 使用 ocaml/setup-ocaml@v2
GitHub 工作流程现已更新为在
.github/workflows/main.yml
文件中使用 4.12.x ocaml 编译器和ocaml/setup-ocaml@v2
。 -
ocaml-multicore/tezos#3 添加 cron 作业并运行测试
CI Dockerfile 和 GitHub 工作流程已更改为定期为 Tezos 在多核 OCaml 上运行测试。
-
ocaml-multicore/tezos#4 每天运行 cron 作业
GitHub cron 作业现已安排每天从头开始运行 Tezos 构建。
-
ocaml-multicore/retro-httpaf-bench#12 Dockerfile 构建失败
该问题已不存在,Dockerfile 现在在 CI 中也能正常构建。
-
ocaml-multicore/eio#80 README 示例出现 ENOMEM 错误
@cjen1 (Chris Jensen) 报告了一个
Unix.ENOMEM
错误,该错误阻止了以下 README 示例代码段的执行。使用ulimit
设置较小的内存大小可以修复此问题。#require "eio_main";; open Eio.Std;; let main ~stdout = Eio.Flow.copy_string "hello World" stdout Eio_main.run @@ fun env -> main ~stdout:(Eio.Stdenv.stdout env) ;;
文档
-
ocaml-multicore/parallel-programming-in-multicore-ocaml#10 编辑以改进流程/语法/一致性
已审查并更新了“多核 OCaml 中的并行编程”章节,以确保一致性、语法流畅性和可读性。
-
ocaml-multicore/eio#79 初始编辑以改进一致性、格式和清晰度
已更新 Eio 项目中的 README,以确保一致性、格式和可读性。
-
已更新 ocaml2020-workshop-parallel 的 README,添加了指向书籍、视频、项目存储库和 OCaml 多核维基的参考链接。
基准测试
-
ocaml-multicore/retro-httpaf-bench#15 优化 Go 代码
nethttp-go/httpserv.go
Go 基准测试现在使用Write
而不是fmt.Fprintf
,并删除了 yield() 以进行优化。 -
ocaml-multicore/retro-httpaf-bench 添加异步 HTTP 基准测试
@anuragsoni (Anurag Soni) 贡献了一个异步 HTTP 基准测试,该测试在具有 4 核 i7-8559 CPU(2.70 GHz)、1000 个连接和 60 秒运行时间的 Docker 中运行。
基准测试
Sandmark-nightly
正在进行
-
ocaml-bench/sandmark-nightly#10 将 sandmark-nightly 容器化
需要将 sandmark-nightly 服务容器化,以便能够在多台机器上运行。
-
ocaml-bench/sandmark-nightly#11 重构 sandmark-nightly 笔记本
需要重构和模块化 sandmark-nightly 笔记本中的代码,以便可以将其重用为库。
-
ocaml-bench/sandmark-nightly#12 需要修复归一化图表(包含两个以上基准测试)
即使存在两个以上基准测试,归一化图表也只生成一个彩色条形图组。与基线相比,它需要显示多个彩色图表。
-
ocaml-bench/sandmark-nightly#13 将每晚运行的日志与结果一起存储
可以存储每晚运行的日志,因为它们对调试任何故障很有用。
-
ocaml-bench/sandmark-nightly#14 为顺序基准测试添加
best-fit
变体sandmark-nightly 运行应包含最佳拟合分配器,因为它优于下一个拟合分配器。可以使用以下命令启用最佳拟合分配器
$ OCAMLRUNPARAM="a=2" ./a.out
-
ocaml-bench/sandmark-nightly#16 最新 Navajo 每晚运行中缺少 Cubicle 和 Coq 基准测试
顺序基准测试的 UI 由于缺少 Cubicle 和 Coq 基准测试 .bench 文件而无法加载归一化图表。
-
ocaml-bench/sandmark-nightly#17 Navajo 运行使用过时的 Sandmark
部署在 Navajo 上的 Sandmark 需要更新到最新的 Sandmark,并且由于 Makefile 未提交的更改,
git pull
失败。
Sandmark
正在进行
-
ocaml-bench/sandmark#248 Coq 构建失败
现在可以使用 coq-multicore-2021-09-24 中提供的新 Coq 压缩包进行测试,以使用多核 OCaml 进行构建。
-
Sandmark
2.0-beta
Sandmark 2.0-beta 分支现已提供测试。它包括新的功能,例如包覆盖选项、向基准测试结果添加元信息、运行多次迭代、基准测试分类、用户配置以及简化包依赖项管理。您可以针对以下 OCaml 编译器变体测试该分支
- 4.12.0+domains
- 4.12.0+stock
- 4.14.0+trunk
$ git clone https://github.com/ocaml-bench/sandmark.github $ cd sandmark $ git checkout 2.0-beta $ make clean; TAG='"run_in_ci"' make run_config_filtered.json $ RUN_CONFIG_JSON=run_config_filtered.json make ocaml-versions/4.12.0+domains.bench $ make clean; TAG='"run_in_ci"' make run_config_filtered.json $ RUN_CONFIG_JSON=run_config_filtered.json make ocaml-versions/4.12.0+stock.bench $ make clean; TAG='"run_in_ci"' make run_config_filtered.json $ RUN_CONFIG_JSON=run_config_filtered.json make ocaml-versions/4.14.0+trunk.bench $ make clean; TAG='"macro_bench"' make multicore_parallel_run_config_filtered.json $ RUN_BENCH_TARGET=run_orunchrt BUILD_BENCH_TARGET=multibench_parallel RUN_CONFIG_JSON=multicore_parallel_run_config_filtered.json make ocaml-versions/4.12.0+domains.bench
如果您在我们的 GitHub 项目 页面中遇到任何问题,请报告。
已完成
-
ocaml-bench/sandmark#251 更新依赖项以与
4.14.0+trunk
一起使用Sandmark 主分支的依赖项现已更新,以便与 4.14.0+trunk 一起构建。
-
ocaml-bench/sandmark#253 从并行基准测试中删除
Domain.Sync.poll()
Domain.Sync.poll() 函数调用现已弃用,并且已从 Sandmark 中的并行基准测试中删除。
-
现在在为 Sandmark 构建设置本地
_opam
目录时,默认情况下将--disable-sandboxing
选项传递给 opam。
我们要感谢社区中所有 OCaml 用户、开发者和贡献者对项目的持续支持。请注意安全!
缩写
- CI:持续集成
- CPU:中央处理器
- GC:垃圾收集器
- HTTP:超文本传输协议
- IO:输入/输出
- OPAM:OCaml 包管理器
- PR:拉取请求
- UI:用户界面
- URL:统一资源定位符
- VS:Visual Studio