#define BT_LOG_TAG "CLOCK-CLASS"
#include <babeltrace/lib-logging-internal.h>
+#include <babeltrace/assert-pre-internal.h>
#include <babeltrace/compat/uuid-internal.h>
#include <babeltrace/ctf-ir/clock-class-internal.h>
#include <babeltrace/ctf-ir/clock-value-internal.h>
#include <babeltrace/compat/string-internal.h>
#include <inttypes.h>
#include <babeltrace/object-internal.h>
+#include <babeltrace/assert-internal.h>
static
void bt_clock_class_destroy(struct bt_object *obj);
+static
+struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class);
+
+static
+void bt_clock_value_destroy(struct bt_clock_value *clock_value);
+
BT_HIDDEN
bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class)
{
}
if (!bt_identifier_is_valid(name)) {
- BT_LOGE("Clock class's name is not a valid CTF identifier: "
+ BT_LOGW("Clock class's name is not a valid CTF identifier: "
"addr=%p, name=\"%s\"",
clock_class, name);
ret = -1;
return is_valid;
}
+static
+void bt_clock_class_free_clock_value(struct bt_clock_value *clock_value,
+ struct bt_clock_class *clock_class)
+{
+ bt_clock_value_destroy(clock_value);
+}
+
struct bt_clock_class *bt_clock_class_create(const char *name,
uint64_t freq)
{
clock_class->precision = 1;
clock_class->frequency = freq;
- bt_object_init(clock_class, bt_clock_class_destroy);
+ bt_object_init_shared(&clock_class->base, bt_clock_class_destroy);
if (name) {
ret = bt_clock_class_set_name(clock_class, name);
if (ret) {
- BT_LOGE("Cannot set clock class's name: "
- "addr=%p, name=\"%s\"",
- clock_class, name);
+ /* bt_clock_class_set_name() logs errors */
goto error;
}
}
+ ret = bt_object_pool_initialize(&clock_class->cv_pool,
+ (bt_object_pool_new_object_func) bt_clock_value_new,
+ (bt_object_pool_destroy_object_func)
+ bt_clock_class_free_clock_value,
+ clock_class);
+ if (ret) {
+ BT_LOGE("Failed to initialize clock value pool: ret=%d",
+ ret);
+ goto error;
+ }
+
BT_LOGD("Created clock class object: addr=%p, name=\"%s\"",
clock_class, name);
return clock_class;
return ret;
}
-static uint64_t ns_from_value(uint64_t frequency, uint64_t value)
-{
- uint64_t ns;
-
- if (frequency == 1000000000) {
- ns = value;
- } else {
- double dblres = ((1e9 * (double) value) / (double) frequency);
-
- if (dblres >= (double) UINT64_MAX) {
- /* Overflows uint64_t */
- ns = -1ULL;
- } else {
- ns = (uint64_t) dblres;
- }
- }
-
- return ns;
-}
-
BT_HIDDEN
void bt_clock_class_freeze(struct bt_clock_class *clock_class)
{
- if (!clock_class) {
- BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+ if (!clock_class || clock_class->frozen) {
return;
}
- if (!clock_class->frozen) {
- BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"",
- clock_class, bt_clock_class_get_name(clock_class));
- clock_class->frozen = 1;
- }
-}
-
-BT_HIDDEN
-void bt_clock_class_serialize(struct bt_clock_class *clock_class,
- struct metadata_context *context)
-{
- unsigned char *uuid;
-
- BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, "
- "name=\"%s\", metadata-context-addr=%p", clock_class,
- bt_clock_class_get_name(clock_class), context);
-
- if (!clock_class || !context) {
- BT_LOGW("Invalid parameter: clock class or metadata context is NULL: "
- "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p",
- clock_class, bt_clock_class_get_name(clock_class),
- context);
- return;
- }
-
- uuid = clock_class->uuid;
- g_string_append(context->string, "clock {\n");
- g_string_append_printf(context->string, "\tname = %s;\n",
- clock_class->name->str);
-
- if (clock_class->uuid_set) {
- g_string_append_printf(context->string,
- "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
- uuid[0], uuid[1], uuid[2], uuid[3],
- uuid[4], uuid[5], uuid[6], uuid[7],
- uuid[8], uuid[9], uuid[10], uuid[11],
- uuid[12], uuid[13], uuid[14], uuid[15]);
- }
-
- if (clock_class->description) {
- g_string_append_printf(context->string, "\tdescription = \"%s\";\n",
- clock_class->description->str);
- }
-
- g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n",
- clock_class->frequency);
- g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n",
- clock_class->precision);
- g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n",
- clock_class->offset_s);
- g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n",
- clock_class->offset);
- g_string_append_printf(context->string, "\tabsolute = %s;\n",
- clock_class->absolute ? "true" : "false");
- g_string_append(context->string, "};\n\n");
+ BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"",
+ clock_class, bt_clock_class_get_name(clock_class));
+ clock_class->frozen = 1;
}
static
clock_class = container_of(obj, struct bt_clock_class, base);
BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"",
obj, bt_clock_class_get_name(clock_class));
+
if (clock_class->name) {
g_string_free(clock_class->name, TRUE);
}
+
if (clock_class->description) {
g_string_free(clock_class->description, TRUE);
}
+ bt_object_pool_finalize(&clock_class->cv_pool);
g_free(clock_class);
}
static
-void bt_clock_value_destroy(struct bt_object *obj)
+void bt_clock_value_destroy(struct bt_clock_value *clock_value)
{
- struct bt_clock_value *value;
-
- if (!obj) {
- return;
- }
-
- value = container_of(obj, struct bt_clock_value, base);
BT_LOGD("Destroying clock value: addr=%p, clock-class-addr=%p, "
- "clock-class-name=\"%s\"", obj, value->clock_class,
- bt_clock_class_get_name(value->clock_class));
- bt_put(value->clock_class);
- g_free(value);
+ "clock-class-name=\"%s\"", clock_value,
+ clock_value->clock_class,
+ bt_clock_class_get_name(clock_value->clock_class));
+ bt_put(clock_value->clock_class);
+ g_free(clock_value);
}
static
-void set_ns_from_epoch(struct bt_clock_value *clock_value)
-{
- struct bt_clock_class *clock_class = clock_value->clock_class;
- int64_t diff;
- int64_t s_ns;
- uint64_t u_ns;
- uint64_t cycles;
-
- /* Initialize nanosecond timestamp to clock's offset in seconds */
- if (clock_class->offset_s <= (INT64_MIN / 1000000000) ||
- clock_class->offset_s >= (INT64_MAX / 1000000000)) {
- /*
- * Overflow: offset in seconds converted to nanoseconds
- * is outside the int64_t range.
- */
- clock_value->ns_from_epoch_overflows = true;
- goto end;
- }
-
- clock_value->ns_from_epoch = clock_class->offset_s * (int64_t) 1000000000;
-
- /* Add offset in cycles */
- if (clock_class->offset < 0) {
- cycles = (uint64_t) (-clock_class->offset);
- } else {
- cycles = (uint64_t) clock_class->offset;
- }
-
- u_ns = ns_from_value(clock_class->frequency, cycles);
-
- if (u_ns == -1ULL || u_ns >= INT64_MAX) {
- /*
- * Overflow: offset in cycles converted to nanoseconds
- * is outside the int64_t range.
- */
- clock_value->ns_from_epoch_overflows = true;
- goto end;
- }
-
- s_ns = (int64_t) u_ns;
- assert(s_ns >= 0);
-
- if (clock_class->offset < 0) {
- if (clock_value->ns_from_epoch >= 0) {
- /*
- * Offset in cycles is negative so it must also
- * be negative once converted to nanoseconds.
- */
- s_ns = -s_ns;
- goto offset_ok;
- }
-
- diff = clock_value->ns_from_epoch - INT64_MIN;
-
- if (s_ns >= diff) {
- /*
- * Overflow: current timestamp in nanoseconds
- * plus the offset in cycles converted to
- * nanoseconds is outside the int64_t range.
- */
- clock_value->ns_from_epoch_overflows = true;
- goto end;
- }
-
- /*
- * Offset in cycles is negative so it must also be
- * negative once converted to nanoseconds.
- */
- s_ns = -s_ns;
- } else {
- if (clock_value->ns_from_epoch <= 0) {
- goto offset_ok;
- }
-
- diff = INT64_MAX - clock_value->ns_from_epoch;
-
- if (s_ns >= diff) {
- /*
- * Overflow: current timestamp in nanoseconds
- * plus the offset in cycles converted to
- * nanoseconds is outside the int64_t range.
- */
- clock_value->ns_from_epoch_overflows = true;
- goto end;
- }
- }
-
-offset_ok:
- clock_value->ns_from_epoch += s_ns;
-
- /* Add clock value (cycles) */
- u_ns = ns_from_value(clock_class->frequency, clock_value->value);
-
- if (u_ns == -1ULL || u_ns >= INT64_MAX) {
- /*
- * Overflow: value converted to nanoseconds is outside
- * the int64_t range.
- */
- clock_value->ns_from_epoch_overflows = true;
- goto end;
- }
-
- s_ns = (int64_t) u_ns;
- assert(s_ns >= 0);
-
- /* Clock value (cycles) is always positive */
- if (clock_value->ns_from_epoch <= 0) {
- goto value_ok;
- }
-
- diff = INT64_MAX - clock_value->ns_from_epoch;
-
- if (s_ns >= diff) {
- /*
- * Overflow: current timestamp in nanoseconds plus the
- * clock value converted to nanoseconds is outside the
- * int64_t range.
- */
- clock_value->ns_from_epoch_overflows = true;
- goto end;
- }
-
-value_ok:
- clock_value->ns_from_epoch += s_ns;
-
-end:
- if (clock_value->ns_from_epoch_overflows) {
- clock_value->ns_from_epoch = 0;
- }
-}
-
-struct bt_clock_value *bt_clock_value_create(
- struct bt_clock_class *clock_class, uint64_t value)
+struct bt_clock_value *bt_clock_value_new(struct bt_clock_class *clock_class)
{
struct bt_clock_value *ret = NULL;
BT_LOGD("Creating clock value object: clock-class-addr=%p, "
- "clock-class-name=\"%s\", value=%" PRIu64, clock_class,
- bt_clock_class_get_name(clock_class), value);
+ "clock-class-name=\"%s\"", clock_class,
+ bt_clock_class_get_name(clock_class));
if (!clock_class) {
BT_LOGW_STR("Invalid parameter: clock class is NULL.");
goto end;
}
- bt_object_init(ret, bt_clock_value_destroy);
+ bt_object_init_unique(&ret->base);
ret->clock_class = bt_get(clock_class);
- ret->value = value;
- set_ns_from_epoch(ret);
bt_clock_class_freeze(clock_class);
BT_LOGD("Created clock value object: clock-value-addr=%p, "
"clock-class-addr=%p, clock-class-name=\"%s\", "
return ret;
}
-int bt_clock_value_get_value(
- struct bt_clock_value *clock_value, uint64_t *raw_value)
+BT_HIDDEN
+struct bt_clock_value *bt_clock_value_create(struct bt_clock_class *clock_class)
+{
+ struct bt_clock_value *clock_value = NULL;
+
+ BT_ASSERT(clock_class);
+ clock_value = bt_object_pool_create_object(&clock_class->cv_pool);
+ if (!clock_value) {
+ BT_LIB_LOGE("Cannot allocate one clock value from clock class's clock value pool: "
+ "%![cc-]+K", clock_class);
+ goto error;
+ }
+
+ if (!clock_value->clock_class) {
+ clock_value->clock_class = bt_get(clock_class);
+ }
+
+ goto end;
+
+error:
+ if (clock_value) {
+ bt_clock_value_recycle(clock_value);
+ clock_value = NULL;
+ }
+
+end:
+ return clock_value;
+}
+
+BT_HIDDEN
+void bt_clock_value_recycle(struct bt_clock_value *clock_value)
+{
+ struct bt_clock_class *clock_class;
+
+ BT_ASSERT(clock_value);
+ BT_LIB_LOGD("Recycling clock value: %!+k", clock_value);
+
+ /*
+ * Those are the important ordered steps:
+ *
+ * 1. Reset the clock value object, but do NOT put its clock
+ * class's reference. This clock class contains the pool to
+ * which we're about to recycle this clock value object, so
+ * we must guarantee its existence thanks to this existing
+ * reference.
+ *
+ * 2. Move the clock class reference to our `clock_class`
+ * variable so that we can set the clock value's clock class
+ * member to NULL before recycling it. We CANNOT do this
+ * after we put the clock class reference because this
+ * bt_put() could destroy the clock class, also destroying
+ * its clock value pool, thus also destroying our clock value
+ * object (this would result in an invalid write access).
+ *
+ * 3. Recycle the clock value object.
+ *
+ * 4. Put our clock class reference.
+ */
+ bt_clock_value_reset(clock_value);
+ bt_clock_value_set_is_frozen(clock_value, false);
+ clock_class = clock_value->clock_class;
+ BT_ASSERT(clock_class);
+ clock_value->clock_class = NULL;
+ bt_object_pool_recycle_object(&clock_class->cv_pool, clock_value);
+ bt_put(clock_class);
+}
+
+int bt_clock_value_get_value(struct bt_clock_value *clock_value,
+ uint64_t *raw_value)
{
int ret = 0;
return ret;
}
-struct bt_clock_class *bt_clock_value_get_class(
+struct bt_clock_class *bt_clock_value_borrow_class(
struct bt_clock_value *clock_value)
{
struct bt_clock_class *clock_class = NULL;
goto end;
}
- clock_class = bt_get(clock_value->clock_class);
+ clock_class = clock_value->clock_class;
end:
return clock_class;
}
+
+BT_HIDDEN
+int bt_clock_class_compare(struct bt_clock_class *clock_class_a,
+ struct bt_clock_class *clock_class_b)
+{
+ int ret = 1;
+ BT_ASSERT(clock_class_a);
+ BT_ASSERT(clock_class_b);
+
+ /* Name */
+ if (strcmp(clock_class_a->name->str, clock_class_b->name->str) != 0) {
+ BT_LOGV("Clock classes differ: different names: "
+ "cc-a-name=\"%s\", cc-b-name=\"%s\"",
+ clock_class_a->name->str,
+ clock_class_b->name->str);
+ goto end;
+ }
+
+ /* Description */
+ if (clock_class_a->description) {
+ if (!clock_class_b->description) {
+ BT_LOGV_STR("Clock classes differ: clock class A has a "
+ "description, but clock class B does not.");
+ goto end;
+ }
+
+ if (strcmp(clock_class_a->name->str, clock_class_b->name->str)
+ != 0) {
+ BT_LOGV("Clock classes differ: different descriptions: "
+ "cc-a-descr=\"%s\", cc-b-descr=\"%s\"",
+ clock_class_a->description->str,
+ clock_class_b->description->str);
+ goto end;
+ }
+ } else {
+ if (clock_class_b->description) {
+ BT_LOGV_STR("Clock classes differ: clock class A has "
+ "no description, but clock class B has one.");
+ goto end;
+ }
+ }
+
+ /* Frequency */
+ if (clock_class_a->frequency != clock_class_b->frequency) {
+ BT_LOGV("Clock classes differ: different frequencies: "
+ "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64,
+ clock_class_a->frequency,
+ clock_class_b->frequency);
+ goto end;
+ }
+
+ /* Precision */
+ if (clock_class_a->precision != clock_class_b->precision) {
+ BT_LOGV("Clock classes differ: different precisions: "
+ "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64,
+ clock_class_a->precision,
+ clock_class_b->precision);
+ goto end;
+ }
+
+ /* Offset (seconds) */
+ if (clock_class_a->offset_s != clock_class_b->offset_s) {
+ BT_LOGV("Clock classes differ: different offsets (seconds): "
+ "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64,
+ clock_class_a->offset_s,
+ clock_class_b->offset_s);
+ goto end;
+ }
+
+ /* Offset (cycles) */
+ if (clock_class_a->offset != clock_class_b->offset) {
+ BT_LOGV("Clock classes differ: different offsets (cycles): "
+ "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64,
+ clock_class_a->offset,
+ clock_class_b->offset);
+ goto end;
+ }
+
+ /* UUIDs */
+ if (clock_class_a->uuid_set) {
+ if (!clock_class_b->uuid_set) {
+ BT_LOGV_STR("Clock classes differ: clock class A has a "
+ "UUID, but clock class B does not.");
+ goto end;
+ }
+
+ if (memcmp(clock_class_a->uuid, clock_class_b->uuid,
+ BABELTRACE_UUID_LEN) != 0) {
+ BT_LOGV("Clock classes differ: different UUIDs: "
+ "cc-a-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", "
+ "cc-b-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+ (unsigned int) clock_class_a->uuid[0],
+ (unsigned int) clock_class_a->uuid[1],
+ (unsigned int) clock_class_a->uuid[2],
+ (unsigned int) clock_class_a->uuid[3],
+ (unsigned int) clock_class_a->uuid[4],
+ (unsigned int) clock_class_a->uuid[5],
+ (unsigned int) clock_class_a->uuid[6],
+ (unsigned int) clock_class_a->uuid[7],
+ (unsigned int) clock_class_a->uuid[8],
+ (unsigned int) clock_class_a->uuid[9],
+ (unsigned int) clock_class_a->uuid[10],
+ (unsigned int) clock_class_a->uuid[11],
+ (unsigned int) clock_class_a->uuid[12],
+ (unsigned int) clock_class_a->uuid[13],
+ (unsigned int) clock_class_a->uuid[14],
+ (unsigned int) clock_class_a->uuid[15],
+ (unsigned int) clock_class_b->uuid[0],
+ (unsigned int) clock_class_b->uuid[1],
+ (unsigned int) clock_class_b->uuid[2],
+ (unsigned int) clock_class_b->uuid[3],
+ (unsigned int) clock_class_b->uuid[4],
+ (unsigned int) clock_class_b->uuid[5],
+ (unsigned int) clock_class_b->uuid[6],
+ (unsigned int) clock_class_b->uuid[7],
+ (unsigned int) clock_class_b->uuid[8],
+ (unsigned int) clock_class_b->uuid[9],
+ (unsigned int) clock_class_b->uuid[10],
+ (unsigned int) clock_class_b->uuid[11],
+ (unsigned int) clock_class_b->uuid[12],
+ (unsigned int) clock_class_b->uuid[13],
+ (unsigned int) clock_class_b->uuid[14],
+ (unsigned int) clock_class_b->uuid[15]);
+ goto end;
+ }
+ } else {
+ if (clock_class_b->uuid_set) {
+ BT_LOGV_STR("Clock classes differ: clock class A has "
+ "no UUID, but clock class B has one.");
+ goto end;
+ }
+ }
+
+ /* Absolute */
+ if (!!clock_class_a->absolute != !!clock_class_b->absolute) {
+ BT_LOGV("Clock classes differ: one is absolute, the other "
+ "is not: cc-a-is-absolute=%d, cc-b-is-absolute=%d",
+ !!clock_class_a->absolute,
+ !!clock_class_b->absolute);
+ goto end;
+ }
+
+ /* Equal */
+ ret = 0;
+
+end:
+ return ret;
+}
+
+int bt_clock_class_cycles_to_ns(struct bt_clock_class *clock_class,
+ uint64_t cycles, int64_t *ns)
+{
+ int ret;
+ bool overflows;
+
+ BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+ BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds");
+
+ ret = ns_from_epoch(clock_class, cycles, ns, &overflows);
+ if (ret) {
+ if (overflows) {
+ BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
+ "from Epoch for given clock class: "
+ "value overflow: %![cc-]+K, cycles=%" PRIu64,
+ clock_class, cycles);
+ } else {
+ BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
+ "from Epoch for given clock class: "
+ "%![cc-]+K, cycles=%" PRIu64,
+ clock_class, cycles);
+ }
+
+ goto end;
+ }
+
+end:
+ return ret;
+}