package devkit
Development kit - general purpose library
Install
Dune Dependency
Authors
Maintainers
Sources
devkit-1.20240429.tbz
sha256=222f8ac131b1d970dab7eeb2714bfd6b9338b88b1082e6e01c136ae19e7eaef4
sha512=c9e6d93e3d21e5530c0f4d5baca51bf1f0a5d19248f8af7678d0665bb5cdf295d7aaaaa3e50eb2e44b8720e55097cc675af4dc8ec45acf9da39feb3eae1405d5
doc/src/devkit.core/memory.ml.html
Source file memory.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
(** Memory reporting - GC and OS, optionally malloc General background: - VSZ is not very intersting, this is the amount of memory which is mapped to the process address space. It's not really memory use, only the amount of memory the process can access without triggering a segfault. - RSS is resident set size: this is the real world data. It's tracked by kernel and is the amount of memory currently allocated to this process. Most of the time this is what you want to look at. - Malloc stats: those are metrics tracked by C malloc (jemalloc, tcmalloc, glibc, etc). - size is basically like VSZ but from malloc point of view. That is it does not include mmap files for instance. - used is basically RSS from malloc point of view. - heap is the sum of all currently malloced values for which [free] had not been called. So this is what application requested, not including metadata, cache, etc - Gc stats are one level above and are tracked by ocaml gc. e.g. heap is the total size allocate for ocaml program. See [Gc] module documentation for more details. *) open Prelude open ExtLib open Printf let log = Log.from "memory" type t = { rss : int; (** resident set size *) vsize : int; (** virtual memory size *) nr_maps : int; (** number of VM mappings *) swap_used : int; (** used swap size *) } let get_num = int_of_string $ String.replace_chars (fun c -> if Stre.ASCII.is_digit c then String.of_char c else "") let pagesize = Int64.to_int ExtUnix.Specific.(sysconf PAGESIZE) (** @param swap whether to compute swap used, can be slow (many seconds), default [false] @return virtual memory info *) let get_vm_info ?(swap=false) () = let (vsize,rss) = match Action.file_lines "/proc/self/statm" with | [] -> Log.self #warn "cannot read /proc/self/statm, no VM info"; (0,0) | s::_ -> Scanf.sscanf s "%d %d" (fun vsize rss -> (pagesize * vsize, pagesize * rss)) in let nr_maps = List.length @@ Action.file_lines ("/proc/self/maps") in (* FIXME deleted *) (* process smaps *) let swap_used = match swap with | false -> 0 | true -> Action.file_lines ("/proc/self/smaps") |> List.fold_left (fun acc s -> if Stre.starts_with s "Swap:" then acc + get_num s else acc) 0 in { rss; vsize; nr_maps; swap_used = swap_used * 1024; } let show_vm_info () = let bytes = Action.bytes_string in let { rss; vsize; nr_maps; swap_used } = get_vm_info () in let swap = if swap_used > 0 then sprintf " %s," (bytes swap_used) else "" in sprintf "VM: rss %s, vsz %s,%s maps %d" (bytes rss) (bytes vsize) swap nr_maps let show_gc_heap ?(st=Gc.quick_stat ()) () = let open Action in sprintf "%s (max %s, chunks %d)" (caml_words st.Gc.heap_words) (caml_words st.Gc.top_heap_words) st.Gc.heap_chunks let show_gc_info () = let open Action in let st = Gc.quick_stat () in let gc_heap = show_gc_heap ~st () in let gc_ctrs = sprintf "%s %s %s" (caml_words_f st.Gc.minor_words) (caml_words_f st.Gc.promoted_words) (caml_words_f st.Gc.major_words) in let gc_coll = sprintf "%u %u %u" st.Gc.compactions st.Gc.major_collections st.Gc.minor_collections in sprintf "GC: Heap: %s Counters(mi,pr,ma): %s Collections(mv,ma,mi): %s" gc_heap gc_ctrs gc_coll let show_lwt_info () = let (r, w, t) = Lwt_engine.(readable_count (), writable_count (), timer_count ()) in sprintf "lwt readable %d, writable %d, timer %d" r w t (* hooks for Memory_gperftools *) let show_crt_info = ref (fun () -> "MALLOC: ?") let malloc_release = ref (ignore : unit -> unit) let reclaim_s () = let module A = Action in let st1 = Gc.stat () in let { rss; _ } = get_vm_info () in let t1 = Time.now () in Gc.compact (); let t2 = Time.now () in !malloc_release (); let t3 = Time.now () in let st3 = Gc.stat () in let { rss=rss'; _ } = get_vm_info () in let changed f a b = if a = b then sprintf "= %s" (f a) else sprintf "%s -> %s" (f a) (f b) in sprintf "Memory.reclaim: heap %s live %s freelist %s (%s), rss %s" (changed A.caml_words st1.heap_words st3.heap_words) (changed A.caml_words st1.live_words st3.live_words) (changed string_of_int st1.free_blocks st3.free_blocks) (Time.duration_str @@ t2 -. t1) (if !malloc_release == ignore then A.bytes_string rss else sprintf "%s (%s)" (changed A.bytes_string rss rss') (Time.duration_str @@ t3 -. t2)) let reclaim () = log #info "%s" @@ reclaim_s () let reclaim_silent () = Gc.compact (); !malloc_release () let (add_stats,new_stats,log_stats,get_stats) = let f_print = ref [] in (* called in reverse - and it is fine *) let f_get = ref [] in let log_stats () = List.iter (fun f -> f ()) !f_print; List.iter (fun f -> log #info_s @@ f ()) !f_get in let get_stats () = List.map (fun f -> f ()) !f_get in (tuck f_print), (tuck f_get), log_stats, get_stats let track_global = ref [] let show_global_reachable () = let l = List.map (fun (name,repr) -> sprintf "%s %s" name (Action.caml_words @@ Obj.reachable_words repr)) !track_global in sprintf "reachable: %s" (String.concat " " l) let track_global name var = tuck track_global (name,Obj.repr var) let show_c_info () = sprintf "%s. %s" (show_vm_info ()) (!show_crt_info ()) let show_all_info () = [ show_c_info (); show_gc_info (); show_lwt_info (); ] let log_all_info () = show_all_info () |> List.iter log#info_s let () = new_stats show_c_info let () = new_stats show_gc_info let () = new_stats show_lwt_info let () = new_stats show_global_reachable
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>