OCaml 多核 - 2021 年 11 月

欢迎来到 2021 年 11 月的 Multicore OCaml 月度报告!本月的更新以及 之前的更新 由我 @ctk21、@kayceesrk 和 @shakthimaan 共同整理。

核心团队代码审查

11 月下旬,整个 OCaml 开发团队召开了为期一周的代码审查和决策会议,讨论 OCaml 5.0 的多核合并。由于补丁集的规模庞大,我们将设计和演示分解为五个工作组。以下是对每个对话的总结。如往常一样,这些决定可能会随着我们发现问题而由核心团队更改,因此请不要根据这些决定做出任何对下游项目至关重要的决定。我们将公开这些内容的目的是,希望听到您可能认为我们需要根据您从自己的代码库中获得的额外数据进行的任何更正。

出于简洁的考虑,我们不包括开发人员会议的全部记录。总体而言,多核补丁被认为大体上是健全且合适的,我们记录了重要的决定和任务。

  • MVP 之前:在未来一个月内向 ocaml/ocaml 提交 PR 之前需要完成的任务。
  • 5.00 的 MVP 之后:在 5.00 版本发布之前需要在 ocaml/ocaml 上完成的任务。这些任务将阻碍 OCaml 5.00 的发布。
  • 5.00 之后:在 2022 年初/年中发布 5.00 版本之后的展望性任务。

WG1:垃圾收集器

多核运行时更改了内存分配和垃圾收集器,以支持多个并行 OCaml 执行线程。它利用了一个停止世界并行次要收集器、一个类似 StreamFlow 的多线程分配器和一个几乎完全并发的主要收集器。

WG1 决定在 5.0 的初始版本中不会包含压缩,因为我们最适合的分配器已经表明,良好的内存分配策略避免了对昂贵的压缩的需求。当然,多核内存分配器与 bestfit 不同,因此我们需要社区的反馈,以确保我们关于不需要压缩的假设是合理的。如果您在 5.0 处于测试阶段时发现您的应用程序堆变得非常分散,请与我们联系。

MVP 之前

  • 删除任何不使用裸指针检查器的痕迹,因为它在无页表的多核运行时中无关紧要。
  • 运行 make parallel 以进行测试套件应该可以正常工作。
  • assert 迁移到 CAMLassert
  • 如何从 C 进行安全点:添加有关 caml_process_pending_actions 的文档以及针对多核的长时间运行 C 绑定进行测试套件测试案例。
  • 采用 ephemeron 桶接口,并与 4.x OCaml 主干执行相同的操作。
  • 检查并记录 NOT_MARKABLE 可用于希望从堆对象中排除的库,例如 ancient。
  • 检查我们是否记录了我们返回的各种统计信息的 GC 统计信息类型(全局还是域本地)。

5.00 的 MVP 之后

  • 标记堆栈溢出修复,这不会影响大多数运行时分配配置文件。

5.00 之后

  • Statmemprof 实现。
  • 标记预取。
  • 调查替代的次要堆实现,这些实现保持性能,但减少了虚拟内存使用。

WG2:域

多核中的每个域都可以与其他域并行执行 OCaml 线程。在 OCaml 中添加了几个功能,用于生成新域、加入正在终止的域以及提供域本地存储。有一个 stdlib 模块 Domain 以及底层运行时域结构。最近几个月的一项重大简化是,可以改用标准的 Mutex/Channel/Semaphore 模块,而不是以前在 Domain 中提供的低级同步原语。

运行时结构面临的挑战是,在域终止和生成的情况下,准确地维护必须参与停止世界部分的域集,并确保域在主变异器处于阻塞调用时为停止世界请求提供服务;这使用从 caml_enter_blocking_section / caml_leave_blocking_section 发出的备份线程来处理。

讨论了 Multicore OCaml 内存模型,并为 arm64 选择了正确的方案(来自 论文 的表 5b)。一致同意本地数据竞争自由 (LDRF) 属性是一种平衡且可预测的 OCaml 5.0 内存模型方法。我们可能需要依赖 >C11 编译器来实现 OCaml 5.0 中的松散原子操作,因此这意味着将放弃 MVP 对 Windows MSVC 的支持(但 mingw 将可以使用)。

MVP 之前

  • 使域 ID 抽象化,并提供 string_of_id
  • 记录使用 Field 宏进行的初始化写入在内存模型方面是允许的。此外,强调所有写入都需要使用 caml_modify(即使是立即值)。
  • 检查 selectgen “协同效应” 是否针对 DLS.get 正确。
  • domain.c 需要更多注释以帮助读者理解
    • 有关备份线程状态机和事件发生位置。
    • 域生成/加入。
  • 注释/检查为什么 install_backup_thread 在生成方和被生成方中被调用。
  • 检查为什么域终止使用互斥量用于加入(而不是互斥量、条件变量对)。

