[libvirt] [PATCHv4] add-vcpu-usage

show `vcpu usages' by `virt-top -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 | 72 ++++++++++++++++++++++++++++++++++++------------- 1 files changed, 53 insertions(+), 19 deletions(-) diff --git a/virt-top/virt_top.ml b/virt-top/virt_top.ml index e2fe554..0dcb170 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,12 +653,17 @@ 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 rec find_usages_from_stats = function + let cpu_stats = D.get_cpu_stats rd.rd_dom false in + let rec find_cpu_usages = function | ("cpu_time", D.TypedFieldUInt64 usages) :: _ -> usages - | _ :: params -> find_usages_from_stats params + | _ :: params -> find_cpu_usages params | [] -> 0L in - let pcpu_usages = Array.map find_usages_from_stats cpu_stats in + let rec find_vcpu_usages = function + | ("vcpu_time", D.TypedFieldUInt64 usages) :: _ -> usages + | _ :: params -> find_vcpu_usages params + | [] -> 0L in + + let pcpu_usages = Array.map find_cpu_usages cpu_stats in let maxinfo = rd.rd_info.D.nr_virt_cpu in let nr_vcpus, vcpu_infos, cpumaps = D.get_vcpus rd.rd_dom maxinfo maplen in @@ -669,11 +675,19 @@ 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_usages = Array.map find_vcpu_usages cpu_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 +705,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 +734,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 +938,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 +947,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 +966,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 the value because we can get it from the libvirt API --- examples/.depend | 4 ++-- examples/get_cpu_stats.ml | 2 +- libvirt/.depend | 6 +++--- libvirt/libvirt.ml | 2 +- libvirt/libvirt.mli | 4 ++-- libvirt/libvirt_c_oneoffs.c | 10 +++++++--- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/examples/.depend b/examples/.depend index 831adf6..f58db3d 100644 --- a/examples/.depend +++ b/examples/.depend @@ -1,6 +1,6 @@ -node_info.cmo: ../libvirt/libvirt.cmi -node_info.cmx: ../libvirt/libvirt.cmx get_cpu_stats.cmo: ../libvirt/libvirt.cmi get_cpu_stats.cmx: ../libvirt/libvirt.cmx list_domains.cmo: ../libvirt/libvirt.cmi list_domains.cmx: ../libvirt/libvirt.cmx +node_info.cmo: ../libvirt/libvirt.cmi +node_info.cmx: ../libvirt/libvirt.cmx diff --git a/examples/get_cpu_stats.ml b/examples/get_cpu_stats.ml index 79d5c3c..d7a8d0c 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 in Array.iteri ( fun n params -> diff --git a/libvirt/.depend b/libvirt/.depend index 43a2367..3f2297e 100644 --- a/libvirt/.depend +++ b/libvirt/.depend @@ -1,6 +1,6 @@ -libvirt_version.cmi: libvirt.cmi: -libvirt_version.cmo: libvirt_version.cmi -libvirt_version.cmx: libvirt_version.cmi +libvirt_version.cmi: libvirt.cmo: libvirt.cmi libvirt.cmx: libvirt.cmi +libvirt_version.cmo: libvirt_version.cmi +libvirt_version.cmx: libvirt_version.cmi diff --git a/libvirt/libvirt.ml b/libvirt/libvirt.ml index 53c5bb4..07542a9 100644 --- a/libvirt/libvirt.ml +++ b/libvirt/libvirt.ml @@ -417,7 +417,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 -> 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..5a288c0 100644 --- a/libvirt/libvirt.mli +++ b/libvirt/libvirt.mli @@ -559,8 +559,8 @@ 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 - (** [get_pcpu_stats dom nr_pcpu] returns the physical CPU stats + val get_cpu_stats : [>`R] t -> typed_param list array + (** [get_pcpu_stats dom] returns the physical CPU stats for a domain. See the libvirt documentation for details. *) val get_max_vcpus : [>`R] t -> int diff --git a/libvirt/libvirt_c_oneoffs.c b/libvirt/libvirt_c_oneoffs.c index 3d42b73..70cf96f 100644 --- a/libvirt/libvirt_c_oneoffs.c +++ b/libvirt/libvirt_c_oneoffs.c @@ -532,17 +532,21 @@ 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) { #ifdef HAVE_VIRDOMAINGETCPUSTATS - CAMLparam2 (domv, nr_pcpusv); + CAMLparam1 (domv); 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); virTypedParameterPtr params; int r, cpu, ncpus, nparams, i, j, pos; + int nr_pcpus; + + /* get number of pcpus */ + NONBLOCKING (nr_pcpus = virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0)); + CHECK_ERROR (nr_pcpus < 0, conn, "virDomainGetCPUStats"); /* get percpu information */ NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, 0, 1, 0)); -- 1.7.1

This parameter is to indicate wheter to get total cpu statistic or per_cpu statistics. --- examples/get_cpu_stats.ml | 48 ++++++++++++++----------- libvirt/libvirt.ml | 2 +- libvirt/libvirt.mli | 4 +- libvirt/libvirt_c_oneoffs.c | 83 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 111 insertions(+), 26 deletions(-) diff --git a/examples/get_cpu_stats.ml b/examples/get_cpu_stats.ml index d7a8d0c..a33f2f8 100644 --- a/examples/get_cpu_stats.ml +++ b/examples/get_cpu_stats.ml @@ -18,32 +18,38 @@ 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 in + let dom = D.lookup_by_name conn domname in + let stats = D.get_cpu_stats dom false in + let total_stats = D.get_cpu_stats dom true 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 + ) stats; + + Array.iteri ( + fun n params -> + printf "total:"; + print_params n params; + printf "\n" + ) 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 07542a9..a9abc2f 100644 --- a/libvirt/libvirt.ml +++ b/libvirt/libvirt.ml @@ -417,7 +417,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 -> typed_param list array = "ocaml_libvirt_domain_get_cpu_stats" + external get_cpu_stats : [>`R] t -> bool -> 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 5a288c0..e1a4b99 100644 --- a/libvirt/libvirt.mli +++ b/libvirt/libvirt.mli @@ -559,8 +559,8 @@ 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 -> typed_param list array - (** [get_pcpu_stats dom] returns the physical CPU stats + val get_cpu_stats : [>`R] t -> bool -> typed_param list array + (** [get_pcpu_stats dom get_total] returns the physical CPU stats for a domain. See the libvirt documentation for details. *) val get_max_vcpus : [>`R] t -> int diff --git a/libvirt/libvirt_c_oneoffs.c b/libvirt/libvirt_c_oneoffs.c index 70cf96f..6fcd515 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) +ocaml_libvirt_domain_get_cpu_stats (value domv, value totalv) { #ifdef HAVE_VIRDOMAINGETCPUSTATS - CAMLparam1 (domv); + CAMLparam2 (domv, totalv); CAMLlocal5 (cpustats, param_head, param_node, typed_param, typed_param_value); CAMLlocal1 (v); virDomainPtr dom = Domain_val (domv); virConnectPtr conn = Connect_domv (domv); + int get_total = totalv == Val_true ? 1 : 0; virTypedParameterPtr params; int r, cpu, ncpus, nparams, i, j, pos; int nr_pcpus; + if (get_total) + goto do_total; + /* get number of pcpus */ NONBLOCKING (nr_pcpus = virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0)); CHECK_ERROR (nr_pcpus < 0, conn, "virDomainGetCPUStats"); @@ -633,6 +637,81 @@ ocaml_libvirt_domain_get_cpu_stats (value domv) } free(params); CAMLreturn (cpustats); + +do_total: + + /* get total information */ + NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0)); + 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, 0)); + 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

Hi Rich, The libvirt counterpart have been already in, do you have time to look at the ocaml-libvirt and virt-top patches? On Wed, May 09, 2012 at 04:48:29PM +0800, Hu Tao wrote:
show `vcpu usages' by `virt-top -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 | 72 ++++++++++++++++++++++++++++++++++++------------- 1 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/virt-top/virt_top.ml b/virt-top/virt_top.ml index e2fe554..0dcb170 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,12 +653,17 @@ 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 rec find_usages_from_stats = function + let cpu_stats = D.get_cpu_stats rd.rd_dom false in + let rec find_cpu_usages = function | ("cpu_time", D.TypedFieldUInt64 usages) :: _ -> usages - | _ :: params -> find_usages_from_stats params + | _ :: params -> find_cpu_usages params | [] -> 0L in - let pcpu_usages = Array.map find_usages_from_stats cpu_stats in + let rec find_vcpu_usages = function + | ("vcpu_time", D.TypedFieldUInt64 usages) :: _ -> usages + | _ :: params -> find_vcpu_usages params + | [] -> 0L in + + let pcpu_usages = Array.map find_cpu_usages cpu_stats in let maxinfo = rd.rd_info.D.nr_virt_cpu in let nr_vcpus, vcpu_infos, cpumaps = D.get_vcpus rd.rd_dom maxinfo maplen in @@ -669,11 +675,19 @@ 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_usages = Array.map find_vcpu_usages cpu_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 +705,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 +734,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 +938,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 +947,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 +966,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
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Thanks, Hu Tao

On Thu, May 31, 2012 at 06:54:47PM +0800, Hu Tao wrote:
Hi Rich,
The libvirt counterpart have been already in, do you have time to look at the ocaml-libvirt and virt-top patches?
I am intending to look at them, don't worry about that, but I'm busy for the next week. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora

On Thu, May 31, 2012 at 01:24:11PM +0100, Richard W.M. Jones wrote:
On Thu, May 31, 2012 at 06:54:47PM +0800, Hu Tao wrote:
Hi Rich,
The libvirt counterpart have been already in, do you have time to look at the ocaml-libvirt and virt-top patches?
I am intending to look at them, don't worry about that, but I'm busy for the next week.
I hope it is still on your todo list to review these two patches:) -- Thanks, Hu Tao

Hi Rich, The corresponding bugzilla item is 841759. Will you have a look at this patch? On Wed, May 09, 2012 at 04:48:29PM +0800, Hu Tao wrote:
show `vcpu usages' by `virt-top -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 | 72 ++++++++++++++++++++++++++++++++++++------------- 1 files changed, 53 insertions(+), 19 deletions(-)
diff --git a/virt-top/virt_top.ml b/virt-top/virt_top.ml index e2fe554..0dcb170 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,12 +653,17 @@ 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 rec find_usages_from_stats = function + let cpu_stats = D.get_cpu_stats rd.rd_dom false in + let rec find_cpu_usages = function | ("cpu_time", D.TypedFieldUInt64 usages) :: _ -> usages - | _ :: params -> find_usages_from_stats params + | _ :: params -> find_cpu_usages params | [] -> 0L in - let pcpu_usages = Array.map find_usages_from_stats cpu_stats in + let rec find_vcpu_usages = function + | ("vcpu_time", D.TypedFieldUInt64 usages) :: _ -> usages + | _ :: params -> find_vcpu_usages params + | [] -> 0L in + + let pcpu_usages = Array.map find_cpu_usages cpu_stats in let maxinfo = rd.rd_info.D.nr_virt_cpu in let nr_vcpus, vcpu_infos, cpumaps = D.get_vcpus rd.rd_dom maxinfo maplen in @@ -669,11 +675,19 @@ 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_usages = Array.map find_vcpu_usages cpu_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 +705,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 +734,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 +938,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 +947,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 +966,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
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- Thanks, Hu Tao
participants (2)
-
Hu Tao
-
Richard W.M. Jones