This patch adds virHistogram, a list of (x,y) pairs denoting a histogram
as a virTypedParameterType.
Signed-off-by: Amneesh Singh <natto(a)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