4 * Babeltrace Trace Converter
6 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
8 * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 #include <babeltrace/babeltrace.h>
30 #include <babeltrace/plugin/plugin.h>
31 #include <babeltrace/common-internal.h>
32 #include <babeltrace/component/component.h>
33 #include <babeltrace/component/component-source.h>
34 #include <babeltrace/component/component-sink.h>
35 #include <babeltrace/component/component-filter.h>
36 #include <babeltrace/component/component-class.h>
37 #include <babeltrace/component/notification/iterator.h>
38 #include <babeltrace/ref.h>
39 #include <babeltrace/values.h>
41 #include <babeltrace/ctf-ir/metadata.h> /* for clocks */
46 #include "babeltrace-cfg.h"
47 #include "default-cfg.h"
49 GPtrArray
*loaded_plugins
;
52 void init_loaded_plugins_array(void)
54 loaded_plugins
= g_ptr_array_new_full(8, bt_put
);
58 void fini_loaded_plugins_array(void)
60 g_ptr_array_free(loaded_plugins
, TRUE
);
64 struct bt_plugin
*find_plugin(const char *name
)
67 struct bt_plugin
*plugin
= NULL
;
69 for (i
= 0; i
< loaded_plugins
->len
; i
++) {
70 plugin
= g_ptr_array_index(loaded_plugins
, i
);
72 if (strcmp(name
, bt_plugin_get_name(plugin
)) == 0) {
79 return bt_get(plugin
);
83 struct bt_component_class
*find_component_class(const char *plugin_name
,
84 const char *comp_class_name
,
85 enum bt_component_class_type comp_class_type
)
87 struct bt_component_class
*comp_class
= NULL
;
88 struct bt_plugin
*plugin
= find_plugin(plugin_name
);
94 comp_class
= bt_plugin_get_component_class_by_name_and_type(plugin
,
95 comp_class_name
, comp_class_type
);
102 void print_indent(size_t indent
)
106 for (i
= 0; i
< indent
; i
++) {
112 void print_value(struct bt_value
*, size_t);
115 bool print_map_value(const char *key
, struct bt_value
*object
, void *data
)
117 size_t *indent
= data
;
119 print_indent(*indent
);
122 if (bt_value_is_array(object
) &&
123 bt_value_array_is_empty(object
)) {
128 if (bt_value_is_map(object
) &&
129 bt_value_map_is_empty(object
)) {
134 if (bt_value_is_array(object
) ||
135 bt_value_is_map(object
)) {
139 print_value(object
, *indent
+ 2);
144 void print_value(struct bt_value
*value
, size_t indent
)
157 switch (bt_value_get_type(value
)) {
158 case BT_VALUE_TYPE_NULL
:
161 case BT_VALUE_TYPE_BOOL
:
162 bt_value_bool_get(value
, &bool_val
);
163 printf("%s\n", bool_val
? "yes" : "no");
165 case BT_VALUE_TYPE_INTEGER
:
166 bt_value_integer_get(value
, &int_val
);
167 printf("%" PRId64
"\n", int_val
);
169 case BT_VALUE_TYPE_FLOAT
:
170 bt_value_float_get(value
, &dbl_val
);
171 printf("%lf\n", dbl_val
);
173 case BT_VALUE_TYPE_STRING
:
174 bt_value_string_get(value
, &str_val
);
175 printf("%s\n", str_val
);
177 case BT_VALUE_TYPE_ARRAY
:
178 size
= bt_value_array_size(value
);
182 print_indent(indent
);
187 for (i
= 0; i
< size
; i
++) {
188 struct bt_value
*element
=
189 bt_value_array_get(value
, i
);
192 print_indent(indent
);
195 if (bt_value_is_array(element
) &&
196 bt_value_array_is_empty(element
)) {
201 if (bt_value_is_map(element
) &&
202 bt_value_map_is_empty(element
)) {
207 if (bt_value_is_array(element
) ||
208 bt_value_is_map(element
)) {
212 print_value(element
, indent
+ 2);
216 case BT_VALUE_TYPE_MAP
:
217 if (bt_value_map_is_empty(value
)) {
218 print_indent(indent
);
223 bt_value_map_foreach(value
, print_map_value
, &indent
);
231 void print_bt_config_component(struct bt_config_component
*bt_config_component
)
233 printf(" %s.%s:\n", bt_config_component
->plugin_name
->str
,
234 bt_config_component
->component_name
->str
);
235 printf(" Parameters:\n");
236 print_value(bt_config_component
->params
, 8);
240 void print_bt_config_components(GPtrArray
*array
)
244 for (i
= 0; i
< array
->len
; i
++) {
245 struct bt_config_component
*cfg_component
=
246 bt_config_get_component(array
, i
);
247 print_bt_config_component(cfg_component
);
248 BT_PUT(cfg_component
);
253 void print_plugin_paths(struct bt_value
*plugin_paths
)
255 printf(" Plugin paths:\n");
256 print_value(plugin_paths
, 4);
260 void print_cfg_convert(struct bt_config
*cfg
)
262 printf(" Force correlate: %s\n",
263 cfg
->cmd_data
.convert
.force_correlate
? "yes" : "no");
264 print_plugin_paths(cfg
->cmd_data
.convert
.plugin_paths
);
265 printf(" Source component instances:\n");
266 print_bt_config_components(cfg
->cmd_data
.convert
.sources
);
267 printf(" Sink component instances:\n");
268 print_bt_config_components(cfg
->cmd_data
.convert
.sinks
);
272 void print_cfg_list_plugins(struct bt_config
*cfg
)
274 print_plugin_paths(cfg
->cmd_data
.list_plugins
.plugin_paths
);
278 void print_cfg(struct bt_config
*cfg
)
280 if (!babeltrace_verbose
) {
284 printf("Configuration:\n");
285 printf(" Debug mode: %s\n", cfg
->debug
? "yes" : "no");
286 printf(" Verbose mode: %s\n", cfg
->verbose
? "yes" : "no");
288 switch (cfg
->command
) {
289 case BT_CONFIG_COMMAND_CONVERT
:
290 print_cfg_convert(cfg
);
292 case BT_CONFIG_COMMAND_LIST_PLUGINS
:
293 print_cfg_list_plugins(cfg
);
301 struct bt_component
*create_trimmer(struct bt_config_component
*source_cfg
)
303 struct bt_component
*trimmer
= NULL
;
304 struct bt_component_class
*trimmer_class
= NULL
;
305 struct bt_value
*trimmer_params
= NULL
;
306 struct bt_value
*value
;
308 trimmer_params
= bt_value_map_create();
309 if (!trimmer_params
) {
313 value
= bt_value_map_get(source_cfg
->params
, "begin");
315 enum bt_value_status ret
;
317 ret
= bt_value_map_insert(trimmer_params
, "begin",
324 value
= bt_value_map_get(source_cfg
->params
, "end");
326 enum bt_value_status ret
;
328 ret
= bt_value_map_insert(trimmer_params
, "end",
335 value
= bt_value_map_get(source_cfg
->params
, "clock-gmt");
337 enum bt_value_status ret
;
339 ret
= bt_value_map_insert(trimmer_params
, "clock-gmt",
347 trimmer_class
= find_component_class("utils", "trimmer",
348 BT_COMPONENT_CLASS_TYPE_FILTER
);
349 if (!trimmer_class
) {
350 fprintf(stderr
, "Could not find trimmer component class. Aborting...\n");
353 trimmer
= bt_component_create(trimmer_class
, "source_trimmer",
359 bt_put(trimmer_params
);
360 bt_put(trimmer_class
);
365 int connect_source_sink(struct bt_component
*source
,
366 struct bt_config_component
*source_cfg
,
367 struct bt_component
*sink
)
370 enum bt_component_status sink_status
;
371 struct bt_component
*trimmer
= NULL
;
372 struct bt_notification_iterator
*source_it
= NULL
;
373 struct bt_notification_iterator
*to_sink_it
= NULL
;
375 source_it
= bt_component_source_create_notification_iterator(source
);
377 fprintf(stderr
, "Failed to instantiate source iterator. Aborting...\n");
382 if (bt_value_map_has_key(source_cfg
->params
, "begin")
383 || bt_value_map_has_key(source_cfg
->params
, "end")) {
384 /* A trimmer must be inserted in the graph. */
385 enum bt_component_status trimmer_status
;
387 trimmer
= create_trimmer(source_cfg
);
389 fprintf(stderr
, "Failed to create trimmer component. Aborting...\n");
394 trimmer_status
= bt_component_filter_add_iterator(trimmer
,
397 if (trimmer_status
!= BT_COMPONENT_STATUS_OK
) {
398 fprintf(stderr
, "Failed to connect source to trimmer. Aborting...\n");
403 to_sink_it
= bt_component_filter_create_notification_iterator(trimmer
);
405 fprintf(stderr
, "Failed to instantiate trimmer iterator. Aborting...\n");
410 BT_MOVE(to_sink_it
, source_it
);
413 sink_status
= bt_component_sink_add_iterator(sink
, to_sink_it
);
414 if (sink_status
!= BT_COMPONENT_STATUS_OK
) {
415 fprintf(stderr
, "Failed to connect to sink component. Aborting...\n");
427 void add_to_loaded_plugins(struct bt_plugin
**plugins
)
430 struct bt_plugin
*plugin
= *plugins
;
431 /* Check if it's already loaded (from another path). */
432 struct bt_plugin
*loaded_plugin
=
433 find_plugin(bt_plugin_get_name(plugin
));
436 printf_verbose("Not loading plugin `%s`: already loaded from `%s`\n",
437 bt_plugin_get_path(plugin
),
438 bt_plugin_get_path(loaded_plugin
));
439 BT_PUT(loaded_plugin
);
442 /* Transfer ownership to global array. */
443 g_ptr_array_add(loaded_plugins
, plugin
);
450 int load_dynamic_plugins(struct bt_value
*plugin_paths
)
452 int nr_paths
, i
, ret
= 0;
454 nr_paths
= bt_value_array_size(plugin_paths
);
460 for (i
= 0; i
< nr_paths
; i
++) {
461 struct bt_value
*plugin_path_value
= NULL
;
462 const char *plugin_path
;
463 struct bt_plugin
**plugins
;
465 plugin_path_value
= bt_value_array_get(plugin_paths
, i
);
466 if (bt_value_string_get(plugin_path_value
,
468 BT_PUT(plugin_path_value
);
472 plugins
= bt_plugin_create_all_from_dir(plugin_path
, false);
474 printf_debug("Unable to dynamically load plugins from path %s.\n",
476 BT_PUT(plugin_path_value
);
480 add_to_loaded_plugins(plugins
);
483 BT_PUT(plugin_path_value
);
490 int load_static_plugins(void)
493 struct bt_plugin
**plugins
;
495 plugins
= bt_plugin_create_all_from_static();
497 printf_debug("Unable to load static plugins.\n");
502 add_to_loaded_plugins(plugins
);
509 const char *component_type_str(enum bt_component_class_type type
)
512 case BT_COMPONENT_CLASS_TYPE_SOURCE
:
514 case BT_COMPONENT_CLASS_TYPE_SINK
:
516 case BT_COMPONENT_CLASS_TYPE_FILTER
:
518 case BT_COMPONENT_CLASS_TYPE_UNKNOWN
:
524 static int load_all_plugins(struct bt_value
*plugin_paths
)
528 if (load_dynamic_plugins(plugin_paths
)) {
529 fprintf(stderr
, "Failed to load dynamic plugins.\n");
534 if (load_static_plugins()) {
535 fprintf(stderr
, "Failed to load static plugins.\n");
544 static int cmd_list_plugins(struct bt_config
*cfg
)
547 int plugins_count
, component_classes_count
= 0, i
;
549 ret
= load_all_plugins(cfg
->cmd_data
.list_plugins
.plugin_paths
);
554 plugins_count
= loaded_plugins
->len
;
555 if (plugins_count
== 0) {
556 fprintf(stderr
, "%s%sNo plugins found.%s\n",
557 bt_common_color_bold(), bt_common_color_fg_red(),
558 bt_common_color_reset());
559 fprintf(stderr
, "\n");
560 fprintf(stderr
, "Please make sure your plugin search path is set correctly. You can use\n");
561 fprintf(stderr
, "the --plugin-path command-line option or the BABELTRACE_PLUGIN_PATH\n");
562 fprintf(stderr
, "environment variable.\n");
567 for (i
= 0; i
< plugins_count
; i
++) {
568 struct bt_plugin
*plugin
= g_ptr_array_index(loaded_plugins
, i
);
570 component_classes_count
+= bt_plugin_get_component_class_count(plugin
);
573 printf("Found %s%d%s component classes in %s%d%s plugins.\n",
574 bt_common_color_bold(),
575 component_classes_count
,
576 bt_common_color_reset(),
577 bt_common_color_bold(),
579 bt_common_color_reset());
581 for (i
= 0; i
< plugins_count
; i
++) {
583 struct bt_plugin
*plugin
= g_ptr_array_index(loaded_plugins
, i
);
584 unsigned int major
, minor
, patch
;
586 enum bt_plugin_status version_status
;
587 const char *plugin_name
= bt_plugin_get_name(plugin
);
588 const char *path
= bt_plugin_get_path(plugin
);
589 const char *author
= bt_plugin_get_author(plugin
);
590 const char *license
= bt_plugin_get_license(plugin
);
591 const char *plugin_description
=
592 bt_plugin_get_description(plugin
);
594 component_classes_count
=
595 bt_plugin_get_component_class_count(plugin
);
596 version_status
= bt_plugin_get_version(plugin
, &major
, &minor
,
599 printf("\n%s%s%s%s:\n", bt_common_color_bold(),
600 bt_common_color_fg_blue(), plugin_name
,
601 bt_common_color_reset());
602 printf(" %sPath%s: %s\n", bt_common_color_bold(),
603 bt_common_color_reset(), path
? path
: "(None)");
605 if (version_status
== BT_PLUGIN_STATUS_OK
) {
606 printf(" %sVersion%s: %u.%u.%u",
607 bt_common_color_bold(), bt_common_color_reset(),
608 major
, minor
, patch
);
617 printf(" %sDescription%s: %s\n", bt_common_color_bold(),
618 bt_common_color_reset(),
619 plugin_description
? plugin_description
: "(None)");
620 printf(" %sAuthor%s: %s\n", bt_common_color_bold(),
621 bt_common_color_reset(), author
? author
: "(Unknown)");
622 printf(" %sLicense%s: %s\n", bt_common_color_bold(),
623 bt_common_color_reset(),
624 license
? license
: "(Unknown)");
626 if (component_classes_count
== 0) {
627 printf(" %sComponent classes%s: (None)\n",
628 bt_common_color_bold(),
629 bt_common_color_reset());
631 printf(" %sComponent classes%s:\n",
632 bt_common_color_bold(),
633 bt_common_color_reset());
636 for (j
= 0; j
< component_classes_count
; j
++) {
637 struct bt_component_class
*comp_class
=
638 bt_plugin_get_component_class(plugin
, j
);
639 const char *comp_class_name
=
640 bt_component_class_get_name(comp_class
);
641 const char *comp_class_description
=
642 bt_component_class_get_description(comp_class
);
643 enum bt_component_class_type type
=
644 bt_component_class_get_type(comp_class
);
646 printf(" %s%s--%s%s %s%s%s.%s%s%s",
647 bt_common_color_bold(),
648 bt_common_color_fg_cyan(),
649 component_type_str(type
),
650 bt_common_color_fg_default(),
651 bt_common_color_fg_blue(),
653 bt_common_color_fg_default(),
654 bt_common_color_fg_yellow(),
656 bt_common_color_reset());
658 if (comp_class_description
) {
659 printf(": %s", comp_class_description
);
671 static int cmd_convert(struct bt_config
*cfg
)
674 struct bt_component_class
*source_class
= NULL
;
675 struct bt_component_class
*sink_class
= NULL
;
676 struct bt_component
*source
= NULL
, *sink
= NULL
;
677 struct bt_value
*source_params
= NULL
, *sink_params
= NULL
;
678 enum bt_component_status sink_status
;
679 struct bt_config_component
*source_cfg
= NULL
, *sink_cfg
= NULL
;
681 /* TODO handle more than 1 source and 1 sink. */
682 if (cfg
->cmd_data
.convert
.sources
->len
!= 1 ||
683 cfg
->cmd_data
.convert
.sinks
->len
!= 1) {
688 ret
= load_all_plugins(cfg
->cmd_data
.convert
.plugin_paths
);
693 source_cfg
= bt_config_get_component(cfg
->cmd_data
.convert
.sources
, 0);
694 source_params
= bt_get(source_cfg
->params
);
695 source_class
= find_component_class(source_cfg
->plugin_name
->str
,
696 source_cfg
->component_name
->str
,
697 BT_COMPONENT_CLASS_TYPE_SOURCE
);
699 fprintf(stderr
, "Could not find %s.%s source component class. Aborting...\n",
700 source_cfg
->plugin_name
->str
,
701 source_cfg
->component_name
->str
);
706 sink_cfg
= bt_config_get_component(cfg
->cmd_data
.convert
.sinks
, 0);
707 sink_params
= bt_get(sink_cfg
->params
);
708 sink_class
= find_component_class(sink_cfg
->plugin_name
->str
,
709 sink_cfg
->component_name
->str
,
710 BT_COMPONENT_CLASS_TYPE_SINK
);
712 fprintf(stderr
, "Could not find %s.%s output component class. Aborting...\n",
713 sink_cfg
->plugin_name
->str
,
714 sink_cfg
->component_name
->str
);
719 source
= bt_component_create(source_class
, "source", source_params
);
721 fprintf(stderr
, "Failed to instantiate selected source component. Aborting...\n");
726 sink
= bt_component_create(sink_class
, "sink", sink_params
);
728 fprintf(stderr
, "Failed to instantiate selected output component. Aborting...\n");
733 ret
= connect_source_sink(source
, source_cfg
, sink
);
740 sink_status
= bt_component_sink_consume(sink
);
741 switch (sink_status
) {
742 case BT_COMPONENT_STATUS_AGAIN
:
743 /* Wait for an arbitraty 500 ms. */
746 case BT_COMPONENT_STATUS_OK
:
748 case BT_COMPONENT_STATUS_END
:
751 fprintf(stderr
, "Sink component returned an error, aborting...\n");
759 BT_PUT(source_class
);
762 BT_PUT(source_params
);
769 static void warn_command_name_and_directory_clash(struct bt_config
*cfg
)
771 if (!cfg
->command_name
) {
775 if (g_file_test(cfg
->command_name
,
776 G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_DIR
)) {
777 fprintf(stderr
, "\nNOTE: The `%s` command was executed. If you meant to convert a\n",
779 fprintf(stderr
, "trace located in the local `%s` directory, please use:\n",
781 fprintf(stderr
, "\n");
782 fprintf(stderr
, " babeltrace convert %s [OPTIONS]\n",
787 int main(int argc
, const char **argv
)
791 struct bt_config
*cfg
;
793 init_loaded_plugins_array();
794 cfg
= bt_config_from_args_with_defaults(argc
, argv
, &retcode
);
797 /* Quit without errors; typically usage/version */
807 fprintf(stderr
, "Failed to create Babeltrace configuration\n");
811 babeltrace_debug
= cfg
->debug
;
812 babeltrace_verbose
= cfg
->verbose
;
815 switch (cfg
->command
) {
816 case BT_CONFIG_COMMAND_CONVERT
:
817 ret
= cmd_convert(cfg
);
819 case BT_CONFIG_COMMAND_LIST_PLUGINS
:
820 ret
= cmd_list_plugins(cfg
);
826 warn_command_name_and_directory_clash(cfg
);
827 retcode
= ret
? 1 : 0;
831 fini_loaded_plugins_array();