1919
2020type slot = Printexc .backtrace_slot
2121
22+ let equal_slot s1 s2 =
23+ let name_eq =
24+ Option. equal String. equal (Printexc.Slot. name s1) (Printexc.Slot. name s2)
25+ in
26+ let loc1 = Printexc.Slot. location s1 in
27+ let loc2 = Printexc.Slot. location s2 in
28+ let loc_eq =
29+ match (loc1, loc2) with
30+ | None , None -> true
31+ | Some l1 , Some l2 ->
32+ l1.filename = l2.filename && l1.line_number = l2.line_number
33+ | _ , _ -> false
34+ in
35+ name_eq && loc_eq
36+
37+ (* Looking ahead by up to 3 can be useful for recursive functions to make them
38+ much more legible. E.g. List.map can be very recursive, and pyroscope has a
39+ ~1000 stack frame limit, so if we iterate through say, 10k items there's a
40+ good chance we may max out, which will cause any frames past the limit to be
41+ dropped and instead replaced with a single frame that says "other".
42+
43+ It's also nice to do this on the client side since it reduces how much data
44+ we have to turn into runtime events and reduces the overall number of events
45+ since there will be less partial events needed.
46+ *)
47+ let compress_slot_array array =
48+ (* TODO how to do this inline w/an array? *)
49+ let array_list = Array. to_list array in
50+ let rec aux acc = function
51+ | [] -> List. rev acc
52+ | s1 :: s2 :: s3 :: (s4 :: s5 :: s6 :: _ as rest)
53+ when equal_slot s1 s4 && equal_slot s2 s5 && equal_slot s3 s6 ->
54+ aux acc rest
55+ | s1 :: s2 :: (s3 :: s4 :: _ as rest)
56+ when equal_slot s1 s3 && equal_slot s2 s4 ->
57+ aux acc rest
58+ | s1 :: (s2 :: _ as rest ) when equal_slot s1 s2 -> aux acc rest
59+ | s :: rest -> aux (s :: acc) rest
60+ in
61+ aux [] array_list
62+
2263(* What's sent via runtime events. this HAS to be marshalable*)
2364type raw_stack_trace = {
24- slots : slot array ;
65+ slots : slot list ;
2566 domain_id : int ;
2667 thread_name : string ;
2768}
@@ -33,7 +74,12 @@ let raw_stack_trace_of_backtrace bt : raw_stack_trace =
3374 (* Nice to call it main but probably not necessary *)
3475 let name = if Domain. is_main_domain () then " main" else string_of_int did in
3576 (* if there aren't any slots then not much we can do *)
36- let slots = Option. value ~default: [||] Printexc. (backtrace_slots bt) in
77+ let slots =
78+ bt
79+ |> Printexc. (backtrace_slots)
80+ |> Option. map compress_slot_array
81+ |> Option. value ~default: []
82+ in
3783 { slots; domain_id = did; thread_name = name }
3884
3985(* ****************************************************************************)
@@ -65,27 +111,7 @@ let stack_frame_of_slot (slot : Printexc.backtrace_slot) : frame =
65111 let inlined = Printexc.Slot. is_inline slot in
66112 { name; filename; line; inlined }
67113
68- (* Looking ahead by up to 3 can be useful for recursive functions to make them
69- much more legible. E.g. List.map can be very recursive, and pyroscope has a
70- ~1000 stack frame limit, so if we iterate through say, 10k items there's a
71- good chance we may max out, which will cause any frames past the limit to be
72- dropped and instead replaced with a single frame that says "other"*)
73- let compress frames =
74- let rec aux acc = function
75- | [] -> List. rev acc
76- | f1 :: f2 :: f3 :: (f4 :: f5 :: f6 :: _ as rest)
77- when equal_frame f1 f4 && equal_frame f2 f5 && equal_frame f3 f6 ->
78- aux acc rest
79- | f1 :: f2 :: (f3 :: f4 :: _ as rest)
80- when equal_frame f1 f3 && equal_frame f2 f4 ->
81- aux acc rest
82- | f1 :: (f2 :: _ as rest ) when equal_frame f1 f2 -> aux acc rest
83- | f :: rest -> aux (f :: acc) rest
84- in
85- aux [] frames
86-
87- let stack_frames_of_slots slots =
88- slots |> List. map stack_frame_of_slot |> compress
114+ let stack_frames_of_slots = List. map stack_frame_of_slot
89115
90116(* ****************************************************************************)
91117(* Stack traces *)
@@ -94,7 +120,7 @@ let stack_frames_of_slots slots =
94120type t = { frames : frame list ; thread_id : int ; thread_name : string }
95121
96122let t_of_raw_stack_trace raw_stack_trace =
97- let frames = stack_frames_of_slots ( Array. to_list raw_stack_trace.slots) in
123+ let frames = stack_frames_of_slots raw_stack_trace.slots in
98124 {
99125 frames;
100126 thread_id = raw_stack_trace.domain_id;
0 commit comments