5.00 之后

  • 提供一种机制,允许用户检索可用于使用的处理器数量。这也可以由库实现。
  • 添加原子可变记录字段。
  • 添加原子变量数组。

WG3:运行时多域安全性

Multicore OCaml 以向后兼容的方式支持系统线程。执行模型保持不变,只是从单个执行上下文转置到域。

每个域将获得自己的线程链:这意味着虽然在一个域上一次只能执行一个系统线程(类似于主干),但许多域仍然可以并行执行,它们的系统线程链相互独立。为了实现这一点,使用了一个线程表,允许每个域维护自己的独立链。上下文切换现在需要格外小心地处理备份线程。当线程当前处于阻塞部分时,备份线程负责 GC 任务。系统线程需要谨慎地决定何时发出信号。

用于定期强制线程抢占的滴答线程已更新,不再依赖信号(因为多核信号模型不允许这样做)。相反,我们依赖于多核运行时的中断基础设施并触发一个“外部”中断,这将回调到系统线程中以强制进行让步。

现有的 Dynlink API 是几十年前为用 OCaml 编写的 Web 浏览器(称为 "mmm")设计的,并且是有状态的。我们将在 OCaml 5.0 MVP 中使其能够并发调用,但 WG3 决定开始重新设计 Dynlink API,使其成为无状态的。

代码片段现在存储在一个无锁跳跃列表中,以允许多个线程以线程安全的方式并发地处理代码片段结构。在清理(即释放未使用的代码片段条目)方面需要格外小心:这应该只在一个域上发生,并且在主要循环结束时进行。对于有兴趣的读者,ocaml-multicore#672 是一个推荐的阅读材料,可以了解现在使用的并发跳跃列表结构。

多核中的信号具有以下行为,WG3 决定更改其行为,以便从变异器的角度来看,允许合并多个信号。

  • 具有单个域的程序应该具有与主干几乎相同的信号行为。这包括将信号传递给该域上的系统线程。
  • 具有多个域的程序以全局方式处理信号。无法将信号定向到各个域或线程,除非通过线程信号掩码进行控制。记录信号的域可能不是正在执行 OCaml 信号处理程序的域。

框架描述符修改现在被锁定在一个互斥量之后,以避免如果不同的线程尝试同时对框架表应用更改时发生竞争条件。在主要循环结束时释放旧框架表(这是一个 STW 部分),以确保没有线程再使用此旧框架表。

Multicore OCaml 包含一个适用于多个域的 eventlog 版本。它是通过为每个域使用单独的 CTF 文件来实现这一点的,但这只是一个临时解决方案。我们希望用基于每个域环形缓冲区的现有原型来替换此实现,该原型可以从 OCaml 和 C 中以编程方式进行使用。这将是 eventlog 的泛化,因此如果现有接口尚未被广泛采用,我们应该能够删除它。

MVP 之前

  • 重写 intern.c 以便它不再执行 GC。这段代码对性能敏感,因为编译器通过反序列化来读取 cmi 文件。
    • big.ml(来自 @stedolan) 和二叉树基准测试(来自 @xavierleroy) 上进行基准测试。
  • 确保 systhreads 中的 m->waiters 原子操作是正确且安全的。
  • 写下 Thread.exit 的选项,以便在合并期间或之后讨论,以及如果只有一个域退出而其他域继续运行该怎么办。不应该是一个阻塞问题。从 vanilla trunk 中更改语义是可以的。
  • m->busyocaml-multicore/ocaml-multicore#740 开始不再是原子操作,应该被审查并合并。
  • Dynlink 限制为域 0,因为它是一个可变接口,难以并发使用。
  • 信号栈应该从计数语义转换为合并语义。
  • 尝试在域生成时延迟信号处理,以便 Caml_state 有效。
  • 如果可能,删除 total_signals_pending

5.00 版本的 MVP 之后

  • 探测 opam 以了解事件日志的使用情况(在 OCaml 4.13 中引入),以确定删除它是否会破坏任何应用程序。
  • Eventring 合并是可以的,如果功能等效,可以更改 eventlog API。
  • (也可能在 5.00 之后)systhreads 的 TLS。

5.00 版本之后

  • 获取更多关于 Dynlink 使用情况的数据,并设计一个更少状态的新 API。
  • @xavierleroy 建议根据新的分配器重新设计序列化。

WG4:Stdlib 的变更

将 Stdlib 移植到 OCaml 5.00 的主要指导原则是

  1. OCaml 5.00 不会为可变数据结构和接口默认提供线程安全性。
  2. OCaml 5.00 即使在多个域并发使用 stdlib 时也能确保内存安全性(不会崩溃)。
  3. 在 OCaml 5.00 中,观察上纯的接口仍然是纯的。

