From d7d42080f35ebe59493e56175c949ccf2220c3e8 Mon Sep 17 00:00:00 2001 From: Marcin Kolny Date: Sat, 9 Nov 2019 16:44:26 +0000 Subject: [PATCH] lib: add command line parser, allow setting global timeline buffer size --- lib/CMakeLists.txt | 1 + lib/command_line_parser.c | 114 +++++++++++++++++++++ lib/global_timeline.cpp | 17 ++- lib/include/hawktracer/base_types.h | 6 +- lib/include/internal/command_line_parser.h | 13 +++ lib/include/internal/global_timeline.h | 16 +++ lib/init.c | 7 +- tests/lib/CMakeLists.txt | 1 + tests/lib/test_command_line_parser.cpp | 81 +++++++++++++++ 9 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 lib/command_line_parser.c create mode 100644 lib/include/internal/command_line_parser.h create mode 100644 lib/include/internal/global_timeline.h create mode 100644 tests/lib/test_command_line_parser.cpp diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4a0782a7..47cfafb1 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -39,6 +39,7 @@ set(HAWKTRACER_LISTENERS_SOURCES set(HAWKTRACER_CORE_SOURCES alloc.c bag.c + command_line_parser.c event_id_provider.cpp event_utils.c events.c diff --git a/lib/command_line_parser.c b/lib/command_line_parser.c new file mode 100644 index 00000000..79db100c --- /dev/null +++ b/lib/command_line_parser.c @@ -0,0 +1,114 @@ +#include "internal/command_line_parser.h" +#include "internal/global_timeline.h" + +#include +#include +#include +#include + +typedef HT_ErrorCode(*HT_CommandLineArgumentParser)(int, char**, int); + +typedef struct +{ + const char* argument; + const char* help; + HT_CommandLineArgumentParser parser; + HT_Boolean is_flag; +} HT_CommandLineArgument; + +static HT_ErrorCode print_help(int argc, char** argv, int pos); +static HT_ErrorCode set_global_timeline_buffer_size(int argc, char** argv, int pos); + +HT_CommandLineArgument arguments[] = { + { + "--ht-global-timeline-buffer-size", + "Set Global Timeline buffer size", + set_global_timeline_buffer_size, + HT_FALSE + }, + { + "--ht-help", "Print this help and exits the process", + print_help, + HT_TRUE + } +}; + +static HT_ErrorCode +set_global_timeline_buffer_size(int argc, char** argv, int pos) +{ + if (pos + 1 >= argc) + { + return HT_ERR_MISSING_ARGUMENT; + } + + const char* s = argv[pos + 1]; + char* end; + errno = 0; + unsigned long value = strtoul(s, &end, 10); + + if (errno == ERANGE || + (sizeof(size_t) < sizeof(unsigned long) && (unsigned long)SIZE_MAX < value)) + { + return HT_ERR_OUT_OF_RANGE; + } + + if (end - s == 0) + { + return HT_ERR_INVALID_FORMAT; + } + + ht_global_timeline_set_buffer_size((size_t) value); + return HT_ERR_OK; +} + +static HT_ErrorCode +print_help(int argc, char** argv, int pos) +{ + HT_UNUSED(argc); + HT_UNUSED(argv); + HT_UNUSED(pos); + + printf("HawkTracer options:\n"); + + for (unsigned int x = 0; x < sizeof(arguments) / sizeof(arguments[0]); x++) + { + printf(" %s %s %s\n", + arguments[x].argument, + arguments[x].is_flag ? " " : "VALUE", + arguments[x].help); + } + + exit(0); + + return HT_ERR_OK; +} + +void +ht_command_line_parse_args(int argc, char** argv) +{ + for (int i = 1; i < argc; i++) + { + for (unsigned int x = 0; x < sizeof(arguments) / sizeof(arguments[0]); x++) + { + const char* argname = arguments[x].argument; + if (strcmp(argname, argv[i]) != 0) + { + continue; + } + + HT_ErrorCode error = arguments[x].parser(argc, argv, i); + + if (error != HT_ERR_OK) + { + printf("Failed to process argument %s. Error code: %d\n", + argname, error); + } + + if (arguments[x].is_flag == HT_FALSE) + { + i++; + } + break; + } + } +} diff --git a/lib/global_timeline.cpp b/lib/global_timeline.cpp index b49ca6ac..f3bce5eb 100644 --- a/lib/global_timeline.cpp +++ b/lib/global_timeline.cpp @@ -1,8 +1,23 @@ +#include "internal/global_timeline.h" #include "hawktracer/global_timeline.h" +static size_t global_timeline_buffer_size = 1024; + +void +ht_global_timeline_set_buffer_size(size_t buffer_size) +{ + global_timeline_buffer_size = buffer_size; +} + +size_t +ht_global_timeline_get_buffer_size(void) +{ + return global_timeline_buffer_size; +} + static HT_Timeline* _ht_global_timeline_create(void) { - HT_Timeline* c_timeline = ht_timeline_create(1024, HT_FALSE, HT_TRUE, "HT_GlobalTimeline", NULL); + HT_Timeline* c_timeline = ht_timeline_create(global_timeline_buffer_size, HT_FALSE, HT_TRUE, "HT_GlobalTimeline", NULL); ht_feature_callstack_enable(c_timeline); ht_feature_cached_string_enable(c_timeline, HT_FALSE); diff --git a/lib/include/hawktracer/base_types.h b/lib/include/hawktracer/base_types.h index 788ac7a1..88826a66 100644 --- a/lib/include/hawktracer/base_types.h +++ b/lib/include/hawktracer/base_types.h @@ -61,7 +61,11 @@ typedef enum /** Format of an input data is invalid. */ HT_ERR_INVALID_FORMAT, /** Invalid argument */ - HT_ERR_INVALID_ARGUMENT + HT_ERR_INVALID_ARGUMENT, + /** Out of range */ + HT_ERR_OUT_OF_RANGE, + /** Missing argument */ + HT_ERR_MISSING_ARGUMENT } HT_ErrorCode; /** Defines supported byte ordering */ diff --git a/lib/include/internal/command_line_parser.h b/lib/include/internal/command_line_parser.h new file mode 100644 index 00000000..8615ab4a --- /dev/null +++ b/lib/include/internal/command_line_parser.h @@ -0,0 +1,13 @@ +#ifndef HAWKTRACER_INTERNAL_COMMAND_LINE_PARSER_H +#define HAWKTRACER_INTERNAL_COMMAND_LINE_PARSER_H + +#include +#include + +HT_DECLS_BEGIN + +void ht_command_line_parse_args(int argc, char** argv); + +HT_DECLS_END + +#endif /* HAWKTRACER_INTERNAL_COMMAND_LINE_PARSER_H */ diff --git a/lib/include/internal/global_timeline.h b/lib/include/internal/global_timeline.h new file mode 100644 index 00000000..66930ff1 --- /dev/null +++ b/lib/include/internal/global_timeline.h @@ -0,0 +1,16 @@ +#ifndef HAWKTRACER_INTERNAL_GLOBAL_TIMELINE_H +#define HAWKTRACER_INTERNAL_GLOBAL_TIMELINE_H + +#include + +#include + +HT_DECLS_BEGIN + +void ht_global_timeline_set_buffer_size(size_t buffer_size); + +size_t ht_global_timeline_get_buffer_size(void); + +HT_DECLS_END + +#endif /* HAWKTRACER_INTERNAL_GLOBAL_TIMELINE_H */ diff --git a/lib/init.c b/lib/init.c index 3011df8b..9ccf14a3 100644 --- a/lib/init.c +++ b/lib/init.c @@ -3,19 +3,19 @@ #include "hawktracer/scoped_tracepoint.h" #include "internal/registry.h" #include "internal/feature.h" +#include "internal/command_line_parser.h" #ifdef HT_USE_PTHREADS # include "hawktracer/posix_mapped_tracepoint.h" #endif + static int _ht_init_counter = 0; void ht_init(int argc, char** argv) { - /* For future use */ - HT_UNUSED(argc); - HT_UNUSED(argv); + ht_command_line_parse_args(argc, argv); ht_registry_init(); @@ -44,7 +44,6 @@ ht_is_initialized(void) return _ht_init_counter > 0; } - void ht_deinit(void) { diff --git a/tests/lib/CMakeLists.txt b/tests/lib/CMakeLists.txt index b61de556..9c017534 100644 --- a/tests/lib/CMakeLists.txt +++ b/tests/lib/CMakeLists.txt @@ -4,6 +4,7 @@ set(LIB_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_alloc.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_allocator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_bag.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_command_line_parser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_duration_conversion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_feature_cached_string.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_feature_callstack.cpp diff --git a/tests/lib/test_command_line_parser.cpp b/tests/lib/test_command_line_parser.cpp new file mode 100644 index 00000000..f4ffe1b0 --- /dev/null +++ b/tests/lib/test_command_line_parser.cpp @@ -0,0 +1,81 @@ +#include +#include + +#include "test_common.h" + +class TestCommandLineParserLib : public ::testing::Test +{ +protected: + void SetUp() override + { + _buff_size = ht_global_timeline_get_buffer_size(); + } + + void TearDown() override + { + ht_global_timeline_set_buffer_size(_buff_size); + } + + size_t _buff_size; +}; + +TEST_F(TestCommandLineParserLib, SettingBufferSizeShouldPassForValidInput) +{ + // Arrange + const char* args[] = {"app", "--ht-global-timeline-buffer-size", "76"}; + + // Act + ht_command_line_parse_args(3, (char**)args); + + // Assert + ASSERT_EQ(76u, ht_global_timeline_get_buffer_size()); + + // Cleanup + ht_global_timeline_set_buffer_size(_buff_size); +} + +TEST_F(TestCommandLineParserLib, SettingBufferSizeShouldFailForOutOfRangeValue) +{ + // Arrange + const char* args[] = {"app", "--ht-global-timeline-buffer-size", "9999999999999999999999999999"}; + + // Act + ht_command_line_parse_args(3, (char**)args); + + // Assert + ASSERT_EQ(_buff_size, ht_global_timeline_get_buffer_size()); +} + +TEST_F(TestCommandLineParserLib, SettingBufferSizeShouldFailForInvalidString) +{ + // Arrange + const char* args[] = {"app", "--ht-global-timeline-buffer-size", "test"}; + + // Act + ht_command_line_parse_args(3, (char**)args); + + // Assert + ASSERT_EQ(_buff_size, ht_global_timeline_get_buffer_size()); +} + +TEST_F(TestCommandLineParserLib, SettingBufferSizeShouldFailIfValueIsMissing) +{ + // Arrange + const char* args[] = {"app", "--ht-global-timeline-buffer-size"}; + + // Act + ht_command_line_parse_args(2, (char**)args); + + // Assert + ASSERT_EQ(_buff_size, ht_global_timeline_get_buffer_size()); +} + +TEST_F(TestCommandLineParserLib, PassingInvalidArgumentShouldSkipTheArgument) +{ + // Arrange + const char* args[] = {"app", "--ht-non-existing-parameter"}; + + // Act + ht_command_line_parse_args(2, (char**)args); +} +