From 9d16a1789dce8cccc6bc706d76b900f4b49c69b3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 10 Sep 2019 14:34:03 +0200 Subject: record: Add support for user defined event names --- trace/record/client.h | 29 ++++++++ trace/record/record-client-base.cc | 40 ++++++++++ trace/record/record-main-lttng.cc | 145 ++++++++++++++++++++++++------------- 3 files changed, 164 insertions(+), 50 deletions(-) diff --git a/trace/record/client.h b/trace/record/client.h index fc240ca..2fe8d51 100644 --- a/trace/record/client.h +++ b/trace/record/client.h @@ -37,8 +37,10 @@ #include #include #include +#include #include #include +#include class ErrnoException : public std::runtime_error { public: @@ -69,6 +71,33 @@ class FileDescriptor { ssize_t (*reader_)(int fd, void* buf, size_t n) = nullptr; }; +class ConfigFile { + public: + static const std::string kNoError; + + ConfigFile() = default; + + ConfigFile(const ConfigFile&) = delete; + + ConfigFile& operator=(const ConfigFile&) = delete; + + typedef std::string (*Parser)(void* arg, const char* name, const char* value); + + void AddParser(const char* section, Parser parser, void* arg); + + void Parse(const char* file); + + private: + std::map > parser_; + + std::string error_; + + static int INIHandler(void* user, + const char* section, + const char* name, + const char* value); +}; + class Client { public: Client() = default; diff --git a/trace/record/record-client-base.cc b/trace/record/record-client-base.cc index 197b654..8c467d4 100644 --- a/trace/record/record-client-base.cc +++ b/trace/record/record-client-base.cc @@ -48,6 +48,8 @@ #include #include +#include + static ssize_t ReadFile(int fd, void* buf, size_t n) { return ::read(fd, buf, n); } @@ -104,6 +106,44 @@ void FileDescriptor::Destroy() { } } +const std::string ConfigFile::kNoError; + +void ConfigFile::AddParser(const char* section, Parser parser, void* arg) { + parser_[section] = std::make_pair(parser, arg); +} + +void ConfigFile::Parse(const char* file) { + int status = ini_parse(file, INIHandler, this); + if (status < 0) { + throw ErrnoException(std::string("cannot parse configuration file '") + + file + "'"); + } else if (status > 0) { + throw std::runtime_error( + std::string("invalid line ") + std::to_string(status) + + " in configuration file '" + file + "': " + error_); + } +} + +int ConfigFile::INIHandler(void* user, + const char* section, + const char* name, + const char* value) { + ConfigFile* self = static_cast(user); + auto it = self->parser_.find(section); + if (it != self->parser_.end()) { + std::string error = (*it->second.first)(it->second.second, name, value); + if (error == kNoError) { + return 1; + } + + self->error_ = error; + } else { + self->error_ = std::string("unknown section: ") + section; + } + + return 0; +} + void Client::Run() { uint64_t todo = UINT64_MAX; diff --git a/trace/record/record-main-lttng.cc b/trace/record/record-main-lttng.cc index 267c1f8..891281e 100644 --- a/trace/record/record-main-lttng.cc +++ b/trace/record/record-main-lttng.cc @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -152,26 +153,11 @@ struct PerCPUContext { class LTTNGClient : public Client { public: - LTTNGClient() { - Initialize(LTTNGClient::HandlerCaller); - - std::memset(&pkt_ctx_, 0, sizeof(pkt_ctx_)); - std::memcpy(pkt_ctx_.header.uuid, kUUID, sizeof(pkt_ctx_.header.uuid)); - pkt_ctx_.header.ctf_magic = CTF_MAGIC; - - for (size_t i = 0; i < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT; ++i) { - PerCPUContext& pcpu = per_cpu_[i]; - pcpu.sched_switch.header.id = COMPACT_HEADER_ID; - pcpu.sched_switch.header.event_id = 1024; - pcpu.irq_handler_entry.header.id = COMPACT_HEADER_ID; - pcpu.irq_handler_entry.header.event_id = 1025; - pcpu.irq_handler_entry.name[0] = '\0'; - pcpu.irq_handler_exit.header.id = COMPACT_HEADER_ID; - pcpu.irq_handler_exit.header.event_id = 1026; - pcpu.irq_handler_exit.ret = 1; - pcpu.record_item.header.id = COMPACT_HEADER_ID; - } - } + LTTNGClient(); + + void ParseConfigFile(const char* config_file); + + void GenerateMetadata(); void OpenExecutable(const char* elf_file); @@ -207,6 +193,8 @@ class LTTNGClient : public Client { AddressToLineMap address_to_line_; + std::vector event_to_name_; + static rtems_record_client_status HandlerCaller(uint64_t bt, uint32_t cpu, rtems_record_event event, @@ -237,6 +225,10 @@ class LTTNGClient : public Client { void PrintItem(const ClientItem& item); + static std::string EventNameParser(void* arg, + const char* name, + const char* value); + void OpenStreamFiles(uint64_t data); void CloseStreamFiles(); @@ -246,6 +238,32 @@ class LTTNGClient : public Client { AddressToLineMap::iterator ResolveAddress(const ClientItem& item); }; +LTTNGClient::LTTNGClient() : event_to_name_(RTEMS_RECORD_LAST + 1) { + Initialize(LTTNGClient::HandlerCaller); + + std::memset(&pkt_ctx_, 0, sizeof(pkt_ctx_)); + std::memcpy(pkt_ctx_.header.uuid, kUUID, sizeof(pkt_ctx_.header.uuid)); + pkt_ctx_.header.ctf_magic = CTF_MAGIC; + + for (size_t i = 0; i < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT; ++i) { + PerCPUContext& pcpu = per_cpu_[i]; + pcpu.sched_switch.header.id = COMPACT_HEADER_ID; + pcpu.sched_switch.header.event_id = 1024; + pcpu.irq_handler_entry.header.id = COMPACT_HEADER_ID; + pcpu.irq_handler_entry.header.event_id = 1025; + pcpu.irq_handler_entry.name[0] = '\0'; + pcpu.irq_handler_exit.header.id = COMPACT_HEADER_ID; + pcpu.irq_handler_exit.header.event_id = 1026; + pcpu.irq_handler_exit.ret = 1; + pcpu.record_item.header.id = COMPACT_HEADER_ID; + } + + for (int i = 0; i <= RTEMS_RECORD_LAST; ++i) { + event_to_name_[i] = + rtems_record_event_text(static_cast(i)); + } +} + static uint32_t GetAPIIndexOfID(uint32_t id) { return ((id >> 24) & 0x7) - 1; } @@ -512,6 +530,29 @@ rtems_record_client_status LTTNGClient::Handler(uint64_t bt, return RTEMS_RECORD_CLIENT_SUCCESS; } +std::string LTTNGClient::EventNameParser(void* arg, + const char* name, + const char* value) { + LTTNGClient* self = static_cast(arg); + errno = 0; + char* end; + long event = std::strtol(name, &end, 0); + if (errno == 0 && *end == '\0' && event >= 0 && event <= RTEMS_RECORD_LAST) { + self->event_to_name_[event] = value; + return ConfigFile::kNoError; + } + + return std::string("invalid event: ") + name; +} + +void LTTNGClient::ParseConfigFile(const char* config_file) { + if (config_file != nullptr) { + ConfigFile file; + file.AddParser("EventNames", EventNameParser, this); + file.Parse(config_file); + } +} + void LTTNGClient::OpenStreamFiles(uint64_t data) { // Assertions are ensured by C record client assert(cpu_count_ == 0 && data < RTEMS_RECORD_CLIENT_MAXIMUM_CPU_COUNT); @@ -671,7 +712,7 @@ static const char kMetadata[] = "\t};\n" "};\n"; -static void GenerateMetadata() { +void LTTNGClient::GenerateMetadata() { FILE* f = std::fopen("metadata", "w"); if (f == NULL) { throw ErrnoException("cannot create file 'metadata'"); @@ -684,28 +725,26 @@ static void GenerateMetadata() { std::fprintf(f, "\n" "event {\n" - "\tname = %s;\n" + "\tname = \"%s\";\n" "\tid = %i;\n" "\tstream_id = 0;\n" "\tfields := struct {\n" "\t\tstring _code;\n" "\t};\n" "};\n", - rtems_record_event_text(static_cast(i)), - i); + event_to_name_[i].c_str(), i); } else { std::fprintf(f, "\n" "event {\n" - "\tname = %s;\n" + "\tname = \"%s\";\n" "\tid = %i;\n" "\tstream_id = 0;\n" "\tfields := struct {\n" "\t\txint64_t _data;\n" "\t};\n" "};\n", - rtems_record_event_text(static_cast(i)), - i); + event_to_name_[i].c_str(), i); } } @@ -719,29 +758,30 @@ static void SignalHandler(int s) { std::signal(s, SIG_DFL); } -static const struct option kLongOpts[] = {{"help", 0, NULL, 'h'}, - {"host", 1, NULL, 'H'}, - {"port", 1, NULL, 'p'}, - {NULL, 0, NULL, 0}}; +static const struct option kLongOpts[] = { + {"elf", 1, NULL, 'e'}, {"help", 0, NULL, 'h'}, {"host", 1, NULL, 'H'}, + {"limit", 1, NULL, 'l'}, {"port", 1, NULL, 'p'}, {"config", 1, NULL, 'c'}, + {NULL, 0, NULL, 0}}; static void Usage(char** argv) { - std::cout - << argv[0] - << " [--host=HOST] [--port=PORT] [--limit=LIMIT] [--elf=ELF] [INPUT-FILE]" - << std::endl - << std::endl - << "Mandatory arguments to long options are mandatory for short " - "options too." - << std::endl - << " -h, --help print this help text" << std::endl - << " -H, --host=HOST the host IPv4 address of the " - "record server" - << std::endl - << " -p, --port=PORT the TCP port of the record server" - << std::endl - << " -l, --limit=LIMIT limit in bytes to process" << std::endl - << " -e, --elf=ELF the ELF executable file" << std::endl - << " INPUT-FILE the input file" << std::endl; + std::cout << argv[0] << " [OPTION]... [INPUT-FILE]" << std::endl + << std::endl + << "Mandatory arguments to long options are mandatory for short " + "options too." + << std::endl + << " -h, --help print this help text" << std::endl + << " -H, --host=HOST the host IPv4 address of the " + "record server" + << std::endl + << " -p, --port=PORT the TCP port of the record server" + << std::endl + << " -l, --limit=LIMIT limit in bytes to process" + << std::endl + << " -e, --elf=ELF the ELF executable file" + << std::endl + << " -c, --config=CONFIG an INI-style configuration file" + << std::endl + << " INPUT-FILE the input file" << std::endl; } int main(int argc, char** argv) { @@ -749,10 +789,11 @@ int main(int argc, char** argv) { uint16_t port = 1234; const char* elf_file = nullptr; const char* input_file = nullptr; + const char* config_file = nullptr; int opt; int longindex; - while ((opt = getopt_long(argc, argv, "e:hH:l:p:", &kLongOpts[0], + while ((opt = getopt_long(argc, argv, "e:hH:l:p:c:", &kLongOpts[0], &longindex)) != -1) { switch (opt) { case 'e': @@ -770,6 +811,9 @@ int main(int argc, char** argv) { case 'p': port = (uint16_t)strtoul(optarg, NULL, 0); break; + case 'c': + config_file = optarg; + break; default: return 1; } @@ -790,7 +834,8 @@ int main(int argc, char** argv) { } try { - GenerateMetadata(); + client.ParseConfigFile(config_file); + client.GenerateMetadata(); if (elf_file != nullptr) { client.OpenExecutable(elf_file); -- cgit v1.2.3