对于具有特定可变接口的 OCaml 库(例如 Queue、Hashtbl、Stack 等),它们不会被设置为域安全的,以避免影响顺序性能。使用并行的程序需要在并发访问此类模块时添加自己的锁安全性。具有顶层可变状态的模块(例如 Filename、Random、Format 等)将被设置为域安全的。一些模块,例如 Random,正在被广泛地重新设计,以使用新的方法,例如可分割的 PRNG。这些选择的动机和进一步的讨论可以在 Multicore OCaml wiki 页面 中找到。

WG4 还注意到,我们将接受并发安全的可变 stdlib 模块的替代版本(例如,具有 Concurrent.Hashtbl 的模块),并且希望看到 OCaml 社区独立开发更多无锁库。总的来说,WG4 认识到社区参与将 OCaml 库移植到并行安全性的重要性。我们旨在向语言添加 ocamldoc 标签以标记模块/函数的安全性,并希望在 OCaml 5.0 之前将此标签添加到新的统一包数据库 v3.ocaml.org 中。

惰性

OCaml 中的惰性值允许通过强制它们来运行延迟计算。一旦惰性计算运行完成,惰性值就会被更新,这样,进一步的强制操作就会从之前的强制操作中获取结果。次要 GC 也会对强制的惰性值进行短路处理,避免通过惰性对象进行跳转。惰性的实现使用来自 Obj 模块的不安全操作

在 OCaml 5.00 中,Lazy 的实现已经被设置为线程安全的。对于单线程使用,Lazy 模块保留了向后兼容性。对于多线程使用,Lazy 模块添加了同步机制,这样,当多个域并发强制一个未强制的惰性值时,其中一个域将运行延迟计算,而另一个域将获得一个新的异常 RacyLazy

随机数

通过 ocaml-multicore#582,我们有了域本地 PRNG,它们与 stock OCaml 的 PRNG 非常接近。特别是,对于顺序的 OCaml 程序,行为保持不变。但是,对于并行程序来说,情况并不理想。如果没有显式初始化,所有域都将提取相同的初始序列。

关于可分割 PRNG 的讨论正在 ocaml/RFCs#28 中进行,并且在 ocaml/ocaml#10701 中,使用 Xoshiro256++ PRNG 对 Random 进行了重新实现。

格式化

Format 模块为实现漂亮打印框有一些隐藏的全局状态。虽然该模块有显式 API 用于将格式化程序状态传递给函数,但它为 stdoutstderr 和标准缓冲区提供了预定义的格式化程序,这些格式化程序的状态由该模块维护。

Format 模块已经为预定义的格式化程序设置了线程安全性。我们为每个域使用域本地版本的格式化程序状态,并在第一个域生成时懒惰地切换到此版本。这保留了单线程代码的性能,同时对多线程用例线程安全。有关总结,请参见 ocaml/ocaml#10453 中的讨论。

互斥量、条件、信号量

Mutex、Condition 和 Semaphore 模块与 stock OCaml 中的 systhreads 相同。它们现在位于 stdlib 中。当链接 systhreads 时,相同的模块被用于 systhreads 之间的同步。

MVP 之前

  • 将惰性标记为非线程安全。
    • 将 RacyLazy 和 Undefined 合并。
    • 删除域本地唯一令牌。
    • 删除 try_force。
  • 添加 Bucket 模块,用于在 OCaml 4.13 中看到的具有默认顺序实现的短暂对象。

5.00 版本的 MVP 之后

  • 为不同的并发安全性引入 ocamldoc 标签
    • 域安全
    • systhread 安全
    • fiber 安全
    • 非并发安全(= !域安全 || !systhread 安全 || !fiber 安全)——也用作未分析并发性的库和函数的占位符。
  • 在手册中添加有关内存模型的文档。具体来说,没有凭空产生的值——除了指向论文之外,不需要详细记录内存模型。
  • 对于 Arg 模块,弃用当前版本,但不要弃用整个模块。
  • 删除 ThreadUnix,因为它是一个不再需要 Unix 的简单模块。
  • Dynlink 应该在内部有一个互斥量,以确保它不会崩溃,尤其是在字节码中。

5.00 版本之后

  • 原子数组
  • 根据 Bucket 模块重新实现短暂对象。
  • 通过使用字节大小的写入和 CAS 来使惰性标签更新和标记分离。

WG5:纤维

纤维是运行时系统机制,支持效果处理程序。OCaml 中效果处理程序的设计已在 PLDI 2021 论文 中写明。添加效果处理程序的动机以及更多示例可以在 这些幻灯片 中找到。

使用效果处理程序进行编程

