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_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)

View file

@ -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

View file

@ -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
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
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 () ->

View file

@ -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" ;
]

View file

@ -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))))

View file

@ -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

View file

@ -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