[RFC PATCH 1/5] virtypedparam: add virHistogram as a virTypedParameterType

Amneesh Singh natto at weirdnatto.in
Thu Sep 22 02:18:59 UTC 2022


This patch adds virHistogram, a list of (x,y) pairs denoting a histogram
as a virTypedParameterType.

Signed-off-by: Amneesh Singh <natto at weirdnatto.in>
---
 include/libvirt/libvirt-common.h.in |  54 +++++++++--
 src/libvirt_private.syms            |   7 ++
 src/libvirt_public.syms             |   6 ++
 src/util/virtypedparam-public.c     | 101 ++++++++++++++++++++
 src/util/virtypedparam.c            | 138 ++++++++++++++++++++++++++++
 src/util/virtypedparam.h            |  22 +++++
 tools/vsh.c                         |   5 +
 7 files changed, 326 insertions(+), 7 deletions(-)

diff --git a/include/libvirt/libvirt-common.h.in b/include/libvirt/libvirt-common.h.in
index ccdbb2a100..11338d9191 100644
--- a/include/libvirt/libvirt-common.h.in
+++ b/include/libvirt/libvirt-common.h.in
@@ -128,6 +128,35 @@ typedef enum {
 # endif
 } virConnectCloseReason;
 
+/**
+ * virHistogramBucket:
+ *
+ * Simple wrapper for containing the values corresponding to the X and Y axes
+ * of a histogram entry.
+ *
+ * Since: 8.8.0
+ */
+typedef struct _virHistogramBucket virHistogramBucket;
+
+struct _virHistogramBucket {
+    long long x;
+    long long y;
+};
+
+/**
+ * virHistogram:
+ *
+ * Contains a list of virHistogramBuckets to represent a histogram.
+ *
+ * Since: 8.8.0
+ */
+typedef struct _virHistogram virHistogram;
+
+struct _virHistogram {
+    size_t nbuckets;
+    virHistogramBucket *buckets;
+};
+
 /**
  * virTypedParameterType:
  *
@@ -136,13 +165,14 @@ typedef enum {
  * Since: 0.9.2
  */
 typedef enum {
-    VIR_TYPED_PARAM_INT     = 1, /* integer case (Since: 0.9.2) */
-    VIR_TYPED_PARAM_UINT    = 2, /* unsigned integer case (Since: 0.9.2) */
-    VIR_TYPED_PARAM_LLONG   = 3, /* long long case (Since: 0.9.2) */
-    VIR_TYPED_PARAM_ULLONG  = 4, /* unsigned long long case (Since: 0.9.2) */
-    VIR_TYPED_PARAM_DOUBLE  = 5, /* double case (Since: 0.9.2) */
-    VIR_TYPED_PARAM_BOOLEAN = 6, /* boolean(character) case (Since: 0.9.2) */
-    VIR_TYPED_PARAM_STRING  = 7, /* string case (Since: 0.9.8) */
+    VIR_TYPED_PARAM_INT       = 1, /* integer case (Since: 0.9.2) */
+    VIR_TYPED_PARAM_UINT      = 2, /* unsigned integer case (Since: 0.9.2) */
+    VIR_TYPED_PARAM_LLONG     = 3, /* long long case (Since: 0.9.2) */
+    VIR_TYPED_PARAM_ULLONG    = 4, /* unsigned long long case (Since: 0.9.2) */
+    VIR_TYPED_PARAM_DOUBLE    = 5, /* double case (Since: 0.9.2) */
+    VIR_TYPED_PARAM_BOOLEAN   = 6, /* boolean(character) case (Since: 0.9.2) */
+    VIR_TYPED_PARAM_STRING    = 7, /* string case (Since: 0.9.8) */
+    VIR_TYPED_PARAM_HISTOGRAM = 8, /* histogram case (Since: 8.8.0) */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_TYPED_PARAM_LAST /* (Since: 0.9.10) */
@@ -211,6 +241,7 @@ struct _virTypedParameter {
         double d;                   /* type is DOUBLE */
         char b;                     /* type is BOOLEAN */
         char *s;                    /* type is STRING, may not be NULL */
+        virHistogram *h;            /* type is HISTOGRAM, may not be NULL */
     } value; /* parameter value */
 };
 
