diff --git a/infer/src/base/ProcessPool.ml b/infer/src/base/ProcessPool.ml index 8c7f18479..35c074a79 100644 --- a/infer/src/base/ProcessPool.ml +++ b/infer/src/base/ProcessPool.ml @@ -173,47 +173,27 @@ let send_work_to_child pool slot = marshal_to_pipe down_pipe (Do x) ) -let proc_meminfo = "/proc/meminfo" - (* this should not be called in any other arch than Linux *) let should_throttle = - Option.iter Config.oom_threshold ~f:(fun _threshold -> - match Sys.file_exists proc_meminfo with - | `Yes -> - () - | _ -> - L.die UserError "Can't access %s even though oom detection was requested." proc_meminfo - ) ; let currently_throttled = ref false in - let get_available_memory_MB () = - let rec aux in_channel = - match In_channel.input_line in_channel with - | None -> - L.die UserError - "Cannot find available memory line in %s even though oom detection was requested." - proc_meminfo - | Some line -> ( - try Scanf.sscanf line "MemAvailable: %u kB" (fun mem_kB -> mem_kB / 1024) - with Scanf.Scan_failure _ -> aux in_channel ) - in - Utils.with_file_in proc_meminfo ~f:aux - in fun threshold -> - let available_memory = get_available_memory_MB () in - if available_memory < threshold then ( - if not !currently_throttled then - L.user_warning - "Available memory (%d MB) is below configured threshold, throttling back scheduling \ - analysis work.@." - available_memory ; - currently_throttled := true ) - else ( - if !currently_throttled then - L.user_warning - "Available memory (%d MB) exceeds configured threshold, resuming scheduling analysis \ - work.@." - available_memory ; - currently_throttled := false ) ; + ( match Utils.get_available_memory_MB () with + | None -> + L.die UserError "Can't obtain available memory even though oom detection was requested.@." + | Some available_memory when available_memory < threshold -> + if not !currently_throttled then + L.user_warning + "Available memory (%d MB) is below configured threshold, throttling back scheduling \ + analysis work.@." + available_memory ; + currently_throttled := true + | Some available_memory -> + if !currently_throttled then + L.user_warning + "Available memory (%d MB) exceeds configured threshold, resuming scheduling analysis \ + work.@." + available_memory ; + currently_throttled := false ) ; !currently_throttled diff --git a/infer/src/base/Utils.ml b/infer/src/base/Utils.ml index e41863fed..03f3562af 100644 --- a/infer/src/base/Utils.ml +++ b/infer/src/base/Utils.ml @@ -404,3 +404,17 @@ let do_in_dir ~dir ~f = let cwd = Unix.getcwd () in Unix.chdir dir ; try_finally_swallow_timeout ~f ~finally:(fun () -> Unix.chdir cwd) + + +let get_available_memory_MB () = + let proc_meminfo = "/proc/meminfo" in + let rec scan_for_expected_output in_channel = + match In_channel.input_line in_channel with + | None -> + None + | Some line -> ( + try Scanf.sscanf line "MemAvailable: %u kB" (fun mem_kB -> Some (mem_kB / 1024)) + with Scanf.Scan_failure _ -> scan_for_expected_output in_channel ) + in + if Sys.file_exists proc_meminfo <> `Yes then None + else with_file_in proc_meminfo ~f:scan_for_expected_output diff --git a/infer/src/base/Utils.mli b/infer/src/base/Utils.mli index 116056f81..7b95451fd 100644 --- a/infer/src/base/Utils.mli +++ b/infer/src/base/Utils.mli @@ -139,3 +139,7 @@ val timeit : f:(unit -> 'a) -> 'a * int val do_in_dir : dir:string -> f:(unit -> 'a) -> 'a (** executes [f] after cding into [dir] and then restores original cwd *) + +val get_available_memory_MB : unit -> int option +(** On Linux systems, return [Some x] where [MemAvailable x] is in [/proc/meminfo]. + Returns [None] in all other cases. *) diff --git a/infer/src/infer.ml b/infer/src/infer.ml index e6ec47bbf..5fa703075 100644 --- a/infer/src/infer.ml +++ b/infer/src/infer.ml @@ -90,8 +90,14 @@ let log_environment_info () = |> Option.map ~f:(String.split ~on:CLOpt.env_var_sep) |> Option.value ~default:[""] in - L.environment_info "INFER_ARGS = %a" Pp.cli_args infer_args ; - L.environment_info "command line arguments: %a" Pp.cli_args (Array.to_list Sys.argv) ; + L.environment_info "INFER_ARGS = %a@\n" Pp.cli_args infer_args ; + L.environment_info "command line arguments: %a@\n" Pp.cli_args (Array.to_list Sys.argv) ; + ( match Utils.get_available_memory_MB () with + | None -> + L.environment_info "Could not retrieve available memory (possibly not on Linux)@\n" + | Some available_memory -> + L.environment_info "Available memory at startup: %d MB@\n" available_memory ; + ScubaLogging.log_count ~label:"startup_mem_avail_MB" ~value:available_memory ) ; print_active_checkers ()