inspect kinfo_proc structure for information about:
- virtual size - resident size (in pages) - text size (in pages) - data size (in pages) - stack size (in pages) develop independent vmmc_stat for testing (not installed)
This commit is contained in:
parent
030f5aa379
commit
fd4a5a5e22
1
_tags
1
_tags
|
@ -15,6 +15,7 @@ true : package(rresult logs ipaddr bos hex ptime astring duration cstruct decomp
|
|||
<app/vmmd_log.{ml,native,byte}>: package(ptime.clock.os)
|
||||
<app/vmmd_tls*.{ml,native,byte}>: package(tls.lwt ptime.clock.os)
|
||||
<app/vmmd_stats.{ml,native,byte}>: link_vmm_stats
|
||||
<app/vmmc_stat.{ml,native,byte}>: link_vmm_stats
|
||||
|
||||
<app/vmmc_remote.{ml,native,byte}>: package(nocrypto tls.lwt nocrypto.lwt)
|
||||
<app/vmmc_bistro.{ml,native,byte}>: package(nocrypto tls.lwt nocrypto.lwt)
|
||||
|
|
|
@ -6,6 +6,7 @@ open Rresult.R.Infix
|
|||
open Vmm_core
|
||||
|
||||
external sysctl_rusage : int -> Stats.rusage = "vmmanage_sysctl_rusage"
|
||||
external sysctl_kinfo_mem : int -> Stats.kinfo_mem = "vmmanage_sysctl_kinfo_mem"
|
||||
external sysctl_ifcount : unit -> int = "vmmanage_sysctl_ifcount"
|
||||
external sysctl_ifdata : int -> Stats.ifdata = "vmmanage_sysctl_ifdata"
|
||||
|
||||
|
@ -83,6 +84,7 @@ let try_open_vmmapi pid_nic =
|
|||
|
||||
let gather pid vmctx nics =
|
||||
wrap sysctl_rusage pid,
|
||||
wrap sysctl_kinfo_mem pid,
|
||||
(match vmctx with
|
||||
| Error _ -> None
|
||||
| Ok vmctx -> wrap vmmapi_stats vmctx),
|
||||
|
@ -105,13 +107,13 @@ let tick t =
|
|||
| xs -> match IM.find_opt pid t.pid_nic with
|
||||
| None -> Logs.warn (fun m -> m "couldn't find nics of %d" pid) ; out
|
||||
| Some (vmctx, nics) ->
|
||||
let ru, vmm, ifd = gather pid vmctx nics in
|
||||
let ru, mem, vmm, ifd = gather pid vmctx nics in
|
||||
match ru with
|
||||
| None -> Logs.err (fun m -> m "failed to get rusage for %d" pid) ; out
|
||||
| Some ru' ->
|
||||
let stats =
|
||||
let vmm' = match vmm with None -> None | Some xs -> Some (List.combine !descr xs) in
|
||||
ru', vmm', ifd
|
||||
ru', mem, vmm', ifd
|
||||
in
|
||||
List.fold_left (fun out (id, socket) ->
|
||||
match Vmm_core.Name.drop_super ~super:id ~sub:vmid with
|
||||
|
|
|
@ -21,6 +21,34 @@
|
|||
#include <net/if_mib.h>
|
||||
#include <vmmapi.h>
|
||||
|
||||
CAMLprim value vmmanage_sysctl_kinfo_mem (value pid_r) {
|
||||
CAMLparam1(pid_r);
|
||||
CAMLlocal3(res, utime, stime);
|
||||
int name[4];
|
||||
int error;
|
||||
size_t len;
|
||||
struct kinfo_proc p;
|
||||
|
||||
len = sizeof(p);
|
||||
name[0] = CTL_KERN;
|
||||
name[1] = KERN_PROC;
|
||||
name[2] = KERN_PROC_PID;
|
||||
name[3] = Int_val(pid_r);
|
||||
|
||||
error = sysctl(name, nitems(name), &p, &len, NULL, 0);
|
||||
if (error < 0)
|
||||
uerror("sysctl", Nothing);
|
||||
|
||||
res = caml_alloc(5, 0);
|
||||
Store_field (res, 0, Val64(p.ki_size));
|
||||
Store_field (res, 1, Val64(p.ki_rssize));
|
||||
Store_field (res, 2, Val64(p.ki_tsize));
|
||||
Store_field (res, 3, Val64(p.ki_dsize));
|
||||
Store_field (res, 4, Val64(p.ki_ssize));
|
||||
|
||||
CAMLreturn(res);
|
||||
}
|
||||
|
||||
CAMLprim value vmmanage_sysctl_rusage (value pid_r) {
|
||||
CAMLparam1(pid_r);
|
||||
CAMLlocal3(res, utime, stime);
|
||||
|
@ -201,6 +229,11 @@ CAMLprim value vmmanage_sysctl_rusage (value pid_r) {
|
|||
uerror("sysctl_rusage", Nothing);
|
||||
}
|
||||
|
||||
CAMLprim value vmmanage_sysctl_kinfo_mem (value pid_r) {
|
||||
CAMLparam1(pid_r);
|
||||
uerror("sysctl_kinfo_mem", Nothing);
|
||||
}
|
||||
|
||||
CAMLprim value vmmanage_sysctl_ifcount (value unit) {
|
||||
CAMLparam1(unit);
|
||||
uerror("sysctl_ifcount", Nothing);
|
||||
|
|
57
app/vmmc_stat.ml
Normal file
57
app/vmmc_stat.ml
Normal file
|
@ -0,0 +1,57 @@
|
|||
open Vmm_core
|
||||
open Vmm_stats_pure
|
||||
|
||||
let timer pid vmmapi =
|
||||
let rusage = sysctl_rusage pid in
|
||||
Logs.app (fun m -> m "sysctl rusage: %a" Stats.pp_rusage_mem rusage) ;
|
||||
let kinfo_mem = sysctl_kinfo_mem pid in
|
||||
Logs.app (fun m -> m "kinfo mem: %a" Stats.pp_kinfo_mem kinfo_mem) ;
|
||||
match vmmapi with
|
||||
| None -> ()
|
||||
| Some vmctx -> match wrap vmmapi_stats vmctx with
|
||||
| None -> Logs.app (fun m -> m "no vmctx stats")
|
||||
| Some st ->
|
||||
let all = List.combine !descr st in
|
||||
Logs.app (fun m -> m "bhyve stats %a" Stats.pp_vmm_mem all)
|
||||
|
||||
let jump _ pid name interval =
|
||||
Sys.(set_signal sigpipe Signal_ignore) ;
|
||||
let interval = Duration.(to_f (of_sec interval)) in
|
||||
Lwt_main.run (
|
||||
let vmmapi = match name with
|
||||
| None ->
|
||||
Logs.warn (fun m -> m "no name, no vmmapi") ;
|
||||
None
|
||||
| Some name -> match wrap vmmapi_open name with
|
||||
| None ->
|
||||
Logs.warn (fun m -> m "vmmapi_open failed for %s" name) ;
|
||||
None
|
||||
| Some vmctx ->
|
||||
Logs.info (fun m -> m "vmmapi_open succeeded for %s" name) ;
|
||||
Vmm_stats_pure.fill_descr vmctx ;
|
||||
Some vmctx
|
||||
in
|
||||
let _ev = Lwt_engine.on_timer interval true (fun _e -> timer pid vmmapi) in
|
||||
let t, _u = Lwt.task () in
|
||||
t)
|
||||
|
||||
open Cmdliner
|
||||
open Vmm_cli
|
||||
|
||||
let interval =
|
||||
let doc = "Interval between statistics gatherings (in seconds)" in
|
||||
Arg.(value & opt int 10 & info [ "interval" ] ~doc)
|
||||
|
||||
let pid =
|
||||
let doc = "Process id (defaults to own pid)" in
|
||||
Arg.(value & opt int (Unix.getpid ()) & info [ "pid" ] ~doc)
|
||||
|
||||
let vmname =
|
||||
let doc = "VM name" in
|
||||
Arg.(value & opt (some string) None & info [ "name" ] ~doc)
|
||||
|
||||
let cmd =
|
||||
Term.(ret (const jump $ setup_log $ pid $ vmname $ interval)),
|
||||
Term.info "vmmd_stats" ~version:"%%VERSION_NUM%%"
|
||||
|
||||
let () = match Term.eval cmd with `Ok () -> exit 0 | _ -> exit 1
|
|
@ -100,6 +100,18 @@ module P = struct
|
|||
let fields = List.map (fun (k, v) -> k ^ "=" ^ v) fields in
|
||||
Printf.sprintf "resource_usage,vm=%s %s" vm (String.concat ~sep:"," fields)
|
||||
|
||||
let encode_kinfo_mem vm mem =
|
||||
let fields =
|
||||
[ "vsize", i64 mem.vsize ;
|
||||
"rss", i64 mem.rss ;
|
||||
"rsize", i64 mem.tsize ;
|
||||
"dsize", i64 mem.dsize ;
|
||||
"ssize", i64 mem.ssize ;
|
||||
]
|
||||
in
|
||||
let fields = List.map (fun (k, v) -> k ^ "=" ^ v) fields in
|
||||
Printf.sprintf "kinfo_mem,vm=%s %s" vm (String.concat ~sep:"," fields)
|
||||
|
||||
let encode_vmm vm xs =
|
||||
let escape s =
|
||||
let cutted = String.cuts ~sep:"," s in
|
||||
|
@ -190,7 +202,7 @@ let rec read_sock_write_tcp c ?fd addr addrtype =
|
|||
safe_close fd >>= fun () ->
|
||||
safe_close c >|= fun () ->
|
||||
true
|
||||
| Ok (hdr, `Data (`Stats_data (ru, vmm, ifs))) ->
|
||||
| Ok (hdr, `Data (`Stats_data (ru, mem, vmm, ifs))) ->
|
||||
begin
|
||||
if not (Vmm_commands.version_eq hdr.Vmm_commands.version my_version) then begin
|
||||
Logs.err (fun m -> m "unknown wire protocol version") ;
|
||||
|
@ -200,9 +212,10 @@ let rec read_sock_write_tcp c ?fd addr addrtype =
|
|||
end else
|
||||
let name = Name.to_string hdr.Vmm_commands.name in
|
||||
let ru = P.encode_ru name ru in
|
||||
let vmm = match vmm with None -> [] | Some xs -> [ P.encode_vmm name xs ] in
|
||||
let mem = match mem with None -> [] | Some m -> [ P.encode_kinfo_mem name m ] in
|
||||
let vmm = match vmm with None -> [] | Some vmm -> [ P.encode_vmm name vmm ] in
|
||||
let taps = List.map (P.encode_if name) ifs in
|
||||
let out = (String.concat ~sep:"\n" (ru :: vmm @ taps)) ^ "\n" in
|
||||
let out = (String.concat ~sep:"\n" (ru :: mem @ vmm @ taps)) ^ "\n" in
|
||||
Logs.debug (fun m -> m "writing %d via tcp" (String.length out)) ;
|
||||
Vmm_lwt.write_raw fd (Bytes.unsafe_of_string out) >>= function
|
||||
| Ok () ->
|
||||
|
|
|
@ -18,4 +18,5 @@ let () =
|
|||
Pkg.bin "app/vmmc_bistro" ;
|
||||
Pkg.bin "app/vmmp_request" ;
|
||||
Pkg.bin "app/vmmp_ca" ;
|
||||
Pkg.test ~run:false "app/vmmc_stat" ;
|
||||
]
|
||||
|
|
|
@ -120,6 +120,21 @@ let ru =
|
|||
@ (required ~label:"nvcsw" int64)
|
||||
-@ (required ~label:"nivcsw" int64))
|
||||
|
||||
let kinfo_mem =
|
||||
let open Stats in
|
||||
let f (vsize, rss, tsize, dsize, ssize) =
|
||||
{ vsize ; rss ; tsize ; dsize ; ssize }
|
||||
and g t =
|
||||
(t.vsize, t.rss, t.tsize, t.dsize, t.ssize)
|
||||
in
|
||||
Asn.S.map f g @@
|
||||
Asn.S.(sequence5
|
||||
(required ~label:"bsize" int64)
|
||||
(required ~label:"rss" int64)
|
||||
(required ~label:"tsize" int64)
|
||||
(required ~label:"dsize" int64)
|
||||
(required ~label:"ssize" int64))
|
||||
|
||||
(* TODO is this good? *)
|
||||
let int32 =
|
||||
let f i = Int32.of_int i
|
||||
|
@ -349,11 +364,11 @@ let wire_command =
|
|||
let data =
|
||||
let f = function
|
||||
| `C1 (timestamp, data) -> `Console_data (timestamp, data)
|
||||
| `C2 (ru, ifs, vmm) -> `Stats_data (ru, vmm, ifs)
|
||||
| `C2 (ru, ifs, vmm, mem) -> `Stats_data (ru, mem, vmm, ifs)
|
||||
| `C3 (timestamp, event) -> `Log_data (timestamp, event)
|
||||
and g = function
|
||||
| `Console_data (timestamp, data) -> `C1 (timestamp, data)
|
||||
| `Stats_data (ru, ifs, vmm) -> `C2 (ru, vmm, ifs)
|
||||
| `Stats_data (ru, mem, ifs, vmm) -> `C2 (ru, vmm, ifs, mem)
|
||||
| `Log_data (timestamp, event) -> `C3 (timestamp, event)
|
||||
in
|
||||
Asn.S.map f g @@
|
||||
|
@ -361,13 +376,14 @@ let data =
|
|||
(explicit 0 (sequence2
|
||||
(required ~label:"timestamp" utc_time)
|
||||
(required ~label:"data" utf8_string)))
|
||||
(explicit 1 (sequence3
|
||||
(explicit 1 (sequence4
|
||||
(required ~label:"resource_usage" ru)
|
||||
(required ~label:"ifdata" (sequence_of ifdata))
|
||||
(optional ~label:"vmm_stats"
|
||||
(optional ~label:"vmm_stats" @@ explicit 0
|
||||
(sequence_of (sequence2
|
||||
(required ~label:"key" utf8_string)
|
||||
(required ~label:"value" int64))))))
|
||||
(required ~label:"value" int64))))
|
||||
(optional ~label:"kinfo_mem" @@ implicit 1 kinfo_mem)))
|
||||
(explicit 2 (sequence2
|
||||
(required ~label:"timestamp" utc_time)
|
||||
(required ~label:"event" log_event))))
|
||||
|
|
|
@ -213,11 +213,28 @@ module Stats = struct
|
|||
let pp_rusage ppf r =
|
||||
Fmt.pf ppf "utime %Lu.%d stime %Lu.%d maxrss %Lu ixrss %Lu idrss %Lu isrss %Lu minflt %Lu majflt %Lu nswap %Lu inblock %Lu outblock %Lu msgsnd %Lu msgrcv %Lu signals %Lu nvcsw %Lu nivcsw %Lu"
|
||||
(fst r.utime) (snd r.utime) (fst r.stime) (snd r.stime) r.maxrss r.ixrss r.idrss r.isrss r.minflt r.majflt r.nswap r.inblock r.outblock r.msgsnd r.msgrcv r.nsignals r.nvcsw r.nivcsw
|
||||
let pp_rusage_mem ppf r =
|
||||
Fmt.pf ppf "maxrss %Lu ixrss %Lu idrss %Lu isrss %Lu minflt %Lu majflt %Lu"
|
||||
r.maxrss r.ixrss r.idrss r.isrss r.minflt r.majflt
|
||||
|
||||
type kinfo_mem = {
|
||||
vsize : int64 ;
|
||||
rss : int64 ;
|
||||
tsize : int64 ;
|
||||
dsize : int64 ;
|
||||
ssize : int64 ;
|
||||
}
|
||||
|
||||
let pp_kinfo_mem ppf t =
|
||||
Fmt.pf ppf "virtual-size %Lu rss %Lu text-size %Lu data-size %Lu stack-size %Lu"
|
||||
t.vsize t.rss t.tsize t.dsize t.ssize
|
||||
|
||||
type vmm = (string * int64) list
|
||||
let pp_vmm ppf vmm =
|
||||
Fmt.(list ~sep:(unit "@.") (pair ~sep:(unit ": ") string int64)) ppf vmm
|
||||
let pp_vmm_mem ppf vmm =
|
||||
Fmt.(list ~sep:(unit "@.") (pair ~sep:(unit ": ") string int64)) ppf
|
||||
(List.filter (fun (k, _) -> k = "Resident memory" || k = "Wired memory") vmm)
|
||||
|
||||
type ifdata = {
|
||||
ifname : string ;
|
||||
|
@ -244,10 +261,11 @@ module Stats = struct
|
|||
Fmt.pf ppf "ifname %s flags %lX send_length %lu max_send_length %lu send_drops %lu mtu %lu baudrate %Lu input_packets %Lu input_errors %Lu output_packets %Lu output_errors %Lu collisions %Lu input_bytes %Lu output_bytes %Lu input_mcast %Lu output_mcast %Lu input_dropped %Lu output_dropped %Lu"
|
||||
i.ifname i.flags i.send_length i.max_send_length i.send_drops i.mtu i.baudrate i.input_packets i.input_errors i.output_packets i.output_errors i.collisions i.input_bytes i.output_bytes i.input_mcast i.output_mcast i.input_dropped i.output_dropped
|
||||
|
||||
type t = rusage * vmm option * ifdata list
|
||||
let pp ppf (ru, vmm, ifs) =
|
||||
Fmt.pf ppf "%a@.%a@.%a"
|
||||
type t = rusage * kinfo_mem option * vmm option * ifdata list
|
||||
let pp ppf (ru, mem, vmm, ifs) =
|
||||
Fmt.pf ppf "%a@.%a@.%a@.%a"
|
||||
pp_rusage ru
|
||||
Fmt.(option ~none:(unit "no kinfo_mem stats") pp_kinfo_mem) mem
|
||||
Fmt.(option ~none:(unit "no vmm stats") pp_vmm) vmm
|
||||
Fmt.(list ~sep:(unit "@.@.") pp_ifdata) ifs
|
||||
end
|
||||
|
@ -279,8 +297,8 @@ module Log = struct
|
|||
|
||||
let pp_log_event ppf = function
|
||||
| `Startup -> Fmt.string ppf "startup"
|
||||
| `Login (name, ip, port) -> Fmt.pf ppf "%a login %a:%d" Name.pp name Ipaddr.V4.pp_hum ip port
|
||||
| `Logout (name, ip, port) -> Fmt.pf ppf "%a logout %a:%d" Name.pp name Ipaddr.V4.pp_hum ip port
|
||||
| `Login (name, ip, port) -> Fmt.pf ppf "%a login %a:%d" Name.pp name Ipaddr.V4.pp ip port
|
||||
| `Logout (name, ip, port) -> Fmt.pf ppf "%a logout %a:%d" Name.pp name Ipaddr.V4.pp ip port
|
||||
| `Unikernel_start (name, pid, taps, block) ->
|
||||
Fmt.pf ppf "%a started %d (tap %a, block %a)"
|
||||
Name.pp name pid Fmt.(list ~sep:(unit "; ") string) taps
|
||||
|
|
|
@ -101,9 +101,21 @@ module Stats : sig
|
|||
nivcsw : int64;
|
||||
}
|
||||
val pp_rusage : rusage Fmt.t
|
||||
val pp_rusage_mem : rusage Fmt.t
|
||||
|
||||
type kinfo_mem = {
|
||||
vsize : int64 ;
|
||||
rss : int64 ;
|
||||
tsize : int64 ;
|
||||
dsize : int64 ;
|
||||
ssize : int64 ;
|
||||
}
|
||||
|
||||
val pp_kinfo_mem : kinfo_mem Fmt.t
|
||||
|
||||
type vmm = (string * int64) list
|
||||
val pp_vmm : vmm Fmt.t
|
||||
val pp_vmm_mem : vmm Fmt.t
|
||||
|
||||
type ifdata = {
|
||||
ifname : string;
|
||||
|
@ -127,7 +139,7 @@ module Stats : sig
|
|||
}
|
||||
val pp_ifdata : ifdata Fmt.t
|
||||
|
||||
type t = rusage * vmm option * ifdata list
|
||||
type t = rusage * kinfo_mem option * vmm option * ifdata list
|
||||
val pp : t Fmt.t
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue