From bd09a0173fc46b1c9c3228f2ad62f4ad1dc20fad Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 26 Jun 2016 00:56:24 +0300 Subject: [PATCH] statistics gathering --- include/profiler/reader.h | 41 ++++++++++- src/reader.cpp | 144 +++++++++++++++++++++++++++++++++++++- 2 files changed, 181 insertions(+), 4 deletions(-) diff --git a/include/profiler/reader.h b/include/profiler/reader.h index 48d1d66..6a814a2 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -39,12 +39,36 @@ namespace profiler { ::profiler::timestamp_t average_duration; ::profiler::calls_number_t calls_number; - BlockStatistics() : total_duration(0), min_duration(0), max_duration(0), average_duration(0), calls_number(0) + BlockStatistics() : total_duration(0), min_duration(0), max_duration(0), average_duration(0), calls_number(1) + { + } + + BlockStatistics(::profiler::timestamp_t _duration) + : total_duration(_duration) + , min_duration(_duration) + , max_duration(_duration) + , average_duration(_duration) + , calls_number(1) { } }; // END of struct BlockStatistics. + inline void release(BlockStatistics*& _stats) + { + if (!_stats) + { + return; + } + + if (--_stats->calls_number == 0) + { + delete _stats; + } + + _stats = nullptr; + } + } // END of namespace profiler. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -80,6 +104,9 @@ struct BlocksTree { delete node; } + + release(total_statistics); + release(frame_statistics); } bool operator < (const BlocksTree& other) const @@ -100,6 +127,16 @@ private: delete node; } + if (total_statistics != that.total_statistics) + { + release(total_statistics); + } + + if (frame_statistics != that.frame_statistics) + { + release(frame_statistics); + } + children = ::std::move(that.children); node = that.node; frame_statistics = that.frame_statistics; @@ -116,7 +153,7 @@ private: typedef ::std::map<::profiler::thread_id_t, BlocksTree> thread_blocks_tree_t; extern "C"{ - int PROFILER_API fillTreesFromFile(const char* filename, thread_blocks_tree_t& threaded_trees); + int PROFILER_API fillTreesFromFile(const char* filename, thread_blocks_tree_t& threaded_trees, bool gather_statistics = false); } diff --git a/src/reader.cpp b/src/reader.cpp index ed62b09..4cb20ac 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -1,10 +1,106 @@ #include "profiler/reader.h" #include #include -#include +#include +#include + +////////////////////////////////////////////////////////////////////////// + +#ifdef _WIN32 + +class cstring +{ +protected: + + const char* str; + size_t str_len; + +public: + + cstring(const char* _str) : str(_str), str_len(strlen(_str)) + { + } + + cstring(const cstring& _other) : str(_other.str), str_len(_other.str_len) + { + } + + inline bool operator == (const cstring& _other) const + { + return str_len == _other.str_len && !strncmp(str, _other.str, str_len); + } + + inline bool operator != (const cstring& _other) const + { + return !operator == (_other); + } + + inline bool operator < (const cstring& _other) const + { + if (str_len == _other.str_len) + { + return strncmp(str, _other.str, str_len) < 0; + } + + return str_len < _other.str_len; + } +}; + +class hashed_cstr : public cstring +{ + typedef cstring Parent; + +public: + + size_t str_hash; + + hashed_cstr(const char* _str) : Parent(_str), str_hash(0) + { + str_hash = ::std::_Hash_seq((const unsigned char *)str, str_len); + } + + hashed_cstr(const hashed_cstr& _other) : Parent(_other), str_hash(_other.str_hash) + { + } + + inline bool operator == (const hashed_cstr& _other) const + { + return str_hash == _other.str_hash && Parent::operator == (_other); + } + + inline bool operator != (const hashed_cstr& _other) const + { + return !operator == (_other); + } +}; + +namespace std { + + template <> + struct hash + { + inline size_t operator () (const hashed_cstr& _str) const + { + return _str.str_hash; + } + }; + +} + +typedef ::std::unordered_map StatsMap; + +#else + +// TODO: optimize for Linux too +#include +typedef ::std::unordered_map<::std::string, ::profiler::BlockStatistics*> StatsMap; + +#endif + +////////////////////////////////////////////////////////////////////////// extern "C"{ - int fillTreesFromFile(const char* filename, thread_blocks_tree_t& threaded_trees) + int fillTreesFromFile(const char* filename, thread_blocks_tree_t& threaded_trees, bool gather_statistics) { std::ifstream inFile(filename, std::fstream::binary); @@ -12,6 +108,8 @@ extern "C"{ return -1; } + StatsMap overall_statistics; + int blocks_counter = 0; while (!inFile.eof()){ @@ -22,6 +120,8 @@ extern "C"{ inFile.read((char*)&sz, sizeof(sz)); continue; } + + // TODO: use salloc::shared_allocator for allocation/deallocation safety char* data = new char[sz]; inFile.read((char*)&data[0], sz); profiler::BaseBlockData* baseData = (profiler::BaseBlockData*)data; @@ -32,6 +132,35 @@ extern "C"{ tree.node = new profiler::SerilizedBlock(sz, data); blocks_counter++; + if (gather_statistics) + { + auto duration = tree.node->block()->duration(); + StatsMap::key_type key(tree.node->getBlockName()); + auto it = overall_statistics.find(key); + if (it != overall_statistics.end()) + { + tree.total_statistics = it->second; + + ++tree.total_statistics->calls_number; + tree.total_statistics->total_duration += duration; + + if (duration > tree.total_statistics->max_duration) + { + tree.total_statistics->max_duration = duration; + } + + if (duration < tree.total_statistics->min_duration) + { + tree.total_statistics->min_duration = duration; + } + } + else + { + tree.total_statistics = new ::profiler::BlockStatistics(duration); + overall_statistics.insert(::std::make_pair(key, tree.total_statistics)); + } + } + if (root.children.empty()){ root.children.push_back(std::move(tree)); } @@ -56,6 +185,17 @@ extern "C"{ //delete[] data; } + + if (gather_statistics) + { + for (auto it = overall_statistics.begin(), end = overall_statistics.end(); it != end; ++it) + { + it->second->average_duration = it->second->total_duration / it->second->calls_number; + } + + // No need to delete BlockStatistics instances - they will be deleted on BlocksTree destructors + } + return blocks_counter; } } \ No newline at end of file