mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-28 17:28:14 +08:00
statistics gathering
This commit is contained in:
parent
aa8fde2434
commit
bd09a0173f
@ -39,12 +39,36 @@ namespace profiler {
|
|||||||
::profiler::timestamp_t average_duration;
|
::profiler::timestamp_t average_duration;
|
||||||
::profiler::calls_number_t calls_number;
|
::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.
|
}; // 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.
|
} // END of namespace profiler.
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -80,6 +104,9 @@ struct BlocksTree
|
|||||||
{
|
{
|
||||||
delete node;
|
delete node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
release(total_statistics);
|
||||||
|
release(frame_statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator < (const BlocksTree& other) const
|
bool operator < (const BlocksTree& other) const
|
||||||
@ -100,6 +127,16 @@ private:
|
|||||||
delete node;
|
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);
|
children = ::std::move(that.children);
|
||||||
node = that.node;
|
node = that.node;
|
||||||
frame_statistics = that.frame_statistics;
|
frame_statistics = that.frame_statistics;
|
||||||
@ -116,7 +153,7 @@ private:
|
|||||||
typedef ::std::map<::profiler::thread_id_t, BlocksTree> thread_blocks_tree_t;
|
typedef ::std::map<::profiler::thread_id_t, BlocksTree> thread_blocks_tree_t;
|
||||||
|
|
||||||
extern "C"{
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
144
src/reader.cpp
144
src/reader.cpp
@ -1,10 +1,106 @@
|
|||||||
#include "profiler/reader.h"
|
#include "profiler/reader.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#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<hashed_cstr>
|
||||||
|
{
|
||||||
|
inline size_t operator () (const hashed_cstr& _str) const
|
||||||
|
{
|
||||||
|
return _str.str_hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef ::std::unordered_map<hashed_cstr, ::profiler::BlockStatistics*> StatsMap;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// TODO: optimize for Linux too
|
||||||
|
#include <string>
|
||||||
|
typedef ::std::unordered_map<::std::string, ::profiler::BlockStatistics*> StatsMap;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
extern "C"{
|
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);
|
std::ifstream inFile(filename, std::fstream::binary);
|
||||||
|
|
||||||
@ -12,6 +108,8 @@ extern "C"{
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StatsMap overall_statistics;
|
||||||
|
|
||||||
int blocks_counter = 0;
|
int blocks_counter = 0;
|
||||||
|
|
||||||
while (!inFile.eof()){
|
while (!inFile.eof()){
|
||||||
@ -22,6 +120,8 @@ extern "C"{
|
|||||||
inFile.read((char*)&sz, sizeof(sz));
|
inFile.read((char*)&sz, sizeof(sz));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use salloc::shared_allocator for allocation/deallocation safety
|
||||||
char* data = new char[sz];
|
char* data = new char[sz];
|
||||||
inFile.read((char*)&data[0], sz);
|
inFile.read((char*)&data[0], sz);
|
||||||
profiler::BaseBlockData* baseData = (profiler::BaseBlockData*)data;
|
profiler::BaseBlockData* baseData = (profiler::BaseBlockData*)data;
|
||||||
@ -32,6 +132,35 @@ extern "C"{
|
|||||||
tree.node = new profiler::SerilizedBlock(sz, data);
|
tree.node = new profiler::SerilizedBlock(sz, data);
|
||||||
blocks_counter++;
|
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()){
|
if (root.children.empty()){
|
||||||
root.children.push_back(std::move(tree));
|
root.children.push_back(std::move(tree));
|
||||||
}
|
}
|
||||||
@ -56,6 +185,17 @@ extern "C"{
|
|||||||
//delete[] data;
|
//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;
|
return blocks_counter;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user