From 3253fe2633b50c5b805181b4b9818b33ea34113b Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Mon, 2 Apr 2018 01:53:29 +0300 Subject: [PATCH] #48 [Core] Rearranged file header members order to minimize padding; [Core] Changed version to 2.0.0; --- CMakeLists.txt | 4 +- README.md | 2 +- easy_profiler_converter/reader.cpp | 184 ++++++++++++++++++------- easy_profiler_core/profile_manager.cpp | 10 +- easy_profiler_core/profile_manager.h | 2 +- easy_profiler_core/reader.cpp | 182 +++++++++++++++++------- 6 files changed, 273 insertions(+), 111 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 785d5fa..04d36f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,8 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) option(EASY_PROFILER_NO_GUI "Build easy_profiler without the GUI application (required Qt)" OFF) -set(EASY_PROGRAM_VERSION_MAJOR 1) -set(EASY_PROGRAM_VERSION_MINOR 3) +set(EASY_PROGRAM_VERSION_MAJOR 2) +set(EASY_PROGRAM_VERSION_MINOR 0) set(EASY_PROGRAM_VERSION_PATCH 0) set(EASY_PRODUCT_VERSION_STRING "${EASY_PROGRAM_VERSION_MAJOR}.${EASY_PROGRAM_VERSION_MINOR}.${EASY_PROGRAM_VERSION_PATCH}") diff --git a/README.md b/README.md index da5844e..f05193d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# easy_profiler [![1.3.0](https://img.shields.io/badge/version-1.3.0-009688.svg)](https://github.com/yse/easy_profiler/releases) +# easy_profiler [![2.0.0](https://img.shields.io/badge/version-2.0.0-009688.svg)](https://github.com/yse/easy_profiler/releases) [![Build Status](https://travis-ci.org/yse/easy_profiler.svg?branch=develop)](https://travis-ci.org/yse/easy_profiler) [![Build Status](https://ci.appveyor.com/api/projects/status/github/yse/easy_profiler?branch=develop&svg=true)](https://ci.appveyor.com/project/yse/easy-profiler/branch/develop) diff --git a/easy_profiler_converter/reader.cpp b/easy_profiler_converter/reader.cpp index f01ffdb..6c0699c 100644 --- a/easy_profiler_converter/reader.cpp +++ b/easy_profiler_converter/reader.cpp @@ -20,6 +20,7 @@ extern const uint32_t PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8 const uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///< minimal compatible version (.prof file format was not changed seriously since this version) const uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file const uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t +const uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged # undef EASY_VERSION_INT const uint64_t TIME_FACTOR = 1000000000ULL; @@ -78,6 +79,117 @@ using CsStatsMap = ::std::unordered_map<::profiler::hashed_stdstring, ::profiler using namespace profiler::reader; +////////////////////////////////////////////////////////////////////////// + +struct EasyFileHeader +{ + uint32_t signature = 0; + uint32_t version = 0; + processid_t pid = 0; + int64_t cpu_frequency = 0; + ::profiler::timestamp_t begin_time = 0; + ::profiler::timestamp_t end_time = 0; + uint64_t memory_size = 0; + uint64_t descriptors_memory_size = 0; + uint32_t total_blocks_number = 0; + uint32_t total_descriptors_number = 0; +}; + +bool readHeader_v1(EasyFileHeader& _header, ::std::stringstream& inFile, ::std::stringstream& _log) +{ + // File header before v2.0.0 + + if (_header.version > EASY_V_100) + { + if (_header.version < EASY_V_130) + { + uint32_t old_pid = 0; + inFile.read((char*)&old_pid, sizeof(uint32_t)); + _header.pid = old_pid; + } + else + { + inFile.read((char*)&_header.pid, sizeof(processid_t)); + } + } + + inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t)); + inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_t)); + inFile.read((char*)&_header.end_time, sizeof(::profiler::timestamp_t)); + + inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t)); + if (_header.total_blocks_number == 0) + { + _log << "Profiled blocks number == 0"; + return false; + } + + inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size))); + if (_header.memory_size == 0) + { + _log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks"; + return false; + } + + inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t)); + if (_header.total_descriptors_number == 0) + { + _log << "Blocks description number == 0"; + return false; + } + + inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size))); + if (_header.descriptors_memory_size == 0) + { + _log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions"; + return false; + } + + return true; +} + +bool readHeader_v2(EasyFileHeader& _header, std::stringstream& inFile, std::stringstream& _log) +{ + // File header after v2.0.0 + + inFile.read((char*)&_header.pid, sizeof(processid_t)); + inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t)); + inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_t)); + inFile.read((char*)&_header.end_time, sizeof(::profiler::timestamp_t)); + + inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size))); + if (_header.memory_size == 0) + { + _log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks"; + return false; + } + + inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size))); + if (_header.descriptors_memory_size == 0) + { + _log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions"; + return false; + } + + inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t)); + if (_header.total_blocks_number == 0) + { + _log << "Profiled blocks number == 0"; + return false; + } + + inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t)); + if (_header.total_descriptors_number == 0) + { + _log << "Blocks description number == 0"; + return false; + } + + return true; +} + +////////////////////////////////////////////////////////////////////////// + ::profiler::block_index_t FileReader::readFile(const ::std::string &filename) { ::std::ifstream file(filename, ::std::fstream::binary); @@ -108,68 +220,38 @@ using namespace profiler::reader; return 0; } - processid_t pid = 0; - if (m_version > EASY_V_100) + EasyFileHeader header; + header.signature = signature; + header.version = m_version; + + if (m_version < EASY_V_200) { - if (m_version < EASY_V_130) - { - uint32_t old_pid = 0; - inFile.read((char*)&old_pid, sizeof(uint32_t)); - pid = old_pid; - } - else - { - inFile.read((char*)&pid, sizeof(processid_t)); - } + if (!readHeader_v1(header, inFile, errorMessage)) + return 0; + } + else + { + if (!readHeader_v2(header, inFile, errorMessage)) + return 0; } - int64_t file_cpu_frequency = 0LL; - inFile.read((char*)&file_cpu_frequency, sizeof(int64_t)); - const uint64_t cpu_frequency = file_cpu_frequency; + const uint64_t cpu_frequency = header.cpu_frequency; const double conversion_factor = (cpu_frequency != 0 ? static_cast(TIME_FACTOR) / static_cast(cpu_frequency) : 1.); - ::profiler::timestamp_t begin_time = 0ULL; - ::profiler::timestamp_t end_time = 0ULL; - inFile.read((char*)&begin_time, sizeof(::profiler::timestamp_t)); - inFile.read((char*)&end_time, sizeof(::profiler::timestamp_t)); + auto begin_time = header.begin_time; + auto end_time = header.end_time; + + const auto memory_size = header.memory_size; + const auto descriptors_memory_size = header.descriptors_memory_size; + const auto total_blocks_number = header.total_blocks_number; + uint32_t total_descriptors_number = header.total_descriptors_number; + if (cpu_frequency != 0) { EASY_CONVERT_TO_NANO(begin_time, cpu_frequency, conversion_factor); EASY_CONVERT_TO_NANO(end_time, cpu_frequency, conversion_factor); } - uint32_t total_blocks_number = 0; - inFile.read((char*)&total_blocks_number, sizeof(uint32_t)); - if (total_blocks_number == 0) - { - errorMessage << "Profiled blocks number == 0"; - return 0; - } - - uint64_t memory_size = 0; - inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); - if (memory_size == 0) - { - errorMessage << "Wrong memory size == 0 for " << total_blocks_number << " blocks"; - return 0; - } - - uint32_t total_descriptors_number = 0; - inFile.read((char*)&total_descriptors_number, sizeof(uint32_t)); - if (total_descriptors_number == 0) - { - errorMessage << "Blocks description number == 0"; - return 0; - } - - uint64_t descriptors_memory_size = 0; - inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); - if (descriptors_memory_size == 0) - { - errorMessage << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions"; - return 0; - } - m_BlockDescriptors.reserve(total_descriptors_number); serialized_descriptors.set(descriptors_memory_size); diff --git a/easy_profiler_core/profile_manager.cpp b/easy_profiler_core/profile_manager.cpp index 61a0ab6..8f3abfa 100644 --- a/easy_profiler_core/profile_manager.cpp +++ b/easy_profiler_core/profile_manager.cpp @@ -654,7 +654,7 @@ ProfileManager::ProfileManager() : #else m_processId((processid_t)getpid()) #endif - , m_usedMemorySize(0) + , m_descriptorsMemorySize(0) , m_beginTime(0) , m_endTime(0) { @@ -751,7 +751,7 @@ const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _d return m_descriptors[it->second]; const auto nameLen = strlen(_name); - m_usedMemorySize += sizeof(profiler::SerializedBlockDescriptor) + nameLen + strlen(_filename) + 2; + m_descriptorsMemorySize += sizeof(profiler::SerializedBlockDescriptor) + nameLen + strlen(_filename) + 2; #if EASY_BLOCK_DESC_FULL_COPY == 0 BlockDescriptor* desc = nullptr; @@ -1395,10 +1395,10 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo _outputStream.write(m_endTime); // Write blocks number and used memory size - _outputStream.write(blocks_number); _outputStream.write(usedMemorySize); + _outputStream.write(m_descriptorsMemorySize); + _outputStream.write(blocks_number); _outputStream.write(static_cast(m_descriptors.size())); - _outputStream.write(m_usedMemorySize); // Write block descriptors for (const auto descriptor : m_descriptors) @@ -1818,7 +1818,7 @@ void ProfileManager::listen(uint16_t _port) // Write block descriptors m_storedSpin.lock(); os.write(static_cast(m_descriptors.size())); - os.write(m_usedMemorySize); + os.write(m_descriptorsMemorySize); for (const auto descriptor : m_descriptors) { const auto name_size = descriptor->nameSize(); diff --git a/easy_profiler_core/profile_manager.h b/easy_profiler_core/profile_manager.h index 805bd68..c0a0cc0 100644 --- a/easy_profiler_core/profile_manager.h +++ b/easy_profiler_core/profile_manager.h @@ -94,7 +94,7 @@ class ProfileManager map_of_threads_stacks m_threads; block_descriptors_t m_descriptors; descriptors_map_t m_descriptorsMap; - uint64_t m_usedMemorySize; + uint64_t m_descriptorsMemorySize; profiler::timestamp_t m_beginTime; profiler::timestamp_t m_endTime; std::atomic m_frameMax; diff --git a/easy_profiler_core/reader.cpp b/easy_profiler_core/reader.cpp index fe6de38..13a7ff5 100644 --- a/easy_profiler_core/reader.cpp +++ b/easy_profiler_core/reader.cpp @@ -90,6 +90,7 @@ extern const uint32_t EASY_CURRENT_VERSION; const uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///< minimal compatible version (.prof file format was not changed seriously since this version) const uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file const uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t +const uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged # undef EASY_VERSION_INT const uint64_t TIME_FACTOR = 1000000000ULL; @@ -390,6 +391,115 @@ static bool update_progress(::std::atomic& progress, int new_value, ::std:: ////////////////////////////////////////////////////////////////////////// +struct EasyFileHeader +{ + uint32_t signature = 0; + uint32_t version = 0; + processid_t pid = 0; + int64_t cpu_frequency = 0; + profiler::timestamp_t begin_time = 0; + profiler::timestamp_t end_time = 0; + uint64_t memory_size = 0; + uint64_t descriptors_memory_size = 0; + uint32_t total_blocks_number = 0; + uint32_t total_descriptors_number = 0; +}; + +bool readHeader_v1(EasyFileHeader& _header, ::std::stringstream& inFile, std::stringstream& _log) +{ + // File header before v2.0.0 + + if (_header.version > EASY_V_100) + { + if (_header.version < EASY_V_130) + { + uint32_t old_pid = 0; + inFile.read((char*)&old_pid, sizeof(uint32_t)); + _header.pid = old_pid; + } + else + { + inFile.read((char*)&_header.pid, sizeof(processid_t)); + } + } + + inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t)); + inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_t)); + inFile.read((char*)&_header.end_time, sizeof(::profiler::timestamp_t)); + + inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t)); + if (_header.total_blocks_number == 0) + { + _log << "Profiled blocks number == 0"; + return false; + } + + inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size))); + if (_header.memory_size == 0) + { + _log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks"; + return false; + } + + inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t)); + if (_header.total_descriptors_number == 0) + { + _log << "Blocks description number == 0"; + return false; + } + + inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size))); + if (_header.descriptors_memory_size == 0) + { + _log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions"; + return false; + } + + return true; +} + +bool readHeader_v2(EasyFileHeader& _header, ::std::stringstream& inFile, std::stringstream& _log) +{ + // File header after v2.0.0 + + inFile.read((char*)&_header.pid, sizeof(processid_t)); + inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t)); + inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_t)); + inFile.read((char*)&_header.end_time, sizeof(::profiler::timestamp_t)); + + inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size))); + if (_header.memory_size == 0) + { + _log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks"; + return false; + } + + inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size))); + if (_header.descriptors_memory_size == 0) + { + _log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions"; + return false; + } + + inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t)); + if (_header.total_blocks_number == 0) + { + _log << "Profiled blocks number == 0"; + return false; + } + + inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t)); + if (_header.total_descriptors_number == 0) + { + _log << "Blocks description number == 0"; + return false; + } + + return true; +} + +////////////////////////////////////////////////////////////////////////// + extern "C" { PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic& progress, const char* filename, @@ -468,68 +578,38 @@ extern "C" { return 0; } - processid_t pid = 0; - if (version > EASY_V_100) + EasyFileHeader header; + header.signature = signature; + header.version = version; + + if (version < EASY_V_200) { - if (version < EASY_V_130) - { - uint32_t old_pid = 0; - inFile.read((char*)&old_pid, sizeof(uint32_t)); - pid = old_pid; - } - else - { - inFile.read((char*)&pid, sizeof(processid_t)); - } + if (!readHeader_v1(header, inFile, _log)) + return 0; + } + else + { + if (!readHeader_v2(header, inFile, _log)) + return 0; } - int64_t file_cpu_frequency = 0LL; - inFile.read((char*)&file_cpu_frequency, sizeof(int64_t)); - const uint64_t cpu_frequency = file_cpu_frequency; + const uint64_t cpu_frequency = header.cpu_frequency; const double conversion_factor = (cpu_frequency != 0 ? static_cast(TIME_FACTOR) / static_cast(cpu_frequency) : 1.); - ::profiler::timestamp_t begin_time = 0ULL; - ::profiler::timestamp_t end_time = 0ULL; - inFile.read((char*)&begin_time, sizeof(::profiler::timestamp_t)); - inFile.read((char*)&end_time, sizeof(::profiler::timestamp_t)); + auto begin_time = header.begin_time; + auto end_time = header.end_time; + + const auto memory_size = header.memory_size; + const auto descriptors_memory_size = header.descriptors_memory_size; + const auto total_blocks_number = header.total_blocks_number; + total_descriptors_number = header.total_descriptors_number; + if (cpu_frequency != 0) { EASY_CONVERT_TO_NANO(begin_time, cpu_frequency, conversion_factor); EASY_CONVERT_TO_NANO(end_time, cpu_frequency, conversion_factor); } - uint32_t total_blocks_number = 0; - inFile.read((char*)&total_blocks_number, sizeof(uint32_t)); - if (total_blocks_number == 0) - { - _log << "Profiled blocks number == 0"; - return 0; - } - - uint64_t memory_size = 0; - inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); - if (memory_size == 0) - { - _log << "Wrong memory size == 0 for " << total_blocks_number << " blocks"; - return 0; - } - - total_descriptors_number = 0; - inFile.read((char*)&total_descriptors_number, sizeof(uint32_t)); - if (total_descriptors_number == 0) - { - _log << "Blocks description number == 0"; - return 0; - } - - uint64_t descriptors_memory_size = 0; - inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); - if (descriptors_memory_size == 0) - { - _log << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions"; - return 0; - } - descriptors.reserve(total_descriptors_number); //const char* olddata = append_regime ? serialized_descriptors.data() : nullptr; serialized_descriptors.set(descriptors_memory_size);