[ANN] memprof-limits (first official release): Memory limits, allocation limits, and thread cancellation, with interrupt-safe resources

Dear OCamlers, I am satisfied to announce the first official release of the package memprof-limits (v0.2.0).

From the user guide (which has detailed examples and use-cases):

This package lets you interrupt tasks in a thread-safe and resource-safe way, when a resource limit is reached or a cancellation token is set. A task is an isolated piece of computation running within a thread.

Global memory limits interrupt a task when the major heap exceeds a certain size. Allocation limits interrupt a task when a certain number of words have been allocated, a portable mesure of time elapsed and quantity of work done. Token limits interrupt an allocating task when an arbitrary token is set.

It is available on opam for OCaml ≥ 4.12.

The name comes from the fact that it uses OCaml’s Memprof statistical profiler engine (to perform limit checks frequently-enough, related to the allocation rate of the program, and at the same time rarely-enough to not affect performance).

It comes with an implementation of masking that lets you define interrupt-safe resources that are guaranteed to be cleaned-up, and with them ensure that your program remains in a valid state after being interrupted.

To learn more about it, I recommend again the user guide.

Example

You can try it with OCaml 4.12 on the following example (opam install memprof-limits → utop → #require "memprof-limits";;):

A worker task allocates 300M words, only 3k of which live simultaneously. This comes close to an allocation limit of 330M words set by the monitor. The probability that the worker is interrupted is less than 10^-50, and thus the computation successfully completes, in about a second.

(* worker *)
let f () =
 let rec alloc n x =
   if n = 0 then x else alloc (n-1) (()::x)
 in
 (* allocate 300'000 kw *)
 for i = 0 to 100_000 do ignore (alloc 1_000 []) done

(* monitor *)
let g () =
 match Memprof_limits.limit_allocations ~limit:330_000L f with
 | Ok ((), n) -> Printf.printf "success (est. alloc. %#Lu kw)\n" n
 | Error _ -> print_endline "out of fuel"

(* main *)
let () =
 Memprof_limits.start_memprof_limits () ;
 g ()

Changes

Major changes to last year’s experimental release:

  • The internal state is now protected against asynchronous exceptions arising from memprof callbacks (especially the own interrupt of memprof-limits), so it is no longer buggy (“experimental”).
  • And now it works under bytecode too.
  • Added token limits: interrupts that can be triggered at a distance.
  • Detailed guide and reference manuals, now generated by odoc.
  • Features to program with interrupt- and resource-safety in mind.
  • API revamp.

Links

9 Likes

My talk at the OCaml workshop about memprof-limits (and reasoning about exceptions in general) is now available online:

2 Likes