效果处理程序可以通过 stdlib/effectHandlers.ml(虽然它可能很快被重命名为 Effect)提供给 OCaml 程序员。EffectHandlers 模块公开了两种效果处理程序变体——深度和浅层。深度处理程序类似于对计算树的折叠,而浅层处理程序类似于 情况拆分。在深度处理程序中,处理程序围绕着延续,而在浅层处理程序中则没有。

这是一个使用深度处理程序来模拟类似于 Reader 单子的程序示例。

open EffectHandlers
open EffectHandlers.Deep

type _ eff += Ask : int eff

let main () =
  try_with (fun _ -> perform Ask + perform Ask) ()
  { effc = fun (type a) (e : a eff) ->
      match e with
      | Ask -> Some (fun (k : (a,_) continuation) -> continue k 1)
      | _ -> None }

let _ = assert (main () = 2)

观察到,当我们恢复延续 k 时,计算执行的后续效果也由同一个处理程序处理。与之相反,浅层处理程序则不会。对于浅层处理程序,我们使用 continue_with 而不是 continue。

open EffectHandlers
open EffectHandlers.Shallow

type _ eff += Ask : int eff

let main () =
  let rec loop (k: (int,_) continuation) (state : int) =
    continue_with k state
    { retc = (fun v -> v);
      exnc = (fun e -> raise e);
      effc = fun (type a) (e : a eff) ->
        match e with
        | Ask -> Some (fun (k : (a, _) continuation) -> loop k 1)
        | _ -> None }
  in
  let k = fiber (fun _ -> perform Ask + perform Ask) in
  loop k 1

let _ = assert (main () = 2)

观察到,使用浅层处理程序,递归是显式的。浅层处理程序使得更容易编码需要将状态贯穿其中的情况。例如,以下是编码计数器的 State 处理程序的变体。

open EffectHandlers
open EffectHandlers.Shallow

type _ eff += Next : int eff

let main () =
  let rec loop (k: (int,_) continuation) (state : int) =
    continue_with k state
    { retc = (fun v -> v);
      exnc = (fun e -> raise e);
      effc = fun (type a) (e : a eff) ->
        match e with
        | Next -> Some (fun (k : (a, _) continuation) -> loop k (state + 1))
        | _ -> None }
  in
  let k = fiber (fun _ -> perform Next + perform Next) in
  loop k 0

let _ = assert (main () = 3)

虽然可以使用深度处理程序(通过使用闭包来构建计算的通常 State 单子技巧)来进行这种编码,但使用浅层处理程序感觉更自然。一般来说,可以使用浅层处理程序轻松地编码深度处理程序,但反过来则很困难。在目前正在开发的类型化效果工作中,默认将是浅层处理程序,而深度处理程序将使用浅层处理程序进行编码。

作为历史回顾,当前的实现针对深度处理程序进行了调整,并且经过了几次迭代的优化。如果浅层处理程序在未来几年变得更加普及,那么可能可以进行一些调整来减少一些分配。也就是说,这种未来实现中深度处理程序和浅层处理程序的语义将与当前在 OCaml 5.00 分支中使用的语义保持一致。

5.00 版本的 MVP 之后

  • 添加 ARM64 后端
  • 有关使用效果处理程序的文档。
  • 当前的堆栈大小应该是纤维堆栈的堆栈大小之和。目前,它只捕获顶层纤维的大小。
    • 这并不像看起来那么简单。恢复延续会附加一个堆栈。我们应该在那里进行堆栈溢出检查吗?我不会,因为这会导致恢复延续变慢。一种想法可能是只在堆栈重新分配时进行堆栈溢出检查,这样可以捕获常见情况。

5.00 版本之后

  • 添加对使用帧指针进行编译的支持。

十一月活动

这份庞大的代码审查总结和重要的决策已经结束。总体而言,我们正全力以赴准备生成一个 OCaml 5.0 的 PR,尽管我们未来几个月还有很多工作要做!现在,我们继续我们的常规报告,介绍 11 月份的其他事件。生态系统正在不断发展,OCaml 的基于 Effects 的并行 IO Eio 有重大更新。

Lwt.5.5.0 已经发布,它支持将纯计算分派到多核域。Sandmark 基准测试现在已经更新为 5.00 版本构建,并且 current-bench 工具正在改进,以便更好地跟踪性能分析和上游合并更改。

与往常一样,多核 OCaml 更新首先列出,其中包含上游工作、文档更改和 PR 修复。接下来是生态系统更新,涉及 EioTezos。最后列出了 Sandmark、sandmark-nightly 和 current-bench 任务,供您参考。

多核 OCaml

正在进行

