From 86c6c5ad927e3fefb981f5db7ee97324ddee0686 Mon Sep 17 00:00:00 2001 From: Tim McGilchrist Date: Fri, 17 Apr 2026 10:51:15 +1000 Subject: [PATCH 1/2] Add OCaml 5.5 implementation of gc_stats using word sized counters --- .github/workflows/main.yml | 9 +++++++++ lib/olly_gc_stats/dune | 18 ++++++++++++++++++ lib/olly_gc_stats/gc_counters_shim.5.3.ml | 16 ++++++++++++++++ lib/olly_gc_stats/gc_counters_shim.5.5.ml | 15 +++++++++++++++ lib/olly_gc_stats/olly_gc_stats.5.3.ml | 22 +++------------------- 5 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 lib/olly_gc_stats/gc_counters_shim.5.3.ml create mode 100644 lib/olly_gc_stats/gc_counters_shim.5.5.ml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d185975..6a7e887 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,6 +13,7 @@ jobs: build: strategy: + fail-fast: false matrix: ocaml-compiler: - 5.0 @@ -23,8 +24,16 @@ jobs: os: - ubuntu-latest - macos-15 + include: + - ocaml-compiler: ocaml-base-compiler.5.5.0~alpha3 + os: ubuntu-latest + experimental: true + - ocaml-compiler: ocaml-base-compiler.5.5.0~alpha3 + os: macos-15 + experimental: true runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.experimental == true }} steps: - name: Checkout code diff --git a/lib/olly_gc_stats/dune b/lib/olly_gc_stats/dune index 04f49bd..d1a9d59 100644 --- a/lib/olly_gc_stats/dune +++ b/lib/olly_gc_stats/dune @@ -18,3 +18,21 @@ (>= %{ocaml_version} 5.3)) (action (copy %{deps} %{target}))) + +(rule + (deps gc_counters_shim.5.3.ml) + (target gc_counters_shim.ml) + (enabled_if + (and + (>= %{ocaml_version} 5.3) + (< %{ocaml_version} 5.5))) + (action + (copy %{deps} %{target}))) + +(rule + (deps gc_counters_shim.5.5.ml) + (target gc_counters_shim.ml) + (enabled_if + (>= %{ocaml_version} 5.5)) + (action + (copy %{deps} %{target}))) diff --git a/lib/olly_gc_stats/gc_counters_shim.5.3.ml b/lib/olly_gc_stats/gc_counters_shim.5.3.ml new file mode 100644 index 0000000..e49a026 --- /dev/null +++ b/lib/olly_gc_stats/gc_counters_shim.5.3.ml @@ -0,0 +1,16 @@ +(* OCaml 5.3 / 5.4: minor allocation counters report bytes, so convert to + words. EV_C_MAJOR_ALLOCATED_WORDS already reports words. *) +let bytes_per_word = Sys.word_size / 8 + +let runtime_counter ~domain_minor_words ~domain_promoted_words + ~domain_major_words ring_id _ts counter_type value = + match counter_type with + | Runtime_events.EV_C_MINOR_PROMOTED -> + domain_promoted_words.(ring_id) <- + domain_promoted_words.(ring_id) + (value / bytes_per_word) + | Runtime_events.EV_C_MINOR_ALLOCATED -> + domain_minor_words.(ring_id) <- + domain_minor_words.(ring_id) + (value / bytes_per_word) + | Runtime_events.EV_C_MAJOR_ALLOCATED_WORDS -> + domain_major_words.(ring_id) <- domain_major_words.(ring_id) + value + | _ -> () diff --git a/lib/olly_gc_stats/gc_counters_shim.5.5.ml b/lib/olly_gc_stats/gc_counters_shim.5.5.ml new file mode 100644 index 0000000..224467e --- /dev/null +++ b/lib/olly_gc_stats/gc_counters_shim.5.5.ml @@ -0,0 +1,15 @@ +(* OCaml 5.5+: prefer the word-sized minor counters added in ocaml/ocaml#14189. + The legacy bytes counters (EV_C_MINOR_ALLOCATED / EV_C_MINOR_PROMOTED) are + still emitted for backwards compatibility — we must ignore them here to + avoid double-counting. *) +let runtime_counter ~domain_minor_words ~domain_promoted_words + ~domain_major_words ring_id _ts counter_type value = + match counter_type with + | Runtime_events.EV_C_MINOR_PROMOTED_WORDS -> + domain_promoted_words.(ring_id) <- + domain_promoted_words.(ring_id) + value + | Runtime_events.EV_C_MINOR_ALLOCATED_WORDS -> + domain_minor_words.(ring_id) <- domain_minor_words.(ring_id) + value + | Runtime_events.EV_C_MAJOR_ALLOCATED_WORDS -> + domain_major_words.(ring_id) <- domain_major_words.(ring_id) + value + | _ -> () diff --git a/lib/olly_gc_stats/olly_gc_stats.5.3.ml b/lib/olly_gc_stats/olly_gc_stats.5.3.ml index bf90627..ae14985 100644 --- a/lib/olly_gc_stats/olly_gc_stats.5.3.ml +++ b/lib/olly_gc_stats/olly_gc_stats.5.3.ml @@ -404,25 +404,9 @@ let gc_stats poll_sleep json output runtime_events_dir runtime_events_log_wsize domain_gc_times.(ring_id) <- domain_gc_times.(ring_id) + latency | _ -> () in - (* TODO: OCaml 5.5 adds EV_C_MINOR_PROMOTED_WORDS and - EV_C_MINOR_ALLOCATED_WORDS (ocaml/ocaml#14189) which report in words - directly, replacing the bytes-to-words conversion below. *) - let bytes_per_word = Sys.word_size / 8 in - let runtime_counter ring_id _ts counter_type value = - match counter_type with - | Runtime_events.EV_C_MINOR_PROMOTED -> - (* Reported as bytes, convert to words *) - domain_promoted_words.(ring_id) <- - domain_promoted_words.(ring_id) + (value / bytes_per_word) - | Runtime_events.EV_C_MINOR_ALLOCATED -> - (* Reported as bytes, convert to words *) - domain_minor_words.(ring_id) <- - domain_minor_words.(ring_id) + (value / bytes_per_word) - | Runtime_events.EV_C_MAJOR_ALLOCATED_WORDS -> - (* Allocations to the major heap of this Domain in words, - since the last major slice. *) - domain_major_words.(ring_id) <- domain_major_words.(ring_id) + value - | _ -> () + let runtime_counter = + Gc_counters_shim.runtime_counter ~domain_minor_words ~domain_promoted_words + ~domain_major_words in let init = Fun.id in From 8c06c674bac51aadba991eb913cc7b734a1da62e Mon Sep 17 00:00:00 2001 From: Tim McGilchrist Date: Fri, 17 Apr 2026 17:11:00 +1000 Subject: [PATCH 2/2] fixup! Add OCaml 5.5 implementation of gc_stats using word sized counters --- lib/olly_gc_stats/gc_counters_shim.5.5.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/olly_gc_stats/gc_counters_shim.5.5.ml b/lib/olly_gc_stats/gc_counters_shim.5.5.ml index 224467e..396daca 100644 --- a/lib/olly_gc_stats/gc_counters_shim.5.5.ml +++ b/lib/olly_gc_stats/gc_counters_shim.5.5.ml @@ -6,8 +6,7 @@ let runtime_counter ~domain_minor_words ~domain_promoted_words ~domain_major_words ring_id _ts counter_type value = match counter_type with | Runtime_events.EV_C_MINOR_PROMOTED_WORDS -> - domain_promoted_words.(ring_id) <- - domain_promoted_words.(ring_id) + value + domain_promoted_words.(ring_id) <- domain_promoted_words.(ring_id) + value | Runtime_events.EV_C_MINOR_ALLOCATED_WORDS -> domain_minor_words.(ring_id) <- domain_minor_words.(ring_id) + value | Runtime_events.EV_C_MAJOR_ALLOCATED_WORDS ->