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