upstream: https://github.com/janestreet/memtrace
at main 117 lines 3.4 kB view raw
1open Memtrace.Trace 2 3module Str_tbl = Hashtbl.Make (struct 4 type t = string 5 6 let equal = String.equal 7 let hash = Hashtbl.hash 8end) 9 10type summary = { mutable samples : int; subsums : summary Str_tbl.t } 11 12let rec dedup = function 13 | [] -> [] 14 | [ x ] -> [ x ] 15 | x :: x' :: xs when x = x' -> dedup (x :: xs) 16 | x :: xs -> x :: dedup xs 17 18let process_alloc_backtrace trace backtrace_buffer backtrace_length = 19 let str_of_location (l : Location.t) = 20 l.defname 21 (*Printf.sprintf "%s:%d" filename line*) 22 in 23 let _print_location ppf Location.{ filename; line; start_char; end_char; _ } = 24 Fmt.pf ppf "%s:%d:%d-%d" filename line start_char end_char 25 in 26 let filenames = 27 List.concat 28 (Array.sub backtrace_buffer 0 backtrace_length 29 |> Array.map (fun l -> 30 let locs = Reader.lookup_location_code trace l in 31 List.map 32 (fun (Location.{ filename = _; _ } as l) -> str_of_location l) 33 locs) 34 |> Array.to_list) 35 in 36 let seen = Str_tbl.create 10 in 37 let filenames = dedup filenames in 38 let first_filenames = (*List.rev*) filenames in 39 first_filenames 40 |> List.filter (fun f -> 41 if Str_tbl.mem seen f then false 42 else ( 43 Str_tbl.add seen f (); 44 true)) 45 46let rec dump_summary files_rev summary = 47 (if summary.samples > 0 then 48 match List.rev files_rev with 49 | [] -> () 50 | [ _ ] -> () 51 | x :: xs -> 52 Fmt.pr "%s" x; 53 List.iter (Fmt.pr ";%s") xs; 54 Fmt.pr " %d@\n" summary.samples); 55 let keys = 56 Str_tbl.fold (fun k _ ks -> k :: ks) summary.subsums [] 57 |> List.sort String.compare 58 in 59 keys 60 |> List.iter (fun f -> 61 let s = Str_tbl.find summary.subsums f in 62 dump_summary (f :: files_rev) s) 63 64let summary filename = 65 let summary = { samples = 0; subsums = Str_tbl.create 20 } in 66 let count (filenames, nsamples) = 67 let lastsum = 68 List.fold_left 69 (fun sum f -> 70 if Str_tbl.mem sum.subsums f then Str_tbl.find sum.subsums f 71 else 72 let s = { samples = 0; subsums = Str_tbl.create 10 } in 73 Str_tbl.add sum.subsums f s; 74 s) 75 summary filenames 76 in 77 lastsum.samples <- lastsum.samples + nsamples 78 in 79 let allocs = Hashtbl.create 20 in 80 let sz = ref 0 in 81 let nallocs = ref 0 in 82 let trace = Reader.open_ ~filename in 83 Reader.iter trace (fun _time ev -> 84 match ev with 85 | Alloc 86 { 87 obj_id; 88 length = _; 89 domain = _; 90 nsamples; 91 source = _; 92 backtrace_buffer; 93 backtrace_length; 94 common_prefix = _; 95 } -> 96 let first_filenames = 97 process_alloc_backtrace trace backtrace_buffer backtrace_length 98 in 99 Hashtbl.add allocs obj_id (first_filenames, nsamples); 100 sz := !sz + backtrace_length; 101 incr nallocs; 102 if true then count (first_filenames, nsamples) 103 (* count (first_filenames, nsamples) *) 104 (* first_filenames |> List.iter (Printf.printf " %s"); 105 Printf.printf "\n%!"*) 106 | Promote _ -> () 107 (*count (Hashtbl.find allocs i)*) 108 | Collect (i, _) -> 109 assert (Hashtbl.mem allocs i); 110 Hashtbl.remove allocs i); 111 Reader.close trace; 112 dump_summary [] summary 113 114let () = 115 if Array.length Sys.argv <> 2 then 116 Fmt.epr "Usage: %s <trace file>@\n" Sys.executable_name 117 else summary Sys.argv.(1)