上游

  • ocaml-multicore/ocaml-multicore#669 为域设置线程名称

    这是一个为多核 OCaml 实现线程命名的补丁。它提供了一个接口,用于以不同的方式命名域和线程。更改现在已经重新整理并修复了拼写错误。

  • ocaml-multicore/ocaml-multicore#733 改善 Linux 上的虚拟内存占用

    这是一个关于为虚拟内存性能、域生成和终止、Is_young 运行时使用性能和安全性以及使用 Gc 集更改小堆大小而协调域的小堆分配的设计讨论。

  • ocaml-multicore/ocaml-multicore#735minor_gc.c 中添加 caml_young_alloc_startcaml_young_alloc_end

    caml_young_alloc_startcaml_young_alloc_end 不存在于多核 OCaml 中,它们应该与 young_startyoung_end 相同。

  • ocaml-multicore/ocaml-multicore#736 解压缩测试套件因缺少 pthread 链接标志而无法在 5.0 中运行

    在测试解压缩测试套件时,如果没有链接 -lpthread,则会观察到对 pthread_sigmask 的未定义引用。

  • ocaml-multicore/ocaml-multicore#737 将新的 ephemeron API 移植到 5.00

    一个用于不可变 ephemeron 的 API 已经合并到主干中,需要将相应的更改移植到 5.00。

  • ocaml-multicore/ocaml-multicore#740 Systhread 生命周期

    此 PR 解决多核中 systhread 的生命周期问题,并在 caml_thread_domain_stop_hookThread.exitcaml_c_thread_unregister 中提供修复。

  • ocaml-multicore/ocaml-multicore#742 来自异步审查的次要任务

    这是 OCaml 5.00 发布的异步审查中的一些次要任务。主要任务将有其自己的 GitHub 问题。

  • ocaml-multicore/ocaml-multicore#745 Systhreads WG3 评论

    提交名称应该具有自描述性,优先使用非原子变量,并且如果无法分配线程描述符,我们应该引发 OOM。

  • ocaml-multicore/ocaml-multicore#748 WG3 将 gen_sizeclasses 移动

    此 PR 将 runtime/gen_sizeclasses.ml 移动到 tools/gen_sizeclasses.ml 并修复了拼写错误。

  • ocaml-multicore/ocaml-multicore#750 讨论多核下 Lazy 的设计

    这是关于多核 OCaml 中 Lazy 设计的持续讨论,它讨论了顺序 Lazy、并发问题、重复计算和内存安全性。

  • ocaml-multicore/ocaml-multicore#753 C API 用于将域固定到 C 线程?

    这是一个关于如何设计一个 API 的问题,该 API 允许从 C 中创建“固定”到现有 C 线程的域。

  • ocaml-multicore/ocaml-multicore#754emit.mlp 组织的改进

    preproc_fun 函数应该移动到一个目标无关的模块中,并且所有序言代码都需要在一个地方发出。

  • ocaml-multicore/ocaml-multicore#756 RFC: 将 Domain.DLS 接口泛化,以便为子域拆分 PRNG 状态

    此 PR 演示了“正确”PRNG+域语义的实现,其中生成一个域会“拆分”PRNG 状态。

  • ocaml-multicore/ocaml-multicore#757 审计 stdlib 以查找可变状态

    这是一个用于跟踪 stdlib 中可变状态审计状态的跟踪器。OCaml 5.00 stdlib 将必须保证内存和线程安全。

文档

  • ocaml-multicore/ocaml-multicore#741 确保版权页眉格式正确

    源文件中的版权页眉必须使用新格式整齐地格式化。如果旧格式已经存在,那么必须添加作者、机构详细信息,如下所示

    /**************************************************************************/
    /*                                                                        */
    /*                                 OCaml                                  */
    /*                                                                        */
    /*          Xavier Leroy and Damien Doligez, INRIA Rocquencourt           */
    /*          <author's name>, <author's institution>                       */
    /*                                                                        */
    /*   Copyright 1996 Institut National de Recherche en Informatique et     */
    /*     en Automatique.                                                    */
    /*   Copyright <first year written>, <author OR author's institution>     */
    /*   Included in OCaml under the terms of a Contributor License Agreement */
    /*   granted to Institut National de Recherche en Informatique et en      */
    /*   Automatique.                                                         */
    /*                                                                        */
    /*   All rights reserved.  This file is distributed under the terms of    */
    /*   the GNU Lesser General Public License version 2.1, with the          */
    /*   special exception on linking described in the file LICENSE.          */
    /*                                                                        */
    /**************************************************************************/
    
  • ocaml-multicore/ocaml-multicore#743 未处理的异常应该显示更好的错误消息

    一个请求,要求在编译器输出中输出信息丰富的 Unhandled_effect <EFFECT_NAME> 错误消息,而不是 Unhandled

  • ocaml-multicore/ocaml-multicore#752 文档化当前的多核测试套件情况

    这是一个关于如何运行多核 OCaml 测试套件的文档更新。步骤如下

    $ make world.opt
    $ cd testsuite
    $ make all-enabled
    
  • ocaml-multicore/ocaml-multicore#759 为了清晰起见,重命名类型变量

    stdlib/fiber.ml 中的类型变量已经更新,以确保一致性和清晰性。

