From 99ba7e0eae5ea7567aded458ab63c5984ed43191 Mon Sep 17 00:00:00 2001
From: Hu Tao <hutao@cn.fujitsu.com>
Date: Wed, 9 May 2012 16:48:31 +0800
Subject: [PATCH] Add Libvirt.Domain.get_cpu_stats_total.

Original patch by Hu Tao.

RWMJ modified the patch to split this into two functions
(old get_cpu_stats and new get_cpu_stats_total).  Apart
from that split, the code is identical.
---
 examples/.depend            | 12 +++---
 examples/get_cpu_stats.ml   | 48 +++++++++++++-----------
 libvirt/.depend             | 12 +++---
 libvirt/libvirt.ml          |  1 +
 libvirt/libvirt.mli         |  6 ++-
 libvirt/libvirt_c_oneoffs.c | 89 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 134 insertions(+), 34 deletions(-)

diff --git a/examples/.depend b/examples/.depend
index f58db3d..3d955f9 100644
--- a/examples/.depend
+++ b/examples/.depend
@@ -1,6 +1,6 @@
-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
+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
diff --git a/examples/get_cpu_stats.ml b/examples/get_cpu_stats.ml
index d7a8d0c..10b3840 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 in
+    let total_stats = D.get_cpu_stats_total dom 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/.depend b/libvirt/.depend
index 3f2297e..7d32e13 100644
--- a/libvirt/.depend
+++ b/libvirt/.depend
@@ -1,6 +1,6 @@
-libvirt.cmi:
-libvirt_version.cmi:
-libvirt.cmo: libvirt.cmi
-libvirt.cmx: libvirt.cmi
-libvirt_version.cmo: libvirt_version.cmi
-libvirt_version.cmx: libvirt_version.cmi
+libvirt_version.cmi :
+libvirt.cmi :
+libvirt_version.cmo : libvirt_version.cmi
+libvirt_version.cmx : libvirt_version.cmi
+libvirt.cmo : libvirt.cmi
+libvirt.cmx : libvirt.cmi
diff --git a/libvirt/libvirt.ml b/libvirt/libvirt.ml
index 07542a9..2997b0b 100644
--- a/libvirt/libvirt.ml
+++ b/libvirt/libvirt.ml
@@ -418,6 +418,7 @@ struct
   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_total : [>`R] t -> typed_param list array = "ocaml_libvirt_domain_get_cpu_stats_total"
   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..020be59 100644
--- a/libvirt/libvirt.mli
+++ b/libvirt/libvirt.mli
@@ -560,7 +560,11 @@ sig
 	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
+    (** [get_cpu_stats dom] returns the per-CPU physical CPU stats
+	for a domain.  See the libvirt documentation for details.
+    *)
+  val get_cpu_stats_total : [>`R] t -> typed_param list array
+    (** [get_cpu_stats dom] returns the total 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..2a1850f 100644
--- a/libvirt/libvirt_c_oneoffs.c
+++ b/libvirt/libvirt_c_oneoffs.c
@@ -638,6 +638,95 @@ ocaml_libvirt_domain_get_cpu_stats (value domv)
 #endif
 }
 
+CAMLprim value
+ocaml_libvirt_domain_get_cpu_stats_total (value domv)
+{
+#ifdef HAVE_VIRDOMAINGETCPUSTATS
+  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);
+  virTypedParameterPtr params;
+  int r, nparams, j, pos;
+
+  /* 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
+}
+
 #ifdef HAVE_WEAK_SYMBOLS
 #ifdef HAVE_VIRDOMAINMIGRATE
 extern virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
-- 
1.7.11.4

