What is the semantic of Domain.self()?

Hello,

Does a sequential program has id 0?

How do I even get the underlying integer?

Do I really have to do this:

let my_id: int = Obj.magic (Domain.self ()) in

Does Domain.spawn increments this value by 1?
So, as long as the program is running, there is a domain with id 0.

What is the range of this value?
If we have spawned N domains, is it guaranteed to be in [0,N] ?
0 being the initial domain, 1…N being the additional ones.

I am looking for something like get_rank in MPI.
The ocamldoc for parallel programming in ocaml is not explicit enough
about this domain id thing.
Knowing ones rank is essential in order to compute things using indexes
and guaranteeing that threads don’t walk on each others toes.

Thanks,
F.

Is the first domain id 0, but then for additional spawned threads, it is related to the core
on which I am running?

Are each spawned threads tied to a particular core (core-pinning)?

You could always implement it yourself:

let rank = Domain.DLS.new_key (
  let id = Atomic.make 0 in
  fun () -> Atomic.fetch_and_add id 1)

let get_rank () = Domain.DLS.get rank
3 Likes

You can use (Domain.self () :> int) to get the integer.

The semantics are a mystery to me as well, but I’ve made those assumptions in my experimental code to implement efficient access to domain local stuff (work deque/stack).

1 Like

Not sure if this is helpful at all, but Domain.self indirectly calls a C function named caml_ml_domain_id

It looks like spawn gets a value from the C runtime. The implementation is here:

Note that if you have to look at the runtime implementation this means that you are starting to rely on internal implementation details with no guarantees of backward stability.

In other words, you should consider that the domain ids are opaque identifiers that happen to be integers.

5 Likes

Sure, I can implement it myself, but the fact that such a basic functionality is not implemented worries me.

It also means that the documentation is incomplete / not good enough.

There is nothing basic about get_rank (cf the existence of rank files and communicators). It exists because, in the MPI world, programs are replicated by an external supervising process, e.g., mpiexec -n 16 ./a.out runs 16 instances of a.out on various nodes. In OCaml, the program itself is responsible for spawning as many domains as it needs (on the current node). So, the get_rank approach does not bring anything useful to the table. You can just pass the rank at domain-creation time. Having a get_rank function would not make the code below any simpler or faster.

let foo rank () = ... in
Array.init 16 (fun i -> Domain.spawn (foo i))

It would make your example code simpler.
Because then, the rank of a thread is a global variable only accessible to that thread,
that you don’t need to pass around everywhere, and that you just access when you need it using get_rank().