From 8c0b889427f8e4794d1a2f53663fca27d5e3fc80 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Thu, 30 Mar 2017 22:28:59 -0400 Subject: [PATCH] Add clock class priority map object MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This new object is a simple map of clock classes to their priorities against the other clock classes of the same map. See the header file's documentation for more information (clock-class-priority-map.h). Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- include/Makefile.am | 2 + include/babeltrace/ctf-ir/trace.h | 1 - .../graph/clock-class-priority-map-internal.h | 48 +++ .../graph/clock-class-priority-map.h | 278 ++++++++++++++++++ lib/component/Makefile.am | 1 + lib/component/clock-class-priority-map.c | 267 +++++++++++++++++ 6 files changed, 596 insertions(+), 1 deletion(-) create mode 100644 include/babeltrace/graph/clock-class-priority-map-internal.h create mode 100644 include/babeltrace/graph/clock-class-priority-map.h create mode 100644 lib/component/clock-class-priority-map.c diff --git a/include/Makefile.am b/include/Makefile.am index a4ef7ecd..5f01846b 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -42,6 +42,8 @@ babeltraceplugininclude_HEADERS = \ babeltrace/plugin/plugin-dev.h babeltracegraphinclude_HEADERS = \ + babeltrace/graph/clock-class-priority-map.h \ + babeltrace/graph/clock-class-priority-map-internal.h \ babeltrace/graph/component-class-filter.h \ babeltrace/graph/component-class-sink.h \ babeltrace/graph/component-class-source.h \ diff --git a/include/babeltrace/ctf-ir/trace.h b/include/babeltrace/ctf-ir/trace.h index 07daabe3..1753d55d 100644 --- a/include/babeltrace/ctf-ir/trace.h +++ b/include/babeltrace/ctf-ir/trace.h @@ -651,7 +651,6 @@ extern int bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace_class) the trace class \p trace_class (see bt_ctf_trace_get_stream_class_count()). @postrefcountsame{trace_class} -@postsuccessrefcountretinc @sa bt_ctf_trace_get_stream_class_by_id(): Finds a stream class by ID. @sa bt_ctf_trace_add_stream_class(): Adds a stream class to a trace class. diff --git a/include/babeltrace/graph/clock-class-priority-map-internal.h b/include/babeltrace/graph/clock-class-priority-map-internal.h new file mode 100644 index 00000000..57c6c86a --- /dev/null +++ b/include/babeltrace/graph/clock-class-priority-map-internal.h @@ -0,0 +1,48 @@ +#ifndef BABELTRACE_GRAPH_CLOCK_CLASS_PRIORITY_MAP_INTERNAL_H +#define BABELTRACE_GRAPH_CLOCK_CLASS_PRIORITY_MAP_INTERNAL_H + +/* + * Copyright 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include +#include +#include +#include + +struct bt_clock_class_priority_map { + struct bt_object base; + + /* Array of struct bt_ctf_clock_class *, owned by this */ + GPtrArray *entries; + + /* struct bt_ctf_clock_class * (weak) to priority (uint64_t) */ + GHashTable *prios; + + /* Clock class (weak) with the currently highest priority */ + struct bt_ctf_clock_class *highest_prio_cc; +}; + +#endif /* BABELTRACE_GRAPH_CLOCK_CLASS_PRIORITY_MAP_INTERNAL_H */ diff --git a/include/babeltrace/graph/clock-class-priority-map.h b/include/babeltrace/graph/clock-class-priority-map.h new file mode 100644 index 00000000..18c27308 --- /dev/null +++ b/include/babeltrace/graph/clock-class-priority-map.h @@ -0,0 +1,278 @@ +#ifndef BABELTRACE_GRAPH_CLOCK_CLASS_PRIORITY_MAP_H +#define BABELTRACE_GRAPH_CLOCK_CLASS_PRIORITY_MAP_H + +/* + * Copyright 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** +@defgroup graphclockclassprioritymap Clock class priority map +@ingroup graph +@brief Clock class priority map. + +@code +#include +@endcode + +A clock class priority map object associates +CTF IR clock classes to priorities. A clock class priority indicates +which clock class you should choose to sort notifications by time. + +You need a clock class priority map object when you create +an \link graphnotifevent event notification\endlink or +an \link graphnotifinactivity inactivity notification\endlink. + +A priority is a 64-bit unsigned integer. A lower value has a +\em higher priority. Multiple clock classes can have the same priority +within a given clock class priority map. + +As with any Babeltrace object, clock class priority map objects have +reference +counts. See \ref refs to learn more about the reference counting +management of Babeltrace objects. + +@file +@brief Clock class priority map type and functions. +@sa graphclockclassprioritymap + +@addtogroup graphclockclassprioritymap +@{ +*/ + +/** +@struct bt_clock_class_priority_map +@brief A clock class priority map. +@sa graphclockclassprioritymap +*/ +struct bt_clock_class_priority_map; + +/** +@brief Creates an empty clock class priority map. + +@returns Created clock class priority map object, or \c NULL on error. + +@postsuccessrefcountret1 +*/ +extern struct bt_clock_class_priority_map *bt_clock_class_priority_map_create(); + +/** +@brief Returns the number of CTF IR clock classes contained in the + clock class priority map \p clock_class_priority_map. + +@param[in] clock_class_priority_map Clock class priority map of + which to get the number of + clock classes. +@returns Number of clock classes contained + in \p clock_class_priority_map, + or a negative value on error. + +@prenotnull{clock_class_priority_map} +@postrefcountsame{clock_class_priority_map} +*/ +extern int bt_clock_class_priority_map_get_clock_class_count( + struct bt_clock_class_priority_map *clock_class_priority_map); + +/** +@brief Returns the CTF IR clock class at index \p index in the clock + class priority map \p clock_class_priority_map. + +@param[in] clock_class_priority_map Clock class priority map of which + to get the clock class at index + \p index. +@param[in] index Index of the clock class to find + in \p clock_class_priority_map. +@returns Clock class at index \p index in + \p clock_class_priority_map, + or \c NULL on error. + +@prenotnull{clock_class_priority_map} +@pre \p index is lesser than the number of clock classes contained in + the clock class priority map \p clock_class_priority_map (see + bt_clock_class_priority_map_get_clock_class_count()). +@postrefcountsame{clock_class_priority_map} + +@sa bt_clock_class_priority_map_get_clock_class_by_name(): Finds a clock + class by name in a given clock class priority map. +@sa bt_clock_class_priority_map_get_highest_priority_clock_class(): + Returns the clock class with the highest priority contained + in a given clock class priority map. +@sa bt_clock_class_priority_map_add_clock_class(): Adds a clock class + to a clock class priority map. +*/ +extern struct bt_ctf_clock_class *bt_clock_class_priority_map_get_clock_class( + struct bt_clock_class_priority_map *clock_class_priority_map, + unsigned int index); + +/** +@brief Returns the CTF IR clock class named \c name found in the clock + class priority map \p clock_class_priority_map. + +@param[in] clock_class_priority_map Clock class priority map of + which to get the clock class + named \p name. +@param[in] name Name of the clock class to find + in \p clock_class_priority_map. +@returns Clock class named \p name in + \p clock_class_priority_map, + or \c NULL on error. + +@prenotnull{clock_class_priority_map} +@prenotnull{name} +@postrefcountsame{clock_class_priority_map} +@postsuccessrefcountretinc + +@sa bt_clock_class_priority_map_get_clock_class(): Returns the clock + class contained in a given clock class priority map at + a given index. +@sa bt_clock_class_priority_map_get_highest_priority_clock_class(): + Returns the clock class with the highest priority contained in + a given clock class priority map. +@sa bt_clock_class_priority_map_add_clock_class(): Adds a clock class + to a clock class priority map. +*/ +extern struct bt_ctf_clock_class * +bt_clock_class_priority_map_get_clock_class_by_name( + struct bt_clock_class_priority_map *clock_class_priority_map, + const char *name); + +/** +@brief Returns the CTF IR clock class with the currently highest + priority within the clock class priority map + \p clock_class_priority_map. + +If multiple clock classes share the same highest priority in +\p clock_class_priority_map, you cannot deterministically know which one +this function returns. + +@param[in] clock_class_priority_map Clock class priority map of which + to get the clock class with the + highest priority. +@returns Clock class with the highest + priority within + \p clock_class_priority_map, or + \c NULL on error or if there are + no clock classes in + \p clock_class_priority_map. + +@prenotnull{clock_class_priority_map} +@postrefcountsame{clock_class_priority_map} +@postsuccessrefcountretinc + +@sa bt_clock_class_priority_map_get_clock_class(): Returns the clock + class contained in a given clock class priority map at + a given index. +@sa bt_clock_class_priority_map_get_clock_class_by_name(): Finds a + clock class by name in a given clock class priority map. +@sa bt_clock_class_priority_map_add_clock_class(): Adds a clock class + to a clock class priority map. +*/ +extern struct bt_ctf_clock_class * +bt_clock_class_priority_map_get_highest_priority_clock_class( + struct bt_clock_class_priority_map *clock_class_priority_map); + +/** +@brief Returns the priority of the CTF IR clock class \p clock_class + contained within the clock class priority map + \p clock_class_priority_map. + +@param[in] clock_class_priority_map Clock class priority map + containing \p clock_class. +@param[in] clock_class Clock class of which to get the + priority. +@param[out] priority Returned priority of + \p clock_class within + \p clock_class_priority_map. +@returns 0 on success, or a negative + value on error. + +@prenotnull{clock_class_priority_map} +@prenotnull{clock_class} +@prenotnull{priority} +@pre \p clock_class is contained in \p clock_class_priority_map (was + previously added to \p clock_class_priority_map with + bt_clock_class_priority_map_add_clock_class()). +@postrefcountsame{clock_class_priority_map} +@postrefcountsame{clock_class} + +@sa bt_clock_class_priority_map_get_highest_priority_clock_class(): + Returns the clock class with the highest priority contained + in a given clock class priority map. +*/ +extern int bt_clock_class_priority_map_get_clock_class_priority( + struct bt_clock_class_priority_map *clock_class_priority_map, + struct bt_ctf_clock_class *clock_class, uint64_t *priority); + +/** +@brief Adds the CTF IR clock class \p clock_class to the clock class + priority map \p clock_class_priority_map with the + priority \p priority. + +You can call this function even if \p clock_class is frozen. + +A lower priority value means a \em higher priority. Multiple clock +classes can have the same priority within a given clock class priority +map. + +@param[in] clock_class_priority_map Clock class priority map to + which to add \p clock_class. +@param[in] clock_class Clock class to add to + \p clock_class_priority_map. +@param[in] priority Priority of \p clock_class within + \p clock_class_priority_map, + where a lower value means a + higher priority. +@returns 0 on success, or a negative + value on error. + +@prenotnull{clock_class_priority_map} +@prenotnull{clock_class} +@postrefcountsame{clock_class_priority_map} +@postsuccessrefcountinc{clock_class} + +@sa bt_clock_class_priority_map_get_clock_class(): Returns the clock + class contained in a given clock class priority map + at a given index. +@sa bt_clock_class_priority_map_get_clock_class_by_name(): Finds a + clock class by name in a given clock class priority map. +*/ +extern int bt_clock_class_priority_map_add_clock_class( + struct bt_clock_class_priority_map *clock_class_priority_map, + struct bt_ctf_clock_class *clock_class, uint64_t priority); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_GRAPH_CLOCK_CLASS_PRIORITY_MAP_H */ diff --git a/lib/component/Makefile.am b/lib/component/Makefile.am index 7471a4b5..a72766e0 100644 --- a/lib/component/Makefile.am +++ b/lib/component/Makefile.am @@ -6,6 +6,7 @@ noinst_LTLIBRARIES = libcomponent.la # Plug-in system library libcomponent_la_SOURCES = \ + clock-class-priority-map.c \ component.c \ component-class.c \ graph.c \ diff --git a/lib/component/clock-class-priority-map.c b/lib/component/clock-class-priority-map.c new file mode 100644 index 00000000..e917ea50 --- /dev/null +++ b/lib/component/clock-class-priority-map.c @@ -0,0 +1,267 @@ +/* + * clock-class-priority-map.c + * + * Copyright 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static +void bt_clock_class_priority_map_destroy(struct bt_object *obj) +{ + struct bt_clock_class_priority_map *cc_prio_map = (void *) obj; + + if (!cc_prio_map) { + return; + } + + if (cc_prio_map->entries) { + g_ptr_array_free(cc_prio_map->entries, TRUE); + } + + if (cc_prio_map->prios) { + g_hash_table_destroy(cc_prio_map->prios); + } + + g_free(cc_prio_map); +} + +struct bt_clock_class_priority_map *bt_clock_class_priority_map_create() +{ + struct bt_clock_class_priority_map *cc_prio_map = NULL; + + cc_prio_map = g_new0(struct bt_clock_class_priority_map, 1); + if (!cc_prio_map) { + goto error; + } + + bt_object_init(cc_prio_map, bt_clock_class_priority_map_destroy); + cc_prio_map->entries = g_ptr_array_new_with_free_func( + (GDestroyNotify) bt_put); + if (!cc_prio_map->entries) { + goto error; + } + + cc_prio_map->prios = g_hash_table_new_full(g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) g_free); + if (!cc_prio_map->entries) { + goto error; + } + + goto end; + +error: + BT_PUT(cc_prio_map); + +end: + return cc_prio_map; +} + +int bt_clock_class_priority_map_get_clock_class_count( + struct bt_clock_class_priority_map *cc_prio_map) +{ + int ret = -1; + + if (!cc_prio_map) { + goto end; + } + + ret = (int) cc_prio_map->entries->len; + +end: + return ret; +} + +struct bt_ctf_clock_class *bt_clock_class_priority_map_get_clock_class( + struct bt_clock_class_priority_map *cc_prio_map, + unsigned int index) +{ + struct bt_ctf_clock_class *clock_class = NULL; + + if (!cc_prio_map || index >= cc_prio_map->entries->len) { + goto end; + } + + clock_class = g_ptr_array_index(cc_prio_map->entries, index); + bt_get(clock_class); + +end: + return clock_class; +} + +struct bt_ctf_clock_class *bt_clock_class_priority_map_get_clock_class_by_name( + struct bt_clock_class_priority_map *cc_prio_map, + const char *name) +{ + size_t i; + struct bt_ctf_clock_class *clock_class = NULL; + + if (!cc_prio_map || !name) { + goto end; + } + + for (i = 0; i < cc_prio_map->entries->len; i++) { + struct bt_ctf_clock_class *cur_cc = + g_ptr_array_index(cc_prio_map->entries, i); + // FIXME when available: use bt_ctf_clock_class_get_name() + const char *cur_cc_name = + cur_cc->name ? cur_cc->name->str : NULL; + + if (!cur_cc_name) { + goto end; + } + + if (strcmp(cur_cc_name, name) == 0) { + clock_class = bt_get(cur_cc); + goto end; + } + } + +end: + return clock_class; +} + + +struct clock_class_prio { + uint64_t prio; + struct bt_ctf_clock_class *clock_class; +}; + +static +void current_highest_prio_gh_func(gpointer key, gpointer value, + gpointer user_data) +{ + struct clock_class_prio *func_data = user_data; + uint64_t *prio = value; + + if (*prio <= func_data->prio) { + func_data->prio = *prio; + func_data->clock_class = key; + } +} + +static +struct clock_class_prio bt_ctf_clock_class_priority_map_current_highest_prio( + struct bt_clock_class_priority_map *cc_prio_map) +{ + struct clock_class_prio func_data = { + .prio = -1ULL, + .clock_class = NULL, + }; + + g_hash_table_foreach(cc_prio_map->prios, current_highest_prio_gh_func, + &func_data); + return func_data; +} + +struct bt_ctf_clock_class * +bt_clock_class_priority_map_get_highest_priority_clock_class( + struct bt_clock_class_priority_map *cc_prio_map) +{ + struct bt_ctf_clock_class *clock_class = NULL; + + if (!cc_prio_map) { + goto end; + } + + clock_class = bt_get(cc_prio_map->highest_prio_cc); + +end: + return clock_class; +} + +int bt_clock_class_priority_map_get_clock_class_priority( + struct bt_clock_class_priority_map *cc_prio_map, + struct bt_ctf_clock_class *clock_class, uint64_t *priority) +{ + int ret = 0; + uint64_t *prio; + + if (!cc_prio_map || !clock_class || !priority) { + ret = -1; + goto end; + } + + prio = g_hash_table_lookup(cc_prio_map->prios, clock_class); + if (!prio) { + ret = -1; + goto end; + } + + *priority = *prio; + +end: + return ret; +} + +int bt_clock_class_priority_map_add_clock_class( + struct bt_clock_class_priority_map *cc_prio_map, + struct bt_ctf_clock_class *clock_class, uint64_t priority) +{ + int ret = 0; + uint64_t *prio_ptr = NULL; + struct clock_class_prio cc_prio; + + // FIXME when available: check + // bt_ctf_clock_class_is_valid(clock_class) + if (!cc_prio_map) { + ret = -1; + goto end; + } + + /* Check for duplicate clock classes */ + prio_ptr = g_hash_table_lookup(cc_prio_map->prios, clock_class); + if (prio_ptr) { + prio_ptr = NULL; + ret = -1; + goto end; + } + + prio_ptr = g_new(uint64_t, 1); + if (!prio_ptr) { + ret = -1; + goto end; + } + + *prio_ptr = priority; + bt_get(clock_class); + g_ptr_array_add(cc_prio_map->entries, clock_class); + g_hash_table_insert(cc_prio_map->prios, clock_class, prio_ptr); + prio_ptr = NULL; + cc_prio = bt_ctf_clock_class_priority_map_current_highest_prio( + cc_prio_map); + assert(cc_prio.clock_class); + cc_prio_map->highest_prio_cc = cc_prio.clock_class; + +end: + if (prio_ptr) { + g_free(prio_ptr); + } + + return ret; +} -- 2.34.1