let domid = rd.rd_domid in
let maplen = C.cpumaplen nr_pcpus in
let cpu_stats = D.get_cpu_stats rd.rd_dom in
- let rec find_cpu_usages = function
- | ("cpu_time", D.TypedFieldUInt64 usages) :: _ -> usages
- | _ :: params -> find_cpu_usages params
- | [] -> 0L in
+
+ (* Note the terminology is confusing.
+ *
+ * In libvirt, cpu_time is the total time (hypervisor + vCPU).
+ * vcpu_time is the time only taken by the vCPU,
+ * excluding time taken inside the hypervisor.
+ *
+ * For each pCPU, libvirt may return either "cpu_time"
+ * or "vcpu_time" or neither or both. This function
+ * returns an array pair [|cpu_time, vcpu_time|];
+ * if either is missing it is returned as 0.
+ *)
+ let find_cpu_usages params =
+ let rec find_uint64_field name = function
+ | (n, D.TypedFieldUInt64 usage) :: _ when n = name -> usage
+ | _ :: params -> find_uint64_field name params
+ | [] -> 0L
+ in
+ [| find_uint64_field "cpu_time" params;
+ find_uint64_field "vcpu_time" params |]
+ 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 =
(* Rearrange the data into a matrix. Major axis (down) is
* pCPUs. Minor axis (right) is domains. At each node we store:
- * cpu_time (on this pCPU only, nanosecs),
+ * cpu_time hypervisor + domain (on this pCPU only, nanosecs),
+ * vcpu_time domain only (on this pCPU only, nanosecs).
*)
- let pcpus = Array.make_matrix nr_pcpus nr_doms 0L in
+ let make_3d_array dimx dimy dimz e =
+ Array.init dimx (fun _ -> Array.make_matrix dimy dimz e)
+ in
+ let pcpus = make_3d_array nr_pcpus nr_doms 2 0L in
List.iteri (
fun di (domid, name, nr_vcpus, vcpu_infos, pcpu_usages,
prev_pcpu_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
+ pcpus.(p).(di).(0) <-
+ pcpu_usages.(p).(0) -^ prev_pcpu_usages.(p).(0);
+ pcpus.(p).(di).(1) <-
+ pcpu_usages.(p).(1) -^ prev_pcpu_usages.(p).(1)
+ done
) doms;
- (* Sum the CPU time used by each pCPU, for the %CPU column. *)
+ (* Sum the total CPU time used by each pCPU, for the %CPU column. *)
let pcpus_cpu_time = Array.map (
fun row ->
let cpu_time = ref 0L in
for di = 0 to Array.length row-1 do
- let t = row.(di) in
+ let t = row.(di).(0) in
cpu_time := !cpu_time +^ t
done;
Int64.to_float !cpu_time
List.map (
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
List.iteri (
fun di (domid, name, _, _, _, _, _, _) ->
- let t = pcpus.(p).(di) in
+ let t = pcpus.(p).(di).(0) in (* hypervisor + domain *)
+ let t_only = pcpus.(p).(di).(1) in (* domain only *)
let len = String.length name in
- let width = max (len+1) 7 in
- let str =
+ let width = max (len+1) 12 in
+ let str_t =
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)
+ Show.percent percent
) in
- addstr (pad width str);
+ let str_t_only =
+ if t_only <= 0L then ""
+ else (
+ let t_only = Int64.to_float t_only in
+ let percent = 100. *. t_only /. total_cpu_per_pcpu in
+ Show.percent percent
+ ) in
+ addstr (pad 5 str_t);
+ addstr (pad 5 str_t_only);
+ addstr (pad (width-10) " ");
()
) doms
) pcpus;