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:
Hannes Mehnert 2019-01-06 01:12:56 +01:00
parent 030f5aa379
commit fd4a5a5e22
9 changed files with 169 additions and 16 deletions

1
_tags
View file

@ -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_log.{ml,native,byte}>: package(ptime.clock.os)
<app/vmmd_tls*.{ml,native,byte}>: package(tls.lwt 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/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_remote.{ml,native,byte}>: package(nocrypto tls.lwt nocrypto.lwt)
<app/vmmc_bistro.{ml,native,byte}>: package(nocrypto tls.lwt nocrypto.lwt) <app/vmmc_bistro.{ml,native,byte}>: package(nocrypto tls.lwt nocrypto.lwt)

View file

@ -6,6 +6,7 @@ open Rresult.R.Infix
open Vmm_core open Vmm_core
external sysctl_rusage : int -> Stats.rusage = "vmmanage_sysctl_rusage" 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_ifcount : unit -> int = "vmmanage_sysctl_ifcount"
external sysctl_ifdata : int -> Stats.ifdata = "vmmanage_sysctl_ifdata" external sysctl_ifdata : int -> Stats.ifdata = "vmmanage_sysctl_ifdata"
@ -83,6 +84,7 @@ let try_open_vmmapi pid_nic =
let gather pid vmctx nics = let gather pid vmctx nics =
wrap sysctl_rusage pid, wrap sysctl_rusage pid,
wrap sysctl_kinfo_mem pid,
(match vmctx with (match vmctx with
| Error _ -> None | Error _ -> None
| Ok vmctx -> wrap vmmapi_stats vmctx), | Ok vmctx -> wrap vmmapi_stats vmctx),
@ -105,13 +107,13 @@ let tick t =
| xs -> match IM.find_opt pid t.pid_nic with | xs -> match IM.find_opt pid t.pid_nic with
| None -> Logs.warn (fun m -> m "couldn't find nics of %d" pid) ; out | None -> Logs.warn (fun m -> m "couldn't find nics of %d" pid) ; out
| Some (vmctx, nics) -> | 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 match ru with
| None -> Logs.err (fun m -> m "failed to get rusage for %d" pid) ; out | None -> Logs.err (fun m -> m "failed to get rusage for %d" pid) ; out
| Some ru' -> | Some ru' ->
let stats = let stats =
let vmm' = match vmm with None -> None | Some xs -> Some (List.combine !descr xs) in let vmm' = match vmm with None -> None | Some xs -> Some (List.combine !descr xs) in
ru', vmm', ifd ru', mem, vmm', ifd
in in
List.fold_left (fun out (id, socket) -> List.fold_left (fun out (id, socket) ->
match Vmm_core.Name.drop_super ~super:id ~sub:vmid with match Vmm_core.Name.drop_super ~super:id ~sub:vmid with

View file

@ -21,6 +21,34 @@
#include <net/if_mib.h> #include <net/if_mib.h>
#include <vmmapi.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) { CAMLprim value vmmanage_sysctl_rusage (value pid_r) {
CAMLparam1(pid_r); CAMLparam1(pid_r);
CAMLlocal3(res, utime, stime); CAMLlocal3(res, utime, stime);
@ -201,6 +229,11 @@ CAMLprim value vmmanage_sysctl_rusage (value pid_r) {
uerror("sysctl_rusage", Nothing); 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) { CAMLprim value vmmanage_sysctl_ifcount (value unit) {
CAMLparam1(unit); CAMLparam1(unit);
uerror("sysctl_ifcount", Nothing); uerror("sysctl_ifcount", Nothing);

57
app/vmmc_stat.ml Normal file
View 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

View file

@ -100,6 +100,18 @@ module P = struct
let fields = List.map (fun (k, v) -> k ^ "=" ^ v) fields in let fields = List.map (fun (k, v) -> k ^ "=" ^ v) fields in
Printf.sprintf "resource_usage,vm=%s %s" vm (String.concat ~sep:"," fields) 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 encode_vmm vm xs =
let escape s = let escape s =
let cutted = String.cuts ~sep:"," s in 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 fd >>= fun () ->
safe_close c >|= fun () -> safe_close c >|= fun () ->
true true
| Ok (hdr, `Data (`Stats_data (ru, vmm, ifs))) -> | Ok (hdr, `Data (`Stats_data (ru, mem, vmm, ifs))) ->
begin begin
if not (Vmm_commands.version_eq hdr.Vmm_commands.version my_version) then begin if not (Vmm_commands.version_eq hdr.Vmm_commands.version my_version) then begin
Logs.err (fun m -> m "unknown wire protocol version") ; 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 end else
let name = Name.to_string hdr.Vmm_commands.name in let name = Name.to_string hdr.Vmm_commands.name in
let ru = P.encode_ru name ru 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 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)) ; Logs.debug (fun m -> m "writing %d via tcp" (String.length out)) ;
Vmm_lwt.write_raw fd (Bytes.unsafe_of_string out) >>= function Vmm_lwt.write_raw fd (Bytes.unsafe_of_string out) >>= function
| Ok () -> | Ok () ->

View file

@ -18,4 +18,5 @@ let () =
Pkg.bin "app/vmmc_bistro" ; Pkg.bin "app/vmmc_bistro" ;
Pkg.bin "app/vmmp_request" ; Pkg.bin "app/vmmp_request" ;
Pkg.bin "app/vmmp_ca" ; Pkg.bin "app/vmmp_ca" ;
Pkg.test ~run:false "app/vmmc_stat" ;
] ]

