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