* [PATCH v3 0/4] libtraceevent: Handling cpumask event fields
@ 2022-12-13 16:56 Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 1/4] libtraceevent: Ensure print_field_raw() terminates with '\0' Valentin Schneider
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Valentin Schneider @ 2022-12-13 16:56 UTC (permalink / raw)
To: linux-trace-devel
Cc: Steven Rostedt, Daniel Bristot de Oliveira, Clark Williams,
Douglas RAILLARD
Hi folks,
While discussing around [1], Steve had the idea [2] of creating a "proper" type
for cpumask event fields so that userspace tooling doesn't have to guess whether
an unsigned long [] is meant to be a cpumask or not.
o Patch 1 is a collateral fix found by running the new units tests.
o Patch 2 introduces a small amount of boiler plate to get cpumask fields on the same level
as bitmask fields
o Patch 3 adds pretty-print output for cpumasks
o Patch 4 is unit tests for the above
Cheers,
Valentin
Revisions
=========
v2 -> v3
++++++++
o Rebased on top of latest libtraceevent
o Added unit tests (Steven)
o Moved TEP_PRINT_CPUMASK definition to the tail of tep_print_arg_type (Steven)
v1 -> v2
++++++++
o Rebased on top of latest libtraceevent
o Fixed s/__get_cpumask/__get_rel_cpumask/ typo
[1]: http://lore.kernel.org/r/xhsmhilkqfi7z.mognet@vschneid.remote.csb
[2]: http://lore.kernel.org/r/20221014080456.1d32b989@rorschach.local.home
Valentin Schneider (4):
libtraceevent: Ensure print_field_raw() terminates with '\0'
libtraceevent: Add boiler-plate code for cpumask types
libtraceevent: Pretty-print cpumask fields as a cpulist
libtraceevent: Add unit tests for cpumask processing
include/traceevent/event-parse.h | 1 +
src/event-parse.c | 191 +++++++++++++++++++++++++++++++
utest/traceevent-utest.c | 161 ++++++++++++++++++++++++++
3 files changed, 353 insertions(+)
--
2.31.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3 1/4] libtraceevent: Ensure print_field_raw() terminates with '\0'
2022-12-13 16:56 [PATCH v3 0/4] libtraceevent: Handling cpumask event fields Valentin Schneider
@ 2022-12-13 16:56 ` Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 2/4] libtraceevent: Add boiler-plate code for cpumask types Valentin Schneider
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Valentin Schneider @ 2022-12-13 16:56 UTC (permalink / raw)
To: linux-trace-devel
Cc: Steven Rostedt, Daniel Bristot de Oliveira, Clark Williams,
Douglas RAILLARD
Testing printing cpumasks reveals an issue in print_field_raw()'s handling
of arrays: its final operation is trace_seq_putc(']'), which omits a final
'\0'.
The other cases in the function invoke trace_seq_printf() which does the
right thing, only the TEP_FIELD_IS_ARRAY case has that issue. Still, to
prevent any future surprises, add a call to trace_seq_terminate() at the
end of print_field_raw().
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
src/event-parse.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/event-parse.c b/src/event-parse.c
index a6e9e93..093b345 100644
--- a/src/event-parse.c
+++ b/src/event-parse.c
@@ -5681,6 +5681,7 @@ static void print_field_raw(struct trace_seq *s, void *data, int size,
trace_seq_printf(s, "%llu", val);
}
}
+ trace_seq_terminate(s);
}
static int print_parse_data(struct tep_print_parse *parse, struct trace_seq *s,
--
2.31.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 2/4] libtraceevent: Add boiler-plate code for cpumask types
2022-12-13 16:56 [PATCH v3 0/4] libtraceevent: Handling cpumask event fields Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 1/4] libtraceevent: Ensure print_field_raw() terminates with '\0' Valentin Schneider
@ 2022-12-13 16:56 ` Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 3/4] libtraceevent: Pretty-print cpumask fields as a cpulist Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 4/4] libtraceevent: Add unit tests for cpumask processing Valentin Schneider
3 siblings, 0 replies; 5+ messages in thread
From: Valentin Schneider @ 2022-12-13 16:56 UTC (permalink / raw)
To: linux-trace-devel
Cc: Steven Rostedt, Daniel Bristot de Oliveira, Clark Williams,
Douglas RAILLARD
A cpumask event field type was recently added to Linux, which helps
distinguish any odd bitmask from a cpumask. Right now this field type is
not recognized by libtraceevent:
[ipi:ipi_send_cpumask] function __get_cpumask not defined
CPU 0 is empty
CPU 1 is empty
CPU 3 is empty
cpus=4
echo-173 [002] 11.859745: ipi_send_cpumask: [FAILED TO PARSE] cpumask=ARRAY[02,
00, 00, 00, 00, 00, 00, 00] callsite=0xffffffff81121013
Since a cpumask is still a bitmask, define the boiler plate code for this
new field type and wire it all to bitmask handling.
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
include/traceevent/event-parse.h | 1 +
src/event-parse.c | 24 ++++++++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/include/traceevent/event-parse.h b/include/traceevent/event-parse.h
index 3be98b0..2171ad7 100644
--- a/include/traceevent/event-parse.h
+++ b/include/traceevent/event-parse.h
@@ -244,6 +244,7 @@ enum tep_print_arg_type {
TEP_PRINT_BITMASK,
TEP_PRINT_DYNAMIC_ARRAY_LEN,
TEP_PRINT_HEX_STR,
+ TEP_PRINT_CPUMASK,
};
struct tep_print_arg {
diff --git a/src/event-parse.c b/src/event-parse.c
index 093b345..ba8e727 100644
--- a/src/event-parse.c
+++ b/src/event-parse.c
@@ -1120,6 +1120,7 @@ static void free_arg(struct tep_print_arg *arg)
free(arg->string.string);
break;
case TEP_PRINT_BITMASK:
+ case TEP_PRINT_CPUMASK:
free(arg->bitmask.bitmask);
break;
case TEP_PRINT_DYNAMIC_ARRAY:
@@ -2853,6 +2854,7 @@ static int arg_num_eval(struct tep_print_arg *arg, long long *val)
case TEP_PRINT_STRING:
case TEP_PRINT_BSTRING:
case TEP_PRINT_BITMASK:
+ case TEP_PRINT_CPUMASK:
default:
do_warning("invalid eval type %d", arg->type);
ret = 0;
@@ -2882,6 +2884,7 @@ static char *arg_eval (struct tep_print_arg *arg)
case TEP_PRINT_STRING:
case TEP_PRINT_BSTRING:
case TEP_PRINT_BITMASK:
+ case TEP_PRINT_CPUMASK:
default:
do_warning("invalid eval type %d", arg->type);
break;
@@ -3362,6 +3365,17 @@ process_bitmask(struct tep_event *event __maybe_unused, struct tep_print_arg *ar
return TEP_EVENT_ERROR;
}
+static enum tep_event_type
+process_cpumask(struct tep_event *event __maybe_unused, struct tep_print_arg *arg,
+ char **tok)
+{
+ enum tep_event_type type = process_bitmask(event, arg, tok);
+ if (type != TEP_EVENT_ERROR)
+ arg->type = TEP_PRINT_CPUMASK;
+
+ return type;
+}
+
static struct tep_function_handler *
find_func_handler(struct tep_handle *tep, char *func_name)
{
@@ -3521,6 +3535,11 @@ process_function(struct tep_event *event, struct tep_print_arg *arg,
free_token(token);
return process_bitmask(event, arg, tok);
}
+ if (strcmp(token, "__get_cpumask") == 0 ||
+ strcmp(token, "__get_rel_cpumask") == 0) {
+ free_token(token);
+ return process_cpumask(event, arg, tok);
+ }
if (strcmp(token, "__get_dynamic_array") == 0 ||
strcmp(token, "__get_rel_dynamic_array") == 0 ||
strcmp(token, "__get_sockaddr") == 0 ||
@@ -4181,6 +4200,7 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg
case TEP_PRINT_STRING:
case TEP_PRINT_BSTRING:
case TEP_PRINT_BITMASK:
+ case TEP_PRINT_CPUMASK:
return 0;
case TEP_PRINT_FUNC: {
struct trace_seq s;
@@ -4674,6 +4694,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
case TEP_PRINT_BSTRING:
print_str_to_seq(s, format, len_arg, arg->string.string);
break;
+ case TEP_PRINT_CPUMASK:
case TEP_PRINT_BITMASK: {
if (!arg->bitmask.field) {
arg->bitmask.field = tep_find_any_field(event, arg->bitmask.bitmask);
@@ -7196,6 +7217,9 @@ static void print_args(struct tep_print_arg *args)
case TEP_PRINT_BITMASK:
printf("__get_bitmask(%s)", args->bitmask.bitmask);
break;
+ case TEP_PRINT_CPUMASK:
+ printf("__get_cpumask(%s)", args->bitmask.bitmask);
+ break;
case TEP_PRINT_TYPE:
printf("(%s)", args->typecast.type);
print_args(args->typecast.item);
--
2.31.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 3/4] libtraceevent: Pretty-print cpumask fields as a cpulist
2022-12-13 16:56 [PATCH v3 0/4] libtraceevent: Handling cpumask event fields Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 1/4] libtraceevent: Ensure print_field_raw() terminates with '\0' Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 2/4] libtraceevent: Add boiler-plate code for cpumask types Valentin Schneider
@ 2022-12-13 16:56 ` Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 4/4] libtraceevent: Add unit tests for cpumask processing Valentin Schneider
3 siblings, 0 replies; 5+ messages in thread
From: Valentin Schneider @ 2022-12-13 16:56 UTC (permalink / raw)
To: linux-trace-devel
Cc: Steven Rostedt, Daniel Bristot de Oliveira, Clark Williams,
Douglas RAILLARD
Now that we can denote which bitmasks are cpumasks, it makes sense to
pretty-print them to a more user-friendly format: a cpulist.
There's two hurdles to that:
1) Estimating the required string buffer size.
I've tried to condense it down to an estimator function that is
computationally simple enough, though it overestimates by ~1/3.
For reference, this estimates:
180 bytes for NR_CPUS=64 (x86 defconfig)
911 bytes for NR_CPUS=256 (arm64 defconfig)
2) Iterating through the bits and bytes.
The kernel has a collection of carefully crafted bitmask iterators which
make this relatively simple (cf. bitmap_list_string()), but I didn't
feel justified in importing half a dozen helpers just for one function.
I've implemented a "homegrown" byte-parsing logic which isn't the
fastest, but is at least condensed to a single function.
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
src/event-parse.c | 168 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 167 insertions(+), 1 deletion(-)
diff --git a/src/event-parse.c b/src/event-parse.c
index ba8e727..d1363a5 100644
--- a/src/event-parse.c
+++ b/src/event-parse.c
@@ -4491,6 +4491,161 @@ static void print_bitmask_to_seq(struct tep_handle *tep,
free(str);
}
+#define log10(n) \
+( \
+ n < 10UL ? 0 : \
+ n < 100UL ? 1 : \
+ n < 1000UL ? 2 : \
+ n < 10000UL ? 3 : \
+ n < 100000UL ? 4 : \
+ n < 1000000UL ? 5 : \
+ n < 10000000UL ? 6 : \
+ n < 100000000UL ? 7 : \
+ n < 1000000000UL ? 8 : \
+ 9 \
+)
+
+/* ilog10(0) should be 1 but the 0 simplifies below math */
+#define ilog10(n) \
+( \
+ n == 0 ? 0UL : \
+ n == 1 ? 10UL : \
+ n == 2 ? 100UL : \
+ n == 3 ? 1000UL : \
+ n == 4 ? 10000UL : \
+ n == 5 ? 100000UL : \
+ n == 6 ? 1000000UL : \
+ n == 7 ? 10000000UL : \
+ n == 8 ? 100000000UL : \
+ 1000000000UL \
+)
+
+static unsigned int cpumask_worst_size(unsigned int nr_bits)
+{
+ /*
+ * Printing all the CPUs separated by a comma is a decent bound for the
+ * maximum memory required to print a cpumask (a slightly better bound
+ * is chunks of 2 bits set, i.e. 0-1,3-4,6-7...).
+ *
+ * e.g. for nr_bits=132:
+ * - 131 commas
+ * - 10 * 1 chars for CPUS [0, 9]
+ * - 90 * 2 chars for CPUS [10-99]
+ * - 32 * 3 chars for CPUS [100-131]
+ */
+ unsigned int last_cpu = nr_bits - 1;
+ unsigned int nr_chars = nr_bits - 1;
+ int last_lvl = log10(last_cpu);
+
+ /* All log10 levels before the last one have all values used */
+ for (int lvl = 0; lvl < last_lvl; lvl++) {
+ int nr_values = ilog10(lvl + 1) - ilog10(lvl);
+
+ nr_chars += nr_values * (lvl + 1);
+ }
+ /* Last level is incomplete */
+ nr_chars += (nr_bits - ilog10(last_lvl)) * (last_lvl + 1);
+
+ return nr_chars;
+}
+
+static void print_cpumask_to_seq(struct tep_handle *tep,
+ struct trace_seq *s, const char *format,
+ int len_arg, const void *data, int size)
+{
+ int firstone = -1, firstzero = -1;
+ int nr_bits = size * 8;
+ bool first = true;
+ int str_size = 0;
+ char buf[12]; /* '-' + log10(2^32) + 1 digits + '\0' */
+ char *str;
+ int index;
+ int i;
+
+ str = malloc(cpumask_worst_size(nr_bits) + 1);
+ if (!str) {
+ do_warning("%s: not enough memory!", __func__);
+ return;
+ }
+
+ for (i = 0; i < size; i++) {
+ unsigned char byte;
+ int fmtsize;
+
+ if (tep->file_bigendian)
+ index = size - (i + 1);
+ else
+ index = i;
+
+ /* Byte by byte scan, not the best... */
+ byte = *(((unsigned char *)data) + index);
+more:
+ /* First find a bit set to one...*/
+ if (firstone < 0 && byte) {
+ /*
+ * Set all lower bits, so a later ffz on this same byte
+ * is guaranteed to find a later bit.
+ */
+ firstone = ffs(byte) - 1;
+ byte |= (1 << firstone) - 1;
+ firstone += i * 8;
+ }
+
+ if (firstone < 0)
+ continue;
+
+ /* ...Then find a bit set to zero */
+ if ((~byte) & 0xFF) {
+ /*
+ * Clear all lower bits, so a later ffs on this same
+ * byte is guaranteed to find a later bit.
+ */
+ firstzero = ffs(~byte) - 1;
+ byte &= ~((1 << (firstzero)) - 1);
+ firstzero += i * 8;
+ } else if (i == size - 1) { /* ...Or reach the end of the mask */
+ firstzero = nr_bits;
+ byte = 0;
+ } else {
+ continue;
+ }
+
+ /* We've found a bit set to one, and a later bit set to zero. */
+ if (!first) {
+ str[str_size] = ',';
+ str_size++;
+ }
+ first = false;
+
+ /* It takes {log10(number) + 1} chars to format a number */
+ fmtsize = log10(firstone) + 1;
+ snprintf(buf, fmtsize + 1, "%d", firstone);
+ memcpy(str + str_size, buf, fmtsize);
+ str_size += fmtsize;
+
+ if (firstzero > firstone + 1) {
+ fmtsize = log10(firstzero - 1) + 2;
+ snprintf(buf, fmtsize + 1, "-%d", firstzero - 1);
+ memcpy(str + str_size, buf, fmtsize);
+ str_size += fmtsize;
+ }
+
+ firstzero = firstone = -1;
+ if (byte)
+ goto more;
+ }
+
+ str[str_size] = 0;
+ str_size++;
+
+ if (len_arg >= 0)
+ trace_seq_printf(s, format, len_arg, str);
+ else
+ trace_seq_printf(s, format, str);
+
+ free(str);
+}
+
static void print_str_arg(struct trace_seq *s, void *data, int size,
struct tep_event *event, const char *format,
int len_arg, struct tep_print_arg *arg)
@@ -4694,7 +4849,6 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
case TEP_PRINT_BSTRING:
print_str_to_seq(s, format, len_arg, arg->string.string);
break;
- case TEP_PRINT_CPUMASK:
case TEP_PRINT_BITMASK: {
if (!arg->bitmask.field) {
arg->bitmask.field = tep_find_any_field(event, arg->bitmask.bitmask);
@@ -4707,6 +4861,18 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
data + offset, len);
break;
}
+ case TEP_PRINT_CPUMASK: {
+ if (!arg->bitmask.field) {
+ arg->bitmask.field = tep_find_any_field(event, arg->bitmask.bitmask);
+ arg->bitmask.offset = arg->bitmask.field->offset;
+ }
+ if (!arg->bitmask.field)
+ break;
+ dynamic_offset_field(tep, arg->bitmask.field, data, size, &offset, &len);
+ print_cpumask_to_seq(tep, s, format, len_arg,
+ data + offset, len);
+ break;
+ }
case TEP_PRINT_OP:
/*
* The only op for string should be ? :
--
2.31.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v3 4/4] libtraceevent: Add unit tests for cpumask processing
2022-12-13 16:56 [PATCH v3 0/4] libtraceevent: Handling cpumask event fields Valentin Schneider
` (2 preceding siblings ...)
2022-12-13 16:56 ` [PATCH v3 3/4] libtraceevent: Pretty-print cpumask fields as a cpulist Valentin Schneider
@ 2022-12-13 16:56 ` Valentin Schneider
3 siblings, 0 replies; 5+ messages in thread
From: Valentin Schneider @ 2022-12-13 16:56 UTC (permalink / raw)
To: linux-trace-devel
Cc: Steven Rostedt, Daniel Bristot de Oliveira, Clark Williams,
Douglas RAILLARD
Add units tests that cover the TEP_PRINT_CPUMASK cases.
Sicne print_cpumask_to_seq() is based on a per-byte scan, add some tests
that cross byte boundaries when looking for the next non-zero byte.
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
utest/traceevent-utest.c | 161 +++++++++++++++++++++++++++++++++++++++
1 file changed, 161 insertions(+)
diff --git a/utest/traceevent-utest.c b/utest/traceevent-utest.c
index 99900de..4fc09e5 100644
--- a/utest/traceevent-utest.c
+++ b/utest/traceevent-utest.c
@@ -100,6 +100,86 @@ static char dyn_str_old_data[] = {
};
static void *dyn_str_old_event_data = (void *)dyn_str_old_data;
+#define CPUMASK_EVENT_SYSTEM "ipi"
+#define CPUMASK_EVENT_FIELD "cpumask"
+static const char cpumask_event_format[] =
+ "name: ipi_send_cpumask\n"
+ "ID: 3\n"
+ "format:\n"
+ "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\n"
+ "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\n"
+ "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\n"
+ "\tfield:int common_pid;\toffset:4;\tsize:4;\n"
+ "\n"
+ "\tfield:__data_loc cpumask_t *[] cpumask;\toffset:8;\tsize:4;\tsigned:0;\n"
+ "\n"
+ "print fmt: \"cpumask=%s\", __get_cpumask(cpumask)\n";
+
+/* Mind the endianness! */
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define DECL_CPUMASK_EVENT_DATA(name, args...) \
+ static char cpumask_##name##_event_data[] = { \
+ /* common type */ 3, 0x00, \
+ /* common flags */ 0x00, \
+ /* common_preempt_count */ 0x00, \
+ /* common_pid */ 0x00, 0x00, 0x00, 0x00, \
+ /* [offset, size] */ 16, 0x00, 8, 0x00, \
+ /* padding */ 0x00, 0x00, 0x00, 0x00, \
+ /* cpumask */ args, \
+}
+#else
+#define DECL_CPUMASK_EVENT_DATA(name, args...) \
+static char cpumask_##name##_event_data[] = { \
+ /* common type */ 0x00, 3, \
+ /* common flags */ 0x00, \
+ /* common_preempt_count */ 0x00, \
+ /* common_pid */ 0x00, 0x00, 0x00, 0x00, \
+ /* [offset, size] */ 0x00, 8, 0x00, 16, \
+ /* padding */ 0x00, 0x00, 0x00, 0x00, \
+ /* cpumask */ args, \
+}
+#endif
+
+DECL_CPUMASK_EVENT_DATA(full, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
+#define CPUMASK_FULL "ARRAY[ff, ff, ff, ff, ff, ff, ff, ff]"
+#define CPUMASK_FULL_FMT "cpumask=0-63"
+
+DECL_CPUMASK_EVENT_DATA(empty, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+#define CPUMASK_EMPTY "ARRAY[00, 00, 00, 00, 00, 00, 00, 00]"
+#define CPUMASK_EMPTY_FMT "cpumask="
+
+DECL_CPUMASK_EVENT_DATA(half, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55);
+#define CPUMASK_HALF "ARRAY[55, 55, 55, 55, 55, 55, 55, 55]"
+#define CPUMASK_HALF_FMT "cpumask=0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62"
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+DECL_CPUMASK_EVENT_DATA(bytep1, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+#define CPUMASK_BYTEP1 "ARRAY[01, 80, 00, 00, 00, 00, 00, 00]"
+#define CPUMASK_BYTEP1_FMT "cpumask=0,15"
+
+DECL_CPUMASK_EVENT_DATA(bytep2, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00);
+#define CPUMASK_BYTEP2 "ARRAY[01, 00, 80, 00, 00, 00, 00, 00]"
+#define CPUMASK_BYTEP2_FMT "cpumask=0,23"
+
+DECL_CPUMASK_EVENT_DATA(bytepn, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80);
+#define CPUMASK_BYTEPN "ARRAY[01, 00, 00, 00, 00, 00, 00, 80]"
+#define CPUMASK_BYTEPN_FMT "cpumask=0,63"
+
+#else
+
+DECL_CPUMASK_EVENT_DATA(bytep1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01);
+#define CPUMASK_BYTEP1 "ARRAY[00, 00, 00, 00, 00, 00, 80, 01]"
+#define CPUMASK_BYTEP1_FMT "cpumask=0,15"
+
+DECL_CPUMASK_EVENT_DATA(bytep2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x01);
+#define CPUMASK_BYTEP2 "ARRAY[00, 00, 00, 00, 00, 80, 00, 01]"
+#define CPUMASK_BYTEP2_FMT "cpumask=0,23"
+
+DECL_CPUMASK_EVENT_DATA(bytepn, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
+#define CPUMASK_BYTEPN "ARRAY[80, 00, 00, 00, 00, 00, 80, 01]"
+#define CPUMASK_BYTEPN_FMT "cpumask=0,63"
+#endif
+
static struct tep_handle *test_tep;
static struct trace_seq *test_seq;
static struct trace_seq seq_storage;
@@ -139,6 +219,75 @@ static void test_parse_dyn_str_old_event(void)
parse_dyn_str(dyn_str_old_event, dyn_str_old_event_data, sizeof(dyn_str_old_data));
}
+static void parse_cpumask(const char *format, void *data, int size,
+ const char* expected_raw, const char* expected)
+{
+ struct tep_format_field *field;
+ struct tep_event *event;
+ struct tep_record record;
+
+ record.data = data;
+ record.size = size;
+
+ CU_TEST(tep_parse_format(test_tep, &event,
+ format, strlen(format),
+ CPUMASK_EVENT_SYSTEM) == TEP_ERRNO__SUCCESS);
+
+ field = tep_find_any_field(event, CPUMASK_EVENT_FIELD);
+ CU_TEST(field != NULL);
+
+ trace_seq_reset(test_seq);
+ tep_print_field_content(test_seq, data, size, field);
+ CU_TEST(strcmp(test_seq->buffer, expected_raw) == 0);
+
+ trace_seq_reset(test_seq);
+ tep_print_event(test_tep, test_seq, &record, "%s", TEP_PRINT_INFO);
+ trace_seq_do_printf(test_seq);
+ CU_TEST(strcmp(test_seq->buffer, expected) == 0);
+}
+
+static void test_parse_cpumask_full(void)
+{
+ parse_cpumask(cpumask_event_format,
+ cpumask_full_event_data, sizeof(cpumask_full_event_data),
+ CPUMASK_FULL, CPUMASK_FULL_FMT);
+}
+
+static void test_parse_cpumask_empty(void)
+{
+ parse_cpumask(cpumask_event_format,
+ cpumask_empty_event_data, sizeof(cpumask_empty_event_data),
+ CPUMASK_EMPTY, CPUMASK_EMPTY_FMT);
+}
+
+static void test_parse_cpumask_half(void)
+{
+ parse_cpumask(cpumask_event_format,
+ cpumask_half_event_data, sizeof(cpumask_half_event_data),
+ CPUMASK_HALF, CPUMASK_HALF_FMT);
+}
+
+static void test_parse_cpumask_bytep1(void)
+{
+ parse_cpumask(cpumask_event_format,
+ cpumask_bytep1_event_data, sizeof(cpumask_bytep1_event_data),
+ CPUMASK_BYTEP1, CPUMASK_BYTEP1_FMT);
+}
+
+static void test_parse_cpumask_bytep2(void)
+{
+ parse_cpumask(cpumask_event_format,
+ cpumask_bytep2_event_data, sizeof(cpumask_bytep2_event_data),
+ CPUMASK_BYTEP2, CPUMASK_BYTEP2_FMT);
+}
+
+static void test_parse_cpumask_bytepn(void)
+{
+ parse_cpumask(cpumask_event_format,
+ cpumask_bytepn_event_data, sizeof(cpumask_bytepn_event_data),
+ CPUMASK_BYTEPN, CPUMASK_BYTEPN_FMT);
+}
+
static int test_suite_destroy(void)
{
tep_free(test_tep);
@@ -169,4 +318,16 @@ void test_traceevent_lib(void)
test_parse_dyn_str_event);
CU_add_test(suite, "parse old dynamic string event",
test_parse_dyn_str_old_event);
+ CU_add_test(suite, "parse full cpumask",
+ test_parse_cpumask_full);
+ CU_add_test(suite, "parse empty cpumask",
+ test_parse_cpumask_empty);
+ CU_add_test(suite, "parse half-filled cpumask",
+ test_parse_cpumask_half);
+ CU_add_test(suite, "parse cpumask spanning 2 bytes",
+ test_parse_cpumask_bytep1);
+ CU_add_test(suite, "parse cpumask spanning 3 bytes",
+ test_parse_cpumask_bytep2);
+ CU_add_test(suite, "parse cpumask spanning all bytes",
+ test_parse_cpumask_bytepn);
}
--
2.31.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2022-12-13 17:04 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-12-13 16:56 [PATCH v3 0/4] libtraceevent: Handling cpumask event fields Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 1/4] libtraceevent: Ensure print_field_raw() terminates with '\0' Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 2/4] libtraceevent: Add boiler-plate code for cpumask types Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 3/4] libtraceevent: Pretty-print cpumask fields as a cpulist Valentin Schneider
2022-12-13 16:56 ` [PATCH v3 4/4] libtraceevent: Add unit tests for cpumask processing Valentin Schneider
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).