fix: relayd: unaligned access in trace_chunk_registry_ht_key_hash
[lttng-tools.git] / tests / utils / bt2_plugins / field_stats / field_stats.cpp
1 /**
2 * Copyright (C) 2023 Kienan Stewart <kstewart@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include "../fmt.hpp"
9 #include "../utils.hpp"
10 #include "field_stats.hpp"
11
12 #include <common/make-unique-wrapper.hpp>
13 #include <common/make-unique.hpp>
14
15 #include <assert.h>
16 #include <babeltrace2/babeltrace.h>
17 #include <cstdint>
18 #include <cstring>
19 #include <iostream>
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 class bad_alloc_with_msg : public std::bad_alloc {
24 public:
25 explicit bad_alloc_with_msg(const std::string& msg) : _msg(msg)
26 {
27 }
28
29 virtual const char *what() const noexcept override
30 {
31 return _msg.c_str();
32 }
33
34 private:
35 std::string _msg;
36 };
37
38 struct field_stats {
39 public:
40 field_stats() : stats_value{ lttng::bt2::make_value_ref(bt_value_map_create()) }
41 {
42 if (!stats_value) {
43 throw bad_alloc_with_msg(
44 "Failed to allocate memory for field_stats.stats map");
45 }
46 }
47
48 ~field_stats()
49 {
50 }
51
52 lttng::bt2::message_iterator_ref upstream_iterator;
53 lttng::bt2::event_class_const_ref event_class;
54 const lttng::bt2::value_ref stats_value;
55 };
56
57 namespace {
58 bt_value_map_foreach_entry_const_func_status
59 stats_value_print_summary(const char *key, const bt_value *value, void *)
60 {
61 LTTNG_ASSERT(bt_value_is_map(value));
62
63 const auto *min = bt_value_map_borrow_entry_value_const(value, "min");
64 LTTNG_ASSERT(min != nullptr);
65 const auto *max = bt_value_map_borrow_entry_value_const(value, "max");
66 LTTNG_ASSERT(max != nullptr);
67
68 const auto *display_base = bt_value_map_borrow_entry_value_const(value, "display_base");
69 auto display_base_value = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
70
71 if (display_base != nullptr) {
72 display_base_value = (enum bt_field_class_integer_preferred_display_base)
73 bt_value_integer_unsigned_get(display_base);
74 }
75
76 LTTNG_ASSERT(bt_value_get_type(min) == bt_value_get_type(max));
77
78 switch (bt_value_get_type(min)) {
79 case BT_VALUE_TYPE_STRING:
80 fmt::print("{} \"{}\" \"{}\"\n",
81 key,
82 bt_value_string_get(min),
83 bt_value_string_get(max));
84 break;
85 case BT_VALUE_TYPE_UNSIGNED_INTEGER:
86 switch (display_base_value) {
87 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
88 std::cout << lttng::format("{} 0x{:X} 0x{:X}\n",
89 key,
90 bt_value_integer_unsigned_get(min),
91 bt_value_integer_unsigned_get(max));
92 break;
93 default:
94 std::cout << lttng::format("{} {} {}\n",
95 key,
96 bt_value_integer_unsigned_get(min),
97 bt_value_integer_unsigned_get(max));
98 break;
99 }
100
101 break;
102 case BT_VALUE_TYPE_SIGNED_INTEGER:
103 switch (display_base_value) {
104 case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
105 std::cout << lttng::format("{} 0x{:X} 0x{:X}\n",
106 key,
107 std::uint64_t(bt_value_integer_signed_get(min)),
108 std::uint64_t(bt_value_integer_signed_get(max)));
109 break;
110 default:
111 std::cout << lttng::format("{} {} {}\n",
112 key,
113 bt_value_integer_signed_get(min),
114 bt_value_integer_signed_get(max));
115 break;
116 }
117
118 break;
119 case BT_VALUE_TYPE_REAL:
120 std::cout << lttng::format(
121 "{} {:0g} {:0g}\n", key, bt_value_real_get(min), bt_value_real_get(max));
122 break;
123 default:
124 abort();
125 }
126
127 return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK;
128 }
129
130 void member_stats_set_min_max(bt_value *member_map,
131 const bt_field_class_structure_member *member,
132 const bt_field *member_field,
133 const bt_field_class *member_class,
134 const bt_field_class_type *member_class_type)
135 {
136 lttng::bt2::value_ref min, max, display_base;
137 const char *name = bt_field_class_structure_member_get_name(member);
138
139 if (bt_field_class_type_is(*member_class_type, BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)) {
140 min = lttng::bt2::make_value_ref(bt_value_integer_unsigned_create_init(
141 bt_field_integer_unsigned_get_value(member_field)));
142 max = lttng::bt2::make_value_ref(bt_value_integer_unsigned_create_init(
143 bt_field_integer_unsigned_get_value(member_field)));
144 display_base = lttng::bt2::make_value_ref(bt_value_integer_unsigned_create_init(
145 bt_field_class_integer_get_preferred_display_base(member_class)));
146 } else if (bt_field_class_type_is(*member_class_type, BT_FIELD_CLASS_TYPE_SIGNED_INTEGER)) {
147 min = lttng::bt2::make_value_ref(bt_value_integer_signed_create_init(
148 bt_field_integer_signed_get_value(member_field)));
149 max = lttng::bt2::make_value_ref(bt_value_integer_signed_create_init(
150 bt_field_integer_signed_get_value(member_field)));
151 display_base = lttng::bt2::make_value_ref(bt_value_integer_unsigned_create_init(
152 bt_field_class_integer_get_preferred_display_base(member_class)));
153 } else if (bt_field_class_type_is(*member_class_type, BT_FIELD_CLASS_TYPE_STRING)) {
154 min = lttng::bt2::make_value_ref(
155 bt_value_string_create_init(bt_field_string_get_value(member_field)));
156 max = lttng::bt2::make_value_ref(
157 bt_value_string_create_init(bt_field_string_get_value(member_field)));
158 } else if (bt_field_class_type_is(*member_class_type,
159 BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL)) {
160 min = lttng::bt2::make_value_ref(bt_value_real_create_init(
161 bt_field_real_double_precision_get_value(member_field)));
162 max = lttng::bt2::make_value_ref(bt_value_real_create_init(
163 bt_field_real_double_precision_get_value(member_field)));
164 } else if (bt_field_class_type_is(*member_class_type,
165 BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL)) {
166 min = lttng::bt2::make_value_ref(bt_value_real_create_init(
167 bt_field_real_single_precision_get_value(member_field)));
168 max = lttng::bt2::make_value_ref(bt_value_real_create_init(
169 bt_field_real_single_precision_get_value(member_field)));
170 } else if (bt_field_class_type_is(*member_class_type, BT_FIELD_CLASS_TYPE_BIT_ARRAY)) {
171 min = lttng::bt2::make_value_ref(bt_value_integer_unsigned_create_init(
172 bt_field_bit_array_get_value_as_integer(member_field)));
173 max = lttng::bt2::make_value_ref(bt_value_integer_unsigned_create_init(
174 bt_field_bit_array_get_value_as_integer(member_field)));
175 } else {
176 throw std::runtime_error(lttng::format(
177 "Unsupported field type '{}' for member '{}'", *member_class_type, name));
178 }
179
180 if (min) {
181 bt_value_map_insert_entry(member_map, "min", min.get());
182 } else {
183 throw std::runtime_error(lttng::format("No minimum value for member '{}'", name));
184 }
185
186 if (max) {
187 bt_value_map_insert_entry(member_map, "max", max.get());
188 } else {
189 throw std::runtime_error(lttng::format("No maximum value for member '{}'", name));
190 }
191
192 if (display_base) {
193 bt_value_map_insert_entry(member_map, "display_base", display_base.get());
194 }
195 }
196
197 void member_stats_update_min_max(bt_value *member_map,
198 const bt_field_class_structure_member *member,
199 const bt_field *member_field,
200 const bt_field_class_type *member_class_type)
201 {
202 const char *name = bt_field_class_structure_member_get_name(member);
203 bt_value *min = bt_value_map_borrow_entry_value(member_map, "min");
204 bt_value *max = bt_value_map_borrow_entry_value(member_map, "max");
205
206 if (min == nullptr || max == nullptr) {
207 throw std::runtime_error(
208 lttng::format("Missing min or max value for member '{}'", name));
209 }
210
211 if (bt_field_class_type_is(*member_class_type, BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER)) {
212 const auto value = bt_field_integer_unsigned_get_value(member_field);
213
214 if (value < bt_value_integer_unsigned_get(min)) {
215 bt_value_integer_unsigned_set(min, value);
216 }
217
218 if (value > bt_value_integer_unsigned_get(max)) {
219 bt_value_integer_unsigned_set(max, value);
220 }
221 } else if (bt_field_class_type_is(*member_class_type, BT_FIELD_CLASS_TYPE_SIGNED_INTEGER)) {
222 const auto value = bt_field_integer_signed_get_value(member_field);
223
224 if (value < bt_value_integer_signed_get(min)) {
225 bt_value_integer_signed_set(min, value);
226 }
227
228 if (value > bt_value_integer_signed_get(max)) {
229 bt_value_integer_signed_set(max, value);
230 }
231 } else if (bt_field_class_type_is(*member_class_type, BT_FIELD_CLASS_TYPE_STRING)) {
232 const auto value = bt_field_string_get_value(member_field);
233
234 if (strcmp(value, bt_value_string_get(min)) < 0) {
235 bt_value_string_set(min, value);
236 }
237
238 if (strcmp(value, bt_value_string_get(max)) > 0) {
239 bt_value_string_set(max, value);
240 }
241 } else if (bt_field_class_type_is(*member_class_type,
242 BT_FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL)) {
243 const auto value = bt_field_real_double_precision_get_value(member_field);
244
245 if (value < bt_value_real_get(min)) {
246 bt_value_real_set(min, value);
247 }
248
249 if (value > bt_value_real_get(max)) {
250 bt_value_real_set(max, value);
251 }
252 } else if (bt_field_class_type_is(*member_class_type,
253 BT_FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL)) {
254 const auto value = double(bt_field_real_single_precision_get_value(member_field));
255
256 if (value < bt_value_real_get(min)) {
257 bt_value_real_set(min, value);
258 }
259
260 if (value > bt_value_real_get(max)) {
261 bt_value_real_set(max, value);
262 }
263 } else if (bt_field_class_type_is(*member_class_type, BT_FIELD_CLASS_TYPE_BIT_ARRAY)) {
264 const auto value = bt_field_bit_array_get_value_as_integer(member_field);
265
266 if (value < bt_value_integer_unsigned_get(min)) {
267 bt_value_integer_unsigned_set(min, value);
268 }
269
270 if (value > bt_value_integer_unsigned_get(max)) {
271 bt_value_integer_unsigned_set(max, value);
272 }
273 } else {
274 throw std::runtime_error(lttng::format(
275 "Unsupported field type '%{}' for member '{}'", *member_class_type, name));
276 }
277 }
278
279 bt_component_class_sink_consume_method_status
280 update_stats(const bt_message *message,
281 field_stats& field_stats,
282 bt_self_component_sink *self_component_sink)
283 {
284 if (bt_message_get_type(message) != BT_MESSAGE_TYPE_EVENT) {
285 /* It's not an error to get non-EVENT messages. */
286 return BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
287 }
288
289 const auto *event = bt_message_event_borrow_event_const(message);
290 const auto *event_payload = bt_event_borrow_payload_field_const(event);
291 const auto *event_class = bt_event_borrow_class_const(event);
292 const auto *event_payload_class =
293 bt_event_class_borrow_payload_field_class_const(event_class);
294
295 if (field_stats.event_class != nullptr) {
296 LTTNG_ASSERT(event_class == field_stats.event_class.get());
297 } else {
298 bt_event_class_get_ref(event_class);
299 field_stats.event_class.reset(event_class);
300 }
301
302 /* Iterate over each field in the event payload */
303 for (std::uint64_t index = 0;
304 index < bt_field_class_structure_get_member_count(event_payload_class);
305 index++) {
306 const bt_field_class_structure_member *member =
307 bt_field_class_structure_borrow_member_by_index_const(event_payload_class,
308 index);
309 const auto *name = bt_field_class_structure_member_get_name(member);
310 const auto *member_field =
311 bt_field_structure_borrow_member_field_by_name_const(event_payload, name);
312 const auto *member_class =
313 bt_field_class_structure_member_borrow_field_class_const(member);
314 const auto member_class_type = bt_field_class_get_type(member_class);
315
316 if (bt_field_class_type_is(member_class_type, BT_FIELD_CLASS_TYPE_ARRAY) ||
317 bt_field_class_type_is(member_class_type, BT_FIELD_CLASS_TYPE_STRUCTURE)) {
318 /* Ignore array and structure field types. */
319 continue;
320 }
321
322 try {
323 auto *member_map = bt_value_map_borrow_entry_value(
324 field_stats.stats_value.get(), name);
325 if (member_map == nullptr) {
326 /* Initial creation of the value. */
327 if (bt_value_map_insert_empty_map_entry(
328 field_stats.stats_value.get(), name, &member_map) !=
329 BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) {
330 throw std::runtime_error(lttng::format(
331 "Failed to insert new empty map entry for field '{}'",
332 name));
333 }
334
335 member_stats_set_min_max(member_map,
336 member,
337 member_field,
338 member_class,
339 &member_class_type);
340 } else {
341 /* Update the value with min/max values. */
342 member_stats_update_min_max(
343 member_map, member, member_field, &member_class_type);
344 }
345 } catch (const std::exception& ex) {
346 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
347 bt_self_component_sink_as_self_component(self_component_sink),
348 "%s",
349 ex.what());
350 return BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_ERROR;
351 }
352 }
353
354 return BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
355 }
356 } /* namespace */
357
358 bt_component_class_initialize_method_status
359 field_stats_initialize(bt_self_component_sink *self_component_sink,
360 bt_self_component_sink_configuration *,
361 const bt_value *,
362 void *)
363 {
364 if (bt_self_component_sink_add_input_port(self_component_sink, "in", nullptr, nullptr) !=
365 BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) {
366 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
367 bt_self_component_sink_as_self_component(self_component_sink),
368 "Failed to add input port");
369 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
370 }
371
372 std::unique_ptr<struct field_stats> field_stats;
373 try {
374 field_stats = lttng::make_unique<struct field_stats>();
375 } catch (const bad_alloc_with_msg& ex) {
376 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
377 bt_self_component_sink_as_self_component(self_component_sink),
378 "%s",
379 ex.what());
380 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
381 } catch (const std::bad_alloc&) {
382 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
383 bt_self_component_sink_as_self_component(self_component_sink),
384 "Failed to allocate memory for private data");
385 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
386 }
387
388 /* Transfer ownership to the component. */
389 bt_self_component_set_data(bt_self_component_sink_as_self_component(self_component_sink),
390 field_stats.release());
391 return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
392 }
393
394 void field_stats_finalize(bt_self_component_sink *self_component_sink)
395 {
396 auto *field_stats = static_cast<struct field_stats *>(bt_self_component_get_data(
397 bt_self_component_sink_as_self_component(self_component_sink)));
398
399 delete field_stats;
400 }
401
402 bt_component_class_sink_graph_is_configured_method_status
403 field_stats_graph_is_configured(bt_self_component_sink *self_component_sink)
404 {
405 auto& field_stats = *static_cast<struct field_stats *>(bt_self_component_get_data(
406 bt_self_component_sink_as_self_component(self_component_sink)));
407 auto *input_port =
408 bt_self_component_sink_borrow_input_port_by_index(self_component_sink, 0);
409
410 bt_message_iterator *raw_iterator;
411 if (bt_message_iterator_create_from_sink_component(
412 self_component_sink, input_port, &raw_iterator) !=
413 BT_MESSAGE_ITERATOR_CREATE_FROM_SINK_COMPONENT_STATUS_OK) {
414 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
415 bt_self_component_sink_as_self_component(self_component_sink),
416 "input port message iterator creation failed");
417 return BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_ERROR;
418 }
419
420 field_stats.upstream_iterator.reset(raw_iterator);
421 return BT_COMPONENT_CLASS_SINK_GRAPH_IS_CONFIGURED_METHOD_STATUS_OK;
422 }
423
424 bt_component_class_sink_consume_method_status
425 field_stats_consume(bt_self_component_sink *self_component_sink)
426 {
427 auto& field_stats = *static_cast<struct field_stats *>(bt_self_component_get_data(
428 bt_self_component_sink_as_self_component(self_component_sink)));
429
430 std::uint64_t message_count;
431 bt_message_array_const messages;
432 const auto next_status = bt_message_iterator_next(
433 field_stats.upstream_iterator.get(), &messages, &message_count);
434
435 if (next_status != BT_MESSAGE_ITERATOR_NEXT_STATUS_OK) {
436 if (next_status == BT_MESSAGE_ITERATOR_NEXT_STATUS_END) {
437 /* End reached, print the summary. */
438 bt_value_map_foreach_entry_const(
439 field_stats.stats_value.get(), stats_value_print_summary, nullptr);
440 }
441
442 return static_cast<bt_component_class_sink_consume_method_status>(next_status);
443 }
444
445 for (std::uint64_t index = 0; index < message_count; index++) {
446 const auto message = lttng::bt2::message_const_ref(messages[index]);
447
448 const auto status = update_stats(message.get(), field_stats, self_component_sink);
449 if (status != BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK) {
450 return status;
451 }
452 }
453
454 return BT_COMPONENT_CLASS_SINK_CONSUME_METHOD_STATUS_OK;
455 }
This page took 0.037681 seconds and 4 git commands to generate.