From 3adbe6bcc8af775306016b8a78887f978e6dde27 Mon Sep 17 00:00:00 2001 From: Vesa Karvonen Date: Fri, 27 Sep 2024 16:33:45 +0300 Subject: [PATCH] Port to 4.12 and tweak the implementation for size Also a bit of CI maintenance to test on Windows compiler versions. --- .github/workflows/workflow.yml | 22 +++++++++++++++------- .ocamlformat | 2 +- CHANGES.md | 4 ++-- backoff.opam | 2 +- dune-project | 2 +- src/backoff.ml | 24 ++++++++++++++++++------ 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 7ed49fc..804d1af 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -1,4 +1,4 @@ -name: build-and-test +name: ci on: pull_request: @@ -7,20 +7,28 @@ on: - main jobs: - build-windows: + test-on-windows: + strategy: + fail-fast: false + matrix: + ocaml-compiler: + - ocaml.5.0.0,ocaml-option-mingw + - ocaml.5.1.1,ocaml-option-mingw + - ocaml.5.2.0,ocaml-option-mingw + runs-on: windows-latest steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v3 - - name: Set-up OCaml - uses: ocaml/setup-ocaml@v2 + - name: Set up OCaml + uses: ocaml/setup-ocaml@v3 with: - ocaml-compiler: ocaml.5.0.0,ocaml-option-mingw + ocaml-compiler: ${{ matrix.ocaml-compiler }} opam-repositories: | dra27: https://github.com/dra27/opam-repository.git#windows-5.0 - default: https://github.com/fdopen/opam-repository-mingw.git#opam2 + default: https://github.com/ocaml-opam/opam-repository-mingw.git#sunset standard: https://github.com/ocaml/opam-repository.git - name: Install dependencies diff --git a/.ocamlformat b/.ocamlformat index 29a9cf7..0b457a3 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,2 +1,2 @@ profile = default -version = 0.26.0 +version = 0.26.2 diff --git a/CHANGES.md b/CHANGES.md index 02a66c9..ea0500d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ -# Release notes +## Next version -All notable changes to this project will be documented in this file. +- Ported to 4.12 and optimized for size (@polytypic) ## 0.1.0 diff --git a/backoff.opam b/backoff.opam index b0b0734..bdc7c40 100644 --- a/backoff.opam +++ b/backoff.opam @@ -8,7 +8,7 @@ homepage: "https://github.com/ocaml-multicore/backoff" bug-reports: "https://github.com/ocaml-multicore/backoff/issues" depends: [ "dune" {>= "3.3"} - "ocaml" {>= "4.13"} + "ocaml" {>= "4.12"} "alcotest" {>= "1.7.0" & with-test} "domain_shims" {>= "0.1.0" & with-test} "odoc" {with-doc} diff --git a/dune-project b/dune-project index fbe7f06..3712465 100644 --- a/dune-project +++ b/dune-project @@ -10,6 +10,6 @@ (name backoff) (synopsis "Exponential backoff mechanism for OCaml") (depends - (ocaml (>= 4.13)) + (ocaml (>= 4.12)) (alcotest (and (>= 1.7.0) :with-test)) (domain_shims (and (>= 0.1.0) :with-test)))) diff --git a/src/backoff.ml b/src/backoff.ml index cd8d06f..69bad1f 100644 --- a/src/backoff.ml +++ b/src/backoff.ml @@ -40,15 +40,27 @@ let reset backoff = let lower_wait_log = get_lower_wait_log backoff in backoff land lnot mask lor lower_wait_log -let once backoff = +(* We don't want [once] to be inlined. This may avoid code bloat. *) +let[@inline never] once backoff = + (* We call [Random.bits] first. In this case this helps to reduce register + pressure so that fewer words will be allocated from the stack. *) + let t = Random.bits () in let wait_log = get_wait_log backoff in let wait_mask = (1 lsl wait_log) - 1 in - let t = Random.bits () land wait_mask land single_mask in - for _ = 0 to t do - Domain.cpu_relax () + (* We use a ref and countdown while-loop (uses one variable) instead of a + for-loop (uses two variables) to reduce register pressure. Local ref does + not allocate with native compiler. *) + let t = ref (t land wait_mask land single_mask) in + while 0 <= !t do + Domain.cpu_relax (); + t := !t - 1 done; let upper_wait_log = get_upper_wait_log backoff in - let next_wait_log = Int.min upper_wait_log (wait_log + 1) in - backoff lxor wait_log lor next_wait_log + (* We recompute [wait_log] to reduce register pressure. *) + let wait_log = get_wait_log backoff in + (* [Bool.to_int] generates branchless code, this reduces branch predictor + pressure and generates shorter code. *) + let next_wait_log = wait_log + Bool.to_int (wait_log < upper_wait_log) in + backoff - wait_log + next_wait_log let default = create ()