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

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