From fd2102c7fe4fc936de93fe179b3e59758d18f992 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 8 Nov 2023 12:38:34 -0500 Subject: [PATCH] prepare for 0.5 --- CHANGES.md | 36 ++++++++++++++++++++++++++++++++++++ dune-project | 2 +- moonpool.opam | 2 +- src/fifo_pool.mli | 2 +- src/fut.mli | 6 +++--- src/immediate_runner.mli | 2 +- src/moonpool.mli | 10 +++++----- src/runner.mli | 2 +- 8 files changed, 49 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 86f2ca1e..e7c9665b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,40 @@ +# 0.5 + +## features + +- add `Bb_queue.transfer` + -add `Bb_queue.to_{iter,gen,seq}` +- add `Fifo_pool`, a simple pool with a single blocking queue for + workloads with coarse granularity tasks that value + latency (e.g. a web server) +- add a work-stealing pool for heavy compute workloads that + feature a lot of await/fork-join, with a lot of help + from Vesa Karvonen (@polytypic) +- add `Fut.spawn_on_current_runner` +- add `Runner.{spawn_on_current_runner, await}` +- add a few more toplevel aliases in `Moonpool` itself +- add `No_runner`: a runner that runs tasks synchronously in the caller +- on shutdown, pools will finish running all present tasks before + closing. New tasks are immediately rejected. + +- use an optional dependency on `thread-local-storage` to + implement work stealing and `spawn_on_current_runner` + +## optimizations + +- use the main domain to spawn threads on it. This means we can really + use all cores, not all but one. +- in `Fork_join.both`, only one of the two sides schedules a task, + the other runs in the current thread. This reduces scheduling overhead. +- compare to domainslib in benchmarks. With the WS pool we're now slightly + ahead in terms of overhead on the recursive fib benchmark. + +## breaking + +- deprecate `Pool`, now an alias to `Fifo_pool` + + # 0.4 - add `Fut.{reify_error,bind_reify_error}` diff --git a/dune-project b/dune-project index f6ace0a6..d82dfdc7 100644 --- a/dune-project +++ b/dune-project @@ -2,7 +2,7 @@ (using mdx 0.2) (name moonpool) -(version 0.4) +(version 0.5) (generate_opam_files true) (source (github c-cube/moonpool)) diff --git a/moonpool.opam b/moonpool.opam index 62bdcf6e..7f419ce0 100644 --- a/moonpool.opam +++ b/moonpool.opam @@ -1,6 +1,6 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -version: "0.4" +version: "0.5" synopsis: "Pools of threads supported by a pool of domains" maintainer: ["Simon Cruanes"] authors: ["Simon Cruanes"] diff --git a/src/fifo_pool.mli b/src/fifo_pool.mli index 4371db58..9b82081b 100644 --- a/src/fifo_pool.mli +++ b/src/fifo_pool.mli @@ -12,7 +12,7 @@ have higher throughput but they're very unfair to some tasks; by contrast, here, older tasks have priority over younger tasks. - @since NEXT_RELEASE *) + @since 0.5 *) include module type of Runner diff --git a/src/fut.mli b/src/fut.mli index aa4515f5..1eed358a 100644 --- a/src/fut.mli +++ b/src/fut.mli @@ -91,7 +91,7 @@ val spawn_on_current_runner : (unit -> 'a) -> 'a t See {!Runner.get_current_runner} to see how the runner is found. - @since NEXT_RELEASE + @since 0.5 @raise Failure if run from outside a runner. *) val reify_error : 'a t -> 'a or_error t @@ -218,9 +218,9 @@ val wait_block_exn : 'a t -> 'a They were previously present as [module Infix_local] and [val infix], but are now simplified. - @since NEXT_RELEASE *) + @since 0.5 *) -(** @since NEXT_RELEASE *) +(** @since 0.5 *) module Infix : sig val ( >|= ) : 'a t -> ('a -> 'b) -> 'b t val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t diff --git a/src/immediate_runner.mli b/src/immediate_runner.mli index ed017eba..8917d8b5 100644 --- a/src/immediate_runner.mli +++ b/src/immediate_runner.mli @@ -11,7 +11,7 @@ Another situation is when threads cannot be used at all (e.g. because you plan to call [Unix.fork] later). - @since NEXT_RELEASE + @since 0.5 *) include module type of Runner diff --git a/src/moonpool.mli b/src/moonpool.mli index 60c0ede6..b12b739a 100644 --- a/src/moonpool.mli +++ b/src/moonpool.mli @@ -27,29 +27,29 @@ val run_async : Runner.t -> (unit -> unit) -> unit (** [run_async runner task] schedules the task to run on the given runner. This means [task()] will be executed at some point in the future, possibly in another thread. - @since NEXT_RELEASE *) + @since 0.5 *) val recommended_thread_count : unit -> int (** Number of threads recommended to saturate the CPU. For IO pools this makes little sense (you might want more threads than this because many of them will be blocked most of the time). - @since NEXT_RELEASE *) + @since 0.5 *) val spawn : on:Runner.t -> (unit -> 'a) -> 'a Fut.t (** [spawn ~on f] runs [f()] on the runner (a thread pool typically) and returns a future result for it. See {!Fut.spawn}. - @since NEXT_RELEASE *) + @since 0.5 *) val spawn_on_current_runner : (unit -> 'a) -> 'a Fut.t (** See {!Fut.spawn_on_current_runner}. - @since NEXT_RELEASE *) + @since 0.5 *) [@@@ifge 5.0] val await : 'a Fut.t -> 'a (** Await a future. See {!Fut.await}. Only on OCaml >= 5.0. - @since NEXT_RELEASE *) + @since 0.5 *) [@@@endif] diff --git a/src/runner.mli b/src/runner.mli index 471d21af..b0af57ed 100644 --- a/src/runner.mli +++ b/src/runner.mli @@ -70,4 +70,4 @@ end val get_current_runner : unit -> t option (** Access the current runner. This returns [Some r] if the call happens on a thread that belongs in a runner. - @since NEXT_RELEASE *) + @since 0.5 *)