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