+ (* Collect some extra information in PCPUDisplay display_mode. *)
+ let pcpu_display =
+ if !display_mode = PCPUDisplay then (
+ (* Get the VCPU info and VCPU->PCPU mappings for active domains.
+ * Also cull some data we don't care about.
+ *)
+ let doms = List.filter_map (
+ function
+ | (name, Active rd) ->
+ (try
+ 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
+ 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
+
+ (* Got previous pcpu_usages for this domain? *)
+ let prev_pcpu_usages =
+ try Some (Hashtbl.find last_pcpu_usages domid)
+ with Not_found -> None in
+ (* Update last_pcpu_usages. *)
+ Hashtbl.replace last_pcpu_usages domid pcpu_usages;
+
+ (match prev_pcpu_usages with
+ | Some prev_pcpu_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)
+ | _ -> None (* ignore missing / unequal length prev_vcpu_infos *)
+ );
+ with
+ Libvirt.Virterror _ -> None(* ignore transient libvirt errs *)
+ )
+ | (_, Inactive) -> None (* ignore inactive doms *)
+ ) doms in
+ let nr_doms = List.length doms in
+
+ (* 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),
+ *)
+ let pcpus = Array.make_matrix nr_pcpus nr_doms 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
+ ) doms;
+
+ (* Sum the 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
+ cpu_time := !cpu_time +^ t
+ done;
+ Int64.to_float !cpu_time
+ ) pcpus in
+
+ Some (doms, pcpus, pcpus_cpu_time)
+ ) else
+ None in
+
+ (* Calculate totals. *)
+ let totals = List.fold_left (
+ fun (count, running, blocked, paused, shutdown, shutoff,
+ crashed, active, inactive,
+ total_cpu_time, total_memory, total_domU_memory) ->
+ function
+ | (name, Active rd) ->
+ let test state orig =
+ if rd.rd_info.D.state = state then orig+1 else orig
+ in
+ let running = test D.InfoRunning running in
+ let blocked = test D.InfoBlocked blocked in
+ let paused = test D.InfoPaused paused in
+ let shutdown = test D.InfoShutdown shutdown in
+ let shutoff = test D.InfoShutoff shutoff in
+ let crashed = test D.InfoCrashed crashed in
+
+ let total_cpu_time = total_cpu_time +. rd.rd_cpu_time in
+ let total_memory = total_memory +^ rd.rd_info.D.memory in
+ let total_domU_memory = total_domU_memory +^
+ if rd.rd_domid > 0 then rd.rd_info.D.memory else 0L in
+
+ (count+1, running, blocked, paused, shutdown, shutoff,
+ crashed, active+1, inactive,
+ total_cpu_time, total_memory, total_domU_memory)
+
+ | (name, Inactive) -> (* inactive domain *)
+ (count+1, running, blocked, paused, shutdown, shutoff,
+ crashed, active, inactive+1,
+ total_cpu_time, total_memory, total_domU_memory)
+ ) (0,0,0,0,0,0,0,0,0, 0.,0L,0L) doms in
+
+ (* Update last_time, last_info. *)
+ last_time := time;
+ Hashtbl.clear last_info;
+ List.iter (
+ function
+ | (_, Active rd) ->
+ let info = rd.rd_info, rd.rd_block_stats, rd.rd_interface_stats in
+ Hashtbl.add last_info rd.rd_domid info
+ | _ -> ()
+ ) doms;
+
+ (doms,
+ time, printable_time,
+ nr_pcpus, total_cpu, total_cpu_per_pcpu,
+ totals,
+ pcpu_display)
+ in
+
+ collect, clear_pcpu_display_data
+
+(* Redraw the display. *)
+let redraw =
+ (* Keep a historical list of %CPU usages. *)
+ let historical_cpu = ref [] in
+ let historical_cpu_last_time = ref (Unix.gettimeofday ()) in
+ fun
+ (_, _, _, _, _, node_info, _, _) (* setup *)
+ (doms,
+ time, printable_time,
+ nr_pcpus, total_cpu, total_cpu_per_pcpu,
+ totals,
+ pcpu_display) (* state *) ->
+ clear ();
+
+ (* Get the screen/window size. *)
+ let lines, cols = get_size () in
+
+ (* Time. *)
+ mvaddstr top_lineno 0 (sprintf "virt-top %s - " printable_time);
+
+ (* Basic node_info. *)
+ addstr
+ (sprintf "%s %d/%dCPU %dMHz %LdMB "
+ node_info.C.model node_info.C.cpus nr_pcpus node_info.C.mhz
+ (node_info.C.memory /^ 1024L));
+ (* Save the cursor position for when we come to draw the
+ * historical CPU times (down in this function).
+ *)
+ let stdscr = stdscr () in
+ let historical_cursor = getyx stdscr in
+