123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143(* Reimplementation of the memprof interface for two simultaneous
clients *)moduleMemprof_server=struct(* Main instance *)letstarted_1=reffalse(* Secondary instance : memprof limits *)letstarted_2=reffalseletmake_alloc_callback~sampling_rate~callback_1=letlimits_callback()=Limits_callbacks.callback~sampling_ratein(funx->if!started_2thenlimits_callback();callback_1x)letrecreally_do_stop_memprof()=(* FIXME: loops if already stopped *)tryGc.Memprof.stop()with_->really_do_stop_memprof()letstart~sampling_rate?(callstack_size=max_int)(tracker:('a,'b)Gc.Memprof.tracker)=if!started_1thenfailwith"Memprof.start: already started";letsampling_rate=ifsampling_rate<Limits_callbacks.limits_sampling_ratethenfailwith(Printf.sprintf"Cannot go lower than the memprof-limits sampling rate: %g"Limits_callbacks.limits_sampling_rate)else(* make sure the expectancy is an integer *)1./.(Float.round(1./.sampling_rate))inreally_do_stop_memprof();letalloc_minor=make_alloc_callback~sampling_rate~callback_1:tracker.alloc_minorinletalloc_major=make_alloc_callback~sampling_rate~callback_1:tracker.alloc_majorinlettracker_with_limits={trackerwithalloc_major=alloc_major;alloc_minor=alloc_minor}inGc.Memprof.start~sampling_rate~callstack_sizetracker_with_limits;started_1:=trueletrestart_2()=(* if memprof already runs for 1, then starting amounts to just
setting the flag. *)ifnot!started_1then(letsampling_rate=Limits_callbacks.limits_sampling_rateinletcallback=make_alloc_callback~sampling_rate~callback_1:(fun_->None)inlettracker={Gc.Memprof.null_trackerwithalloc_major=callback;alloc_minor=callback}inGc.Memprof.start~sampling_rate~callstack_size:0tracker);started_2:=trueletstop()=ifnot!started_1thenfailwith"Memprof.start: not started";Gc.Memprof.stop();started_1:=false;if!started_2thenrestart_2()letstart_2()=if!started_2thenfailwith"memprof-limits: already started";restart_2()letstop_2()=ifnot!started_2thenfailwith"memprof-limits: not started";(* if the user uses memprof, then stopping is simply setting the
flag. *)ifnot!started_1thenGc.Memprof.stop();started_2:=falseend(* FIXME: can end in an uninterruptible loop if the user interferes by
calling Gc.Memprof.stop. (Inherits Memprof behaviour.) *)letrecreally_do_stop_2()=tryMemprof_server.stop_2()with_->really_do_stop_2()(* public interface *)letwith_memprof_limitsf=(* let () = match Sys.backend_type with
| Native -> ()
| _ -> failwith "Memprof_limits: unsupported backend type (only \
native is supported)"
in *)Fun.with_resource~acquire:Memprof_server.start_2()f~release:(fun()->really_do_stop_2();Limits_callbacks.reset())letset_global_memory_limitl=Limits_callbacks.global_limit:=lletwith_global_memory_limitx=ifnot!Memprof_server.started_2thenfailwith"with_global_memory_limit: not started";Limits_callbacks.with_global_memory_limitxletwith_allocation_limit~limit=ifnot!Memprof_server.started_2thenfailwith"with_allocation_limit: not started";Limits_callbacks.with_allocation_limit~limitletmax_allocation_limit=Limits_callbacks.max_allocation_limittype'aresult=('a,exn)Result.t(* Export interface to memprof for user's profiling needs *)moduleMemprof=structincludeMemprof_servertypeallocation=Stdlib.Gc.Memprof.allocation=private{n_samples:int;size:int;unmarshalled:bool;callstack:Printexc.raw_backtrace}type('minor,'major)tracker=('minor,'major)Stdlib.Gc.Memprof.tracker={alloc_minor:allocation->'minoroption;alloc_major:allocation->'majoroption;promote:'minor->'majoroption;dealloc_minor:'minor->unit;dealloc_major:'major->unit;}letnull_tracker=Stdlib.Gc.Memprof.null_trackerend