5 let outfile = ref "/dev/stderr"
6 let page_size = ref ~-1
8 let max_mem = ref (512*1024)
13 let spec = Arg.align [
14 "-o", Arg.Set_string outfile, " output file (default stderr)";
15 "-p", Arg.Set_int page_size, " page size in bytes (default autodetect)";
16 "-t", Arg.Set_int timeout, " timeout in s (default 30s)";
17 "-m", Arg.Set_int max_mem, " maximum memory in kiB (default 512 MiB)";
18 "-i", Arg.Set_int interval, " refresh interval in ms (default 250ms)";
19 "-q", Arg.Set(quiet), " don't print messages while running";
21 let argument s = args := s :: !args
22 let usage_msg = sprintf "usage: %s [options] <program> [arguments ...]" Sys.argv.(0)
24 let parse_cmdline () =
25 let _ = Arg.parse spec argument usage_msg in
27 [] -> Arg.usage spec usage_msg; exit 1
28 | l -> Array.of_list (List.rev l)
33 (* Utility functions *)
36 let get_page_size () =
37 let cin = open_process_in "getconf PAGESIZE" in
38 let s = input_line cin in
39 match close_process_in cin with
40 WEXITED 0 -> (try int_of_string s with _ -> ~-1)
45 let usleep ms = ignore (Unix.select [] [] [] (float_of_int ms /. 1000.))
47 let read_proc_statm pid =
48 let cin = open_in (sprintf "/proc/%i/statm" pid) in
50 Scanf.fscanf cin "%i %i %s" (fun _ i _ -> m := i);
56 let rec monitor pid start finish mem fmt =
57 let p, s = Unix.waitpid [ Unix.WNOHANG ] pid in
59 let current_mem_pages = read_proc_statm pid in
60 let current_mem = current_mem_pages * !Options.page_size / 1024 in
61 if current_mem >= !max_mem then max_mem := current_mem;
62 let current_time = Unix.gettimeofday () in
63 if (current_time > finish)
65 let () = eprintf "Timeout reached, killing child process\n%!" in
66 Unix.kill pid Sys.sigkill
69 then let () = eprintf "Memory limit reached, killing child process\n%!" in
70 Unix.kill pid Sys.sigkill
73 if not !Options.quiet then
74 fprintf fmt "[% 11.3f] Memory: current=%ikb max=%ikb\n%!"
75 (current_time -. start) current_mem !max_mem;
76 usleep !Options.interval;
77 monitor pid start finish mem fmt
82 WEXITED c -> fprintf fmt "Process exited with code %i\n" c
83 | WSTOPPED s -> fprintf fmt "Process stopped by signal %i\n" s
84 | WSIGNALED s -> fprintf fmt "Process killed by signal %i\n" s
86 fprintf fmt "Peak memory use: %ikb\n%!" !max_mem
90 let run args start finish mem fmt =
91 let pid = Unix.fork () in
92 if pid == 0 then begin
93 eprintf "%s\n" args.(0);
94 Unix.execvp args.(0) args
96 else monitor pid start finish mem fmt
100 let args = Options.parse_cmdline () in
101 if !Options.page_size <= 0 then Options.page_size := get_page_size ();
102 if !Options.page_size <= 0 then
103 eprintf "Warning: could not determine page size. Using 4096 (override with -p)\n%!";
105 let start = gettimeofday () in
106 let finish = start +. float_of_int !Options.timeout in
107 let cout = open_out !Options.outfile in
108 let fmt = formatter_of_out_channel cout in
109 run args start finish !Options.max_mem fmt;
113 Sys_error s -> eprintf "Error: %s\n%!" s; exit 2
114 | e -> eprintf "%s Unknown error\n%!" (Printexc.to_string e); exit 3