diff --git a/.gitmodules b/.gitmodules index 4897d43..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "ocaml-variorum"] - path = ocaml-variorum - url = https://github.com/patricoferris/ocaml-variorum diff --git a/clarke.opam b/clarke.opam index d6490d2..40d6379 100644 --- a/clarke.opam +++ b/clarke.opam @@ -11,8 +11,15 @@ doc: "https://patricoferris.github.io/clarke/" build: ["dune" "build" "-p" name "-j" jobs] depends: [ "dune" {>= "2.0"} - "eio_main" {>= "0.5"} + "eio_luv" "variorum" "ptime" "cmdliner" -] \ No newline at end of file +] +pin-depends: [ + [ "hwloc.dev" "git+https://github.com/patricoferris/ocaml-hwloc#3447dc5c40f0d868529aafcc84b5d2d971062b30" ] + [ "jansson.dev" "git+https://github.com/patricoferris/ocaml-jansson#42cb429e722ec64807d75ae401758eb666c9d189" ] + [ "eio.dev" "git+https://github.com/patricoferris/eio#e22946a7e8de7094f15753cc9084beb1c06dd43b" ] + [ "eio_luv.dev" "git+https://github.com/patricoferris/eio#e22946a7e8de7094f15753cc9084beb1c06dd43b" ] + [ "variorum.dev" "git+https://github.com/patricoferris/ocaml-variorum#9128770e9df08ca7a90f317acc08b9cd49da6766" ] +] diff --git a/dune b/dune index b2a5b53..9f1a3e1 100644 --- a/dune +++ b/dune @@ -1 +1 @@ -(vendored_dirs ocaml-variorum ocaml-ipmi) +(vendored_dirs ocaml-variorum eio) diff --git a/ocaml-variorum b/ocaml-variorum deleted file mode 160000 index 8bad1e3..0000000 --- a/ocaml-variorum +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8bad1e3bac2d9203fbaf783db168da887e67d43c diff --git a/src/bin/dune b/src/bin/dune index 39ea109..8a2c53d 100644 --- a/src/bin/dune +++ b/src/bin/dune @@ -1,4 +1,4 @@ (executable (name main) (public_name clarke) - (libraries eio_main eio.unix clarke cmdliner)) + (libraries eio_luv eio.unix clarke cmdliner)) diff --git a/src/bin/main.ml b/src/bin/main.ml index d55a3f7..3fac045 100644 --- a/src/bin/main.ml +++ b/src/bin/main.ml @@ -43,11 +43,13 @@ module Specs = struct let meter_of_meter_spec ~clock = function | `Const f -> Models.const ~clock f + | `Ipmi -> S.Meter ((module Clarke.Ipmi), { clock }) | `Variorum -> S.Meter ((module Clarke.Variorum), { clock }) let meter_spec_of_string s = match String.lowercase_ascii s with | "variorum" -> Ok `Variorum + | "ipmi" -> Ok `Ipmi | v -> ( match String.split_on_char ':' v with | [ "const"; f ] -> ( @@ -103,4 +105,4 @@ let main_cmd env = let default = Term.(ret @@ const (`Help (`Pager, None))) in Cmd.group info ~default (cmds env) -let () = Eio_main.run @@ fun env -> exit (Cmd.eval_result (main_cmd env)) +let () = Eio_luv.run @@ fun env -> exit (Cmd.eval_result (main_cmd env)) diff --git a/src/lib/dune b/src/lib/dune index f8abfc0..6a9d044 100644 --- a/src/lib/dune +++ b/src/lib/dune @@ -1,4 +1,4 @@ (library (name clarke) (public_name clarke) - (libraries eio ptime variorum ezjsonm)) + (libraries eio_luv eio.unix ptime variorum ezjsonm)) diff --git a/src/lib/ipmi.ml b/src/lib/ipmi.ml index e69de29..63e1a4b 100644 --- a/src/lib/ipmi.ml +++ b/src/lib/ipmi.ml @@ -0,0 +1,47 @@ +(* Ipmi-based monitor *) +open Eio +open Eio_luv.Low_level + +module Ipmi = struct + let ipmi args = ("sudo", "sudo" :: "ipmitool" :: args) + let power_consumption = ipmi [ "sensor"; "reading"; "Pwr Consumption"; "-c" ] + + let parse_power_consumption s = + match String.split_on_char ',' (String.trim s) with + | "Pwr Consumption" :: watts :: _ -> int_of_string watts + | _ -> failwith "Couldn't parse the power consumption" +end + +type t = { clock : Eio.Time.clock } + +let supported = true + +let read_all handle buf = + let rec read acc = + try + let i = Eio_luv.Low_level.Stream.read_into handle buf in + read (acc + i) + with End_of_file -> acc + in + read 0 + +let get_power_consumption () = + let cmd, args = Ipmi.power_consumption in + let parent_pipe = Eio_luv.Low_level.Pipe.init () in + Switch.run @@ fun sw -> + let handle = Eio_luv.Low_level.Pipe.to_handle ~sw parent_pipe in + let buf = Luv.Buffer.create 64 in + let redirect = + Eio_luv.Low_level.Process. + [ to_parent_pipe ~fd:Luv.Process.stdout ~parent_pipe () ] + in + let t = Process.spawn ~redirect cmd args in + let _ = Process.await_exit t in + let read = read_all handle buf in + Luv.Buffer.to_string (Luv.Buffer.sub buf ~offset:0 ~length:read) + +let collect t = + let pc = + get_power_consumption () |> Ipmi.parse_power_consumption |> float_of_int + in + Info.v (Option.get (Ptime.of_float_s @@ Time.now t.clock)) pc