@@ -254,6 +285,10 @@ int virTypedParamsGetString(virTypedParameterPtr params,
                             int nparams,
                             const char *name,
                             const char **value);
+int virTypedParamsGetHistogram(virTypedParameterPtr params,
+                               int nparams,
+                               const char *name,
+                               virHistogram **value);
 
 int virTypedParamsAddInt(virTypedParameterPtr *params,
                          int *nparams,
@@ -290,6 +325,11 @@ int virTypedParamsAddString(virTypedParameterPtr *params,
                             int *maxparams,
                             const char *name,
                             const char *value);
+int virTypedParamsAddHistogram(virTypedParameterPtr *params,
+                               int *nparams,
+                               int *maxparams,
+                               const char *name,
+                               virHistogram *value);
 int virTypedParamsAddStringList(virTypedParameterPtr *params,
                                 int *nparams,
                                 int *maxparams,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 25794bc2f4..c60b21babe 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -3517,12 +3517,19 @@ virTPMSwtpmSetupFeatureTypeFromString;
 
 
 # util/virtypedparam.h
+virHistogramBucketToString;
+virHistogramCopy;
+virHistogramFree;
+virHistogramFromString;
+virHistogramNew;
+virHistogramToString;
 virTypedParameterAssign;
 virTypedParameterToString;
 virTypedParameterTypeFromString;
 virTypedParameterTypeToString;
 virTypedParamListAddBoolean;
 virTypedParamListAddDouble;
+virTypedParamListAddHistogram;
 virTypedParamListAddInt;
 virTypedParamListAddLLong;
 virTypedParamListAddString;
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 297a2c436a..e5c04bd992 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -927,4 +927,10 @@ LIBVIRT_8.5.0 {
         virDomainAbortJobFlags;
 } LIBVIRT_8.4.0;
 
+LIBVIRT_8.8.0 {
+    global:
+        virTypedParamsAddHistogram;
+        virTypedParamsGetHistogram;
+} LIBVIRT_8.5.0;
+
 # .... define new API here using predicted next version number ....
diff --git a/src/util/virtypedparam-public.c b/src/util/virtypedparam-public.c
index 5bd207d1e6..d9336337c3 100644
--- a/src/util/virtypedparam-public.c
+++ b/src/util/virtypedparam-public.c
@@ -106,6 +106,9 @@ virTypedParameterAssignFromStr(virTypedParameterPtr param,
     case VIR_TYPED_PARAM_STRING:
         param->value.s = g_strdup(val);
         break;
+    case VIR_TYPED_PARAM_HISTOGRAM:
+        param->value.h = virHistogramFromString(val);
+        break;
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected type %d for field %s"), type, name);
@@ -432,6 +435,46 @@ virTypedParamsGetString(virTypedParameterPtr params,
 }
 
 
+/**
+ * virTypedParamsGetHistogram:
+ * @params: array of typed parameters
+ * @nparams: number of parameters in the @params array
+ * @name: name of the parameter to find
+ * @value: where to store the parameter's value
+ *
+ * Finds typed parameter called @name and store its virHistogram * value in @value.
+ * The function does not create a copy of the string and the caller must not
+ * free the virHistogram @value points to. The function fails with
+ * VIR_ERR_INVALID_ARG error if the parameter does not have the expected type.
+ * By passing NULL as @value, the function may be used to check presence and
+ * type of the parameter.
+ *
+ * Returns 1 on success, 0 when the parameter does not exist in @params, or
+ * -1 on error.
+ *
+ * Since: 8.8.0
+ */
+int
+virTypedParamsGetHistogram(virTypedParameterPtr params,
+                           int nparams,
+                           const char *name,
+                           virHistogram **value)
+{
+    virTypedParameterPtr param;
+
+    virResetLastError();
+
+    if (!(param = virTypedParamsGet(params, nparams, name)))
+        return 0;
+
+    VIR_TYPED_PARAM_CHECK_TYPE(VIR_TYPED_PARAM_HISTOGRAM);
+    if (value)
+        *value = param->value.h;
+
+    return 1;
+}
+
+
 /**
  * virTypedParamsAddInt:
  * @params: pointer to the array of typed parameters
@@ -774,6 +817,62 @@ virTypedParamsAddString(virTypedParameterPtr *params,
     return -1;
 }
 
+
+/**
+ * virTypedParamsAddHistogram:
+ * @params: pointer to the array of typed parameters
+ * @nparams: number of parameters in the @params array
+ * @maxparams: maximum number of parameters that can be stored in @params
+ *      array without allocating more memory
+ * @name: name of the parameter to find
+ * @value: the value to store into the new parameter
+ *
+ * Adds new parameter called @name with virHistogram * type and sets its value to
+ * @value. The function creates its own copy of virHistogram, which needs to
+ * be freed using virTypedParamsFree or virTypedParamsClear. If @params array
+ * points to NULL or to a space that is not large enough to accommodate the
+ * new parameter (@maxparams < @nparams + 1), the function allocates more
+ * space for it and updates @maxparams. On success, @nparams is incremented
+ * by one. The function fails with VIR_ERR_INVALID_ARG error if the parameter
+ * already exists in @params.
+ *
+ * Returns 0 on success, -1 on error.
+ *
+ * Since: 8.8.0
+ */
+int
+virTypedParamsAddHistogram(virTypedParameterPtr *params,
+                        int *nparams,
+                        int *maxparams,
+                        const char *name,
+                        virHistogram *value)
+{
+    virHistogram *copy = NULL;
+    size_t max = *maxparams;
+    size_t n = *nparams;
+
+    virResetLastError();
+
+    VIR_RESIZE_N(*params, max, n, 1);
+    *maxparams = max;
+
+    copy = virHistogramCopy(value);
+
+    if (virTypedParameterAssign(*params + n, name,
+                                VIR_TYPED_PARAM_HISTOGRAM, copy) < 0) {
+        virHistogramFree(copy);
+        goto error;
+    }
+
+    *nparams += 1;
+    return 0;
+
+ error:
+    virDispatchError(NULL);
+    return -1;
+}
+
+
 /**
  * virTypedParamsAddStringList:
  * @params: array of typed parameters
@@ -889,6 +988,8 @@ virTypedParamsClear(virTypedParameterPtr params,
     for (i = 0; i < nparams; i++) {
         if (params[i].type == VIR_TYPED_PARAM_STRING)
             VIR_FREE(params[i].value.s);
+        else if (params[i].type == VIR_TYPED_PARAM_HISTOGRAM)
+            virHistogramFree(params[i].value.h);
     }
 }
 
diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c
index 2d7e4ab354..87fa69271b 100644
--- a/src/util/virtypedparam.c
+++ b/src/util/virtypedparam.c
@@ -40,6 +40,7 @@ VIR_ENUM_IMPL(virTypedParameter,
               "double",
               "boolean",
               "string",
+              "histogram",
 );
 
 static int
@@ -166,6 +167,71 @@ virTypedParamsCheck(virTypedParameterPtr params,
     return true;
 }
 
+
+char *
+virHistogramBucketToString(virHistogramBucket *bucket) {
+    if (!bucket)
+        return NULL;
+
+    return g_strdup_printf("(%lld - %lld)", bucket->x, bucket->y);
+}
+
+
+char *
+virHistogramToString(virHistogram *histogram)
+{
+    size_t i;
+    g_autoptr(GString) value = g_string_new("");
+
+    if (!histogram)
+        return NULL;
+
+    if (histogram->nbuckets == 0)
+        return g_strdup("");
+
+    for (i = 0; i < histogram->nbuckets; i++) {
+        g_autofree char *bucket_str = virHistogramBucketToString(histogram->buckets + i);
+
+        g_string_append(value, bucket_str);
+
+        if (i != histogram->nbuckets - 1)
+            g_string_append(value, ", ");
+    }
+
+    return g_strdup(value->str);
+}
+
+
+virHistogram *
+virHistogramFromString(const char *str)
+{
+    g_auto(GStrv) split_str = g_strsplit(str, ",", -1);
+    g_autoptr(virHistogram) hist = NULL;
+    unsigned int len;
+    size_t i;
+
+    if (split_str == NULL)
+        return NULL;
+
+    len = g_strv_length(split_str);
+    hist = virHistogramNew(len);
+
+    for (i = 0; i < len; i++) {
+        virHistogramBucket *bucket = hist->buckets + i;
+        long long x, y;
+
+        if (sscanf(split_str[i],
+                   " (%lld - %lld)",
+                   &x, &y) < 2)
+            return NULL;
+
+        bucket->x = x;
+        bucket->y = y;
+    }
+
+    return g_steal_pointer(&hist);
+}
+
 char *
 virTypedParameterToString(virTypedParameterPtr param)
 {
@@ -193,6 +259,9 @@ virTypedParameterToString(virTypedParameterPtr param)
     case VIR_TYPED_PARAM_STRING:
         value = g_strdup(param->value.s);
         break;
+    case VIR_TYPED_PARAM_HISTOGRAM:
+        value = virHistogramToString(param->value.h);
+        break;
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected type %d for field %s"),
@@ -239,6 +308,9 @@ virTypedParameterAssignValueVArgs(virTypedParameterPtr param,
         if (!param->value.s)
             param->value.s = g_strdup("");
         break;
+    case VIR_TYPED_PARAM_HISTOGRAM:
+        param->value.h = va_arg(ap, virHistogram *);
+        break;
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected type %d for field %s"), type,
@@ -347,6 +419,42 @@ virTypedParamsReplaceString(virTypedParameterPtr *params,
 }
 
 
+virHistogram *
+virHistogramNew(size_t size)
+{
+    virHistogram *histogram = g_new(virHistogram, 1);
+    histogram->nbuckets = size;
+    histogram->buckets = g_new0(virHistogramBucket, size);
+
+    return histogram;
+}
+
+
+void
+virHistogramFree(virHistogram *histogram)
+{
+    g_free(histogram->buckets);
+    g_free(histogram);
+}
+
+
+virHistogram *
+virHistogramCopy(virHistogram *src)
+{
+    virHistogram *dst = NULL;
+
+    if (!src)
+        return NULL;
+
+    dst = g_new0(virHistogram, 1);
+    dst->nbuckets = src->nbuckets;
+    dst->buckets = g_new0(virHistogramBucket, dst->nbuckets);
+    memcpy(dst->buckets, src->buckets, dst->nbuckets * sizeof(virHistogramBucket));
+
+    return g_steal_pointer(&dst);
+}
+
+
 int
 virTypedParamsCopy(virTypedParameterPtr *dst,
                    virTypedParameterPtr src,
@@ -365,6 +473,8 @@ virTypedParamsCopy(virTypedParameterPtr *dst,
         (*dst)[i].type = src[i].type;
         if (src[i].type == VIR_TYPED_PARAM_STRING) {
             (*dst)[i].value.s = g_strdup(src[i].value.s);
+        } else if (src[i].type == VIR_TYPED_PARAM_HISTOGRAM) {
+            (*dst)[i].value.h = virHistogramCopy(src[i].value.h);
         } else {
             (*dst)[i].value = src[i].value;
         }
@@ -486,6 +596,8 @@ virTypedParamsRemoteFree(struct _virTypedParameterRemote *remote_params_val,
         g_free(remote_params_val[i].field);
         if (remote_params_val[i].value.type == VIR_TYPED_PARAM_STRING)
             g_free(remote_params_val[i].value.remote_typed_param_value.s);
+        else if (remote_params_val[i].value.type == VIR_TYPED_PARAM_HISTOGRAM)
+            g_free(remote_params_val[i].value.remote_typed_param_value.h);
     }
     g_free(remote_params_val);
 }
@@ -591,6 +703,9 @@ virTypedParamsDeserialize(struct _virTypedParameterRemote *remote_params,
         case VIR_TYPED_PARAM_STRING:
             param->value.s = g_strdup(remote_param->value.remote_typed_param_value.s);
             break;
+        case VIR_TYPED_PARAM_HISTOGRAM:
+            param->value.h = virHistogramCopy(remote_param->value.remote_typed_param_value.h);
+            break;
         default:
             virReportError(VIR_ERR_RPC, _("unknown parameter type: %d"),
                            param->type);
@@ -696,6 +811,9 @@ virTypedParamsSerialize(virTypedParameterPtr params,
         case VIR_TYPED_PARAM_STRING:
             val->value.remote_typed_param_value.s = g_strdup(param->value.s);
             break;
+        case VIR_TYPED_PARAM_HISTOGRAM:
+            val->value.remote_typed_param_value.h = virHistogramCopy(param->value.h);
+            break;
         default:
             virReportError(VIR_ERR_RPC, _("unknown parameter type: %d"),
                            param->type);
@@ -929,3 +1047,23 @@ virTypedParamListAddDouble(virTypedParamList *list,
 
     return ret;
 }
+
+int virTypedParamListAddHistogram(virTypedParamList *list,
+                                  virHistogram *value,
+                                  const char *namefmt,
+                                  ...)
+{
+    virTypedParameterPtr par;
+    va_list ap;
+    int ret;
+
+    if (!(par = virTypedParamListExtend(list)) ||
+        virTypedParameterAssignValue(par, true, VIR_TYPED_PARAM_HISTOGRAM, value) < 0)
+        return -1;
+
+    va_start(ap, namefmt);
+    ret = virTypedParamSetNameVPrintf(par, namefmt, ap);
+    va_end(ap);
+
+    return ret;
+}
diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h
index c4bc58ee8f..8138197493 100644
--- a/src/util/virtypedparam.h
+++ b/src/util/virtypedparam.h
@@ -45,6 +45,7 @@ struct _virTypedParameterRemoteValue {
         double d;
         char b;
         char *s;
+        virHistogram *h;
     } remote_typed_param_value;
 };
 
@@ -86,10 +87,25 @@ int virTypedParamsReplaceString(virTypedParameterPtr *params,
                                 const char *name,
                                 const char *value);
 
+virHistogram *virHistogramNew(size_t size);
+
+void virHistogramFree(virHistogram *histogram);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virHistogram,
+                              virHistogramFree);
+
+virHistogram *virHistogramCopy(virHistogram *src);
+
 int virTypedParamsCopy(virTypedParameterPtr *dst,
                        virTypedParameterPtr src,
                        int nparams);
 
+char *virHistogramBucketToString(virHistogramBucket *bucket);
+
+char *virHistogramToString(virHistogram *histogram);
+
+virHistogram *virHistogramFromString(const char *str);
+
 char *virTypedParameterToString(virTypedParameterPtr param);
 
 void virTypedParamsRemoteFree(struct _virTypedParameterRemote *remote_params_val,
@@ -177,3 +193,9 @@ int virTypedParamListAddDouble(virTypedParamList *list,
                                const char *namefmt,
                                ...)
     G_GNUC_PRINTF(3, 4) G_GNUC_WARN_UNUSED_RESULT;
+
+int virTypedParamListAddHistogram(virTypedParamList *list,
+                                  virHistogram *value,
+                                  const char *namefmt,
+                                  ...)
+    G_GNUC_PRINTF(3, 4) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/tools/vsh.c b/tools/vsh.c
index 0066504ebe..d808524568 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -45,6 +45,7 @@
 #include "vircommand.h"
 #include "virstring.h"
 #include "virutil.h"
+#include "virtypedparam.h"
 
 #ifdef WITH_READLINE
 /* For autocompletion */
@@ -1835,6 +1836,10 @@ vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item)
         return g_strdup(item->value.s);
         break;
 
+    case VIR_TYPED_PARAM_HISTOGRAM:
+        return virHistogramToString(item->value.h);
+        break;
+
     default:
         vshError(ctl, _("unimplemented parameter type %d"), item->type);
         exit(EXIT_FAILURE);
-- 
2.37.1



More information about the libvir-list mailing list