From: Stevie Alvarez <stevie.6strings@gmail.com>
To: linux-trace-devel@vger.kernel.org
Cc: "Stevie Alvarez (Google)" <stevie.6strings@gmail.com>,
Steven Rostedt <rostedt@goodmis.org>,
Ross Zwisler <zwisler@google.com>
Subject: [PATCH v2 4/5] histograms: Add traceeval compare
Date: Thu, 3 Aug 2023 18:54:02 -0400 [thread overview]
Message-ID: <20230803225413.40697-5-stevie.6strings@gmail.com> (raw)
In-Reply-To: <20230803225413.40697-1-stevie.6strings@gmail.com>
From: "Stevie Alvarez (Google)" <stevie.6strings@gmail.com>
traceeval_compare() compares two struct traceeval instances for
equality. This suite of comparitors was made for testing purposes.
Signed-off-by: Stevie Alvarez (Google) <stevie.6strings@gmail.com>
---
include/traceeval-test.h | 16 +++
src/histograms.c | 221 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 234 insertions(+), 3 deletions(-)
create mode 100644 include/traceeval-test.h
diff --git a/include/traceeval-test.h b/include/traceeval-test.h
new file mode 100644
index 0000000..bb8092a
--- /dev/null
+++ b/include/traceeval-test.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * libtraceeval interface for unit testing.
+ *
+ * Copyright (C) 2023 Google Inc, Steven Rostedt <rostedt@goodmis.org>
+ * Copyright (C) 2023 Google Inc, Stevie Alvarez <stevie.6strings@gmail.com>
+ */
+
+#ifndef __LIBTRACEEVAL_TEST_H__
+#define __LIBTRACEEVAL_TEST_H__
+
+#include <traceeval-hist.h>
+
+int traceeval_compare(struct traceeval *orig, struct traceeval *copy);
+
+#endif /* __LIBTRACEEVAL_TEST_H__ */
diff --git a/src/histograms.c b/src/histograms.c
index 95243b0..8094678 100644
--- a/src/histograms.c
+++ b/src/histograms.c
@@ -11,6 +11,20 @@
#include <stdio.h>
#include <traceeval-hist.h>
+#include <traceeval-test.h>
+
+/*
+ * Compare two integers of variable length.
+ *
+ * Return 0 if @a and @b are the same, 1 if @a is greater than @b, and -1
+ * if @b is greater than @a.
+ */
+#define compare_numbers_return(a, b) \
+do { \
+ if ((a) < (b)) \
+ return -1; \
+ return (a) != (b); \
+} while (0) \
/* A key-value pair */
struct entry {
@@ -158,12 +172,13 @@ fail_type_name:
* The @keys and @vals passed in are copied for internal use.
*
* For any member of @keys or @vals that isn't of type TRACEEVAL_TYPE_NONE,
- * the name field must be a null-terminated string. For members of type
- * TRACEEVAL_TYPE_NONE, the name is ignored.
+ * the name field must be a null-terminated string. Members of type
+ * TRACEEVAL_TYPE_NONE are used to terminate the array, therefore their other
+ * fields are ignored.
*
* @vals can be NULL or start with its type field as TRACEEVAL_TYPE_NONE to
* define the values of the histogram to be empty.
- * @keys must be populated with at least one element that is not
+ * @keys must be populated with at least one element that is not of type
* TRACEEVAL_TYPE_NONE.
*
* Returns the descriptor on success, or NULL on error.
@@ -305,3 +320,203 @@ void traceeval_release(struct traceeval *teval)
teval->val_types = NULL;
free(teval);
}
+
+/*
+ * Compare traceeval_type instances for equality.
+ *
+ * Return 0 if @orig and @copy are the same, 1 otherwise.
+ */
+static int compare_traceeval_type(struct traceeval_type *orig,
+ struct traceeval_type *copy, size_t orig_size, size_t copy_size)
+{
+ size_t i;
+
+ /* same memory/NULL */
+ if (orig == copy)
+ return 0;
+ if (!!orig != !!copy)
+ return 1;
+
+ if (orig_size != copy_size)
+ return 1;
+
+ for (i = 0; i < orig_size; i++) {
+ if (orig[i].type != copy[i].type)
+ return 1;
+ if (orig[i].flags != copy[i].flags)
+ return 1;
+ if (orig[i].id != copy[i].id)
+ return 1;
+ if (orig[i].dyn_release != copy[i].dyn_release)
+ return 1;
+ if (orig[i].dyn_cmp != copy[i].dyn_cmp)
+ return 1;
+
+ // make sure both names are same type
+ if (!!orig[i].name != !!copy[i].name)
+ return 1;
+ if (!orig[i].name)
+ continue;
+ if (strcmp(orig[i].name, copy[i].name) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Compare traceeval_data instances.
+ *
+ * Return 0 if @orig and @copy are the same, 1 if @orig is greater than @copy,
+ * -1 for the other way around, and -2 on error.
+ */
+static int compare_traceeval_data(union traceeval_data *orig,
+ const union traceeval_data *copy, struct traceeval_type *type)
+{
+ int i;
+
+ if (orig == copy)
+ return 0;
+
+ if (!orig)
+ return -1;
+
+ if (!copy)
+ return 1;
+
+ switch (type->type) {
+ case TRACEEVAL_TYPE_STRING:
+ i = strcmp(orig->string, copy->string);
+ compare_numbers_return(i, 0);
+
+ case TRACEEVAL_TYPE_NUMBER:
+ compare_numbers_return(orig->number, copy->number);
+
+ case TRACEEVAL_TYPE_NUMBER_64:
+ compare_numbers_return(orig->number_64, copy->number_64);
+
+ case TRACEEVAL_TYPE_NUMBER_32:
+ compare_numbers_return(orig->number_32, copy->number_32);
+
+ case TRACEEVAL_TYPE_NUMBER_16:
+ compare_numbers_return(orig->number_16, copy->number_16);
+
+ case TRACEEVAL_TYPE_NUMBER_8:
+ compare_numbers_return(orig->number_8, copy->number_8);
+
+ case TRACEEVAL_TYPE_DYNAMIC:
+ if (type->dyn_cmp)
+ return type->dyn_cmp(orig->dyn_data, copy->dyn_data, type);
+ return 0;
+
+ default:
+ print_err("%d is an invalid enum traceeval_data_type member",
+ type->type);
+ return -2;
+ }
+}
+
+/*
+ * Compare arrays of union traceeval_data's with respect to @def.
+ *
+ * Return 0 if @orig and @copy are the same, 1 if not, and -1 on error.
+ */
+static int compare_traceeval_data_set(union traceeval_data *orig,
+ const union traceeval_data *copy, struct traceeval_type *defs,
+ size_t size)
+{
+ int check;
+ size_t i;
+
+ /* compare data arrays */
+ for (i = 0; i < size; i++) {
+ if ((check = compare_traceeval_data(&orig[i], ©[i], &defs[i])))
+ goto fail_c_set;
+ }
+
+ return 0;
+
+fail_c_set:
+ return check == -2 ? -1 : 1;
+}
+
+/*
+ * Return 0 if @orig and @copy are the same, 1 if not, and -1 on error.
+ */
+static int compare_entries(struct entry *orig, struct entry *copy,
+ struct traceeval *teval)
+{
+ int check;
+
+ /* compare keys */
+ check = compare_traceeval_data_set(orig->keys, copy->keys,
+ teval->key_types, teval->nr_key_types);
+ if (check)
+ return check;
+
+ /* compare values */
+ check = compare_traceeval_data_set(orig->vals, copy->vals,
+ teval->val_types, teval->nr_val_types);
+ return check;
+}
+
+/*
+ * Compares the hist fields of @orig and @copy for equality.
+ *
+ * Assumes all other aspects of @orig and @copy are the same.
+ *
+ * Return 0 if struct hist_table of @orig and @copy are the same, 1 if not,
+ * and -1 on error.
+ */
+static int compare_hist(struct traceeval *orig, struct traceeval *copy)
+{
+ struct hist_table *o_hist;
+ struct hist_table *c_hist;
+ int c;
+
+ o_hist = orig->hist;
+ c_hist = copy->hist;
+
+ if (o_hist->nr_entries != c_hist->nr_entries)
+ return 1;
+
+ for (size_t i = 0; i < o_hist->nr_entries; i++) {
+ if ((c = compare_entries(&o_hist->map[i], &c_hist->map[i], orig)))
+ return c;
+ }
+
+ return 0;
+}
+
+/*
+ * traceeval_compare - Check equality between two traceeval instances
+ * @orig: The first traceeval instance
+ * @copy: The second traceeval instance
+ *
+ * This compares the values of the key definitions, value definitions, and
+ * inserted data between @orig and @copy in order. It does not compare
+ * by memory address, except for struct traceeval_type's dyn_release() and
+ * dyn_cmp() fields.
+ *
+ * Returns 0 if @orig and @copy are the same, 1 if not, and -1 on error.
+ */
+ int traceeval_compare(struct traceeval *orig, struct traceeval *copy)
+{
+ int keys;
+ int vals;
+ int hists;
+
+ if (!orig || !copy)
+ return -1;
+
+ keys = compare_traceeval_type(orig->key_types, copy->key_types,
+ orig->nr_key_types, copy->nr_key_types);
+ vals = compare_traceeval_type(orig->val_types, copy->val_types,
+ orig->nr_val_types, copy->nr_val_types);
+ hists = compare_hist(orig, copy);
+
+ if (hists == -1)
+ return -1;
+
+ return keys || vals || hists;
+}
--
2.41.0
next prev parent reply other threads:[~2023-08-03 22:54 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-03 22:53 [PATCH v2 0/5] histograms: bug fixes and convention compliance Stevie Alvarez
2023-08-03 22:53 ` [PATCH v2 1/5] histograms: Initial histograms interface Stevie Alvarez
2023-08-04 13:50 ` Steven Rostedt
2023-08-04 17:41 ` Stevie Alvarez
2023-08-04 17:57 ` Steven Rostedt
2023-08-04 18:25 ` Stevie Alvarez
2023-08-03 22:54 ` [PATCH v2 2/5] histograms: Add traceeval initialize Stevie Alvarez
2023-08-04 14:40 ` Steven Rostedt
2023-08-04 18:23 ` Stevie Alvarez
2023-08-04 19:20 ` Steven Rostedt
2023-08-03 22:54 ` [PATCH v2 3/5] histograms: Add traceeval release Stevie Alvarez
2023-08-04 14:55 ` Steven Rostedt
2023-08-03 22:54 ` Stevie Alvarez [this message]
2023-08-04 15:24 ` [PATCH v2 4/5] histograms: Add traceeval compare Steven Rostedt
2023-08-07 23:40 ` Ross Zwisler
2023-08-03 22:54 ` [PATCH v2 5/5] histograms: Initial unit tests Stevie Alvarez
2023-08-04 12:37 ` [PATCH v2 0/5] histograms: bug fixes and convention compliance Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230803225413.40697-5-stevie.6strings@gmail.com \
--to=stevie.6strings@gmail.com \
--cc=linux-trace-devel@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=zwisler@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).