[libvirt] [PATCHv3 1/2] add parameter flags to D.get_cpu_stats()

--- examples/get_cpu_stats.ml | 2 +- libvirt/libvirt.ml | 6 +++++- libvirt/libvirt.mli | 6 +++++- libvirt/libvirt_c_oneoffs.c | 21 +++++++++++++++++---- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/examples/get_cpu_stats.ml b/examples/get_cpu_stats.ml index 79d5c3c..962a2a4 100644 --- a/examples/get_cpu_stats.ml +++ b/examples/get_cpu_stats.ml @@ -25,7 +25,7 @@ let () = let stats = let dom = D.lookup_by_name conn domname in - D.get_cpu_stats dom nr_pcpus in + D.get_cpu_stats dom nr_pcpus [D.None;] in Array.iteri ( fun n params -> diff --git a/libvirt/libvirt.ml b/libvirt/libvirt.ml index 53c5bb4..de303f7 100644 --- a/libvirt/libvirt.ml +++ b/libvirt/libvirt.ml @@ -348,6 +348,10 @@ struct | TypedFieldFloat of float | TypedFieldBool of bool | TypedFieldString of string + type get_cpu_stats_flags = + | None + | Vcpu + type migrate_flag = Live type memory_flag = Virtual @@ -417,7 +421,7 @@ struct external set_vcpus : [>`W] t -> int -> unit = "ocaml_libvirt_domain_set_vcpus" external pin_vcpu : [>`W] t -> int -> string -> unit = "ocaml_libvirt_domain_pin_vcpu" external get_vcpus : [>`R] t -> int -> int -> int * vcpu_info array * string = "ocaml_libvirt_domain_get_vcpus" - external get_cpu_stats : [>`R] t -> int -> typed_param list array = "ocaml_libvirt_domain_get_cpu_stats" + external get_cpu_stats : [>`R] t -> int -> get_cpu_stats_flags list -> typed_param list array = "ocaml_libvirt_domain_get_cpu_stats" external get_max_vcpus : [>`R] t -> int = "ocaml_libvirt_domain_get_max_vcpus" external attach_device : [>`W] t -> xml -> unit = "ocaml_libvirt_domain_attach_device" external detach_device : [>`W] t -> xml -> unit = "ocaml_libvirt_domain_detach_device" diff --git a/libvirt/libvirt.mli b/libvirt/libvirt.mli index 0913a63..5a7e536 100644 --- a/libvirt/libvirt.mli +++ b/libvirt/libvirt.mli @@ -442,6 +442,10 @@ sig | TypedFieldFloat of float | TypedFieldBool of bool | TypedFieldString of string + type get_cpu_stats_flags = + | None + | Vcpu + type migrate_flag = Live type memory_flag = Virtual @@ -559,7 +563,7 @@ sig for a domain. See the libvirt documentation for details of the array and bitmap returned from this function. *) - val get_cpu_stats : [>`R] t -> int -> typed_param list array + val get_cpu_stats : [>`R] t -> int -> get_cpu_stats_flags list -> typed_param list array (** [get_pcpu_stats dom nr_pcpu] returns the physical CPU stats for a domain. See the libvirt documentation for details. *) diff --git a/libvirt/libvirt_c_oneoffs.c b/libvirt/libvirt_c_oneoffs.c index 3d42b73..5d1e8b2 100644 --- a/libvirt/libvirt_c_oneoffs.c +++ b/libvirt/libvirt_c_oneoffs.c @@ -532,20 +532,33 @@ extern int virDomainGetCPUStats (virDomainPtr domain, #endif CAMLprim value -ocaml_libvirt_domain_get_cpu_stats (value domv, value nr_pcpusv) +ocaml_libvirt_domain_get_cpu_stats (value domv, value nr_pcpusv, value flagsv) { #ifdef HAVE_VIRDOMAINGETCPUSTATS - CAMLparam2 (domv, nr_pcpusv); + CAMLparam3 (domv, nr_pcpusv, flagsv); CAMLlocal5 (cpustats, param_head, param_node, typed_param, typed_param_value); CAMLlocal1 (v); virDomainPtr dom = Domain_val (domv); virConnectPtr conn = Connect_domv (domv); int nr_pcpus = Int_val (nr_pcpusv); + int flags = 0; virTypedParameterPtr params; int r, cpu, ncpus, nparams, i, j, pos; + /* Iterate over the list of flags. */ + for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1)) + { + switch (Int_val(Field(flagsv, 0))) { + case 1: /* Vcpu */ + flags |= VIR_DOMAIN_CPU_STATS_VCPU; + break; + default: + break; + } + } + /* get percpu information */ - NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, 0, 1, 0)); + NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, 0, 1, flags)); CHECK_ERROR (nparams < 0, conn, "virDomainGetCPUStats"); if ((params = malloc(sizeof(*params) * nparams * 128)) == NULL) @@ -556,7 +569,7 @@ ocaml_libvirt_domain_get_cpu_stats (value domv, value nr_pcpusv) while (cpu < nr_pcpus) { ncpus = nr_pcpus - cpu > 128 ? 128 : nr_pcpus - cpu; - NONBLOCKING (r = virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, 0)); + NONBLOCKING (r = virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, flags)); CHECK_ERROR (r < 0, conn, "virDomainGetCPUStats"); for (i = 0; i < ncpus; i++) { -- 1.7.1

Before this patch, `virt-top -1' shows total cpu usages which euqal to `vcpu usages' + `hypervisor usages'. This patch adds another column for domains showing `vcpu usages'. An example is: PHYCPU %CPU example_domain 0 10.4 10.4 0.8 1 1.6 1.6 1.4 2 2.6 2.6 2.6 3 0.0 0.0 0.1 --- virt-top/virt_top.ml | 62 +++++++++++++++++++++++++++++++++++++------------- 1 files changed, 46 insertions(+), 16 deletions(-) diff --git a/virt-top/virt_top.ml b/virt-top/virt_top.ml index e2fe554..95e45a8 100644 --- a/virt-top/virt_top.ml +++ b/virt-top/virt_top.ml @@ -448,6 +448,7 @@ let collect, clear_pcpu_display_data = (* Save pcpu_usages structures across redraws too (only for pCPU display). *) let last_pcpu_usages = Hashtbl.create 13 in + let last_vcpu_usages = Hashtbl.create 13 in let clear_pcpu_display_data () = (* Clear out pcpu_usages used by PCPUDisplay display_mode @@ -652,7 +653,7 @@ let collect, clear_pcpu_display_data = (try let domid = rd.rd_domid in let maplen = C.cpumaplen nr_pcpus in - let cpu_stats = D.get_cpu_stats rd.rd_dom nr_pcpus in + let cpu_stats = D.get_cpu_stats rd.rd_dom false [D.None;] in let rec find_usages_from_stats = function | ("cpu_time", D.TypedFieldUInt64 usages) :: _ -> usages | _ :: params -> find_usages_from_stats params @@ -669,11 +670,20 @@ let collect, clear_pcpu_display_data = (* Update last_pcpu_usages. *) Hashtbl.replace last_pcpu_usages domid pcpu_usages; - (match prev_pcpu_usages with - | Some prev_pcpu_usages + (* vcpu usages *) + let vcpu_stats = D.get_cpu_stats rd.rd_dom false [D.Vcpu;] in + let vcpu_usages = Array.map find_usages_from_stats vcpu_stats in + let prev_vcpu_usages = + try Some (Hashtbl.find last_vcpu_usages domid) + with Not_found -> None in + Hashtbl.replace last_vcpu_usages domid vcpu_usages; + + (match prev_pcpu_usages, prev_vcpu_usages with + | Some prev_pcpu_usages, Some prev_vcpu_usages when Array.length prev_pcpu_usages = Array.length pcpu_usages -> - Some (domid, name, nr_vcpus, vcpu_infos, pcpu_usages, - prev_pcpu_usages, cpumaps, maplen) + Some (domid, name, nr_vcpus, vcpu_infos, pcpu_usages, + prev_pcpu_usages, vcpu_usages, prev_vcpu_usages, + cpumaps, maplen) | _ -> None (* ignore missing / unequal length prev_vcpu_infos *) ); with @@ -691,13 +701,24 @@ let collect, clear_pcpu_display_data = List.iteri ( fun di (domid, name, nr_vcpus, vcpu_infos, pcpu_usages, - prev_pcpu_usages, cpumaps, maplen) -> + prev_pcpu_usages, vcpu_usages, prev_vcpu_usages, + cpumaps, maplen) -> (* Which pCPUs can this dom run on? *) for p = 0 to Array.length pcpu_usages - 1 do pcpus.(p).(di) <- pcpu_usages.(p) -^ prev_pcpu_usages.(p) - done + done ) doms; + let vcpus = Array.make_matrix nr_pcpus nr_doms 0L in + List.iteri ( + fun di (domid, name, nr_vcpus, vcpu_infos, pcpu_usages, + prev_pcpu_usages, vcpu_usages, prev_vcpu_usages, + cpumaps, maplen) -> + for p = 0 to Array.length vcpu_usages - 1 do + vcpus.(p).(di) <- vcpu_usages.(p) -^ prev_vcpu_usages.(p) + done + ) doms; + (* Sum the CPU time used by each pCPU, for the %CPU column. *) let pcpus_cpu_time = Array.map ( fun row -> @@ -709,7 +730,7 @@ let collect, clear_pcpu_display_data = Int64.to_float !cpu_time ) pcpus in - Some (doms, pcpus, pcpus_cpu_time) + Some (doms, pcpus, vcpus, pcpus_cpu_time) ) else None in @@ -913,7 +934,7 @@ let redraw = loop domains_lineno doms | PCPUDisplay -> (*---------- Showing physical CPUs ----------*) - let doms, pcpus, pcpus_cpu_time = + let doms, pcpus, vcpus, pcpus_cpu_time = match pcpu_display with | Some p -> p | None -> failwith "internal error: no pcpu_display data" in @@ -922,9 +943,9 @@ let redraw = let dom_names = String.concat "" ( List.map ( - fun (_, name, _, _, _, _, _, _) -> + fun (_, name, _, _, _, _, _, _, _, _) -> let len = String.length name in - let width = max (len+1) 7 in + let width = max (len+1) 12 in pad width name ) doms ) in @@ -941,18 +962,27 @@ let redraw = addch ' '; List.iteri ( - fun di (domid, name, _, _, _, _, _, _) -> + fun di (domid, name, _, _, _, _, _, _, _, _) -> let t = pcpus.(p).(di) in + let tv = vcpus.(p).(di) in let len = String.length name in - let width = max (len+1) 7 in - let str = + let width = max (len+1) 12 in + let str_pcpu = if t <= 0L then "" else ( let t = Int64.to_float t in let percent = 100. *. t /. total_cpu_per_pcpu in - sprintf "%s " (Show.percent percent) + sprintf "%s" (Show.percent percent) ) in - addstr (pad width str); + let str_vcpu = + if tv <= 0L then "" + else ( + let tv = Int64.to_float tv in + let percent = 100. *. tv /. total_cpu_per_pcpu in + sprintf "%s" (Show.percent percent) + ) in + let str = sprintf "%s %s" str_pcpu str_vcpu in + addstr (pad width str); () ) doms ) pcpus; -- 1.7.1

Remove parameter nr_pcpus. Add another parameter total of type bool to indicate wheter to get total cpu statistic or per_cpu statistics. --- examples/get_cpu_stats.ml | 50 ++++++++++++++---------- libvirt/libvirt.ml | 2 +- libvirt/libvirt.mli | 2 +- libvirt/libvirt_c_oneoffs.c | 89 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 117 insertions(+), 26 deletions(-) diff --git a/examples/get_cpu_stats.ml b/examples/get_cpu_stats.ml index 962a2a4..a4e657d 100644 --- a/examples/get_cpu_stats.ml +++ b/examples/get_cpu_stats.ml @@ -18,32 +18,40 @@ let () = let domname = Sys.argv.(1) in let conn = C.connect_readonly () in - - let nr_pcpus = - let info = C.get_node_info conn in - C.maxcpus_of_node_info info in - - let stats = - let dom = D.lookup_by_name conn domname in - D.get_cpu_stats dom nr_pcpus [D.None;] in + let dom = D.lookup_by_name conn domname in + + let stats = D.get_cpu_stats dom false [D.Vcpu;] in + let total_stats = D.get_cpu_stats dom false [D.None;] in + + let print_params n params = + List.iter ( + fun (name, value) -> + printf " %s=" name; + match value with + | D.TypedFieldInt32 i -> printf "%ld" i + | D.TypedFieldUInt32 i -> printf "%ld" i + | D.TypedFieldInt64 i -> printf "%Ld" i + | D.TypedFieldUInt64 i -> printf "%Ld" i + | D.TypedFieldFloat f -> printf "%g" f + | D.TypedFieldBool b -> printf "%b" b + | D.TypedFieldString s -> printf "%S" s + ) params in Array.iteri ( fun n params -> printf "pCPU %d:" n; - List.iter ( - fun (name, value) -> - printf " %s=" name; - match value with - | D.TypedFieldInt32 i -> printf "%ld" i - | D.TypedFieldUInt32 i -> printf "%ld" i - | D.TypedFieldInt64 i -> printf "%Ld" i - | D.TypedFieldUInt64 i -> printf "%Ld" i - | D.TypedFieldFloat f -> printf "%g" f - | D.TypedFieldBool b -> printf "%b" b - | D.TypedFieldString s -> printf "%S" s - ) params; + print_params n params; + printf "\n" + ) stats; + + Array.iteri ( + fun n params -> + printf "total:"; + print_params n params; printf "\n" - ) stats + ) total_stats + + with Libvirt.Virterror err -> eprintf "error: %s\n" (Libvirt.Virterror.to_string err) diff --git a/libvirt/libvirt.ml b/libvirt/libvirt.ml index de303f7..8f7abee 100644 --- a/libvirt/libvirt.ml +++ b/libvirt/libvirt.ml @@ -421,7 +421,7 @@ struct external set_vcpus : [>`W] t -> int -> unit = "ocaml_libvirt_domain_set_vcpus" external pin_vcpu : [>`W] t -> int -> string -> unit = "ocaml_libvirt_domain_pin_vcpu" external get_vcpus : [>`R] t -> int -> int -> int * vcpu_info array * string = "ocaml_libvirt_domain_get_vcpus" - external get_cpu_stats : [>`R] t -> int -> get_cpu_stats_flags list -> typed_param list array = "ocaml_libvirt_domain_get_cpu_stats" + external get_cpu_stats : [>`R] t -> bool -> get_cpu_stats_flags list -> typed_param list array = "ocaml_libvirt_domain_get_cpu_stats" external get_max_vcpus : [>`R] t -> int = "ocaml_libvirt_domain_get_max_vcpus" external attach_device : [>`W] t -> xml -> unit = "ocaml_libvirt_domain_attach_device" external detach_device : [>`W] t -> xml -> unit = "ocaml_libvirt_domain_detach_device" diff --git a/libvirt/libvirt.mli b/libvirt/libvirt.mli index 5a7e536..4be3fe4 100644 --- a/libvirt/libvirt.mli +++ b/libvirt/libvirt.mli @@ -563,7 +563,7 @@ sig for a domain. See the libvirt documentation for details of the array and bitmap returned from this function. *) - val get_cpu_stats : [>`R] t -> int -> get_cpu_stats_flags list -> typed_param list array + val get_cpu_stats : [>`R] t -> bool -> get_cpu_stats_flags list -> typed_param list array (** [get_pcpu_stats dom nr_pcpu] returns the physical CPU stats for a domain. See the libvirt documentation for details. *) diff --git a/libvirt/libvirt_c_oneoffs.c b/libvirt/libvirt_c_oneoffs.c index 5d1e8b2..7f8a103 100644 --- a/libvirt/libvirt_c_oneoffs.c +++ b/libvirt/libvirt_c_oneoffs.c @@ -532,18 +532,22 @@ extern int virDomainGetCPUStats (virDomainPtr domain, #endif CAMLprim value -ocaml_libvirt_domain_get_cpu_stats (value domv, value nr_pcpusv, value flagsv) +ocaml_libvirt_domain_get_cpu_stats (value domv, value totalv, value flagsv) { #ifdef HAVE_VIRDOMAINGETCPUSTATS - CAMLparam3 (domv, nr_pcpusv, flagsv); + CAMLparam3 (domv, totalv, flagsv); CAMLlocal5 (cpustats, param_head, param_node, typed_param, typed_param_value); CAMLlocal1 (v); virDomainPtr dom = Domain_val (domv); virConnectPtr conn = Connect_domv (domv); - int nr_pcpus = Int_val (nr_pcpusv); + int get_total = totalv == Val_true ? 1 : 0; int flags = 0; virTypedParameterPtr params; int r, cpu, ncpus, nparams, i, j, pos; + int nr_pcpus; + + if (get_total) + goto do_total; /* Iterate over the list of flags. */ for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1)) @@ -557,6 +561,10 @@ ocaml_libvirt_domain_get_cpu_stats (value domv, value nr_pcpusv, value flagsv) } } + /* get number of pcpus */ + NONBLOCKING (nr_pcpus = virDomainGetCPUStats(dom, NULL, 0, 0, 0, flags)); + CHECK_ERROR (nr_pcpus < 0, conn, "virDomainGetCPUStats"); + /* get percpu information */ NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, 0, 1, flags)); CHECK_ERROR (nparams < 0, conn, "virDomainGetCPUStats"); @@ -642,6 +650,81 @@ ocaml_libvirt_domain_get_cpu_stats (value domv, value nr_pcpusv, value flagsv) } free(params); CAMLreturn (cpustats); + +do_total: + + /* get total information */ + NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, flags)); + CHECK_ERROR (nparams < 0, conn, "virDomainGetCPUStats"); + + if ((params = malloc(sizeof(*params) * nparams)) == NULL) + caml_failwith ("virDomainGetCPUStats: malloc"); + + cpustats = caml_alloc (1, 0); /* cpustats: array of params(list of typed_param) */ + + NONBLOCKING (r = virDomainGetCPUStats(dom, params, nparams, -1, 1, flags)); + CHECK_ERROR (r < 0, conn, "virDomainGetCPUStats"); + + param_head = Val_emptylist; + if (params[nparams].type != 0) { + for (j = r - 1; j >= 0; j--) { + pos = j; + + param_node = caml_alloc(2, 0); /* param_node: typed_param, next param_node */ + Store_field(param_node, 1, param_head); + param_head = param_node; + + typed_param = caml_alloc(2, 0); /* typed_param: field name(string), typed_param_value */ + Store_field(param_node, 0, typed_param); + Store_field(typed_param, 0, caml_copy_string(params[pos].field)); + + /* typed_param_value: value with the corresponding type tag */ + switch(params[pos].type) { + case VIR_TYPED_PARAM_INT: + typed_param_value = caml_alloc (1, 0); + v = caml_copy_int32 (params[pos].value.i); + break; + case VIR_TYPED_PARAM_UINT: + typed_param_value = caml_alloc (1, 1); + v = caml_copy_int32 (params[pos].value.ui); + break; + case VIR_TYPED_PARAM_LLONG: + typed_param_value = caml_alloc (1, 2); + v = caml_copy_int64 (params[pos].value.l); + break; + case VIR_TYPED_PARAM_ULLONG: + typed_param_value = caml_alloc (1, 3); + v = caml_copy_int64 (params[pos].value.ul); + break; + case VIR_TYPED_PARAM_DOUBLE: + typed_param_value = caml_alloc (1, 4); + v = caml_copy_double (params[pos].value.d); + break; + case VIR_TYPED_PARAM_BOOLEAN: + typed_param_value = caml_alloc (1, 5); + v = Val_bool (params[pos].value.b); + break; + case VIR_TYPED_PARAM_STRING: + typed_param_value = caml_alloc (1, 6); + v = caml_copy_string (params[pos].value.s); + free (params[pos].value.s); + break; + default: + /* XXX Memory leak on this path, if there are more + * VIR_TYPED_PARAM_STRING past this point in the array. + */ + free (params); + caml_failwith ("virDomainGetCPUStats: " + "unknown parameter type returned"); + } + Store_field (typed_param_value, 0, v); + Store_field (typed_param, 1, typed_param_value); + } + } + Store_field (cpustats, 0, param_head); + + free(params); + CAMLreturn (cpustats); #else not_supported ("virDomainGetCPUStats"); #endif -- 1.7.1
participants (1)
-
Hu Tao