Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions rewatch-ocaml/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ to choose another count: a positive integer, lowered to the machine's limit of
`max(12, min(32, CPUs))`. The main domain schedules dependencies;
workers run compiler requests and publish what they produce.

The runtime's allocation report at exit (`OCAMLRUNPARAM=v=0x400`) only counts
the main domain. With `REWATCH_REPORT_WORKER_ALLOCATIONS` set, the build also
prints `worker_allocated_words: <n>`, the words its workers allocated, which
the compiler benchmarks (`scripts/compilerBenchmarks.js`) add to it.

The driver gives each request fresh compiler state (flags, warnings, caches,
predefined types, identifier counters) and restores it on every exit, so
requests on different domains don't interfere and repeated requests produce
Expand Down
24 changes: 20 additions & 4 deletions rewatch-ocaml/process.ml
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,20 @@ let rec worker_loop pool =
memory. 8M added memory for little more speed. *)
let worker_minor_heap_words = 4 * 1024 * 1024

(* The words that finished workers allocated. The runtime's own report at exit
(OCAMLRUNPARAM=v=0x400) counts only the main domain, so the compiler
benchmarks add these to it. Allocated words are counted as the runtime
counts them: minor plus major, without the promoted ones. *)
let worker_allocated_words_total = Atomic.make 0

let record_worker_allocations () =
let minor, promoted, major = Gc.counters () in
ignore
(Atomic.fetch_and_add worker_allocated_words_total
(int_of_float (minor +. major -. promoted)))

let worker_allocated_words () = Atomic.get worker_allocated_words_total

let create_worker_pool ~max_jobs notifier =
let pool =
{
Expand All @@ -251,10 +265,12 @@ let create_worker_pool ~max_jobs notifier =
before re-raising the first error. *)
let run_worker () =
Gc.set {(Gc.get ()) with minor_heap_size = worker_minor_heap_words};
try worker_loop pool
with exn ->
Child.with_lock pool.mutex (fun () ->
if Option.is_none pool.worker_error then pool.worker_error <- Some exn)
(try worker_loop pool
with exn ->
Child.with_lock pool.mutex (fun () ->
if Option.is_none pool.worker_error then
pool.worker_error <- Some exn));
record_worker_allocations ()
in
let rec start_workers remaining =
if remaining > 0 then (
Expand Down
4 changes: 4 additions & 0 deletions rewatch-ocaml/process.mli
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ val succeeded : result -> bool
val status_string : Unix.process_status -> string
val default_max_jobs : int

val worker_allocated_words : unit -> int
(** The words that the worker domains of finished worker pools allocated,
which the runtime's report at exit leaves out. *)

val task : ?env:Spawn.Env.t -> ?on_result:(result -> result) -> job -> task
val concurrent_task :
cancel:(unit -> unit) ->
Expand Down
10 changes: 10 additions & 0 deletions rewatch-ocaml/rescript_ocaml.ml
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,18 @@ let run = function
| command ->
with_termination_handlers (fun ~poll -> run_command ~poll command)

(* For the compiler benchmarks (scripts/compilerBenchmarks.js): the runtime's
report at exit only counts the main domain's allocations, and the compiler
runs on worker domains. *)
let report_worker_allocations () =
if Option.is_some (Sys.getenv_opt "REWATCH_REPORT_WORKER_ALLOCATIONS") then
at_exit (fun () ->
Printf.eprintf "worker_allocated_words: %d\n%!"
(Process.worker_allocated_words ()))

let main () =
Platform.configure_standard_streams ();
report_worker_allocations ();
try
match Cli.eval Sys.argv with
| Cli.Run command -> run command
Expand Down
16 changes: 16 additions & 0 deletions rewatch-ocaml/tests/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2398,3 +2398,19 @@ for attempt in first second; do
exit 1
fi
done

# The compiler benchmarks add the words the worker domains allocated, which
# the runtime's report at exit leaves out, to that report.
worker_allocations="$work/worker-allocations"
mkdir -p "$worker_allocations/src"
printf '%s\n' \
'{"name":"worker-allocations","sources":"src","package-specs":{"module":"esmodule","in-source":true,"suffix":".mjs"}}' \
>"$worker_allocations/rescript.json"
printf 'let x = 1\n' >"$worker_allocations/src/A.res"
env REWATCH_REPORT_WORKER_ALLOCATIONS=1 REWATCH_COMPILER_DOMAINS=1 \
"$port" build "$worker_allocations" >"$worker_allocations/build.log" 2>&1
worker_words=$(sed -n 's/^worker_allocated_words: \([0-9]*\)$/\1/p' "$worker_allocations/build.log")
if ! test "${worker_words:-0}" -gt 0; then
cat "$worker_allocations/build.log" >&2
exit 1
fi
Loading