123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117letinstrument=falseopenBosletinstrument_dir=lazy(letdir=Fpath.v"landmarks"inOS.Dir.deletedir|>Result.get_ok;OS.Dir.createdir|>Result.get_ok|>ignore;dir)typet={cmd:stringlist;time:float;(** Running time in seconds. *)output_file:Fpath.toption;output:string;errors:string;status:[`Exitedofint|`Signaledofint];}(* Environment variables passed to commands. *)(* Record the commands executed, their running time and optionally the path to
the produced file. *)letcommands=ref[]letn=Atomic.make0(** Return the list of executed commands where the first argument was [cmd]. *)letrunenvcmdoutput_file=letcmd=Bos.Cmd.to_listcmdinletmyn=Atomic.fetch_and_addn1inLogs.debug(funm->m"%d - Executing: %s"myn(String.concat" "cmd));letproc_mgr=Eio.Stdenv.process_mgrenvinlett_start=Unix.gettimeofday()inletenv=letenv=OS.Env.current()|>Result.get_okinenvinletenv=Astring.String.Map.fold(funkvenv->Astring.String.concat[k;"=";v]::env)env[]|>Array.of_listin(* Logs.debug (fun m -> m "Running cmd %a" Fmt.(list ~sep:sp string) cmd); *)letoutput,errors,status=Eio.Switch.run~name:"Process.parse_out"@@funsw->letr,w=Eio.Process.pipeproc_mgr~swinletre,we=Eio.Process.pipeproc_mgr~swintryletchild=Eio.Process.spawn~swproc_mgr~stdout:w~stderr:we~envcmdinEio.Flow.closew;Eio.Flow.closewe;letoutput,err=Eio.Fiber.pair(fun()->Eio.Buf_read.parse_exnEio.Buf_read.take_allr~max_size:max_int)(fun()->Eio.Buf_read.parse_exnEio.Buf_read.take_allre~max_size:max_int)inEio.Flow.closer;Eio.Flow.closere;letstatus=Eio.Process.awaitchildin(output,err,status)withEio.Exn.Io_asex->letbt=Printexc.get_raw_backtrace()inEio.Exn.reraise_with_contextexbt"%d - running command: %a"mynEio.Process.pp_argscmdin(* Logs.debug (fun m ->
m "Finished running cmd %a" Fmt.(list ~sep:sp string) cmd); *)lett_end=Unix.gettimeofday()inlettime=t_end-.t_startinletresult={cmd;time;output_file;output;errors;status}incommands:=result::!commands;(matchresult.statuswith|`Exited0->()|_->letverb,n=matchresult.statuswith|`Exitedn->("exited",n)|`Signaledn->("signaled",n)inLogs.err(funm->m"@[<2>Process %s with %d:@ '@[%a'@]@]@\n\n\
Stdout:\n\
%s\n\n\
Stderr:\n\
%s"verbnFmt.(list~sep:spstring)result.cmdresult.outputresult.errors));result(** Print an executed command and its time. *)letfilter_commandscmd=matchList.filter(func->matchc.cmdwith_::cmd'::_->cmd=cmd'|_->false)!commandswith|[]->[]|_::_ascmds->cmdsletprint_cmdc=Printf.printf"[%4.2f] $ %s\n"c.time(String.concat" "c.cmd)(** Returns the [k] commands that took the most time for a given subcommand. *)letk_longest_commandscmdk=filter_commandscmd|>List.sort(funab->Float.compareb.timea.time)|>List.filteri(funi_->i<k)