cache line locking on AMD x86_64 utilising L3 CAT pseudo-locking
26

Configure Feed

Select the types of activity you want to include in your feed.

icepick / bindings / ocaml / icepick.ml
9.8 kB 287 lines
1open Ctypes 2open Foreign 3 4exception Icepick_error of string 5 6type prime_strategy = 7 | Prime_temporal 8 | Prime_prefetcht2 9 | Prime_prefetchnta 10 | Prime_nt_store 11 12type access_pattern = 13 | Pattern_sequential 14 | Pattern_reverse 15 | Pattern_strided 16 | Pattern_pointer_chase 17 18let () = Callback.register_exception "Icepick_error" (Icepick_error "") 19 20let () = 21 let _ = Dl.dlopen ~filename:"/home/oni/Projects/icepick/libicepick.so" 22 ~flags:[Dl.RTLD_NOW; Dl.RTLD_GLOBAL] in 23 () 24 25module C = struct 26 let icepick_strerror = foreign "icepick_strerror" (int @-> returning string) 27 28 let check_error ret = 29 if ret < 0 then raise (Icepick_error (icepick_strerror ret)) 30 31 module Topology = struct 32 type t = unit ptr 33 let t : t typ = ptr void 34 35 let discover = foreign "icepick_discover_topology" (ptr t @-> returning int) 36 let free = foreign "icepick_free_topology" (t @-> returning void) 37 let l3_ways = foreign "icepick_topology_l3_ways" (t @-> returning uint) 38 let l3_size = foreign "icepick_topology_l3_size" (t @-> returning size_t) 39 let way_size = foreign "icepick_topology_way_size" (t @-> returning size_t) 40 let max_clos = foreign "icepick_topology_max_clos" (t @-> returning uint) 41 let ccx_count = foreign "icepick_topology_ccx_count" (t @-> returning uint) 42 let cat_supported = foreign "icepick_topology_cat_supported" (t @-> returning bool) 43 end 44 45 module Region = struct 46 type t = unit ptr 47 let t : t typ = ptr void 48 49 let ptr = foreign "icepick_region_ptr" (t @-> returning (ptr void)) 50 let size = foreign "icepick_region_size" (t @-> returning size_t) 51 let clos = foreign "icepick_region_clos" (t @-> returning uint) 52 end 53 54 module Config = struct 55 type t 56 let t : t structure typ = structure "icepick_config_t" 57 let size = field t "size" size_t 58 let clos_id = field t "clos_id" uint 59 let numa_node = field t "numa_node" int 60 let huge_pages = field t "huge_pages" bool 61 let verify = field t "verify" bool 62 let auto_monitor = field t "auto_monitor" bool 63 let pmu_poll_interval_ns = field t "pmu_poll_interval_ns" uint64_t 64 let probe_interval_ns = field t "probe_interval_ns" uint64_t 65 let miss_threshold = field t "miss_threshold" uint32_t 66 let prime_strategy = field t "prime_strategy" int 67 let access_pattern = field t "access_pattern" int 68 let stride_bytes = field t "stride_bytes" size_t 69 let prime_iterations = field t "prime_iterations" uint 70 let () = seal t 71 end 72 73 module Latency_stats = struct 74 type t 75 let t : t structure typ = structure "icepick_latency_stats_t" 76 let mean_ns = field t "mean_ns" uint64_t 77 let stddev_ns = field t "stddev_ns" uint64_t 78 let p50_ns = field t "p50_ns" uint64_t 79 let p99_ns = field t "p99_ns" uint64_t 80 let p999_ns = field t "p999_ns" uint64_t 81 let min_ns = field t "min_ns" uint64_t 82 let max_ns = field t "max_ns" uint64_t 83 let () = seal t 84 end 85 86 let lock = foreign "icepick_lock" 87 (Topology.t @-> ptr Config.t @-> ptr Region.t @-> returning int) 88 89 let unlock = foreign "icepick_unlock" (Region.t @-> returning int) 90 91 let verify = foreign "icepick_verify" 92 (Region.t @-> ptr Latency_stats.t @-> returning int) 93 94 let bench = foreign "icepick_bench" 95 (ptr void @-> size_t @-> size_t @-> ptr Latency_stats.t @-> returning int) 96 97 module Monitor = struct 98 type t = unit ptr 99 let t : t typ = ptr void 100 101 let start = foreign "icepick_monitor_start" (Region.t @-> ptr t @-> returning int) 102 let start_ex = foreign "icepick_monitor_start_ex" 103 (Region.t @-> uint64_t @-> uint64_t @-> uint32_t @-> ptr t @-> returning int) 104 let stop = foreign "icepick_monitor_stop" (t @-> returning int) 105 let eviction_count = foreign "icepick_monitor_eviction_count" (t @-> returning uint64_t) 106 let reprime_count = foreign "icepick_monitor_reprime_count" (t @-> returning uint64_t) 107 let is_degraded = foreign "icepick_monitor_is_degraded" (t @-> returning bool) 108 end 109end 110 111module Topology = struct 112 type t = { 113 ptr : C.Topology.t; 114 mutable released : bool; 115 } 116 117 let release t = 118 if not t.released then begin 119 C.Topology.free t.ptr; 120 t.released <- true 121 end 122 123 let discover () = 124 let ptr_ref = allocate C.Topology.t (from_voidp void null) in 125 let ret = C.Topology.discover ptr_ref in 126 C.check_error ret; 127 let t = { ptr = !@ ptr_ref; released = false } in 128 Gc.finalise release t; 129 t 130 131 let l3_ways t = Unsigned.UInt.to_int (C.Topology.l3_ways t.ptr) 132 let l3_size t = Unsigned.Size_t.to_int (C.Topology.l3_size t.ptr) 133 let way_size t = Unsigned.Size_t.to_int (C.Topology.way_size t.ptr) 134 let max_clos t = Unsigned.UInt.to_int (C.Topology.max_clos t.ptr) 135 let ccx_count t = Unsigned.UInt.to_int (C.Topology.ccx_count t.ptr) 136 let cat_supported t = C.Topology.cat_supported t.ptr 137end 138 139module Latency_stats = struct 140 type t = { 141 mean_ns : int; 142 stddev_ns : int; 143 p50_ns : int; 144 p99_ns : int; 145 p999_ns : int; 146 min_ns : int; 147 max_ns : int; 148 } 149 150 let of_c stats = 151 { 152 mean_ns = Unsigned.UInt64.to_int (getf stats C.Latency_stats.mean_ns); 153 stddev_ns = Unsigned.UInt64.to_int (getf stats C.Latency_stats.stddev_ns); 154 p50_ns = Unsigned.UInt64.to_int (getf stats C.Latency_stats.p50_ns); 155 p99_ns = Unsigned.UInt64.to_int (getf stats C.Latency_stats.p99_ns); 156 p999_ns = Unsigned.UInt64.to_int (getf stats C.Latency_stats.p999_ns); 157 min_ns = Unsigned.UInt64.to_int (getf stats C.Latency_stats.min_ns); 158 max_ns = Unsigned.UInt64.to_int (getf stats C.Latency_stats.max_ns); 159 } 160end 161 162module Region = struct 163 type t = { 164 ptr : C.Region.t; 165 topo : Topology.t; 166 mutable released : bool; 167 } 168 169 let release t = 170 if not t.released then begin 171 let _ = C.unlock t.ptr in 172 t.released <- true 173 end 174 175 let prime_strategy_to_int = function 176 | Prime_temporal -> 0 177 | Prime_prefetcht2 -> 1 178 | Prime_prefetchnta -> 2 179 | Prime_nt_store -> 3 180 181 let access_pattern_to_int = function 182 | Pattern_sequential -> 0 183 | Pattern_reverse -> 1 184 | Pattern_strided -> 2 185 | Pattern_pointer_chase -> 3 186 187 let lock topo ~size ~clos ?(numa = -1) ?(huge_pages = true) ?(verify = false) 188 ?(prime_strategy = Prime_temporal) ?(access_pattern = Pattern_sequential) 189 ?(stride = 0) ?(prime_iterations = 3) () = 190 let cfg = make C.Config.t in 191 setf cfg C.Config.size (Unsigned.Size_t.of_int size); 192 setf cfg C.Config.clos_id (Unsigned.UInt.of_int clos); 193 setf cfg C.Config.numa_node numa; 194 setf cfg C.Config.huge_pages huge_pages; 195 setf cfg C.Config.verify verify; 196 setf cfg C.Config.auto_monitor false; 197 setf cfg C.Config.pmu_poll_interval_ns (Unsigned.UInt64.of_int 0); 198 setf cfg C.Config.probe_interval_ns (Unsigned.UInt64.of_int 0); 199 setf cfg C.Config.miss_threshold (Unsigned.UInt32.of_int 0); 200 setf cfg C.Config.prime_strategy (prime_strategy_to_int prime_strategy); 201 setf cfg C.Config.access_pattern (access_pattern_to_int access_pattern); 202 setf cfg C.Config.stride_bytes (Unsigned.Size_t.of_int stride); 203 setf cfg C.Config.prime_iterations (Unsigned.UInt.of_int prime_iterations); 204 let ptr_ref = allocate C.Region.t (from_voidp void null) in 205 let ret = C.lock topo.Topology.ptr (addr cfg) ptr_ref in 206 C.check_error ret; 207 let t = { ptr = !@ ptr_ref; topo; released = false } in 208 Gc.finalise release t; 209 t 210 211 let unlock t = 212 if not t.released then begin 213 let ret = C.unlock t.ptr in 214 t.released <- true; 215 C.check_error ret 216 end 217 218 let ptr t = raw_address_of_ptr (C.Region.ptr t.ptr) 219 let size t = Unsigned.Size_t.to_int (C.Region.size t.ptr) 220 let clos t = Unsigned.UInt.to_int (C.Region.clos t.ptr) 221 222 let to_bigarray_float64 t = 223 let region_ptr = C.Region.ptr t.ptr in 224 let region_size = Unsigned.Size_t.to_int (C.Region.size t.ptr) in 225 let len = region_size / 8 in 226 let typed_ptr = from_voidp double (to_voidp region_ptr) in 227 CArray.from_ptr typed_ptr len |> CArray.to_list |> Array.of_list |> 228 Bigarray.Array1.of_array Bigarray.Float64 Bigarray.c_layout 229end 230 231module Monitor = struct 232 type t = { 233 ptr : C.Monitor.t; 234 region : Region.t; 235 mutable stopped : bool; 236 } 237 238 let release t = 239 if not t.stopped then begin 240 let _ = C.Monitor.stop t.ptr in 241 t.stopped <- true 242 end 243 244 let start region = 245 let ptr_ref = allocate C.Monitor.t (from_voidp void null) in 246 let ret = C.Monitor.start region.Region.ptr ptr_ref in 247 C.check_error ret; 248 let t = { ptr = !@ ptr_ref; region; stopped = false } in 249 Gc.finalise release t; 250 t 251 252 let start_ex region ~pmu_poll_ns ~probe_ns ~miss_thresh = 253 let ptr_ref = allocate C.Monitor.t (from_voidp void null) in 254 let ret = C.Monitor.start_ex region.Region.ptr 255 (Unsigned.UInt64.of_int pmu_poll_ns) 256 (Unsigned.UInt64.of_int probe_ns) 257 (Unsigned.UInt32.of_int miss_thresh) 258 ptr_ref in 259 C.check_error ret; 260 let t = { ptr = !@ ptr_ref; region; stopped = false } in 261 Gc.finalise release t; 262 t 263 264 let stop t = 265 if not t.stopped then begin 266 let ret = C.Monitor.stop t.ptr in 267 t.stopped <- true; 268 C.check_error ret 269 end 270 271 let eviction_count t = Unsigned.UInt64.to_int (C.Monitor.eviction_count t.ptr) 272 let reprime_count t = Unsigned.UInt64.to_int (C.Monitor.reprime_count t.ptr) 273 let is_degraded t = C.Monitor.is_degraded t.ptr 274end 275 276let verify region = 277 let stats = make C.Latency_stats.t in 278 let ret = C.verify region.Region.ptr (addr stats) in 279 C.check_error ret; 280 Latency_stats.of_c stats 281 282let bench ptr ~size ~iterations = 283 let stats = make C.Latency_stats.t in 284 let p = ptr_of_raw_address ptr in 285 let ret = C.bench p (Unsigned.Size_t.of_int size) (Unsigned.Size_t.of_int iterations) (addr stats) in 286 C.check_error ret; 287 Latency_stats.of_c stats