杂项

  • ocaml-multicore/ocaml-multicore#725 阻塞信号无限循环修复

    引入了单调的 recorded_signals_counter,以修复当没有域可以处理阻塞信号时 caml_enter_blocking_section 中可能出现的循环。还添加了 signals_block.ml 回调测试。

  • ocaml-multicore/ocaml-multicore#730 ocamlopt 在编译 aws-ec2.1.2color-brewery.0.2 时引发堆栈溢出

    在使用 4.14.0+domains+dev0 编译 aws-ec2.1.2 时,引发了“堆栈溢出”异常。

  • ocaml-multicore/ocaml-multicore#734 当新域在初始化域状态之前收到信号时,可能会出现段错误

    当由 Domain.spawn 创建的域在到达其主入口点并初始化线程本地数据之前收到信号时,可能会出现段错误。

  • ocaml-multicore/ocaml-multicore#738 当外部函数和 GC 并发运行时,断言违反

    当 Z3 尝试在 get_unsat_core 函数中释放 GC 清理的对象时,会抛出一个 断言违反 错误消息。

  • ocaml-multicore/ocaml-multicore#749 Forward_tag 短路可能存在 bug?

    一个关于在类型为 Obj.forcing_tag 的值上短路 Forward_tag 时出现的 bug。在小 GC 中,对类型为 Forward_tagLazy_tagDouble_tag 的值,短路是禁用的。

已完成

上游

  • ocaml-multicore/ocaml-multicore#637 caml_page_table_lookup 不存在于 ocaml-multicore 中

    多核没有页表,如果 ancient 引用 caml_page_table_lookup,则无法构建。删除页表功能的残余部分 PR 修复了此问题。

  • ocaml-multicore/ocaml-multicore#727 更新版本号

    ocaml-variants.opam 文件已更新为使用 ocaml-variants.4.14.0+domains

  • ocaml-multicore/ocaml-multicore#728 更新 5.00 分支的 base-domains

    base-domains 包现在包含 4.14.0+domains。否则,在本地 opam 交换机上进行依赖项解析会导致固定失败。

  • ocaml-multicore/ocaml-multicore#729 引入 caml_process_pending_signals,如果出现异常,则会引发异常

    代码与主干中的 caml_process_pending_actions / caml_process_pending_actions_exn 相匹配,并清理了 caml_raise_if_exception(caml_process_pending_signals_exn()) 调用。

文档

杂项

  • ocaml-multicore/ocaml-multicore#720 改善 ephemeron 与测试套件的兼容性

    此 PR 修复了 weaktest.ml,并导入了上游更改,使 ephemeron 可以与中缀对象一起使用。

  • ocaml-multicore/ocaml-multicore#731 AFL: 段错误和锁定重置(修复 #497

    一个修复,使 AFL 工具能够再次在多核 OCaml 上运行。此 PR 还更改了 caml_init_domains,以一致地使用 caml_fatal_error

生态系统

正在进行

  • ocaml-multicore/tezos#8 ci.Dockerfile 抛出警告

    numerics 库强制使用 c99,它已从 Tezos 中删除,因此不应该出现此警告。

  • ocaml-multicore/domainslib#55 setup_pool: 选项用于排除当前/第一个域?

    不将主线程作为池的一部分包含在内的用例是一个有效请求。使用 async_push 可以解决同样的问题

    (* main thread *)
    let pool = setup_pool ~num_additional_domains () in
    let promise = async_push pool initial_task in
    (* the workers are now executing the [initial_task] and
       its children. main thread is free to do its thing. *)
    ....
    (* when it is time to terminate, for cleanup, you may optionally do *)
    let res = await pool promise (* waits for the promise to resolve, if not already *)
    teardown_pool pool
    
  • ocaml-multicore/eio#91 [讨论] 对象能力/API

    关于在每个函数的第一个参数中使用一个开放对象,以及使用完整的单词和表达式而不是 networkfile_systems 等等的公开讨论。

已完成

