The unpac monorepo manager self-hosting as a monorepo using unpac
0
fork

Configure Feed

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

Merge pull request #70 from talex5/probe

Add support for uring probes

authored by

Thomas Leonard and committed by
GitHub
bf83ebcf d4e50e39

+202 -43
+1
README.md
··· 62 62 | Some { result; data } -> result, data;; 63 63 ``` 64 64 65 + <!-- $MDX non-deterministic=output --> 65 66 ```ocaml 66 67 # let result, data = wait_with_retry uring;; 67 68 val result : int = 8
+5
lib/uring/dune
··· 12 12 13 13 (rule 14 14 (targets config.ml) 15 + (deps 16 + include/liburing.h 17 + include/liburing/io_uring.h 18 + include/liburing/barrier.h 19 + include/liburing/compat.h) 15 20 (action (run ./include/discover.exe))) 16 21 17 22 (rule
+115 -42
lib/uring/include/discover.ml
··· 2 2 3 3 let () = 4 4 C.main ~name:"discover" (fun c -> 5 - C.C_define.import c ~c_flags:["-D_GNU_SOURCE"] 6 - ~includes:["fcntl.h"; "poll.h"; "sys/uio.h"; "linux/time_types.h"] 7 - C.C_define.Type.[ 8 - "POLLIN", Int; 9 - "POLLOUT", Int; 10 - "POLLERR", Int; 11 - "POLLHUP", Int; 5 + let defs = 6 + C.C_define.import c ~c_flags:["-D_GNU_SOURCE"; "-I"; Filename.concat (Sys.getcwd ()) "include"] 7 + ~includes:["fcntl.h"; "poll.h"; "sys/uio.h"; "liburing.h"] 8 + C.C_define.Type.[ 9 + "POLLIN", Int; 10 + "POLLOUT", Int; 11 + "POLLERR", Int; 12 + "POLLHUP", Int; 12 13 13 - "O_RDONLY", Int; 14 - "O_WRONLY", Int; 15 - "O_RDWR", Int; 16 - "O_CREAT", Int; 17 - "O_EXCL", Int; 18 - "O_NOCTTY", Int; 19 - "O_TRUNC", Int; 20 - "O_APPEND", Int; 21 - "O_NONBLOCK", Int; 22 - "O_DSYNC", Int; 23 - "O_DIRECT", Int; 24 - "O_LARGEFILE", Int; 25 - "O_DIRECTORY", Int; 26 - "O_NOFOLLOW", Int; 27 - "O_NOATIME", Int; 28 - "O_CLOEXEC", Int; 29 - "O_SYNC", Int; 30 - "O_PATH", Int; 31 - "O_TMPFILE", Int; 14 + "O_RDONLY", Int; 15 + "O_WRONLY", Int; 16 + "O_RDWR", Int; 17 + "O_CREAT", Int; 18 + "O_EXCL", Int; 19 + "O_NOCTTY", Int; 20 + "O_TRUNC", Int; 21 + "O_APPEND", Int; 22 + "O_NONBLOCK", Int; 23 + "O_DSYNC", Int; 24 + "O_DIRECT", Int; 25 + "O_LARGEFILE", Int; 26 + "O_DIRECTORY", Int; 27 + "O_NOFOLLOW", Int; 28 + "O_NOATIME", Int; 29 + "O_CLOEXEC", Int; 30 + "O_SYNC", Int; 31 + "O_PATH", Int; 32 + "O_TMPFILE", Int; 32 33 33 - "AT_FDCWD", Int; 34 + "AT_FDCWD", Int; 34 35 35 - "sizeof(struct iovec)", Int; 36 - "sizeof(struct __kernel_timespec)", Int; 37 - ] 38 - |> List.map (function 39 - | name, C.C_define.Value.Int v -> 40 - let name = 41 - match name with 42 - | "sizeof(struct iovec)" -> "sizeof_iovec" 43 - | "sizeof(struct __kernel_timespec)" -> "sizeof_kernel_timespec" 44 - | nm -> nm 45 - in 46 - Printf.sprintf "let %s = 0x%x" (String.lowercase_ascii name) v 47 - | _ -> assert false 48 - ) 49 - |> C.Flags.write_lines "config.ml" 36 + "sizeof(struct iovec)", Int; 37 + "sizeof(struct __kernel_timespec)", Int; 38 + ] 39 + |> List.map (function 40 + | name, C.C_define.Value.Int v -> 41 + let name = 42 + match name with 43 + | "sizeof(struct iovec)" -> "sizeof_iovec" 44 + | "sizeof(struct __kernel_timespec)" -> "sizeof_kernel_timespec" 45 + | nm -> nm 46 + in 47 + Printf.sprintf "let %s = 0x%x" (String.lowercase_ascii name) v 48 + | _ -> assert false 49 + ) 50 + in 51 + let ops = 52 + C.C_define.import c ~c_flags:["-D_GNU_SOURCE"; "-I"; Filename.concat (Sys.getcwd ()) "include"] 53 + ~includes:["liburing.h"] 54 + C.C_define.Type.[ 55 + "IORING_OP_NOP", Int; 56 + "IORING_OP_READV", Int; 57 + "IORING_OP_WRITEV", Int; 58 + "IORING_OP_FSYNC", Int; 59 + "IORING_OP_READ_FIXED", Int; 60 + "IORING_OP_WRITE_FIXED", Int; 61 + "IORING_OP_POLL_ADD", Int; 62 + "IORING_OP_POLL_REMOVE", Int; 63 + "IORING_OP_SYNC_FILE_RANGE", Int; 64 + "IORING_OP_SENDMSG", Int; 65 + "IORING_OP_RECVMSG", Int; 66 + "IORING_OP_TIMEOUT", Int; 67 + "IORING_OP_TIMEOUT_REMOVE", Int; 68 + "IORING_OP_ACCEPT", Int; 69 + "IORING_OP_ASYNC_CANCEL", Int; 70 + "IORING_OP_LINK_TIMEOUT", Int; 71 + "IORING_OP_CONNECT", Int; 72 + "IORING_OP_FALLOCATE", Int; 73 + "IORING_OP_OPENAT", Int; 74 + "IORING_OP_CLOSE", Int; 75 + "IORING_OP_FILES_UPDATE", Int; 76 + "IORING_OP_STATX", Int; 77 + "IORING_OP_READ", Int; 78 + "IORING_OP_WRITE", Int; 79 + "IORING_OP_FADVISE", Int; 80 + "IORING_OP_MADVISE", Int; 81 + "IORING_OP_SEND", Int; 82 + "IORING_OP_RECV", Int; 83 + "IORING_OP_OPENAT2", Int; 84 + "IORING_OP_EPOLL_CTL", Int; 85 + "IORING_OP_SPLICE", Int; 86 + "IORING_OP_PROVIDE_BUFFERS", Int; 87 + "IORING_OP_REMOVE_BUFFERS", Int; 88 + "IORING_OP_TEE", Int; 89 + "IORING_OP_SHUTDOWN", Int; 90 + "IORING_OP_RENAMEAT", Int; 91 + "IORING_OP_UNLINKAT", Int; 92 + "IORING_OP_MKDIRAT", Int; 93 + "IORING_OP_SYMLINKAT", Int; 94 + "IORING_OP_LINKAT", Int; 95 + "IORING_OP_MSG_RING", Int; 96 + "IORING_OP_FSETXATTR", Int; 97 + "IORING_OP_SETXATTR", Int; 98 + "IORING_OP_FGETXATTR", Int; 99 + "IORING_OP_GETXATTR", Int; 100 + "IORING_OP_SOCKET", Int; 101 + "IORING_OP_URING_CMD", Int; 102 + ] 103 + |> List.map (function 104 + | name, C.C_define.Value.Int v -> 105 + let prefix_len = String.length "IORING_OP_" in 106 + let ocaml_name = String.sub name prefix_len (String.length name - prefix_len) |> String.lowercase_ascii in 107 + (ocaml_name, v) 108 + | _ -> assert false 109 + ) 110 + in 111 + let op_sig = List.map (fun (name, _) -> Printf.sprintf " val %s : t" name) ops in 112 + let op_struct = List.map (fun (name, v) -> Printf.sprintf " let %s = 0x%x" name v) ops in 113 + C.Flags.write_lines "config.ml" 114 + (defs @ 115 + ["module Op : sig"; 116 + " type t"; 117 + ] @ op_sig @ [ 118 + "end = struct"; 119 + " type t = int" 120 + ] @ op_struct @ [ 121 + "end" 122 + ]) 50 123 )
+13
lib/uring/uring.ml
··· 105 105 let v ~open_flags ~perm ~resolve path = make open_flags perm resolve path 106 106 end 107 107 108 + module Op = Config.Op 109 + 108 110 (* The C stubs rely on the layout of Cstruct.t, so we just check here that it hasn't changed. *) 109 111 module Check_cstruct : sig 110 112 [@@@warning "-34"] ··· 208 210 209 211 type clock = Boottime | Realtime 210 212 213 + type probe 214 + 211 215 module Uring = struct 212 216 type t 213 217 ··· 218 222 external register_bigarray : t -> Cstruct.buffer -> unit = "ocaml_uring_register_ba" 219 223 external submit : t -> int = "ocaml_uring_submit" [@@noalloc] 220 224 external sq_ready : t -> int = "ocaml_uring_sq_ready" [@@noalloc] 225 + 226 + external get_probe_ring : t -> probe = "ocaml_uring_get_probe_ring" 227 + external opcode_supported : probe -> Op.t -> bool = "ocaml_uring_opcode_supported" [@@noalloc] 221 228 222 229 type id = Heap.ptr 223 230 ··· 496 503 497 504 let error_of_errno e = 498 505 Uring.error_of_errno (abs e) 506 + 507 + let get_probe t = 508 + Uring.get_probe_ring t.uring 509 + 510 + let op_supported probe op = 511 + Uring.opcode_supported probe op 499 512 500 513 module Stats = struct 501 514 type t = {
+12 -1
lib/uring/uring.mli
··· 265 265 (** [recv_msg t fd msghdr d] will submit a [recvmsg(2)] request. If the request is 266 266 successful then the [msghdr] will contain the sender address and the data received. *) 267 267 268 + (** {2 Probing} 269 + 270 + You can check which operations are supported by the running kernel. *) 271 + 272 + module Op = Config.Op 273 + 274 + type probe 275 + 276 + val get_probe : _ t -> probe 277 + val op_supported : probe -> Op.t -> bool 278 + 268 279 (** {2 Submitting operations} *) 269 280 270 281 val submit : 'a t -> int ··· 302 313 module Stats : sig 303 314 type t = { 304 315 sqe_ready : int; (** SQEs not yet submitted. *) 305 - active_ops : int; (** See {!active_ops}. *) 316 + active_ops : int; (** See {!Uring.active_ops}. *) 306 317 sketch_buffer_size : int; (** Size of the current sketch buffer. *) 307 318 sketch_used : int; (** Bytes used within current sketch buffer. *) 308 319 sketch_old_buffers : int; (** Old sketch buffers waiting to be freed. *)
+42
lib/uring/uring_stubs.c
··· 741 741 value ocaml_uring_error_of_errno(value v_errno) { 742 742 return unix_error_of_code(Int_val(v_errno)); 743 743 } 744 + 745 + #define Probe_val(v) (*((struct io_uring_probe **) Data_custom_val(v))) 746 + 747 + static void finalize_probe(value v) { 748 + struct io_uring_probe *p = Probe_val(v); 749 + if (p) 750 + io_uring_free_probe(p); 751 + Probe_val(v) = NULL; 752 + } 753 + 754 + static struct custom_operations probe_ops = { 755 + "uring.probe_ops", 756 + finalize_probe, 757 + custom_compare_default, 758 + custom_hash_default, 759 + custom_serialize_default, 760 + custom_deserialize_default, 761 + custom_compare_ext_default, 762 + custom_fixed_length_default 763 + }; 764 + 765 + // Allocates 766 + value ocaml_uring_get_probe_ring(value v_uring) { 767 + CAMLparam1(v_uring); 768 + CAMLlocal1(v_probe); 769 + struct io_uring_probe *probe; 770 + 771 + v_probe = caml_alloc_custom_mem(&probe_ops, sizeof(struct io_uring_probe *), sizeof(struct io_uring_probe)); 772 + Probe_val(v_probe) = io_uring_get_probe_ring(Ring_val(v_uring)); 773 + 774 + CAMLreturn(v_probe); 775 + } 776 + 777 + value /* noalloc */ 778 + ocaml_uring_opcode_supported(value v_probe, value v_op) 779 + { 780 + struct io_uring_probe *probe = Probe_val(v_probe); 781 + if (probe) 782 + return Val_bool(io_uring_opcode_supported(probe, Int_val(v_op))); 783 + else 784 + return Val_false; 785 + }
+14
tests/main.md
··· 848 848 # Uring.exit t;; 849 849 - : unit = () 850 850 ``` 851 + 852 + ## Probing 853 + 854 + ```ocaml 855 + # let t : unit Uring.t = Uring.create ~queue_depth:1 ();; 856 + val t : unit Uring.t = <abstr> 857 + 858 + # let probe = Uring.get_probe t in 859 + Uring.op_supported probe Uring.Op.nop;; 860 + - : bool = true 861 + 862 + # Uring.exit t;; 863 + - : unit = () 864 + ```