-
Notifications
You must be signed in to change notification settings - Fork 18
Support 5.3 statmemprof #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tmcgilchrist
wants to merge
4
commits into
janestreet:master
Choose a base branch
from
tmcgilchrist:5_1_statmemprof
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
0a6759f
Update for statmemprof in OCaml 5.3
tmcgilchrist 5419af9
Synchronise access to write using Mutex and Atomics
tmcgilchrist 1e56edd
Fix lock_tracer logic for external allocations
grouptheoryiscool e315e21
Instructions for setting up multicore OCaml with statmemprof
tmcgilchrist File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| (dirs bin src test trace_ocamlopt) | ||
| (dirs bin src test trace_ocamlopt examples) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| (executables | ||
| (libraries memtrace domainslib) | ||
| (names fib_par)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| (* fib_par.ml *) | ||
| let num_domains = try int_of_string Sys.argv.(1) with _ -> 1 | ||
| let n = try int_of_string Sys.argv.(2) with _ -> 1 | ||
|
|
||
| (* Sequential Fibonacci *) | ||
| let rec fib n = | ||
| if n < 2 then 1 else fib (n - 1) + fib (n - 2) | ||
|
|
||
| module T = Domainslib.Task | ||
|
|
||
| let rec fib_par pool n = | ||
| let _ = Buffer.create 10000 in | ||
| if n > 20 then begin | ||
| let a = T.async pool (fun _ -> fib_par pool (n-1)) in | ||
| let b = T.async pool (fun _ -> fib_par pool (n-2)) in | ||
| T.await pool a + T.await pool b | ||
| end else | ||
| (* Call sequential Fibonacci if the available work is small *) | ||
| fib n | ||
|
|
||
| let main () = | ||
| Memtrace.trace_if_requested ~context:"fib" (); | ||
| let pool = T.setup_pool ~num_domains:(num_domains - 1) () in | ||
| let res = T.run pool (fun _ -> fib_par pool n) in | ||
| T.teardown_pool pool; | ||
| Printf.printf "fib(%d) = %d\n" n res | ||
|
|
||
| let _ = main () |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,53 +1,42 @@ | ||
| type t = | ||
| { mutable locked : bool; | ||
| mutable locked_ext : bool; | ||
| mutable failed : bool; | ||
| mutable stopped : bool; | ||
| { failed : bool Atomic.t; | ||
| stopped : bool Atomic.t; | ||
| mutex : Mutex.t; | ||
| report_exn : exn -> unit; | ||
| trace : Trace.Writer.t; | ||
| ext_sampler : Geometric_sampler.t; } | ||
|
|
||
| let curr_active_tracer : t option ref = ref None | ||
| let curr_active_tracer : t option Atomic.t = Atomic.make None | ||
|
|
||
| let active_tracer () = !curr_active_tracer | ||
| let active_tracer () = Atomic.get curr_active_tracer | ||
|
|
||
| let bytes_before_ext_sample = ref max_int | ||
| let bytes_before_ext_sample = Atomic.make max_int | ||
|
|
||
| let draw_sampler_bytes t = | ||
| Geometric_sampler.draw t.ext_sampler * (Sys.word_size / 8) | ||
|
|
||
| let[@inline never] rec lock_tracer s = | ||
| if s.locked then | ||
| if s.locked_ext then false | ||
| else (Thread.yield (); lock_tracer s) | ||
| else if s.failed then | ||
| let[@inline never] lock_tracer s = | ||
| if Atomic.get s.failed then | ||
| false | ||
| else | ||
| (s.locked <- true; true) | ||
|
|
||
| let[@inline never] rec lock_tracer_ext s = | ||
| if s.locked then | ||
| (Thread.yield (); lock_tracer_ext s) | ||
| else if s.failed then | ||
| false | ||
| else | ||
| (s.locked <- true; s.locked_ext <- true; true) | ||
| (* During external allocations or closing, a thread may try to obtain | ||
| a lock it already holds. In that case, Mutex.lock will throw | ||
| an error and we can ignore it. *) | ||
| else begin | ||
| try | ||
| Mutex.lock s.mutex; | ||
| true | ||
| with | ||
| | Sys_error _ -> false | ||
| end | ||
|
|
||
| let[@inline never] unlock_tracer s = | ||
| assert (s.locked && not s.locked_ext && not s.failed); | ||
| s.locked <- false | ||
|
|
||
| let[@inline never] unlock_tracer_ext s = | ||
| assert (s.locked && s.locked_ext && not s.failed); | ||
| s.locked_ext <- false; | ||
| s.locked <- false | ||
| assert (not (Atomic.get s.failed)); | ||
| Mutex.unlock s.mutex | ||
|
|
||
| let[@inline never] mark_failed s e = | ||
| assert (s.locked && not s.failed); | ||
| s.failed <- true; | ||
| s.locked <- false; | ||
| s.locked_ext <- false; | ||
| s.report_exn e | ||
| if (Atomic.compare_and_set s.failed false true) then | ||
| s.report_exn e; | ||
| Mutex.unlock s.mutex | ||
|
|
||
| let default_report_exn e = | ||
| match e with | ||
|
|
@@ -63,7 +52,8 @@ let default_report_exn e = | |
|
|
||
| let start ?(report_exn=default_report_exn) ~sampling_rate trace = | ||
| let ext_sampler = Geometric_sampler.make ~sampling_rate () in | ||
| let s = { trace; locked = false; locked_ext = false; stopped = false; failed = false; | ||
| let mutex = Mutex.create () in | ||
| let s = { trace; mutex; stopped = Atomic.make false; failed = Atomic.make false; | ||
| report_exn; ext_sampler } in | ||
| let tracker : (_,_) Gc.Memprof.tracker = { | ||
| alloc_minor = (fun info -> | ||
|
|
@@ -75,8 +65,11 @@ let start ?(report_exn=default_report_exn) ~sampling_rate trace = | |
| ~callstack:info.callstack | ||
| with | ||
| | r -> unlock_tracer s; Some r | ||
| | exception e -> mark_failed s e; None | ||
| end else None); | ||
| | exception e -> | ||
| mark_failed s e; | ||
| None | ||
| end | ||
| else None); | ||
| alloc_major = (fun info -> | ||
| if lock_tracer s then begin | ||
| match Trace.Writer.put_alloc_with_raw_backtrace trace (Trace.Timestamp.now ()) | ||
|
|
@@ -104,68 +97,68 @@ let start ?(report_exn=default_report_exn) ~sampling_rate trace = | |
| match Trace.Writer.put_collect trace (Trace.Timestamp.now ()) id with | ||
| | () -> unlock_tracer s | ||
| | exception e -> mark_failed s e) } in | ||
| curr_active_tracer := Some s; | ||
| bytes_before_ext_sample := draw_sampler_bytes s; | ||
| Gc.Memprof.start | ||
| ~sampling_rate | ||
| ~callstack_size:max_int | ||
| tracker; | ||
| Atomic.set curr_active_tracer (Some s); | ||
| Atomic.set bytes_before_ext_sample (draw_sampler_bytes s); | ||
| let _profile = Gc.Memprof.start ~sampling_rate ~callstack_size:max_int tracker in | ||
| s | ||
|
|
||
| let stop s = | ||
| if not s.stopped then begin | ||
| s.stopped <- true; | ||
| (* Call stop to stop sampling on the current profile. | ||
| Promotion and deallocation callbacks from a profile may run | ||
| after stop is called, however we ignore these callbacks when | ||
| stopping. | ||
| *) | ||
| if (Atomic.compare_and_set s.stopped false true) then begin | ||
| Gc.Memprof.stop (); | ||
| if lock_tracer s then begin | ||
| try Trace.Writer.close s.trace with e -> mark_failed s e | ||
| try Trace.Writer.close s.trace with e -> | ||
| (Atomic.set s.failed true; s.report_exn e); | ||
| Mutex.unlock s.mutex | ||
| end; | ||
| curr_active_tracer := None | ||
| Atomic.set curr_active_tracer None | ||
| end | ||
|
|
||
| let[@inline never] ext_alloc_slowpath ~bytes = | ||
| match !curr_active_tracer with | ||
| | None -> bytes_before_ext_sample := max_int; None | ||
| match Atomic.get curr_active_tracer with | ||
| | None -> Atomic.set bytes_before_ext_sample max_int; None | ||
| | Some s -> | ||
| if lock_tracer_ext s then begin | ||
| if lock_tracer s then begin | ||
| match | ||
| let bytes_per_word = Sys.word_size / 8 in | ||
| (* round up to an integer number of words *) | ||
| let size_words = (bytes + bytes_per_word - 1) / bytes_per_word in | ||
| let samples = ref 0 in | ||
| while !bytes_before_ext_sample <= 0 do | ||
| bytes_before_ext_sample := | ||
| !bytes_before_ext_sample + draw_sampler_bytes s; | ||
| incr samples | ||
| let samples = Atomic.make 0 in | ||
| while Atomic.get bytes_before_ext_sample <= 0 do | ||
| ignore (Atomic.fetch_and_add bytes_before_ext_sample (draw_sampler_bytes s)); | ||
| Atomic.incr samples | ||
| done; | ||
| assert (!samples > 0); | ||
| assert (Atomic.get samples > 0); | ||
| let callstack = Printexc.get_callstack max_int in | ||
| Some (Trace.Writer.put_alloc_with_raw_backtrace s.trace | ||
| (Trace.Timestamp.now ()) | ||
| ~length:size_words | ||
| ~nsamples:!samples | ||
| ~nsamples:(Atomic.get samples) | ||
|
Comment on lines
+130
to
+140
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems that |
||
| ~source:External | ||
| ~callstack) | ||
| with | ||
| | r -> unlock_tracer_ext s; r | ||
| | r -> unlock_tracer s; r | ||
| | exception e -> mark_failed s e; None | ||
| end else None | ||
|
|
||
|
|
||
| type ext_token = Trace.Obj_id.t | ||
|
|
||
| let ext_alloc ~bytes = | ||
| let n = !bytes_before_ext_sample - bytes in | ||
| bytes_before_ext_sample := n; | ||
| let n = Atomic.fetch_and_add bytes_before_ext_sample (- bytes) in | ||
| if n <= 0 then ext_alloc_slowpath ~bytes else None | ||
|
|
||
| let ext_free id = | ||
| match !curr_active_tracer with | ||
| match Atomic.get curr_active_tracer with | ||
| | None -> () | ||
| | Some s -> | ||
| if lock_tracer_ext s then begin | ||
| if lock_tracer s then begin | ||
| match | ||
| Trace.Writer.put_collect s.trace (Trace.Timestamp.now ()) id | ||
| with | ||
| | () -> unlock_tracer_ext s; () | ||
| | () -> unlock_tracer s; () | ||
| | exception e -> mark_failed s e; () | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this consider the ocaml-variants
5.2.0+statmemprof?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was treating that variant as an alpha release until 5.3.0 was available. I don't see much appeal in supporting that now that 5.3 is available.