this repo has no description
at main 117 lines 3.5 kB view raw
1let instrument = false 2 3open Bos 4 5let instrument_dir = 6 lazy 7 (let dir = Fpath.v "landmarks" in 8 OS.Dir.delete dir |> Result.get_ok; 9 OS.Dir.create dir |> Result.get_ok |> ignore; 10 dir) 11 12type t = { 13 cmd : string list; 14 time : float; (** Running time in seconds. *) 15 output_file : Fpath.t option; 16 output : string; 17 errors : string; 18 status : [ `Exited of int | `Signaled of int ]; 19} 20 21(* Environment variables passed to commands. *) 22 23(* Record the commands executed, their running time and optionally the path to 24 the produced file. *) 25let commands = ref [] 26 27let n = Atomic.make 0 28 29(** Return the list of executed commands where the first argument was [cmd]. *) 30let run env cmd output_file = 31 let cmd = Bos.Cmd.to_list cmd in 32 let myn = Atomic.fetch_and_add n 1 in 33 Logs.debug (fun m -> m "%d - Executing: %s" myn (String.concat " " cmd)); 34 let proc_mgr = Eio.Stdenv.process_mgr env in 35 let t_start = Unix.gettimeofday () in 36 let env = 37 let env = OS.Env.current () |> Result.get_ok in 38 env 39 in 40 let env = 41 Astring.String.Map.fold 42 (fun k v env -> Astring.String.concat [ k; "="; v ] :: env) 43 env [] 44 |> Array.of_list 45 in 46 (* Logs.debug (fun m -> m "Running cmd %a" Fmt.(list ~sep:sp string) cmd); *) 47 let output, errors, status = 48 Eio.Switch.run ~name:"Process.parse_out" @@ fun sw -> 49 let r, w = Eio.Process.pipe proc_mgr ~sw in 50 let re, we = Eio.Process.pipe proc_mgr ~sw in 51 try 52 let child = 53 Eio.Process.spawn ~sw proc_mgr ~stdout:w ~stderr:we ~env cmd 54 in 55 Eio.Flow.close w; 56 Eio.Flow.close we; 57 let output, err = 58 Eio.Fiber.pair 59 (fun () -> 60 Eio.Buf_read.parse_exn Eio.Buf_read.take_all r ~max_size:max_int) 61 (fun () -> 62 Eio.Buf_read.parse_exn Eio.Buf_read.take_all re ~max_size:max_int) 63 in 64 Eio.Flow.close r; 65 Eio.Flow.close re; 66 let status = Eio.Process.await child in 67 (output, err, status) 68 with Eio.Exn.Io _ as ex -> 69 let bt = Printexc.get_raw_backtrace () in 70 Eio.Exn.reraise_with_context ex bt "%d - running command: %a" myn 71 Eio.Process.pp_args cmd 72 in 73 (* Logs.debug (fun m -> 74 m "Finished running cmd %a" Fmt.(list ~sep:sp string) cmd); *) 75 let t_end = Unix.gettimeofday () in 76 let time = t_end -. t_start in 77 let result = { cmd; time; output_file; output; errors; status } in 78 commands := result :: !commands; 79 (match result.status with 80 | `Exited 0 -> () 81 | _ -> 82 let verb, n = 83 match result.status with 84 | `Exited n -> ("exited", n) 85 | `Signaled n -> ("signaled", n) 86 in 87 Logs.err (fun m -> 88 m 89 "@[<2>Process %s with %d:@ '@[%a'@]@]@\n\n\ 90 Stdout:\n\ 91 %s\n\n\ 92 Stderr:\n\ 93 %s" 94 verb n 95 Fmt.(list ~sep:sp string) 96 result.cmd result.output result.errors)); 97 result 98 99(** Print an executed command and its time. *) 100 101let filter_commands cmd = 102 match 103 List.filter 104 (fun c -> match c.cmd with _ :: cmd' :: _ -> cmd = cmd' | _ -> false) 105 !commands 106 with 107 | [] -> [] 108 | _ :: _ as cmds -> cmds 109 110let print_cmd c = 111 Printf.printf "[%4.2f] $ %s\n" c.time (String.concat " " c.cmd) 112 113(** Returns the [k] commands that took the most time for a given subcommand. *) 114let k_longest_commands cmd k = 115 filter_commands cmd 116 |> List.sort (fun a b -> Float.compare b.time a.time) 117 |> List.filteri (fun i _ -> i < k)