From 1094efa4f2edbf019427bf0322dab3f3ea9ec5ab Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 13 Aug 2019 17:34:02 -0400 Subject: [PATCH] lib: add bit array field class and field types This patch adds the bit array field class (FC) and field to the available library types. A bit array field is a simple array of bits. As opposed to integer fields, a bit array field has no sign: it does not contain a quantity. Such a field can be used to hold CPU register values, for example, or an array of flags which is typically read and written as a (small) unsigned integer. CTF 2 will very likely have such a type, so Babeltrace 2.0 will be ready. You create a bit array FC with bt_field_class_bit_array_create(). This function expects a length parameter which must be in the [1, 64] range as of this version. The length is the number of bits in the array. You can get the length of a bit array with bt_field_class_bit_array_get_length(). You can set the value of a bit array field with bt_field_bit_array_set_value_as_integer(). This function accepts an unsigned integer and conceptually sets all the bits of the array accordingly, where the _first_ bit of the array is the LSB of the value. In other words, should there be a bit accessor (by index), getting the value of bit 0 would return the LSB of that unsigned integer: 0 1 1 0 1 1 0 1 ^ MSB: bit 7 ^ LSB: bit 0 Unsigned integer value: 0x6d As such, you can get the value of the bit array with bt_field_bit_array_get_value_as_integer(). Again, the value of bit 0 is the LSB of the returned unsigned integer. I chose to apply a mask to the received value in bt_field_bit_array_set_value_as_integer() to ensure that there's no set bit outside the bit array's range. This is to lessen the user's burden instead of a having a precondition assertion. This in turns guarantees that bt_field_bit_array_get_value_as_integer() always returns a value without superfluous set bit. If this automatic masking becomes a performance issue in the future, then we can add another function which expects the user to do it (with a precondition assertion). This patch does not adapt existing plugins and the Python bindings to use and wrap the new bit array FC and field; this work is reserved for subsequent patches. Signed-off-by: Philippe Proulx Change-Id: I8ba4d111df275962cfa9f2c4f754f83a1de40e29 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1907 Tested-by: jenkins Reviewed-by: Francis Deslauriers --- .../babeltrace2/trace-ir/field-class-const.h | 4 + include/babeltrace2/trace-ir/field-class.h | 3 + include/babeltrace2/trace-ir/field-const.h | 3 + include/babeltrace2/trace-ir/field.h | 3 + src/lib/lib-logging.c | 16 ++++ src/lib/trace-ir/field-class.c | 48 ++++++++++++ src/lib/trace-ir/field-class.h | 5 ++ src/lib/trace-ir/field.c | 76 +++++++++++++++++++ src/lib/trace-ir/field.h | 5 ++ 9 files changed, 163 insertions(+) diff --git a/include/babeltrace2/trace-ir/field-class-const.h b/include/babeltrace2/trace-ir/field-class-const.h index 2dfade9f..27f22c17 100644 --- a/include/babeltrace2/trace-ir/field-class-const.h +++ b/include/babeltrace2/trace-ir/field-class-const.h @@ -38,6 +38,7 @@ extern "C" { typedef enum bt_field_class_type { BT_FIELD_CLASS_TYPE_BOOL, + BT_FIELD_CLASS_TYPE_BIT_ARRAY, BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER, BT_FIELD_CLASS_TYPE_SIGNED_INTEGER, BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, @@ -63,6 +64,9 @@ typedef enum bt_field_class_integer_preferred_display_base { extern bt_field_class_type bt_field_class_get_type( const bt_field_class *field_class); +extern uint64_t bt_field_class_bit_array_get_length( + const bt_field_class *field_class); + extern uint64_t bt_field_class_integer_get_field_value_range( const bt_field_class *field_class); diff --git a/include/babeltrace2/trace-ir/field-class.h b/include/babeltrace2/trace-ir/field-class.h index 20477296..f4f722c3 100644 --- a/include/babeltrace2/trace-ir/field-class.h +++ b/include/babeltrace2/trace-ir/field-class.h @@ -40,6 +40,9 @@ extern "C" { extern bt_field_class *bt_field_class_bool_create( bt_trace_class *trace_class); +extern bt_field_class *bt_field_class_bit_array_create( + bt_trace_class *trace_class, uint64_t length); + extern bt_field_class *bt_field_class_integer_unsigned_create( bt_trace_class *trace_class); diff --git a/include/babeltrace2/trace-ir/field-const.h b/include/babeltrace2/trace-ir/field-const.h index 01b74239..dcaf40c1 100644 --- a/include/babeltrace2/trace-ir/field-const.h +++ b/include/babeltrace2/trace-ir/field-const.h @@ -44,6 +44,9 @@ extern bt_field_class_type bt_field_get_class_type( extern bt_bool bt_field_bool_get_value(const bt_field *field); +extern uint64_t bt_field_bit_array_get_value_as_integer( + const bt_field *field); + extern int64_t bt_field_integer_signed_get_value(const bt_field *field); extern uint64_t bt_field_integer_unsigned_get_value( diff --git a/include/babeltrace2/trace-ir/field.h b/include/babeltrace2/trace-ir/field.h index 58959be8..a89d13a6 100644 --- a/include/babeltrace2/trace-ir/field.h +++ b/include/babeltrace2/trace-ir/field.h @@ -37,6 +37,9 @@ extern "C" { extern void bt_field_bool_set_value(bt_field *field, bt_bool value); +extern void bt_field_bit_array_set_value_as_integer(bt_field *field, + uint64_t value); + extern void bt_field_integer_signed_set_value(bt_field *field, int64_t value); diff --git a/src/lib/lib-logging.c b/src/lib/lib-logging.c index c38948d6..ce69b30d 100644 --- a/src/lib/lib-logging.c +++ b/src/lib/lib-logging.c @@ -193,6 +193,14 @@ static inline void format_field_class(char **buf_ch, bool extended, } switch (field_class->type) { + case BT_FIELD_CLASS_TYPE_BIT_ARRAY: + { + const struct bt_field_class_bit_array *ba_fc = + (const void *) field_class; + + BUF_APPEND(", %slength=%" PRIu64, PRFIELD(ba_fc->length)); + break; + } case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: { @@ -382,6 +390,14 @@ static inline void format_field(char **buf_ch, bool extended, BUF_APPEND(", %svalue=%d", PRFIELD(bool_field->value)); break; } + case BT_FIELD_CLASS_TYPE_BIT_ARRAY: + { + const struct bt_field_bit_array *ba_field = (const void *) field; + + BUF_APPEND(", %svalue-as-int=%" PRIx64, + PRFIELD(ba_field->value_as_int)); + break; + } case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER: case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER: case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: diff --git a/src/lib/trace-ir/field-class.c b/src/lib/trace-ir/field-class.c index d78aefb3..259a32fe 100644 --- a/src/lib/trace-ir/field-class.c +++ b/src/lib/trace-ir/field-class.c @@ -64,6 +64,54 @@ void init_field_class(struct bt_field_class *fc, enum bt_field_class_type type, fc->type = type; } +static +void destroy_bit_array_field_class(struct bt_object *obj) +{ + BT_ASSERT(obj); + BT_LIB_LOGD("Destroying bit array field class object: %!+F", obj); + g_free(obj); +} + +struct bt_field_class *bt_field_class_bit_array_create( + struct bt_trace_class *trace_class, uint64_t length) +{ + struct bt_field_class_bit_array *ba_fc = NULL; + + BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class"); + BT_ASSERT_PRE(length > 0 && length <= 64, + "Unsupported length for bit array field class " + "(minimum is 1, maximum is 64): length=%" PRIu64, length); + BT_LOGD("Creating default bit array field class object."); + ba_fc = g_new0(struct bt_field_class_bit_array, 1); + if (!ba_fc) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate one bit array field class."); + goto error; + } + + init_field_class((void *) ba_fc, BT_FIELD_CLASS_TYPE_BIT_ARRAY, + destroy_bit_array_field_class); + ba_fc->length = length; + BT_LIB_LOGD("Created bit array field class object: %!+F", ba_fc); + goto end; + +error: + BT_OBJECT_PUT_REF_AND_RESET(ba_fc); + +end: + return (void *) ba_fc; +} + +uint64_t bt_field_class_bit_array_get_length(const struct bt_field_class *fc) +{ + const struct bt_field_class_bit_array *ba_fc = (const void *) fc; + + BT_ASSERT_PRE_DEV_NON_NULL(fc, "Field class"); + BT_ASSERT_PRE_DEV_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_BIT_ARRAY, + "Field class"); + return ba_fc->length; +} + static void destroy_bool_field_class(struct bt_object *obj) { diff --git a/src/lib/trace-ir/field-class.h b/src/lib/trace-ir/field-class.h index f2be12c3..77eece7b 100644 --- a/src/lib/trace-ir/field-class.h +++ b/src/lib/trace-ir/field-class.h @@ -190,6 +190,11 @@ struct bt_field_class_bool { struct bt_field_class common; }; +struct bt_field_class_bit_array { + struct bt_field_class common; + uint64_t length; +}; + struct bt_field_class_integer { struct bt_field_class common; diff --git a/src/lib/trace-ir/field.c b/src/lib/trace-ir/field.c index 664b1ab4..62113d57 100644 --- a/src/lib/trace-ir/field.c +++ b/src/lib/trace-ir/field.c @@ -90,6 +90,13 @@ struct bt_field_methods bool_field_methods = { .reset = reset_single_field, }; +static +struct bt_field_methods bit_array_field_methods = { + .set_is_frozen = set_single_field_is_frozen, + .is_set = single_field_is_set, + .reset = reset_single_field, +}; + static struct bt_field_methods integer_field_methods = { .set_is_frozen = set_single_field_is_frozen, @@ -142,6 +149,9 @@ struct bt_field_methods variant_field_methods = { static struct bt_field *create_bool_field(struct bt_field_class *); +static +struct bt_field *create_bit_array_field(struct bt_field_class *); + static struct bt_field *create_integer_field(struct bt_field_class *); @@ -169,6 +179,7 @@ struct bt_field *create_variant_field(struct bt_field_class *); static struct bt_field *(* const field_create_funcs[])(struct bt_field_class *) = { [BT_FIELD_CLASS_TYPE_BOOL] = create_bool_field, + [BT_FIELD_CLASS_TYPE_BIT_ARRAY] = create_bit_array_field, [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER] = create_integer_field, [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER] = create_integer_field, [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = create_integer_field, @@ -187,6 +198,9 @@ struct bt_field *(* const field_create_funcs[])(struct bt_field_class *) = { static void destroy_bool_field(struct bt_field *field); +static +void destroy_bit_array_field(struct bt_field *field); + static void destroy_integer_field(struct bt_field *field); @@ -211,6 +225,7 @@ void destroy_variant_field(struct bt_field *field); static void (* const field_destroy_funcs[])(struct bt_field *) = { [BT_FIELD_CLASS_TYPE_BOOL] = destroy_bool_field, + [BT_FIELD_CLASS_TYPE_BIT_ARRAY] = destroy_bit_array_field, [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER] = destroy_integer_field, [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER] = destroy_integer_field, [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = destroy_integer_field, @@ -294,6 +309,26 @@ end: return (void *) bool_field; } +static +struct bt_field *create_bit_array_field(struct bt_field_class *fc) +{ + struct bt_field_bit_array *ba_field; + + BT_LIB_LOGD("Creating bit array field object: %![fc-]+F", fc); + ba_field = g_new0(struct bt_field_bit_array, 1); + if (!ba_field) { + BT_LIB_LOGE_APPEND_CAUSE( + "Failed to allocate one bit array field."); + goto end; + } + + init_field((void *) ba_field, fc, &bit_array_field_methods); + BT_LIB_LOGD("Created bit array field object: %!+f", ba_field); + +end: + return (void *) ba_field; +} + static struct bt_field *create_integer_field(struct bt_field_class *fc) { @@ -607,6 +642,38 @@ void bt_field_bool_set_value(struct bt_field *field, bt_bool value) bt_field_set_single(field, true); } +uint64_t bt_field_bit_array_get_value_as_integer(const struct bt_field *field) +{ + const struct bt_field_bit_array *ba_field = (const void *) field; + + BT_ASSERT_PRE_DEV_NON_NULL(field, "Field"); + BT_ASSERT_PRE_DEV_FIELD_IS_SET(field, "Field"); + BT_ASSERT_PRE_DEV_FIELD_HAS_CLASS_TYPE(field, + BT_FIELD_CLASS_TYPE_BIT_ARRAY, "Field"); + return ba_field->value_as_int; +} + +void bt_field_bit_array_set_value_as_integer(struct bt_field *field, + uint64_t value) +{ + struct bt_field_bit_array *ba_field = (void *) field; + struct bt_field_class_bit_array *ba_fc; + + BT_ASSERT_PRE_DEV_NON_NULL(field, "Field"); + BT_ASSERT_PRE_DEV_FIELD_HAS_CLASS_TYPE(field, + BT_FIELD_CLASS_TYPE_BIT_ARRAY, "Field"); + BT_ASSERT_PRE_DEV_FIELD_HOT(field, "Field"); + ba_fc = (void *) field->class; + ba_field->value_as_int = value; + + if (ba_fc->length < 64) { + /* Apply mask */ + ba_field->value_as_int &= ((UINT64_C(1) << ba_fc->length) - 1); + } + + bt_field_set_single(field, true); +} + int64_t bt_field_integer_signed_get_value(const struct bt_field *field) { const struct bt_field_integer *int_field = (const void *) field; @@ -1106,6 +1173,15 @@ void destroy_bool_field(struct bt_field *field) g_free(field); } +static +void destroy_bit_array_field(struct bt_field *field) +{ + BT_ASSERT(field); + BT_LIB_LOGD("Destroying bit array field object: %!+f", field); + bt_field_finalize(field); + g_free(field); +} + static void destroy_integer_field(struct bt_field *field) { diff --git a/src/lib/trace-ir/field.h b/src/lib/trace-ir/field.h index 2882e778..ad25231c 100644 --- a/src/lib/trace-ir/field.h +++ b/src/lib/trace-ir/field.h @@ -110,6 +110,11 @@ struct bt_field_bool { bool value; }; +struct bt_field_bit_array { + struct bt_field common; + uint64_t value_as_int; +}; + struct bt_field_integer { struct bt_field common; -- 2.34.1