Eio

  • ocaml-multicore/eio#86 更新 README,以提及 libuv 后端

    README.md 文件已更新,以提及该库提供了一个基于 libuv 的通用后端,该后端可在大多数平台上运行,并提供了一个使用 io-uring 的 Linux 优化后端。

  • ocaml-multicore/eio#89uring 标记为供应商会中断安装

    使用 pin-depends 用于 uring,以避免出现与 OPAM 相关的任何供应商安装问题。

  • ocaml-multicore/eio#90 隐式取消

    已将 lib_eio/cancel.ml 添加到 Eio 中,它已从 Switch 中分离出来。等待的承诺使用取消上下文,并且许多操作不再需要切换参数。

  • ocaml-multicore/eio#92 更新 README 中的跟踪图

    README 文件中的跟踪图已更新,显示两个计数线程为两条水平线,白色区域表示每个线程运行的时间。

    eio-pr-92-trace|690x157

  • ocaml-multicore/eio#93 添加 Fibre.first

    Fibre.first 返回第一个完成的纤维的结果,并取消另一个纤维。此 PR 还添加了一个 tests/test_fibre.md 文件。

  • ocaml-multicore/eio#94 添加 Time.with_timeout

    Time 模块现在包含 with_timeoutwith_timeout_extn 函数到 lib_eio/eio.ml 中。

  • ocaml-multicore/eio#95 跟踪取消是否来自父上下文

    如果父上下文被要求退出,则会引发 Cancelled 异常,以将取消向上传播。如果取消在内部,则会引发原始异常。

  • ocaml-multicore/eio#96 添加 Fibre.allFibre.pairFibre.anyFibre.await_cancel

    allpairanyawait_cancel 函数已添加到 libe_eio/eio.ml 中的 Fibre 模块。

  • ocaml-multicore/eio#97 修复 MDX 警告

    tests/test_fibre.md 文件已更新以修复 MDX 警告。

  • ocaml-multicore/eio#98 保持明确的取消上下文树

    现在可以将取消上下文树转储到输出,这对于调试很有用。

  • ocaml-multicore/eio#99 使入队线程安全

    线程安全的承诺、流和信号量已添加到 Eio 中。make bench 目标可以测试相同内容。

    dune exec -- ./bench/bench_promise.exe
    Reading a resolved promise: 4.684 ns
    use_domains,   n_iters, ns/iter, promoted/iter
          false,  1000000,   964.73,       26.0096
           true,   100000, 13833.80,       15.7142
    
    dune exec -- ./bench/bench_stream.exe
    use_domains,  n_iters, capacity, ns/iter, promoted/iter
          false, 10000000,        1,  150.95,        0.0090
          false, 10000000,       10,   76.55,        0.0041
          false, 10000000,      100,   52.67,        0.0112
          false, 10000000,     1000,   51.13,        0.0696
           true,  1000000,        1, 4256.24,        1.0048
           true,  1000000,       10,  993.72,        0.2526
           true,  1000000,      100,  280.33,        0.0094
           true,  1000000,     1000,  287.93,        0.0168
    
    dune exec -- ./bench/bench_semaphore.exe
    use_domains,  n_iters, ns/iter, promoted/iter
          false, 10000000,   43.36,        0.0001
           true, 10000000,  303.89,        0.0000
    
  • ocaml-multicore/eio#100 在更多位置传播回溯

    libe_eio/fibre.mllib_eio_linux/eio_linux.ml 已更新以允许传播回溯。

Tezos

  • ocaml-multicore/tezos#10 修复 make build-deps,修复 NixOS 支持

    该补丁修复了 make build-deps/build-dev-deps,并且 conf-perl 已从 tezos-opam-repository 中删除。

  • ocaml-multicore/tezos#15 修复 scripts/version.h

    现在通过在 scripts/version.h 文件中正确导出变量来修复 CI 构建失败。

  • ocaml-multicore/tezos#16 修复 make build-depsmake build-dev-deps 以安装正确的 OCaml 切换

    现在已从脚本文件中删除硬编码的 OCaml 切换,并且来自 script/version.h 的切换信息将与 make build-depsmake build-dev-deps 目标一起使用。

  • ocaml-multicore/tezos#17 在拉取请求到 4.12.0+domains 分支时启用 CI

    CI 已针对 4.12.0+domains 分支的拉取请求启用。

  • ocaml-multicore/tezos#20 上游更新

    来自 Tezos 存储库的最新上游构建、代码和文档更改的合并。

杂项

  • ocaml-multicore/tezos-opam-repository#6 更新

    tezos-opam-repository 中的依赖包已更新,并且 mtime.1.3.0 已添加为依赖项。

  • ocaml-multicore/ocaml-uring#40 删除对 BosRresult 的测试依赖项

    BosRresult 依赖项已从项目中删除,因为我们已经依赖于 OCaml >= 4.12,它提供了所需的功能。

  • ocaml-multicore/ocaml-uring#42 处理 test_cancel_late 中的竞争

    此合并的 PR 修复了 tests/main.mltest_cancel_late 的竞争条件。

  • ocaml-multicore/domainslib#51 利用效果处理程序

    现在使用效果处理程序创建任务,并且添加了一个新的 test_deadlock.ml 测试。

基准测试

Sandmark 和 Sandmark-nightly