View file

@ -120,6 +120,21 @@ let ru =
@ (required ~label:"nvcsw" int64) @ (required ~label:"nvcsw" int64)
-@ (required ~label:"nivcsw" 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? *) (* TODO is this good? *)
let int32 = let int32 =
let f i = Int32.of_int i let f i = Int32.of_int i
@ -349,11 +364,11 @@ let wire_command =
let data = let data =
let f = function let f = function
| `C1 (timestamp, data) -> `Console_data (timestamp, data) | `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) | `C3 (timestamp, event) -> `Log_data (timestamp, event)
and g = function and g = function
| `Console_data (timestamp, data) -> `C1 (timestamp, data) | `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) | `Log_data (timestamp, event) -> `C3 (timestamp, event)
in in
Asn.S.map f g @@ Asn.S.map f g @@
@ -361,13 +376,14 @@ let data =
(explicit 0 (sequence2 (explicit 0 (sequence2
(required ~label:"timestamp" utc_time) (required ~label:"timestamp" utc_time)
(required ~label:"data" utf8_string))) (required ~label:"data" utf8_string)))
(explicit 1 (sequence3 (explicit 1 (sequence4
(required ~label:"resource_usage" ru) (required ~label:"resource_usage" ru)
(required ~label:"ifdata" (sequence_of ifdata)) (required ~label:"ifdata" (sequence_of ifdata))
(optional ~label:"vmm_stats" (optional ~label:"vmm_stats" @@ explicit 0
(sequence_of (sequence2 (sequence_of (sequence2
(required ~label:"key" utf8_string) (required ~label:"key" utf8_string)
(required ~label:"value" int64)))))) (required ~label:"value" int64))))
(optional ~label:"kinfo_mem" @@ implicit 1 kinfo_mem)))
(explicit 2 (sequence2 (explicit 2 (sequence2
(required ~label:"timestamp" utc_time) (required ~label:"timestamp" utc_time)
(required ~label:"event" log_event)))) (required ~label:"event" log_event))))

View file

@ -213,11 +213,28 @@ module Stats = struct
let pp_rusage ppf r = 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" 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 (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 type vmm = (string * int64) list
let pp_vmm ppf vmm = let pp_vmm ppf vmm =
Fmt.(list ~sep:(unit "@.") (pair ~sep:(unit ": ") string int64)) 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 = { type ifdata = {
ifname : string ; 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" 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 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 type t = rusage * kinfo_mem option * vmm option * ifdata list
let pp ppf (ru, vmm, ifs) = let pp ppf (ru, mem, vmm, ifs) =
Fmt.pf ppf "%a@.%a@.%a" Fmt.pf ppf "%a@.%a@.%a@.%a"
pp_rusage ru 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.(option ~none:(unit "no vmm stats") pp_vmm) vmm
Fmt.(list ~sep:(unit "@.@.") pp_ifdata) ifs Fmt.(list ~sep:(unit "@.@.") pp_ifdata) ifs
end end
@ -279,8 +297,8 @@ module Log = struct
let pp_log_event ppf = function let pp_log_event ppf = function
| `Startup -> Fmt.string ppf "startup" | `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 | `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_hum 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) -> | `Unikernel_start (name, pid, taps, block) ->
Fmt.pf ppf "%a started %d (tap %a, block %a)" Fmt.pf ppf "%a started %d (tap %a, block %a)"
Name.pp name pid Fmt.(list ~sep:(unit "; ") string) taps Name.pp name pid Fmt.(list ~sep:(unit "; ") string) taps

View file

@ -101,9 +101,21 @@ module Stats : sig
nivcsw : int64; nivcsw : int64;
} }
val pp_rusage : rusage Fmt.t 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 type vmm = (string * int64) list
val pp_vmm : vmm Fmt.t val pp_vmm : vmm Fmt.t
val pp_vmm_mem : vmm Fmt.t
type ifdata = { type ifdata = {
ifname : string; ifname : string;
@ -127,7 +139,7 @@ module Stats : sig
} }
val pp_ifdata : ifdata Fmt.t 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 val pp : t Fmt.t
end end