Search code examples
ocamlocaml-5

Unhandled Exception with OCaml 5.0.0~beta1


I'm inconsistently getting this error in a first experiment with OCaml 5.0.0~beta1:

Fatal error: exception Stdlib.Effect.Unhandled(Domainslib__Task.Wait(_, _))

My setup:

  1. Processor: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
  2. Debian 10 (buster)
  3. opam version 2.1.3 installed as binary from this script
  4. opam switch: "→ 5.0.0~beta1 ocaml-base-compiler.5.0.0~beta1 5.0.0~beta1"

After a quick read of this tutorial, I copied the parallel_matrix_multiply function and added some code in the end just to use it:

open Domainslib

let parallel_matrix_multiply pool a b =
  let i_n = Array.length a in
  let j_n = Array.length b.(0) in
  let k_n = Array.length b in
  let res = Array.make_matrix i_n j_n 0 in

  Task.parallel_for pool ~start:0 ~finish:(i_n - 1) ~body:(fun i ->
    for j = 0 to j_n - 1 do
      for k = 0 to k_n - 1 do
        res.(i).(j) <- res.(i).(j) + a.(i).(k) * b.(k).(j)
      done
    done);
  res ;;

let pool = Task.setup_pool ~num_domains:3 () in
let a = Array.make_matrix 2 2 1 in
let b = Array.make_matrix 2 2 2 in
let c = parallel_matrix_multiply pool a b in
for i = 0 to 1 do
        for j = 0 to 1 do
          Printf.printf "%d " c.(i).(j)
        done;
        print_char '\n'
done;;

I then compile it with no errors with

ocamlfind ocamlopt -linkpkg -package domainslib parallel_for.ml

and then comes the problem: executing the generated a.out file sometimes (rarely) prints the expected output

4 4 
4 4 

but usually ends with the error mentioned earlier:

Fatal error: exception Stdlib.Effect.Unhandled(Domainslib__Task.Wait(_, _))

Sorry if I am making some trivial mistake, but I can't understand what is going on, especially given that the error happens inconsistently.


Solution

  • The parallel_matrix_multiply computation is running outside of the Domainslib scheduler, thus whenever a task yields to the scheduler, the Wait effect is unhandled and transformed into a Effect.Unhandled exception. The solution is to run the parallel computation within Task.run:

    ...
    let c = Task.run pool (fun () -> parallel_matrix_multiply pool a b) in
    ...