正在进行

  • ocaml-bench/sandmark-nightly#21 添加 5.00 变体

    多核 OCaml 现在跟踪 OCaml 主干,而 4.12.0+domains+effects 和 4.12+domains 仅包含错误修复。以下变体现在需要包含在 sandmark-nightly 中

    • OCaml 主干,顺序,运行时(吞吐量)
    • OCaml 5.00,顺序,运行时
    • OCaml 5.00,并行,运行时
    • OCaml 主干,顺序,暂停时间(延迟)
    • OCaml 5.00,顺序,暂停时间
    • OCaml 5.00,并行,暂停时间
  • ocaml-bench/sandmark#262 ocaml-migrate-parsetree.2.2.0+stock 无法与 ocaml.5.00.0+trunk 编译

    ocaml-migrate-parsetree 依赖项不适用于 OCaml 5.00,我们需要等待 5.00 AST 被冻结才能使用 Sandmark 构建该包。

  • Sandmark 的 -main 分支正在添加 package_remove 功能,该功能允许动态删除已知无法在最近的开发分支上构建的任何依赖包。

已完成

  • ocaml-bench/sandmark-nightly#22 修复数据帧交集顺序问题

    dataframe_intersection 函数已更新以正确过滤掉不在要比较的变体中的基准测试。

  • ocaml-bench/sandmark#248 Coq 无法构建

    现在使用新的 Coq 压缩包 coq-multicore-2021-09-24 与 Sandmark 一起构建以用于各种 OCaml 变体。

  • ocaml-bench/sandmark#257 将最新的 Coq 2019-09 添加到 Sandmark

    Sandmark 中的 Coq 基准测试现在可以针对 4.14.0+domains 和 OCaml 5.00 顺利构建。

  • ocaml-bench/sandmark#260 添加用于顺序运行的 5.00 分支。修复笔记本。

    Sandmark 现在可以构建新的 5.00 OCaml 变体,以便在 CI 中构建顺序和并行基准测试。

  • ocaml-bench/sandmark#261 更新基准测试和 domainslib 以支持 OCaml 4.14.0+domains(OCaml 5.0)

    我们现在可以为 OCaml 5.00 构建 Sandmark 基准测试,并且 PR 更新为使用 domainslib.0.3.2

current-bench

正在进行

  • ocurrent/current-bench#219 支持来自不同编译器变体的图形叠加

    目前,我们能够查看每个 OCaml 版本的前端图形。我们需要将图形叠加到编译器变体以进行更好的比较和可视化。

  • ocurrent/current-bench#220 为 Sandmark 夜间运行设置 current-bench 和 Sandmark

    在经过调整的机器上,我们需要为 Sandmark 设置 current-bench(后端和前端)并安排夜间运行。

  • ocurrent/current-bench#221 支持 Sandmark 运行的开发人员存储库、分支和提交

    请求在夜间基础上针对开发人员分支运行 current-bench,以可视化每个提交的性能基准测试结果。

已完成

  • ocurrent/curren-bench#106 对 Docker run_args 使用 --privileged 以用于多核 OCaml

    current-bench 主分支(3b3b31b...)能够在 Docker 中运行多核 OCaml Sandmark 基准测试,而无需 --privileged 选项。

  • ocurrent/current-bench#146 复制 ocaml-bench-server 设置

    current-bench 现在支持使用自定义 bench.Dockerfile,它允许你覆盖要与 Sandmark 一起使用的 TAG 和 OCaml 变体。

  • ocurrent/current-bench#190 允许选定的项目在多个 CPU 上运行

    已添加一个 OCAML_BENCH_MULTICORE_REPOSITORIES 环境变量,以便在多个 CPU 内核上构建项目。

  • ocurrent/current-bench#195 添加有关仅启动前端和 DB 容器的说明

    HACKING.md 文件已更新,其中包含有关仅启动前端和数据库容器的说明。这允许你在任何机器上运行基准测试,并使用 ETL 脚本将结果转储到数据库,并在 current-bench 前端查看它们。

我们要感谢社区中所有 OCaml 用户、开发人员和贡献者对该项目的持续支持。祝您安全!

缩略语

  • AFL:American Fuzzy Lop
  • API:应用程序编程接口
  • AST:抽象语法树
  • AWS:Amazon Web Services
  • CI:持续集成
  • CPU:中央处理器
  • DB:数据库
  • DLS:域局部存储
  • ETL:提取转换加载
  • GC:垃圾收集器
  • IO:输入/输出
  • MD:Markdown
  • MLP:ML-File 预处理
  • OOM:内存不足
  • opam:OCaml 包管理器
  • OS:操作系统
  • PR:拉取请求
  • PRNG 伪随机数生成器
  • RFC:请求意见
  • WG:工作组