Blame SOURCES/0016-Use-virConnectGetAllDomainStats-API-to-collect-domai.patch

985088
From c513d05fd4e85953701b1023bef71af62613cf79 Mon Sep 17 00:00:00 2001
985088
From: "Richard W.M. Jones" <rjones@redhat.com>
985088
Date: Tue, 28 Mar 2017 13:30:07 +0100
985088
Subject: [PATCH 16/17] Use virConnectGetAllDomainStats API to collect domain
985088
 stats (RHBZ#1422795).
985088
985088
This is much faster than using the basic libvirt APIs to collect
985088
stats for each domain individually.
985088
985088
Note this will not work unless you have the latest ocaml-libvirt
985088
package which includes this new API binding.
985088
---
985088
 src/collect.ml  | 242 +++++++++++++++++++++++++++++++++++++++++---------------
985088
 src/collect.mli |   1 +
985088
 src/utils.ml    |   6 ++
985088
 src/utils.mli   |   3 +
985088
 4 files changed, 190 insertions(+), 62 deletions(-)
985088
985088
diff --git a/src/collect.ml b/src/collect.ml
985088
index 448ce8c..a1e50a1 100644
985088
--- a/src/collect.ml
985088
+++ b/src/collect.ml
985088
@@ -38,6 +38,7 @@ let parse_device_xml : (int -> [>`R] D.t -> string list * string list) ref =
985088
 type rd_domain = Inactive | Active of rd_active
985088
 and rd_active = {
985088
   rd_domid : int;			(* Domain ID. *)
985088
+  rd_domuuid : Libvirt.uuid;            (* Domain UUID. *)
985088
   rd_dom : [`R] D.t;			(* Domain object. *)
985088
   rd_info : D.info;			(* Domain CPU info now. *)
985088
   rd_block_stats : (string * D.block_stats) list;
985088
@@ -110,6 +111,16 @@ let last_pcpu_usages = Hashtbl.create 13
985088
 let clear_pcpu_display_data () =
985088
   Hashtbl.clear last_pcpu_usages
985088
 
985088
+(* What to get from virConnectGetAllDomainStats. *)
985088
+let what = [
985088
+  D.StatsState; D.StatsCpuTotal; D.StatsBalloon; D.StatsVcpu;
985088
+  D.StatsInterface; D.StatsBlock
985088
+]
985088
+(* Which domains to get.  Empty list means return all domains:
985088
+ * active, inactive, persistent, transient etc.
985088
+ *)
985088
+let who = []
985088
+
985088
 let collect (conn, _, _, _, _, node_info, _, _) =
985088
   (* Number of physical CPUs (some may be disabled). *)
985088
   let nr_pcpus = C.maxcpus_of_node_info node_info in
985088
@@ -129,72 +140,179 @@ let collect (conn, _, _, _, _, node_info, _, _) =
985088
 
985088
   (* Get the domains.  Match up with their last_info (if any). *)
985088
   let doms =
985088
-    (* Active domains. *)
985088
-    let n = C.num_of_domains conn in
985088
-    let ids =
985088
-      if n > 0 then Array.to_list (C.list_domains conn n)
985088
-      else [] in
985088
-    let doms =
985088
-      List.filter_map (
985088
-	fun id ->
985088
-	  try
985088
-	    let dom = D.lookup_by_id conn id in
985088
-	    let name = D.get_name dom in
985088
-	    let blkdevs, netifs = get_devices id dom in
985088
+    let doms = D.get_all_domain_stats conn what who in
985088
+    let doms = Array.to_list doms in
985088
+    List.map (
985088
+      fun { D.dom_uuid = uuid; D.params = params } ->
985088
+        let nr_params = Array.length params in
985088
+        let get_param name =
985088
+          let rec loop i =
985088
+            if i = nr_params then None
985088
+            else if fst params.(i) = name then Some (snd params.(i))
985088
+            else loop (i+1)
985088
+          in
985088
+          loop 0
985088
+        in
985088
+        let get_param_int name default =
985088
+          match get_param name with
985088
+          | None -> None
985088
+          | Some (D.TypedFieldInt32 i)
985088
+          | Some (D.TypedFieldUInt32 i) -> Some (Int32.to_int i)
985088
+          | Some (D.TypedFieldInt64 i)
985088
+          | Some (D.TypedFieldUInt64 i) -> Some (Int64.to_int i)
985088
+          | _ -> default
985088
+        in
985088
+        let get_param_int64 name default =
985088
+          match get_param name with
985088
+          | None -> None
985088
+          | Some (D.TypedFieldInt32 i)
985088
+          | Some (D.TypedFieldUInt32 i) -> Some (Int64.of_int32 i)
985088
+          | Some (D.TypedFieldInt64 i)
985088
+          | Some (D.TypedFieldUInt64 i) -> Some i
985088
+          | _ -> default
985088
+        in
985088
 
985088
-	    (* Get current CPU, block and network stats. *)
985088
-	    let info = D.get_info dom in
985088
-	    let block_stats =
985088
-	      try List.map (fun dev -> dev, D.block_stats dom dev) blkdevs
985088
-	      with
985088
-	      | Libvirt.Not_supported "virDomainBlockStats"
985088
-	      | Libvirt.Virterror _ -> [] in
985088
-	    let interface_stats =
985088
-	      try List.map (fun dev -> dev, D.interface_stats dom dev) netifs
985088
-	      with
985088
-	      | Libvirt.Not_supported "virDomainInterfaceStats"
985088
-	      | Libvirt.Virterror _ -> [] in
985088
+        let dom = D.lookup_by_uuid conn uuid in
985088
+        let id = D.get_id dom in
985088
+        let name = D.get_name dom in
985088
+        let state = get_param_int "state.state" None in
985088
 
985088
-	    let prev_info, prev_block_stats, prev_interface_stats =
985088
-	      try
985088
-		let prev_info, prev_block_stats, prev_interface_stats =
985088
-		  Hashtbl.find last_info id in
985088
-		Some prev_info, prev_block_stats, prev_interface_stats
985088
-	      with Not_found -> None, [], [] in
985088
+        if state = Some 5 (* VIR_DOMAIN_SHUTOFF *) then
985088
+          (name, Inactive)
985088
+        else (
985088
+          (* Active domain. *)
985088
 
985088
-	    Some (name,
985088
-                  Active {
985088
-		      rd_domid = id; rd_dom = dom; rd_info = info;
985088
-		      rd_block_stats = block_stats;
985088
-		      rd_interface_stats = interface_stats;
985088
-		      rd_prev_info = prev_info;
985088
-		      rd_prev_block_stats = prev_block_stats;
985088
-		      rd_prev_interface_stats = prev_interface_stats;
985088
-		      rd_cpu_time = 0.; rd_percent_cpu = 0.;
985088
-                      rd_mem_bytes = 0L; rd_mem_percent = 0L;
985088
-		      rd_block_rd_reqs = None; rd_block_wr_reqs = None;
985088
-                      rd_block_rd_bytes = None; rd_block_wr_bytes = None;
985088
-		      rd_net_rx_bytes = None; rd_net_tx_bytes = None;
985088
-		    })
985088
-	  with
985088
-	    Libvirt.Virterror _ -> None (* ignore transient error *)
985088
-      ) ids in
985088
+          (* Synthesize a D.info struct out of the data we have
985088
+           * from virConnectGetAllDomainStats.  Doing this is an
985088
+           * artifact from the old APIs we used to use to fetch
985088
+           * stats, we could simplify here, and also return the
985088
+           * RSS memory. XXX
985088
+           *)
985088
+          let state =
985088
+            match state with
985088
+            | None | Some 0 -> D.InfoNoState
985088
+            | Some 1 -> D.InfoRunning
985088
+            | Some 2 -> D.InfoBlocked
985088
+            | Some 3 -> D.InfoPaused
985088
+            | Some 4 -> D.InfoShutdown
985088
+            | Some 5 -> D.InfoShutoff
985088
+            | Some 6 -> D.InfoCrashed
985088
+            | Some 7 -> D.InfoPaused (* XXX really VIR_DOMAIN_PMSUSPENDED *)
985088
+            | _ -> D.InfoNoState in
985088
+          let memory =
985088
+            match get_param_int64 "balloon.current" None with
985088
+            | None -> 0_L
985088
+            | Some m -> m in
985088
+          let nr_virt_cpu =
985088
+            match get_param_int "vcpu.current" None with
985088
+            | None -> 1
985088
+            | Some v -> v in
985088
+          let cpu_time =
985088
+            (* NB: libvirt does not return cpu.time for non-root domains. *)
985088
+            match get_param_int64 "cpu.time" None with
985088
+            | None -> 0_L
985088
+            | Some ns -> ns in
985088
+          let info = {
985088
+            D.state = state;
985088
+            max_mem = -1_L; (* not used anywhere in virt-top *)
985088
+            memory = memory;
985088
+            nr_virt_cpu = nr_virt_cpu;
985088
+            cpu_time = cpu_time
985088
+          } in
985088
 
985088
-    (* Inactive domains. *)
985088
-    let doms_inactive =
985088
-      try
985088
-	let n = C.num_of_defined_domains conn in
985088
-	let names =
985088
-	  if n > 0 then Array.to_list (C.list_defined_domains conn n)
985088
-	  else [] in
985088
-	List.map (fun name -> name, Inactive) names
985088
-      with
985088
-      (* Ignore transient errors, in particular errors from
985088
-       * num_of_defined_domains if it cannot contact xend.
985088
-       *)
985088
-      | Libvirt.Virterror _ -> [] in
985088
+          let nr_block_devs =
985088
+            match get_param_int "block.count" None with
985088
+            | None -> 0
985088
+            | Some i -> i in
985088
+          let block_stats =
985088
+            List.map (
985088
+              fun i ->
985088
+              let dev =
985088
+                match get_param (sprintf "block.%d.name" i) with
985088
+                | None -> sprintf "blk%d" i
985088
+                | Some (D.TypedFieldString s) -> s
985088
+                | _ -> assert false in
985088
+              dev, {
985088
+                D.rd_req =
985088
+                  (match get_param_int64 (sprintf "block.%d.rd.reqs" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                rd_bytes =
985088
+                  (match get_param_int64 (sprintf "block.%d.rd.bytes" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                wr_req =
985088
+                  (match get_param_int64 (sprintf "block.%d.wr.reqs" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                wr_bytes =
985088
+                  (match get_param_int64 (sprintf "block.%d.wr.bytes" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                errs = 0_L
985088
+              }
985088
+            ) (range 0 (nr_block_devs-1)) in
985088
 
985088
-    doms @ doms_inactive in
985088
+          let nr_interface_devs =
985088
+            match get_param_int "net.count" None with
985088
+            | None -> 0
985088
+            | Some i -> i in
985088
+          let interface_stats =
985088
+            List.map (
985088
+              fun i ->
985088
+              let dev =
985088
+                match get_param (sprintf "net.%d.name" i) with
985088
+                | None -> sprintf "net%d" i
985088
+                | Some (D.TypedFieldString s) -> s
985088
+                | _ -> assert false in
985088
+              dev, {
985088
+                D.rx_bytes =
985088
+                  (match get_param_int64 (sprintf "net.%d.rx.bytes" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                rx_packets =
985088
+                  (match get_param_int64 (sprintf "net.%d.rx.pkts" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                rx_errs =
985088
+                  (match get_param_int64 (sprintf "net.%d.rx.errs" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                rx_drop =
985088
+                  (match get_param_int64 (sprintf "net.%d.rx.drop" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                tx_bytes =
985088
+                  (match get_param_int64 (sprintf "net.%d.tx.bytes" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                tx_packets =
985088
+                  (match get_param_int64 (sprintf "net.%d.tx.pkts" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                tx_errs =
985088
+                  (match get_param_int64 (sprintf "net.%d.tx.errs" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+                tx_drop =
985088
+                  (match get_param_int64 (sprintf "net.%d.tx.drop" i) None
985088
+                   with None -> 0_L | Some v -> v);
985088
+              }
985088
+            ) (range 0 (nr_interface_devs-1)) in
985088
+
985088
+	  let prev_info, prev_block_stats, prev_interface_stats =
985088
+	    try
985088
+	      let prev_info, prev_block_stats, prev_interface_stats =
985088
+		Hashtbl.find last_info uuid in
985088
+	      Some prev_info, prev_block_stats, prev_interface_stats
985088
+	    with Not_found -> None, [], [] in
985088
+
985088
+	  (name,
985088
+           Active {
985088
+	     rd_domid = id; rd_domuuid = uuid; rd_dom = dom;
985088
+             rd_info = info;
985088
+	     rd_block_stats = block_stats;
985088
+	     rd_interface_stats = interface_stats;
985088
+	     rd_prev_info = prev_info;
985088
+	     rd_prev_block_stats = prev_block_stats;
985088
+	     rd_prev_interface_stats = prev_interface_stats;
985088
+	     rd_cpu_time = 0.; rd_percent_cpu = 0.;
985088
+             rd_mem_bytes = 0L; rd_mem_percent = 0L;
985088
+	     rd_block_rd_reqs = None; rd_block_wr_reqs = None;
985088
+             rd_block_rd_bytes = None; rd_block_wr_bytes = None;
985088
+	     rd_net_rx_bytes = None; rd_net_tx_bytes = None;
985088
+	   })
985088
+        )
985088
+    ) doms in
985088
 
985088
   (* Calculate the CPU time (ns) and %CPU used by each domain. *)
985088
   let doms =
985088
@@ -329,7 +447,7 @@ let collect (conn, _, _, _, _, node_info, _, _) =
985088
     function
985088
     | (_, Active rd) ->
985088
        let info = rd.rd_info, rd.rd_block_stats, rd.rd_interface_stats in
985088
-       Hashtbl.add last_info rd.rd_domid info
985088
+       Hashtbl.add last_info rd.rd_domuuid info
985088
     | _ -> ()
985088
   ) doms;
985088
 
985088
diff --git a/src/collect.mli b/src/collect.mli
985088
index 9ad3dcb..3c5492f 100644
985088
--- a/src/collect.mli
985088
+++ b/src/collect.mli
985088
@@ -27,6 +27,7 @@ val parse_device_xml :
985088
 type rd_domain = Inactive | Active of rd_active
985088
 and rd_active = {
985088
   rd_domid : int;			(* Domain ID. *)
985088
+  rd_domuuid : Libvirt.uuid;            (* Domain UUID. *)
985088
   rd_dom : [`R] Libvirt.Domain.t;       (* Domain object. *)
985088
   rd_info : Libvirt.Domain.info;        (* Domain CPU info now. *)
985088
   rd_block_stats : (string * Libvirt.Domain.block_stats) list;
985088
diff --git a/src/utils.ml b/src/utils.ml
985088
index 5fcc905..4332ff7 100644
985088
--- a/src/utils.ml
985088
+++ b/src/utils.ml
985088
@@ -32,6 +32,12 @@ let (/^) = Int64.div
985088
 (* failwithf is a printf-like version of failwith. *)
985088
 let failwithf fs = ksprintf failwith fs
985088
 
985088
+let rec range a b =
985088
+  if a <= b then
985088
+    a :: range (a+1) b
985088
+  else
985088
+    []
985088
+
985088
 (* Input a whole file as a list of lines. *)
985088
 let input_all_lines chan =
985088
   let lines = ref [] in
985088
diff --git a/src/utils.mli b/src/utils.mli
985088
index 6e81215..3c966f8 100644
985088
--- a/src/utils.mli
985088
+++ b/src/utils.mli
985088
@@ -25,6 +25,9 @@ val (//) : string -> string -> string
985088
 (* failwithf is a printf-like version of failwith. *)
985088
 val failwithf : ('a, unit, string, 'b) format4 -> 'a
985088
 
985088
+(* Return the list of integers [a..b] (inclusive). *)
985088
+val range : int -> int -> int list
985088
+
985088
 (* Read a configuration file as a list of (lineno, key, value) pairs.
985088
  * If the config file is missing this returns an empty list.
985088
  *)
985088
-- 
985088
2.9.3
985088