Created
July 9, 2018 21:08
-
-
Save jtpaasch/07b81a42ae7b6240938b7dff214103f7 to your computer and use it in GitHub Desktop.
A simple template for parsing /proc/[pid]/stat files (OCaml).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (* CLI =============================== *) | |
| let pid_value = ref (-1) | |
| let get_pid () = !pid_value | |
| let check () = | |
| match get_pid () with | |
| | (-1) -> | |
| Printf.printf "Error. Please provide a PID.\n%!"; | |
| exit 1 | |
| | _ -> () | |
| let set_pid arg = | |
| match int_of_string_opt arg with | |
| | None -> | |
| Printf.printf "Error. Argument '%s' is not an integer.\n%!" arg; | |
| exit 1 | |
| | Some n -> pid_value := n | |
| let cli () = | |
| Arg.parse [] set_pid "Parse the /proc/[pid]/stat for a PID."; | |
| check () | |
| (* FILES ============================ *) | |
| exception NoSuchFile of string | |
| exception CouldNotRead of string | |
| let open_in_exn f msg = | |
| try open_in f | |
| with Sys_error e -> | |
| raise (NoSuchFile msg) | |
| let read_to_end b c = | |
| try | |
| while true do | |
| Buffer.add_channel b c 1 | |
| done | |
| with End_of_file -> () | |
| let all_to_string ic = | |
| let buf = Buffer.create 32 in | |
| read_to_end buf ic; | |
| Buffer.contents buf | |
| let read f err_msg = | |
| let ic = open_in_exn f err_msg in | |
| all_to_string ic | |
| (* PARSE ============================ *) | |
| exception NotAnInt of string | |
| exception NoSuchDatum of string | |
| let get_page_size = | |
| let size_in_bytes = Unix.open_process_in "getconf PAGE_SIZE" | |
| |> input_line | |
| |> int_of_string in | |
| size_in_bytes / 1024 | |
| let to_int_exn s = | |
| try | |
| int_of_string s | |
| with e -> | |
| let msg = Printf.sprintf "Cannot convert '%s' to an int." s in | |
| raise (NotAnInt msg) | |
| let get_elem_exn data idx msg = | |
| try | |
| List.nth data idx | |
| with e -> | |
| raise (NoSuchDatum msg) | |
| let parse_pid data idx = | |
| let err = Printf.sprintf | |
| "Can't find PID at index '%d' in /proc/[pid]/stat file." idx in | |
| let datum = get_elem_exn data idx err in | |
| let result = to_int_exn datum in | |
| Printf.sprintf "PID: %d" result | |
| let parse_rss data idx pagesize = | |
| let err = Printf.sprintf | |
| "Can't find RSS at index '%d' in /proc/[pid]/stat file." idx in | |
| let datum = get_elem_exn data idx err in | |
| let pages = to_int_exn datum in | |
| let result = pages * pagesize in | |
| Printf.sprintf "RSS: %dK" result | |
| let get_stats src = | |
| let pagesize = get_page_size in | |
| let data = String.split_on_char ' ' src in | |
| [ | |
| parse_pid data 0; | |
| parse_rss data 23 pagesize; | |
| ] | |
| (* MAIN ============================ *) | |
| let main () = | |
| cli (); | |
| let pid = get_pid () in | |
| let stat_file = Printf.sprintf "/proc/%d/stat" pid in | |
| Printf.printf "Stats for PID: %d\n%!" pid; | |
| let err_msg = Printf.sprintf "No such PID: %d" pid in | |
| let data = read stat_file err_msg in | |
| Printf.printf "Data:\n%s\n%!" data; | |
| let stats = get_stats data in | |
| List.iter (Printf.printf "%s\n%!") stats | |
| let handle_errors f () = | |
| Printexc.register_printer | |
| (function | |
| | NoSuchFile msg -> Some msg | |
| | CouldNotRead msg -> Some msg | |
| | NotAnInt msg -> Some msg | |
| | NoSuchDatum msg -> Some msg | |
| | _ -> None | |
| ); | |
| try | |
| Unix.handle_unix_error f () | |
| with e -> | |
| let msg = Printexc.to_string e in | |
| Printf.printf "Error. %s\n%!" msg; | |
| exit 1 | |
| let () = handle_errors main () |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment