mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 08:41:02 +08:00
#91 [UI] Added snapshot tool stub; Working on saving blocks to file from UI
This commit is contained in:
parent
7b7dfc9827
commit
ef7b41fd0d
@ -45,32 +45,36 @@ The Apache License, Version 2.0 (the "License");
|
|||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <easy/serialized_block.h>
|
#include <easy/serialized_block.h>
|
||||||
#include <easy/details/arbitrary_value_public_types.h>
|
#include <easy/details/arbitrary_value_public_types.h>
|
||||||
#include <easy/utility.h>
|
#include <easy/utility.h>
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
namespace profiler {
|
namespace profiler {
|
||||||
|
|
||||||
|
using processid_t = uint64_t;
|
||||||
using calls_number_t = uint32_t;
|
using calls_number_t = uint32_t;
|
||||||
using block_index_t = uint32_t;
|
using block_index_t = uint32_t;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct BlockStatistics EASY_FINAL
|
struct BlockStatistics EASY_FINAL
|
||||||
{
|
{
|
||||||
::profiler::timestamp_t total_duration; ///< Total duration of all block calls
|
profiler::timestamp_t total_duration; ///< Total duration of all block calls
|
||||||
::profiler::timestamp_t total_children_duration; ///< Total duration of all children of all block calls
|
profiler::timestamp_t total_children_duration; ///< Total duration of all children of all block calls
|
||||||
::profiler::block_index_t min_duration_block; ///< Will be used in GUI to jump to the block with min duration
|
profiler::block_index_t min_duration_block; ///< Will be used in GUI to jump to the block with min duration
|
||||||
::profiler::block_index_t max_duration_block; ///< Will be used in GUI to jump to the block with max duration
|
profiler::block_index_t max_duration_block; ///< Will be used in GUI to jump to the block with max duration
|
||||||
::profiler::block_index_t parent_block; ///< Index of block which is "parent" for "per_parent_stats" or "frame" for "per_frame_stats" or thread-id for "per_thread_stats"
|
profiler::block_index_t parent_block; ///< Index of block which is "parent" for "per_parent_stats" or "frame" for "per_frame_stats" or thread-id for "per_thread_stats"
|
||||||
::profiler::calls_number_t calls_number; ///< Block calls number
|
profiler::calls_number_t calls_number; ///< Block calls number
|
||||||
|
|
||||||
explicit BlockStatistics(::profiler::timestamp_t _duration, ::profiler::block_index_t _block_index, ::profiler::block_index_t _parent_index)
|
explicit BlockStatistics(profiler::timestamp_t _duration, profiler::block_index_t _block_index, profiler::block_index_t _parent_index)
|
||||||
: total_duration(_duration)
|
: total_duration(_duration)
|
||||||
, total_children_duration(0)
|
, total_children_duration(0)
|
||||||
, min_duration_block(_block_index)
|
, min_duration_block(_block_index)
|
||||||
@ -82,7 +86,7 @@ namespace profiler {
|
|||||||
|
|
||||||
//BlockStatistics() = default;
|
//BlockStatistics() = default;
|
||||||
|
|
||||||
inline ::profiler::timestamp_t average_duration() const
|
inline profiler::timestamp_t average_duration() const
|
||||||
{
|
{
|
||||||
return total_duration / calls_number;
|
return total_duration / calls_number;
|
||||||
}
|
}
|
||||||
@ -100,20 +104,20 @@ namespace profiler {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using blocks_t = ::std::vector<This>;
|
using blocks_t = std::vector<This>;
|
||||||
using children_t = ::std::vector<::profiler::block_index_t>;
|
using children_t = std::vector<profiler::block_index_t>;
|
||||||
|
|
||||||
children_t children; ///< List of children blocks. May be empty.
|
children_t children; ///< List of children blocks. May be empty.
|
||||||
|
|
||||||
union {
|
union {
|
||||||
::profiler::SerializedBlock* node; ///< Pointer to serialized data for regular block (id, name, begin, end etc.)
|
profiler::SerializedBlock* node; ///< Pointer to serialized data for regular block (id, name, begin, end etc.)
|
||||||
::profiler::SerializedCSwitch* cs; ///< Pointer to serialized data for context switch (thread_id, name, begin, end etc.)
|
profiler::SerializedCSwitch* cs; ///< Pointer to serialized data for context switch (thread_id, name, begin, end etc.)
|
||||||
::profiler::ArbitraryValue* value; ///< Pointer to serialized data for arbitrary value
|
profiler::ArbitraryValue* value; ///< Pointer to serialized data for arbitrary value
|
||||||
};
|
};
|
||||||
|
|
||||||
::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
|
profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
|
||||||
::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks)
|
profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks)
|
||||||
::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread
|
profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread
|
||||||
uint8_t depth; ///< Maximum number of sublevels (maximum children depth)
|
uint8_t depth; ///< Maximum number of sublevels (maximum children depth)
|
||||||
|
|
||||||
BlocksTree(const This&) = delete;
|
BlocksTree(const This&) = delete;
|
||||||
@ -132,12 +136,12 @@ namespace profiler {
|
|||||||
BlocksTree(This&& that) EASY_NOEXCEPT
|
BlocksTree(This&& that) EASY_NOEXCEPT
|
||||||
: BlocksTree()
|
: BlocksTree()
|
||||||
{
|
{
|
||||||
make_move(::std::forward<This&&>(that));
|
make_move(std::forward<This&&>(that));
|
||||||
}
|
}
|
||||||
|
|
||||||
This& operator = (This&& that) EASY_NOEXCEPT
|
This& operator = (This&& that) EASY_NOEXCEPT
|
||||||
{
|
{
|
||||||
make_move(::std::forward<This&&>(that));
|
make_move(std::forward<This&&>(that));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +170,7 @@ namespace profiler {
|
|||||||
// shrink version 2:
|
// shrink version 2:
|
||||||
//children_t new_children;
|
//children_t new_children;
|
||||||
//new_children.reserve(children.size());
|
//new_children.reserve(children.size());
|
||||||
//::std::move(children.begin(), children.end(), ::std::back_inserter(new_children));
|
//std::move(children.begin(), children.end(), std::back_inserter(new_children));
|
||||||
//new_children.swap(children);
|
//new_children.swap(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +187,7 @@ namespace profiler {
|
|||||||
if (per_frame_stats != that.per_frame_stats)
|
if (per_frame_stats != that.per_frame_stats)
|
||||||
release_stats(per_frame_stats);
|
release_stats(per_frame_stats);
|
||||||
|
|
||||||
children = ::std::move(that.children);
|
children = std::move(that.children);
|
||||||
node = that.node;
|
node = that.node;
|
||||||
per_parent_stats = that.per_parent_stats;
|
per_parent_stats = that.per_parent_stats;
|
||||||
per_frame_stats = that.per_frame_stats;
|
per_frame_stats = that.per_frame_stats;
|
||||||
@ -210,11 +214,11 @@ namespace profiler {
|
|||||||
BlocksTree::children_t sync; ///< List of context-switch events
|
BlocksTree::children_t sync; ///< List of context-switch events
|
||||||
BlocksTree::children_t events; ///< List of events indexes
|
BlocksTree::children_t events; ///< List of events indexes
|
||||||
std::string thread_name; ///< Name of this thread
|
std::string thread_name; ///< Name of this thread
|
||||||
::profiler::timestamp_t profiled_time; ///< Profiled time of this thread (sum of all children duration)
|
profiler::timestamp_t profiled_time; ///< Profiled time of this thread (sum of all children duration)
|
||||||
::profiler::timestamp_t wait_time; ///< Wait time of this thread (sum of all context switches)
|
profiler::timestamp_t wait_time; ///< Wait time of this thread (sum of all context switches)
|
||||||
::profiler::thread_id_t thread_id; ///< System Id of this thread
|
profiler::thread_id_t thread_id; ///< System Id of this thread
|
||||||
::profiler::block_index_t frames_number; ///< Total frames number (top-level blocks)
|
profiler::block_index_t frames_number; ///< Total frames number (top-level blocks)
|
||||||
::profiler::block_index_t blocks_number; ///< Total blocks number including their children
|
profiler::block_index_t blocks_number; ///< Total blocks number including their children
|
||||||
uint8_t depth; ///< Maximum stack depth (number of levels)
|
uint8_t depth; ///< Maximum stack depth (number of levels)
|
||||||
|
|
||||||
BlocksTreeRoot(const This&) = delete;
|
BlocksTreeRoot(const This&) = delete;
|
||||||
@ -226,10 +230,10 @@ namespace profiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BlocksTreeRoot(This&& that) EASY_NOEXCEPT
|
BlocksTreeRoot(This&& that) EASY_NOEXCEPT
|
||||||
: children(::std::move(that.children))
|
: children(std::move(that.children))
|
||||||
, sync(::std::move(that.sync))
|
, sync(std::move(that.sync))
|
||||||
, events(::std::move(that.events))
|
, events(std::move(that.events))
|
||||||
, thread_name(::std::move(that.thread_name))
|
, thread_name(std::move(that.thread_name))
|
||||||
, profiled_time(that.profiled_time)
|
, profiled_time(that.profiled_time)
|
||||||
, wait_time(that.wait_time)
|
, wait_time(that.wait_time)
|
||||||
, thread_id(that.thread_id)
|
, thread_id(that.thread_id)
|
||||||
@ -241,10 +245,10 @@ namespace profiler {
|
|||||||
|
|
||||||
This& operator = (This&& that) EASY_NOEXCEPT
|
This& operator = (This&& that) EASY_NOEXCEPT
|
||||||
{
|
{
|
||||||
children = ::std::move(that.children);
|
children = std::move(that.children);
|
||||||
sync = ::std::move(that.sync);
|
sync = std::move(that.sync);
|
||||||
events = ::std::move(that.events);
|
events = std::move(that.events);
|
||||||
thread_name = ::std::move(that.thread_name);
|
thread_name = std::move(that.thread_name);
|
||||||
profiled_time = that.profiled_time;
|
profiled_time = that.profiled_time;
|
||||||
wait_time = that.wait_time;
|
wait_time = that.wait_time;
|
||||||
thread_id = that.thread_id;
|
thread_id = that.thread_id;
|
||||||
@ -271,8 +275,9 @@ namespace profiler {
|
|||||||
|
|
||||||
}; // END of class BlocksTreeRoot.
|
}; // END of class BlocksTreeRoot.
|
||||||
|
|
||||||
using blocks_t = ::profiler::BlocksTree::blocks_t;
|
using blocks_t = profiler::BlocksTree::blocks_t;
|
||||||
using thread_blocks_tree_t = ::std::unordered_map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot, ::estd::hash<::profiler::thread_id_t> >;
|
using thread_blocks_tree_t = std::unordered_map<profiler::thread_id_t, profiler::BlocksTreeRoot, ::estd::hash<profiler::thread_id_t> >;
|
||||||
|
using block_getter_fn = std::function<const profiler::BlocksTree&(profiler::block_index_t)>;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -367,59 +372,113 @@ namespace profiler {
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
using descriptors_list_t = ::std::vector<SerializedBlockDescriptor*>;
|
using descriptors_list_t = std::vector<SerializedBlockDescriptor*>;
|
||||||
|
|
||||||
} // END of namespace profiler.
|
} // END of namespace profiler.
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
|
PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
|
||||||
::profiler::SerializedData& serialized_blocks,
|
profiler::SerializedData& serialized_blocks,
|
||||||
::profiler::SerializedData& serialized_descriptors,
|
profiler::SerializedData& serialized_descriptors,
|
||||||
::profiler::descriptors_list_t& descriptors,
|
profiler::descriptors_list_t& descriptors,
|
||||||
::profiler::blocks_t& _blocks,
|
profiler::blocks_t& _blocks,
|
||||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
profiler::thread_blocks_tree_t& threaded_trees,
|
||||||
uint32_t& total_descriptors_number,
|
uint32_t& total_descriptors_number,
|
||||||
uint32_t& version,
|
uint32_t& version,
|
||||||
|
profiler::processid_t& pid,
|
||||||
bool gather_statistics,
|
bool gather_statistics,
|
||||||
::std::stringstream& _log);
|
std::ostream& _log);
|
||||||
|
|
||||||
PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
|
PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& str,
|
||||||
::profiler::SerializedData& serialized_blocks,
|
profiler::SerializedData& serialized_blocks,
|
||||||
::profiler::SerializedData& serialized_descriptors,
|
profiler::SerializedData& serialized_descriptors,
|
||||||
::profiler::descriptors_list_t& descriptors,
|
profiler::descriptors_list_t& descriptors,
|
||||||
::profiler::blocks_t& _blocks,
|
profiler::blocks_t& _blocks,
|
||||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
profiler::thread_blocks_tree_t& threaded_trees,
|
||||||
uint32_t& total_descriptors_number,
|
uint32_t& total_descriptors_number,
|
||||||
uint32_t& version,
|
uint32_t& version,
|
||||||
|
profiler::processid_t& pid,
|
||||||
bool gather_statistics,
|
bool gather_statistics,
|
||||||
::std::stringstream& _log);
|
std::ostream& _log);
|
||||||
|
|
||||||
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
|
PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& str,
|
||||||
::profiler::SerializedData& serialized_descriptors,
|
profiler::SerializedData& serialized_descriptors,
|
||||||
::profiler::descriptors_list_t& descriptors,
|
profiler::descriptors_list_t& descriptors,
|
||||||
::std::stringstream& _log);
|
std::ostream& _log);
|
||||||
|
|
||||||
|
PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
|
||||||
|
const profiler::SerializedData& serialized_descriptors,
|
||||||
|
profiler::block_id_t descriptors_count,
|
||||||
|
const profiler::thread_blocks_tree_t& trees,
|
||||||
|
profiler::block_getter_fn block_getter,
|
||||||
|
profiler::timestamp_t begin_time,
|
||||||
|
profiler::timestamp_t end_time,
|
||||||
|
profiler::processid_t pid,
|
||||||
|
std::ostream& log);
|
||||||
|
|
||||||
|
PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<int>& progress, std::ostream& str,
|
||||||
|
const profiler::SerializedData& serialized_descriptors,
|
||||||
|
profiler::block_id_t descriptors_count,
|
||||||
|
const profiler::thread_blocks_tree_t& trees,
|
||||||
|
profiler::block_getter_fn block_getter,
|
||||||
|
profiler::timestamp_t begin_time,
|
||||||
|
profiler::timestamp_t end_time,
|
||||||
|
profiler::processid_t pid,
|
||||||
|
std::ostream& log);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks,
|
inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler::SerializedData& serialized_blocks,
|
||||||
::profiler::SerializedData& serialized_descriptors,
|
profiler::SerializedData& serialized_descriptors,
|
||||||
::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks,
|
profiler::descriptors_list_t& descriptors, profiler::blocks_t& _blocks,
|
||||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
profiler::thread_blocks_tree_t& threaded_trees,
|
||||||
uint32_t& total_descriptors_number,
|
uint32_t& total_descriptors_number,
|
||||||
uint32_t& version,
|
uint32_t& version,
|
||||||
|
profiler::processid_t& pid,
|
||||||
bool gather_statistics,
|
bool gather_statistics,
|
||||||
::std::stringstream& _log)
|
std::ostream& _log)
|
||||||
{
|
{
|
||||||
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||||
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, total_descriptors_number, version, gather_statistics, _log);
|
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks,
|
||||||
|
threaded_trees, total_descriptors_number, version, pid, gather_statistics, _log);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool readDescriptionsFromStream(::std::stringstream& str,
|
inline profiler::block_index_t writeTreesToFile(const char* filename,
|
||||||
::profiler::SerializedData& serialized_descriptors,
|
const profiler::SerializedData& serialized_descriptors,
|
||||||
::profiler::descriptors_list_t& descriptors,
|
profiler::block_id_t descriptors_count,
|
||||||
::std::stringstream& _log)
|
const profiler::thread_blocks_tree_t& trees,
|
||||||
|
profiler::block_getter_fn block_getter,
|
||||||
|
profiler::timestamp_t begin_time,
|
||||||
|
profiler::timestamp_t end_time,
|
||||||
|
profiler::processid_t pid,
|
||||||
|
std::ostream& log)
|
||||||
{
|
{
|
||||||
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||||
|
return writeTreesToFile(progress, filename, serialized_descriptors, descriptors_count, trees, std::move(block_getter),
|
||||||
|
begin_time, end_time, pid, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline profiler::block_index_t writeTreesToStream(std::ostream& str,
|
||||||
|
const profiler::SerializedData& serialized_descriptors,
|
||||||
|
profiler::block_id_t descriptors_count,
|
||||||
|
const profiler::thread_blocks_tree_t& trees,
|
||||||
|
profiler::block_getter_fn block_getter,
|
||||||
|
profiler::timestamp_t begin_time,
|
||||||
|
profiler::timestamp_t end_time,
|
||||||
|
profiler::processid_t pid,
|
||||||
|
std::ostream& log)
|
||||||
|
{
|
||||||
|
std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||||
|
return writeTreesToStream(progress, str, serialized_descriptors, descriptors_count, trees, std::move(block_getter),
|
||||||
|
begin_time, end_time, pid, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool readDescriptionsFromStream(std::istream& str,
|
||||||
|
profiler::SerializedData& serialized_descriptors,
|
||||||
|
profiler::descriptors_list_t& descriptors,
|
||||||
|
std::ostream& _log)
|
||||||
|
{
|
||||||
|
std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||||
return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log);
|
return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ The Apache License, Version 2.0 (the "License");
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef uint64_t processid_t;
|
using processid_t = uint64_t;
|
||||||
|
|
||||||
class BlockDescriptor;
|
class BlockDescriptor;
|
||||||
|
|
||||||
@ -79,14 +79,15 @@ class ProfileManager
|
|||||||
|
|
||||||
ProfileManager();
|
ProfileManager();
|
||||||
|
|
||||||
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
|
using atomic_timestamp_t = std::atomic<profiler::timestamp_t>;
|
||||||
typedef std::map<profiler::thread_id_t, ThreadStorage> map_of_threads_stacks;
|
using guard_lock_t = profiler::guard_lock<profiler::spin_lock>;
|
||||||
typedef std::vector<BlockDescriptor*> block_descriptors_t;
|
using map_of_threads_stacks = std::map<profiler::thread_id_t, ThreadStorage>;
|
||||||
|
using block_descriptors_t = std::vector<BlockDescriptor*>;
|
||||||
|
|
||||||
#ifdef EASY_PROFILER_HASHED_CSTR_DEFINED
|
#ifdef EASY_PROFILER_HASHED_CSTR_DEFINED
|
||||||
typedef std::unordered_map<profiler::hashed_cstr, profiler::block_id_t> descriptors_map_t;
|
using descriptors_map_t = std::unordered_map<profiler::hashed_cstr, profiler::block_id_t>;
|
||||||
#else
|
#else
|
||||||
typedef std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t> descriptors_map_t;
|
using descriptors_map_t = std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const processid_t m_processId;
|
const processid_t m_processId;
|
||||||
@ -97,9 +98,9 @@ class ProfileManager
|
|||||||
uint64_t m_descriptorsMemorySize;
|
uint64_t m_descriptorsMemorySize;
|
||||||
profiler::timestamp_t m_beginTime;
|
profiler::timestamp_t m_beginTime;
|
||||||
profiler::timestamp_t m_endTime;
|
profiler::timestamp_t m_endTime;
|
||||||
std::atomic<profiler::timestamp_t> m_frameMax;
|
atomic_timestamp_t m_frameMax;
|
||||||
std::atomic<profiler::timestamp_t> m_frameAvg;
|
atomic_timestamp_t m_frameAvg;
|
||||||
std::atomic<profiler::timestamp_t> m_frameCur;
|
atomic_timestamp_t m_frameCur;
|
||||||
profiler::spin_lock m_spin;
|
profiler::spin_lock m_spin;
|
||||||
profiler::spin_lock m_storedSpin;
|
profiler::spin_lock m_storedSpin;
|
||||||
profiler::spin_lock m_dumpSpin;
|
profiler::spin_lock m_dumpSpin;
|
||||||
|
@ -71,9 +71,7 @@
|
|||||||
|
|
||||||
#include "hashed_cstr.h"
|
#include "hashed_cstr.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -81,8 +79,6 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef uint64_t processid_t;
|
|
||||||
|
|
||||||
extern const uint32_t PROFILER_SIGNATURE;
|
extern const uint32_t PROFILER_SIGNATURE;
|
||||||
extern const uint32_t EASY_CURRENT_VERSION;
|
extern const uint32_t EASY_CURRENT_VERSION;
|
||||||
|
|
||||||
@ -123,20 +119,35 @@ const uint64_t TIME_FACTOR = 1000000000ULL;
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct BlocksRange
|
||||||
|
{
|
||||||
|
profiler::block_index_t begin;
|
||||||
|
profiler::block_index_t end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BlocksAndCSwitchesRange
|
||||||
|
{
|
||||||
|
BlocksRange blocks;
|
||||||
|
BlocksRange cswitches;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
inline bool isCompatibleVersion(uint32_t _version)
|
inline bool isCompatibleVersion(uint32_t _version)
|
||||||
{
|
{
|
||||||
return _version >= MIN_COMPATIBLE_VERSION;
|
return _version >= MIN_COMPATIBLE_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void write(::std::stringstream& _stream, const char* _value, size_t _size)
|
template <typename T>
|
||||||
|
inline void write(std::ostream& _stream, const char* _data, T _size)
|
||||||
{
|
{
|
||||||
_stream.write(_value, _size);
|
_stream.write(_data, _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void write(::std::stringstream& _stream, const T& _value)
|
inline void write(std::ostream& _stream, const T& _data)
|
||||||
{
|
{
|
||||||
_stream.write((const char*)&_value, sizeof(T));
|
_stream.write((const char*)&_data, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -189,20 +200,20 @@ namespace profiler {
|
|||||||
|
|
||||||
#ifdef EASY_PROFILER_HASHED_CSTR_DEFINED
|
#ifdef EASY_PROFILER_HASHED_CSTR_DEFINED
|
||||||
|
|
||||||
using StatsMap = ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, ::estd::hash<::profiler::block_id_t> >;
|
using StatsMap = std::unordered_map<profiler::block_id_t, profiler::BlockStatistics*, estd::hash<profiler::block_id_t> >;
|
||||||
|
|
||||||
/** \note It is absolutely safe to use hashed_cstr (which simply stores pointer) because std::unordered_map,
|
/** \note It is absolutely safe to use hashed_cstr (which simply stores pointer) because std::unordered_map,
|
||||||
which uses it as a key, exists only inside fillTreesFromFile function. */
|
which uses it as a key, exists only inside fillTreesFromFile function. */
|
||||||
using IdMap = ::std::unordered_map<::profiler::hashed_cstr, ::profiler::block_id_t>;
|
using IdMap = std::unordered_map<profiler::hashed_cstr, profiler::block_id_t>;
|
||||||
|
|
||||||
using CsStatsMap = ::std::unordered_map<::profiler::hashed_cstr, ::profiler::BlockStatistics*>;
|
using CsStatsMap = std::unordered_map<profiler::hashed_cstr, profiler::BlockStatistics*>;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// TODO: Create optimized version of profiler::hashed_cstr for Linux too.
|
// TODO: Create optimized version of profiler::hashed_cstr for Linux too.
|
||||||
using StatsMap = ::std::unordered_map<::profiler::block_id_t, ::profiler::BlockStatistics*, ::estd::hash<::profiler::block_id_t> >;
|
using StatsMap = std::unordered_map<profiler::block_id_t, profiler::BlockStatistics*, estd::hash<profiler::block_id_t> >;
|
||||||
using IdMap = ::std::unordered_map<::profiler::hashed_stdstring, ::profiler::block_id_t>;
|
using IdMap = std::unordered_map<profiler::hashed_stdstring, profiler::block_id_t>;
|
||||||
using CsStatsMap = ::std::unordered_map<::profiler::hashed_stdstring, ::profiler::BlockStatistics*>;
|
using CsStatsMap = std::unordered_map<profiler::hashed_stdstring, profiler::BlockStatistics*>;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -220,7 +231,7 @@ using CsStatsMap = ::std::unordered_map<::profiler::hashed_stdstring, ::profiler
|
|||||||
automatically receive statistics update.
|
automatically receive statistics update.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
static ::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, const ::profiler::blocks_t& _blocks, bool _calculate_children = true)
|
static profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, const profiler::BlocksTree& _current, profiler::block_index_t _current_index, profiler::block_index_t _parent_index, const profiler::blocks_t& _blocks, bool _calculate_children = true)
|
||||||
{
|
{
|
||||||
auto duration = _current.node->duration();
|
auto duration = _current.node->duration();
|
||||||
//StatsMap::key_type key(_current.node->name());
|
//StatsMap::key_type key(_current.node->name());
|
||||||
@ -262,7 +273,7 @@ static ::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, cons
|
|||||||
|
|
||||||
// This is first time the block appear in the file.
|
// This is first time the block appear in the file.
|
||||||
// Create new statistics.
|
// Create new statistics.
|
||||||
auto stats = new ::profiler::BlockStatistics(duration, _current_index, _parent_index);
|
auto stats = new profiler::BlockStatistics(duration, _current_index, _parent_index);
|
||||||
//_stats_map.emplace(key, stats);
|
//_stats_map.emplace(key, stats);
|
||||||
_stats_map.emplace(_current.node->id(), stats);
|
_stats_map.emplace(_current.node->id(), stats);
|
||||||
|
|
||||||
@ -275,7 +286,7 @@ static ::profiler::BlockStatistics* update_statistics(StatsMap& _stats_map, cons
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ::profiler::BlockStatistics* update_statistics(CsStatsMap& _stats_map, const ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, const ::profiler::blocks_t& _blocks, bool _calculate_children = true)
|
static profiler::BlockStatistics* update_statistics(CsStatsMap& _stats_map, const profiler::BlocksTree& _current, profiler::block_index_t _current_index, profiler::block_index_t _parent_index, const profiler::blocks_t& _blocks, bool _calculate_children = true)
|
||||||
{
|
{
|
||||||
auto duration = _current.node->duration();
|
auto duration = _current.node->duration();
|
||||||
CsStatsMap::key_type key(_current.node->name());
|
CsStatsMap::key_type key(_current.node->name());
|
||||||
@ -316,7 +327,7 @@ static ::profiler::BlockStatistics* update_statistics(CsStatsMap& _stats_map, co
|
|||||||
|
|
||||||
// This is first time the block appear in the file.
|
// This is first time the block appear in the file.
|
||||||
// Create new statistics.
|
// Create new statistics.
|
||||||
auto stats = new ::profiler::BlockStatistics(duration, _current_index, _parent_index);
|
auto stats = new profiler::BlockStatistics(duration, _current_index, _parent_index);
|
||||||
_stats_map.emplace(key, stats);
|
_stats_map.emplace(key, stats);
|
||||||
|
|
||||||
if (_calculate_children)
|
if (_calculate_children)
|
||||||
@ -330,7 +341,7 @@ static ::profiler::BlockStatistics* update_statistics(CsStatsMap& _stats_map, co
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _current, ::profiler::block_index_t _current_index, ::profiler::block_index_t _parent_index, ::profiler::blocks_t& _blocks)
|
static void update_statistics_recursive(StatsMap& _stats_map, profiler::BlocksTree& _current, profiler::block_index_t _current_index, profiler::block_index_t _parent_index, profiler::blocks_t& _blocks)
|
||||||
{
|
{
|
||||||
_current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index, _blocks, false);
|
_current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index, _blocks, false);
|
||||||
for (auto i : _current.children)
|
for (auto i : _current.children)
|
||||||
@ -342,44 +353,9 @@ static void update_statistics_recursive(StatsMap& _stats_map, ::profiler::Blocks
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/*void validate_pointers(::std::atomic<int>& _progress, const char* _oldbase, ::profiler::SerializedData& _serialized_blocks, ::profiler::blocks_t& _blocks, size_t _size)
|
static bool update_progress(std::atomic<int>& progress, int new_value, std::ostream& _log)
|
||||||
{
|
{
|
||||||
if (_oldbase == nullptr)
|
auto oldprogress = progress.exchange(new_value, std::memory_order_release);
|
||||||
{
|
|
||||||
_progress.store(25, ::std::memory_order_release);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < _size; ++i)
|
|
||||||
{
|
|
||||||
auto& tree = _blocks[i];
|
|
||||||
auto dist = ::std::distance(_oldbase, reinterpret_cast<const char*>(tree.node));
|
|
||||||
tree.node = reinterpret_cast<::profiler::SerializedBlock*>(_serialized_blocks.data() + dist);
|
|
||||||
_progress.store(20 + static_cast<int>(5 * i / _size), ::std::memory_order_release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void validate_pointers(::std::atomic<int>& _progress, const char* _oldbase, ::profiler::SerializedData& _serialized_descriptors, ::profiler::descriptors_list_t& _descriptors, size_t _size)
|
|
||||||
{
|
|
||||||
if (_oldbase == nullptr)
|
|
||||||
{
|
|
||||||
_progress.store(5, ::std::memory_order_release);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < _size; ++i)
|
|
||||||
{
|
|
||||||
auto dist = ::std::distance(_oldbase, reinterpret_cast<const char*>(_descriptors[i]));
|
|
||||||
_descriptors[i] = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(_serialized_descriptors.data() + dist);
|
|
||||||
_progress.store(static_cast<int>(5 * i / _size));
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static bool update_progress(::std::atomic<int>& progress, int new_value, ::std::stringstream& _log)
|
|
||||||
{
|
|
||||||
auto oldprogress = progress.exchange(new_value, ::std::memory_order_release);
|
|
||||||
if (oldprogress < 0)
|
if (oldprogress < 0)
|
||||||
{
|
{
|
||||||
_log << "Reading was interrupted";
|
_log << "Reading was interrupted";
|
||||||
@ -389,13 +365,25 @@ static bool update_progress(::std::atomic<int>& progress, int new_value, ::std::
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool update_progress_write(std::atomic<int>& progress, int new_value, std::ostream& _log)
|
||||||
|
{
|
||||||
|
auto oldprogress = progress.exchange(new_value, std::memory_order_release);
|
||||||
|
if (oldprogress < 0)
|
||||||
|
{
|
||||||
|
_log << "Writing was interrupted";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct EasyFileHeader
|
struct EasyFileHeader
|
||||||
{
|
{
|
||||||
uint32_t signature = 0;
|
uint32_t signature = 0;
|
||||||
uint32_t version = 0;
|
uint32_t version = 0;
|
||||||
processid_t pid = 0;
|
profiler::processid_t pid = 0;
|
||||||
int64_t cpu_frequency = 0;
|
int64_t cpu_frequency = 0;
|
||||||
profiler::timestamp_t begin_time = 0;
|
profiler::timestamp_t begin_time = 0;
|
||||||
profiler::timestamp_t end_time = 0;
|
profiler::timestamp_t end_time = 0;
|
||||||
@ -405,7 +393,7 @@ struct EasyFileHeader
|
|||||||
uint32_t total_descriptors_number = 0;
|
uint32_t total_descriptors_number = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool readHeader_v1(EasyFileHeader& _header, ::std::stringstream& inFile, std::stringstream& _log)
|
bool readHeader_v1(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log)
|
||||||
{
|
{
|
||||||
// File header before v2.0.0
|
// File header before v2.0.0
|
||||||
|
|
||||||
@ -419,13 +407,13 @@ bool readHeader_v1(EasyFileHeader& _header, ::std::stringstream& inFile, std::st
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inFile.read((char*)&_header.pid, sizeof(processid_t));
|
inFile.read((char*)&_header.pid, sizeof(decltype(_header.pid)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
|
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
|
||||||
inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_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.end_time, sizeof(profiler::timestamp_t));
|
||||||
|
|
||||||
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t));
|
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t));
|
||||||
if (_header.total_blocks_number == 0)
|
if (_header.total_blocks_number == 0)
|
||||||
@ -458,14 +446,14 @@ bool readHeader_v1(EasyFileHeader& _header, ::std::stringstream& inFile, std::st
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readHeader_v2(EasyFileHeader& _header, ::std::stringstream& inFile, std::stringstream& _log)
|
bool readHeader_v2(EasyFileHeader& _header, std::istream& inFile, std::ostream& _log)
|
||||||
{
|
{
|
||||||
// File header after v2.0.0
|
// File header after v2.0.0
|
||||||
|
|
||||||
inFile.read((char*)&_header.pid, sizeof(processid_t));
|
inFile.read((char*)&_header.pid, sizeof(decltype(_header.pid)));
|
||||||
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
|
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
|
||||||
inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_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.end_time, sizeof(profiler::timestamp_t));
|
||||||
|
|
||||||
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size)));
|
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size)));
|
||||||
if (_header.memory_size == 0)
|
if (_header.memory_size == 0)
|
||||||
@ -502,60 +490,52 @@ bool readHeader_v2(EasyFileHeader& _header, ::std::stringstream& inFile, std::st
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
|
PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
|
||||||
::profiler::SerializedData& serialized_blocks,
|
profiler::SerializedData& serialized_blocks,
|
||||||
::profiler::SerializedData& serialized_descriptors,
|
profiler::SerializedData& serialized_descriptors,
|
||||||
::profiler::descriptors_list_t& descriptors,
|
profiler::descriptors_list_t& descriptors,
|
||||||
::profiler::blocks_t& blocks,
|
profiler::blocks_t& blocks,
|
||||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
profiler::thread_blocks_tree_t& threaded_trees,
|
||||||
uint32_t& total_descriptors_number,
|
uint32_t& total_descriptors_number,
|
||||||
uint32_t& version,
|
uint32_t& version,
|
||||||
|
profiler::processid_t& pid,
|
||||||
bool gather_statistics,
|
bool gather_statistics,
|
||||||
::std::stringstream& _log)
|
std::ostream& _log)
|
||||||
{
|
{
|
||||||
if (!update_progress(progress, 0, _log))
|
if (!update_progress(progress, 0, _log))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
::std::ifstream inFile(filename, ::std::fstream::binary);
|
std::ifstream inFile(filename, std::fstream::binary);
|
||||||
if (!inFile.is_open())
|
if (!inFile.is_open())
|
||||||
{
|
{
|
||||||
_log << "Can not open file " << filename;
|
_log << "Can not open file " << filename;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
::std::stringstream str;
|
|
||||||
|
|
||||||
// Replace str buffer to inFile buffer to avoid redundant copying
|
|
||||||
typedef ::std::basic_iostream<::std::stringstream::char_type, ::std::stringstream::traits_type> stringstream_parent;
|
|
||||||
stringstream_parent& s = str;
|
|
||||||
auto oldbuf = s.rdbuf(inFile.rdbuf());
|
|
||||||
|
|
||||||
// Read data from file
|
// Read data from file
|
||||||
auto result = fillTreesFromStream(progress, str, serialized_blocks, serialized_descriptors, descriptors, blocks,
|
auto result = fillTreesFromStream(progress, inFile, serialized_blocks, serialized_descriptors, descriptors, blocks,
|
||||||
threaded_trees, total_descriptors_number, version, gather_statistics, _log);
|
threaded_trees, total_descriptors_number, version, pid, gather_statistics, _log);
|
||||||
|
|
||||||
// Restore old str buffer to avoid possible second memory free on stringstream destructor
|
|
||||||
s.rdbuf(oldbuf);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic<int>& progress, ::std::stringstream& inFile,
|
PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& inFile,
|
||||||
::profiler::SerializedData& serialized_blocks,
|
profiler::SerializedData& serialized_blocks,
|
||||||
::profiler::SerializedData& serialized_descriptors,
|
profiler::SerializedData& serialized_descriptors,
|
||||||
::profiler::descriptors_list_t& descriptors,
|
profiler::descriptors_list_t& descriptors,
|
||||||
::profiler::blocks_t& blocks,
|
profiler::blocks_t& blocks,
|
||||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
profiler::thread_blocks_tree_t& threaded_trees,
|
||||||
uint32_t& total_descriptors_number,
|
uint32_t& total_descriptors_number,
|
||||||
uint32_t& version,
|
uint32_t& version,
|
||||||
|
profiler::processid_t& pid,
|
||||||
bool gather_statistics,
|
bool gather_statistics,
|
||||||
::std::stringstream& _log)
|
std::ostream& _log)
|
||||||
{
|
{
|
||||||
EASY_FUNCTION(::profiler::colors::Cyan);
|
EASY_FUNCTION(profiler::colors::Cyan);
|
||||||
|
|
||||||
if (!update_progress(progress, 0, _log))
|
if (!update_progress(progress, 0, _log))
|
||||||
{
|
{
|
||||||
@ -593,6 +573,8 @@ extern "C" {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid = header.pid;
|
||||||
|
|
||||||
const uint64_t cpu_frequency = header.cpu_frequency;
|
const uint64_t cpu_frequency = header.cpu_frequency;
|
||||||
const double conversion_factor = (cpu_frequency != 0 ? static_cast<double>(TIME_FACTOR) / static_cast<double>(cpu_frequency) : 1.);
|
const double conversion_factor = (cpu_frequency != 0 ? static_cast<double>(TIME_FACTOR) / static_cast<double>(cpu_frequency) : 1.);
|
||||||
|
|
||||||
@ -633,7 +615,7 @@ extern "C" {
|
|||||||
|
|
||||||
char* data = serialized_descriptors[i];
|
char* data = serialized_descriptors[i];
|
||||||
inFile.read(data, sz);
|
inFile.read(data, sz);
|
||||||
auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data);
|
auto descriptor = reinterpret_cast<profiler::SerializedBlockDescriptor*>(data);
|
||||||
descriptors.push_back(descriptor);
|
descriptors.push_back(descriptor);
|
||||||
|
|
||||||
i += sz;
|
i += sz;
|
||||||
@ -643,7 +625,7 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using PerThreadStats = ::std::unordered_map<::profiler::thread_id_t, StatsMap, ::estd::hash<::profiler::thread_id_t> >;
|
using PerThreadStats = std::unordered_map<profiler::thread_id_t, StatsMap, estd::hash<profiler::thread_id_t> >;
|
||||||
PerThreadStats parent_statistics, frame_statistics;
|
PerThreadStats parent_statistics, frame_statistics;
|
||||||
IdMap identification_table;
|
IdMap identification_table;
|
||||||
|
|
||||||
@ -654,16 +636,16 @@ extern "C" {
|
|||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
uint32_t read_number = 0;
|
uint32_t read_number = 0;
|
||||||
::profiler::block_index_t blocks_counter = 0;
|
profiler::block_index_t blocks_counter = 0;
|
||||||
::std::vector<char> name;
|
std::vector<char> name;
|
||||||
|
|
||||||
const size_t thread_id_t_size = version < EASY_V_130 ? sizeof(uint32_t) : sizeof(::profiler::thread_id_t);
|
const size_t thread_id_t_size = version < EASY_V_130 ? sizeof(uint32_t) : sizeof(profiler::thread_id_t);
|
||||||
|
|
||||||
while (!inFile.eof())
|
while (!inFile.eof())
|
||||||
{
|
{
|
||||||
EASY_BLOCK("Read thread data", ::profiler::colors::DarkGreen);
|
EASY_BLOCK("Read thread data", profiler::colors::DarkGreen);
|
||||||
|
|
||||||
::profiler::thread_id_t thread_id = 0;
|
profiler::thread_id_t thread_id = 0;
|
||||||
inFile.read((char*)&thread_id, thread_id_t_size);
|
inFile.read((char*)&thread_id, thread_id_t_size);
|
||||||
if (inFile.eof())
|
if (inFile.eof())
|
||||||
break;
|
break;
|
||||||
@ -686,7 +668,7 @@ extern "C" {
|
|||||||
auto threshold = read_number + blocks_number_in_thread;
|
auto threshold = read_number + blocks_number_in_thread;
|
||||||
while (!inFile.eof() && read_number < threshold)
|
while (!inFile.eof() && read_number < threshold)
|
||||||
{
|
{
|
||||||
EASY_BLOCK("Read context switch", ::profiler::colors::Green);
|
EASY_BLOCK("Read context switch", profiler::colors::Green);
|
||||||
|
|
||||||
++read_number;
|
++read_number;
|
||||||
|
|
||||||
@ -701,8 +683,8 @@ extern "C" {
|
|||||||
char* data = serialized_blocks[i];
|
char* data = serialized_blocks[i];
|
||||||
inFile.read(data, sz);
|
inFile.read(data, sz);
|
||||||
i += sz;
|
i += sz;
|
||||||
auto baseData = reinterpret_cast<::profiler::SerializedCSwitch*>(data);
|
auto baseData = reinterpret_cast<profiler::SerializedCSwitch*>(data);
|
||||||
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
|
auto t_begin = reinterpret_cast<profiler::timestamp_t*>(data);
|
||||||
auto t_end = t_begin + 1;
|
auto t_end = t_begin + 1;
|
||||||
|
|
||||||
if (cpu_frequency != 0)
|
if (cpu_frequency != 0)
|
||||||
@ -717,7 +699,7 @@ extern "C" {
|
|||||||
*t_begin = begin_time;
|
*t_begin = begin_time;
|
||||||
|
|
||||||
blocks.emplace_back();
|
blocks.emplace_back();
|
||||||
::profiler::BlocksTree& tree = blocks.back();
|
profiler::BlocksTree& tree = blocks.back();
|
||||||
tree.cs = baseData;
|
tree.cs = baseData;
|
||||||
const auto block_index = blocks_counter++;
|
const auto block_index = blocks_counter++;
|
||||||
|
|
||||||
@ -726,7 +708,7 @@ extern "C" {
|
|||||||
|
|
||||||
if (gather_statistics)
|
if (gather_statistics)
|
||||||
{
|
{
|
||||||
EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral);
|
EASY_BLOCK("Gather per thread statistics", profiler::colors::Coral);
|
||||||
tree.per_thread_stats = update_statistics(per_thread_statistics_cs, tree, block_index, ~0U, blocks);//, thread_id, blocks);
|
tree.per_thread_stats = update_statistics(per_thread_statistics_cs, tree, block_index, ~0U, blocks);//, thread_id, blocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -747,7 +729,7 @@ extern "C" {
|
|||||||
threshold = read_number + blocks_number_in_thread;
|
threshold = read_number + blocks_number_in_thread;
|
||||||
while (!inFile.eof() && read_number < threshold)
|
while (!inFile.eof() && read_number < threshold)
|
||||||
{
|
{
|
||||||
EASY_BLOCK("Read block", ::profiler::colors::Green);
|
EASY_BLOCK("Read block", profiler::colors::Green);
|
||||||
|
|
||||||
++read_number;
|
++read_number;
|
||||||
|
|
||||||
@ -762,7 +744,7 @@ extern "C" {
|
|||||||
char* data = serialized_blocks[i];
|
char* data = serialized_blocks[i];
|
||||||
inFile.read(data, sz);
|
inFile.read(data, sz);
|
||||||
i += sz;
|
i += sz;
|
||||||
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
|
auto baseData = reinterpret_cast<profiler::SerializedBlock*>(data);
|
||||||
if (baseData->id() >= total_descriptors_number)
|
if (baseData->id() >= total_descriptors_number)
|
||||||
{
|
{
|
||||||
_log << "Bad block id == " << baseData->id();
|
_log << "Bad block id == " << baseData->id();
|
||||||
@ -776,7 +758,7 @@ extern "C" {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
|
auto t_begin = reinterpret_cast<profiler::timestamp_t*>(data);
|
||||||
auto t_end = t_begin + 1;
|
auto t_end = t_begin + 1;
|
||||||
|
|
||||||
if (cpu_frequency != 0)
|
if (cpu_frequency != 0)
|
||||||
@ -791,7 +773,7 @@ extern "C" {
|
|||||||
*t_begin = begin_time;
|
*t_begin = begin_time;
|
||||||
|
|
||||||
blocks.emplace_back();
|
blocks.emplace_back();
|
||||||
::profiler::BlocksTree& tree = blocks.back();
|
profiler::BlocksTree& tree = blocks.back();
|
||||||
tree.node = baseData;
|
tree.node = baseData;
|
||||||
const auto block_index = blocks_counter++;
|
const auto block_index = blocks_counter++;
|
||||||
|
|
||||||
@ -810,7 +792,7 @@ extern "C" {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// There were no blocks with such name, generate new id and save it in the table for further usage.
|
// There were no blocks with such name, generate new id and save it in the table for further usage.
|
||||||
auto id = static_cast<::profiler::block_id_t>(descriptors.size());
|
auto id = static_cast<profiler::block_id_t>(descriptors.size());
|
||||||
identification_table.emplace(key, id);
|
identification_table.emplace(key, id);
|
||||||
if (descriptors.capacity() == descriptors.size())
|
if (descriptors.capacity() == descriptors.size())
|
||||||
descriptors.reserve((descriptors.size() * 3) >> 1);
|
descriptors.reserve((descriptors.size() * 3) >> 1);
|
||||||
@ -826,20 +808,20 @@ extern "C" {
|
|||||||
auto mt0 = tree.node->begin();
|
auto mt0 = tree.node->begin();
|
||||||
if (mt0 < t1)//parent - starts earlier than last ends
|
if (mt0 < t1)//parent - starts earlier than last ends
|
||||||
{
|
{
|
||||||
//auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree);
|
//auto lower = std::lower_bound(root.children.begin(), root.children.end(), tree);
|
||||||
/**/
|
/**/
|
||||||
EASY_BLOCK("Find children", ::profiler::colors::Blue);
|
EASY_BLOCK("Find children", profiler::colors::Blue);
|
||||||
auto rlower1 = ++root.children.rbegin();
|
auto rlower1 = ++root.children.rbegin();
|
||||||
for (; rlower1 != root.children.rend() && mt0 <= blocks[*rlower1].node->begin(); ++rlower1);
|
for (; rlower1 != root.children.rend() && mt0 <= blocks[*rlower1].node->begin(); ++rlower1);
|
||||||
auto lower = rlower1.base();
|
auto lower = rlower1.base();
|
||||||
::std::move(lower, root.children.end(), ::std::back_inserter(tree.children));
|
std::move(lower, root.children.end(), std::back_inserter(tree.children));
|
||||||
|
|
||||||
root.children.erase(lower, root.children.end());
|
root.children.erase(lower, root.children.end());
|
||||||
EASY_END_BLOCK;
|
EASY_END_BLOCK;
|
||||||
|
|
||||||
if (gather_statistics)
|
if (gather_statistics)
|
||||||
{
|
{
|
||||||
EASY_BLOCK("Gather statistic within parent", ::profiler::colors::Magenta);
|
EASY_BLOCK("Gather statistic within parent", profiler::colors::Magenta);
|
||||||
auto& per_parent_statistics = parent_statistics[thread_id];
|
auto& per_parent_statistics = parent_statistics[thread_id];
|
||||||
per_parent_statistics.clear();
|
per_parent_statistics.clear();
|
||||||
|
|
||||||
@ -883,14 +865,14 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
++root.blocks_number;
|
++root.blocks_number;
|
||||||
root.children.emplace_back(block_index);// ::std::move(tree));
|
root.children.emplace_back(block_index);// std::move(tree));
|
||||||
if (desc->type() != ::profiler::BlockType::Block)
|
if (desc->type() != profiler::BlockType::Block)
|
||||||
root.events.emplace_back(block_index);
|
root.events.emplace_back(block_index);
|
||||||
|
|
||||||
|
|
||||||
if (gather_statistics)
|
if (gather_statistics)
|
||||||
{
|
{
|
||||||
EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral);
|
EASY_BLOCK("Gather per thread statistics", profiler::colors::Coral);
|
||||||
tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, ~0U, blocks);//, thread_id, blocks);
|
tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, ~0U, blocks);//, thread_id, blocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -907,10 +889,10 @@ extern "C" {
|
|||||||
return 0; // Loading interrupted
|
return 0; // Loading interrupted
|
||||||
}
|
}
|
||||||
|
|
||||||
EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple);
|
EASY_BLOCK("Gather statistics for roots", profiler::colors::Purple);
|
||||||
if (gather_statistics)
|
if (gather_statistics)
|
||||||
{
|
{
|
||||||
::std::vector<::std::thread> statistics_threads;
|
std::vector<std::thread> statistics_threads;
|
||||||
statistics_threads.reserve(threaded_trees.size());
|
statistics_threads.reserve(threaded_trees.size());
|
||||||
|
|
||||||
for (auto& it : threaded_trees)
|
for (auto& it : threaded_trees)
|
||||||
@ -923,19 +905,19 @@ extern "C" {
|
|||||||
auto& per_parent_statistics = parent_statistics[it.first];
|
auto& per_parent_statistics = parent_statistics[it.first];
|
||||||
per_parent_statistics.clear();
|
per_parent_statistics.clear();
|
||||||
|
|
||||||
statistics_threads.emplace_back(::std::thread([&] (::profiler::BlocksTreeRoot& _root)
|
statistics_threads.emplace_back(std::thread([&] (profiler::BlocksTreeRoot& _root)
|
||||||
{
|
{
|
||||||
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
|
//std::sort(root.sync.begin(), root.sync.end(), [&blocks](profiler::block_index_t left, profiler::block_index_t right)
|
||||||
//{
|
//{
|
||||||
// return blocks[left].node->begin() < blocks[right].node->begin();
|
// return blocks[left].node->begin() < blocks[right].node->begin();
|
||||||
//});
|
//});
|
||||||
|
|
||||||
::profiler::block_index_t cs_index = 0;
|
profiler::block_index_t cs_index = 0;
|
||||||
for (auto child_index : _root.children)
|
for (auto child_index : _root.children)
|
||||||
{
|
{
|
||||||
auto& frame = blocks[child_index];
|
auto& frame = blocks[child_index];
|
||||||
|
|
||||||
if (descriptors[frame.node->id()]->type() == ::profiler::BlockType::Block)
|
if (descriptors[frame.node->id()]->type() == profiler::BlockType::Block)
|
||||||
++_root.frames_number;
|
++_root.frames_number;
|
||||||
|
|
||||||
frame.per_parent_stats = update_statistics(per_parent_statistics, frame, child_index, ~0U, blocks);//, root.thread_id, blocks);
|
frame.per_parent_stats = update_statistics(per_parent_statistics, frame, child_index, ~0U, blocks);//, root.thread_id, blocks);
|
||||||
@ -966,14 +948,14 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
++_root.depth;
|
++_root.depth;
|
||||||
}, ::std::ref(root)));
|
}, std::ref(root)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int j = 0, n = static_cast<int>(statistics_threads.size());
|
int j = 0, n = static_cast<int>(statistics_threads.size());
|
||||||
for (auto& thread : statistics_threads)
|
for (auto& thread : statistics_threads)
|
||||||
{
|
{
|
||||||
thread.join();
|
thread.join();
|
||||||
progress.store(90 + (10 * ++j) / n, ::std::memory_order_release);
|
progress.store(90 + (10 * ++j) / n, std::memory_order_release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -984,7 +966,7 @@ extern "C" {
|
|||||||
auto& root = it.second;
|
auto& root = it.second;
|
||||||
root.thread_id = it.first;
|
root.thread_id = it.first;
|
||||||
|
|
||||||
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
|
//std::sort(root.sync.begin(), root.sync.end(), [&blocks](profiler::block_index_t left, profiler::block_index_t right)
|
||||||
//{
|
//{
|
||||||
// return blocks[left].node->begin() < blocks[right].node->begin();
|
// return blocks[left].node->begin() < blocks[right].node->begin();
|
||||||
//});
|
//});
|
||||||
@ -994,7 +976,7 @@ extern "C" {
|
|||||||
{
|
{
|
||||||
auto& frame = blocks[child_block_index];
|
auto& frame = blocks[child_block_index];
|
||||||
|
|
||||||
if (descriptors[frame.node->id()]->type() == ::profiler::BlockType::Block)
|
if (descriptors[frame.node->id()]->type() == profiler::BlockType::Block)
|
||||||
++root.frames_number;
|
++root.frames_number;
|
||||||
|
|
||||||
if (root.depth < frame.depth)
|
if (root.depth < frame.depth)
|
||||||
@ -1005,23 +987,23 @@ extern "C" {
|
|||||||
|
|
||||||
++root.depth;
|
++root.depth;
|
||||||
|
|
||||||
progress.store(90 + (10 * ++j) / n, ::std::memory_order_release);
|
progress.store(90 + (10 * ++j) / n, std::memory_order_release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors
|
// No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors
|
||||||
|
|
||||||
progress.store(100, ::std::memory_order_release);
|
progress.store(100, std::memory_order_release);
|
||||||
return blocks_counter;
|
return blocks_counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& inFile,
|
PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& inFile,
|
||||||
::profiler::SerializedData& serialized_descriptors,
|
profiler::SerializedData& serialized_descriptors,
|
||||||
::profiler::descriptors_list_t& descriptors,
|
profiler::descriptors_list_t& descriptors,
|
||||||
::std::stringstream& _log)
|
std::ostream& _log)
|
||||||
{
|
{
|
||||||
EASY_FUNCTION(::profiler::colors::Cyan);
|
EASY_FUNCTION(profiler::colors::Cyan);
|
||||||
|
|
||||||
progress.store(0);
|
progress.store(0);
|
||||||
|
|
||||||
@ -1080,7 +1062,7 @@ extern "C" {
|
|||||||
|
|
||||||
char* data = serialized_descriptors[i];
|
char* data = serialized_descriptors[i];
|
||||||
inFile.read(data, sz);
|
inFile.read(data, sz);
|
||||||
auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data);
|
auto descriptor = reinterpret_cast<profiler::SerializedBlockDescriptor*>(data);
|
||||||
descriptors.push_back(descriptor);
|
descriptors.push_back(descriptor);
|
||||||
|
|
||||||
i += sz;
|
i += sz;
|
||||||
@ -1094,6 +1076,114 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
|
||||||
|
const profiler::SerializedData& serialized_descriptors,
|
||||||
|
profiler::block_id_t descriptors_count,
|
||||||
|
const profiler::thread_blocks_tree_t& trees,
|
||||||
|
profiler::block_getter_fn block_getter,
|
||||||
|
profiler::timestamp_t begin_time,
|
||||||
|
profiler::timestamp_t end_time,
|
||||||
|
profiler::processid_t pid,
|
||||||
|
std::ostream& log)
|
||||||
|
{
|
||||||
|
if (!update_progress_write(progress, 0, log))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream outFile(filename, std::fstream::binary);
|
||||||
|
if (!outFile.is_open())
|
||||||
|
{
|
||||||
|
log << "Can not open file " << filename;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data to file
|
||||||
|
auto result = writeTreesToStream(progress, outFile, serialized_descriptors, descriptors_count, trees, std::move(block_getter),
|
||||||
|
begin_time, end_time, pid, log);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<int>& progress, std::ostream& str,
|
||||||
|
const profiler::SerializedData& serialized_descriptors,
|
||||||
|
profiler::block_id_t descriptors_count,
|
||||||
|
const profiler::thread_blocks_tree_t& trees,
|
||||||
|
profiler::block_getter_fn block_getter,
|
||||||
|
profiler::timestamp_t begin_time,
|
||||||
|
profiler::timestamp_t end_time,
|
||||||
|
profiler::processid_t pid,
|
||||||
|
std::ostream& log)
|
||||||
|
{
|
||||||
|
if (trees.empty() || serialized_descriptors.empty() || descriptors_count == 0)
|
||||||
|
{
|
||||||
|
log << "Nothing to save";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
using ranges_t = std::unordered_map<profiler::thread_id_t, BlocksAndCSwitchesRange, estd::hash<profiler::thread_id_t> >;
|
||||||
|
ranges_t block_ranges;
|
||||||
|
|
||||||
|
for (const auto& kv : trees)
|
||||||
|
{
|
||||||
|
const auto id = kv.first;
|
||||||
|
const auto& tree = kv.second;
|
||||||
|
|
||||||
|
const auto children_size = tree.children.size();
|
||||||
|
const auto csitches_size = tree.sync.size();
|
||||||
|
BlocksAndCSwitchesRange ranges {{children_size, children_size}, {csitches_size, csitches_size}};
|
||||||
|
|
||||||
|
auto first_it = std::lower_bound(tree.children.begin(), tree.children.end(), begin_time, [&](profiler::block_index_t element, profiler::timestamp_t value)
|
||||||
|
{
|
||||||
|
block_getter(element).node->begin() < value;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (first_it != tree.children.end())
|
||||||
|
{
|
||||||
|
auto last_it = std::lower_bound(tree.children.begin(), tree.children.end(), end_time, [&](profiler::block_index_t element, profiler::timestamp_t value)
|
||||||
|
{
|
||||||
|
block_getter(element).node->end() < value;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (last_it != tree.children.end())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block_ranges[id] = ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
write(str, PROFILER_SIGNATURE);
|
||||||
|
write(str, EASY_CURRENT_VERSION);
|
||||||
|
write(str, pid);
|
||||||
|
|
||||||
|
// write 0 because we do not need to oncvert time from ticks to nanoseconds (it's already converted here)
|
||||||
|
write<int64_t>(str, 0LL); // CPU frequency
|
||||||
|
|
||||||
|
write(str, begin_time);
|
||||||
|
write(str, end_time);
|
||||||
|
|
||||||
|
uint64_t usedMemorySize = 0; // memory size used by profiler blocks
|
||||||
|
profiler::block_index_t blocksCount = 0;
|
||||||
|
|
||||||
|
write(str, usedMemorySize);
|
||||||
|
write(str, serialized_descriptors.size());
|
||||||
|
write(str, blocksCount);
|
||||||
|
write(str, descriptors_count);
|
||||||
|
|
||||||
|
log << "Not implemented";
|
||||||
|
progress.store(100, std::memory_order_release);
|
||||||
|
return blocksCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,6 +614,31 @@ const BlocksGraphicsView::Items &BlocksGraphicsView::getItems() const
|
|||||||
return m_items;
|
return m_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BlocksGraphicsView::getSelectionRegionForSaving(profiler::timestamp_t& _beginTime, profiler::timestamp_t& _endTime) const
|
||||||
|
{
|
||||||
|
if (m_selectedBlocks.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_beginTime = ~0ULL;
|
||||||
|
_endTime = 0;
|
||||||
|
|
||||||
|
for (const auto& selection : m_selectedBlocks)
|
||||||
|
{
|
||||||
|
const auto& tree = easyBlocksTree(selection.tree);
|
||||||
|
_beginTime = std::min(_beginTime, tree.node->begin());
|
||||||
|
_endTime = std::max(_endTime, tree.node->end());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_beginTime > 10)
|
||||||
|
_beginTime -= 10;
|
||||||
|
else
|
||||||
|
_beginTime = 0;
|
||||||
|
|
||||||
|
_endTime += 10;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
qreal BlocksGraphicsView::setTree(BlocksGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, uint32_t& _maxDepthChild, qreal _y, short _level)
|
qreal BlocksGraphicsView::setTree(BlocksGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, uint32_t& _maxDepthChild, qreal _y, short _level)
|
||||||
{
|
{
|
||||||
if (_children.empty())
|
if (_children.empty())
|
||||||
|
@ -190,6 +190,8 @@ public:
|
|||||||
|
|
||||||
const Items& getItems() const;
|
const Items& getItems() const;
|
||||||
|
|
||||||
|
bool getSelectionRegionForSaving(profiler::timestamp_t& _beginTime, profiler::timestamp_t& _endTime) const;
|
||||||
|
|
||||||
void inspectCurrentView(bool _strict) {
|
void inspectCurrentView(bool _strict) {
|
||||||
onInspectCurrentView(_strict);
|
onInspectCurrentView(_strict);
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,6 @@ struct EasyBlock Q_DECL_FINAL
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
EasyBlock(const EasyBlock&) = delete;
|
EasyBlock(const EasyBlock&) = delete;
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
@ -79,6 +79,7 @@ namespace profiler_gui {
|
|||||||
|
|
||||||
Globals::Globals()
|
Globals::Globals()
|
||||||
: theme("default")
|
: theme("default")
|
||||||
|
, pid(0)
|
||||||
, begin_time(0)
|
, begin_time(0)
|
||||||
, selected_thread(0U)
|
, selected_thread(0U)
|
||||||
, selected_block(::profiler_gui::numeric_max<decltype(selected_block)>())
|
, selected_block(::profiler_gui::numeric_max<decltype(selected_block)>())
|
||||||
|
@ -204,6 +204,7 @@ namespace profiler_gui {
|
|||||||
|
|
||||||
SceneData scene; ///< Diagram scene sizes and visible area position
|
SceneData scene; ///< Diagram scene sizes and visible area position
|
||||||
SizeGuide size; ///< Various widgets and font sizes adapted to current device pixel ratio
|
SizeGuide size; ///< Various widgets and font sizes adapted to current device pixel ratio
|
||||||
|
::profiler::processid_t pid; ///< Profiled process ID
|
||||||
::profiler::timestamp_t begin_time; ///< Timestamp of the most left diagram scene point (x=0)
|
::profiler::timestamp_t begin_time; ///< Timestamp of the most left diagram scene point (x=0)
|
||||||
::profiler::thread_id_t selected_thread; ///< Current selected thread id
|
::profiler::thread_id_t selected_thread; ///< Current selected thread id
|
||||||
::profiler::block_index_t selected_block; ///< Current selected profiler block index
|
::profiler::block_index_t selected_block; ///< Current selected profiler block index
|
||||||
@ -263,6 +264,10 @@ inline profiler::SerializedBlockDescriptor& easyDescriptor(profiler::block_id_t
|
|||||||
return *EASY_GLOBALS.descriptors[i];
|
return *EASY_GLOBALS.descriptors[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline profiler::SerializedBlockDescriptor& easyDescriptor(const profiler::BlocksTree& _block) {
|
||||||
|
return easyDescriptor(_block.node->id());
|
||||||
|
}
|
||||||
|
|
||||||
EASY_FORCE_INLINE const profiler::BlocksTree& easyBlocksTree(profiler::block_index_t i) {
|
EASY_FORCE_INLINE const profiler::BlocksTree& easyBlocksTree(profiler::block_index_t i) {
|
||||||
return easyBlock(i).tree;
|
return easyBlock(i).tree;
|
||||||
}
|
}
|
||||||
|
@ -250,7 +250,7 @@ void MainWindow::configureSizes()
|
|||||||
w.hide();
|
w.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhost"), m_lastPort(::profiler::DEFAULT_PORT)
|
MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhost"), m_lastPort(profiler::DEFAULT_PORT)
|
||||||
{
|
{
|
||||||
{ QIcon icon(":/images/logo"); if (!icon.isNull()) QApplication::setWindowIcon(icon); }
|
{ QIcon icon(":/images/logo"); if (!icon.isNull()) QApplication::setWindowIcon(icon); }
|
||||||
|
|
||||||
@ -378,6 +378,10 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
|
|||||||
static_cast<DiagramWidget*>(m_graphicsView->widget())->view()->inspectCurrentView(true);
|
static_cast<DiagramWidget*>(m_graphicsView->widget())->view()->inspectCurrentView(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
action = toolbar->addAction(QIcon(imagePath("crop")), "Crop and save");
|
||||||
|
action->setToolTip("Crop and save selected area\nas separate .prof file.");
|
||||||
|
connect(action, &QAction::triggered, this, &This::onCropAndSaveClicked);
|
||||||
|
|
||||||
toolbar->addSeparator();
|
toolbar->addSeparator();
|
||||||
auto menu = new QMenu("Settings", this);
|
auto menu = new QMenu("Settings", this);
|
||||||
menu->setToolTipsVisible(true);
|
menu->setToolTipsVisible(true);
|
||||||
@ -547,8 +551,8 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
|
|||||||
action = new QAction("Chrono text at top", actionGroup);
|
action = new QAction("Chrono text at top", actionGroup);
|
||||||
action->setToolTip("Draw duration of selected interval\nat the top of the screen.");
|
action->setToolTip("Draw duration of selected interval\nat the top of the screen.");
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setData(static_cast<int>(::profiler_gui::ChronoTextPosition_Top));
|
action->setData(static_cast<int>(profiler_gui::ChronoTextPosition_Top));
|
||||||
if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Top)
|
if (EASY_GLOBALS.chrono_text_position == profiler_gui::ChronoTextPosition_Top)
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
submenu->addAction(action);
|
submenu->addAction(action);
|
||||||
connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged);
|
connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged);
|
||||||
@ -556,8 +560,8 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
|
|||||||
action = new QAction("Chrono text at center", actionGroup);
|
action = new QAction("Chrono text at center", actionGroup);
|
||||||
action->setToolTip("Draw duration of selected interval\nat the center of the screen.");
|
action->setToolTip("Draw duration of selected interval\nat the center of the screen.");
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setData(static_cast<int>(::profiler_gui::ChronoTextPosition_Center));
|
action->setData(static_cast<int>(profiler_gui::ChronoTextPosition_Center));
|
||||||
if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Center)
|
if (EASY_GLOBALS.chrono_text_position == profiler_gui::ChronoTextPosition_Center)
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
submenu->addAction(action);
|
submenu->addAction(action);
|
||||||
connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged);
|
connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged);
|
||||||
@ -565,8 +569,8 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
|
|||||||
action = new QAction("Chrono text at bottom", actionGroup);
|
action = new QAction("Chrono text at bottom", actionGroup);
|
||||||
action->setToolTip("Draw duration of selected interval\nat the bottom of the screen.");
|
action->setToolTip("Draw duration of selected interval\nat the bottom of the screen.");
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setData(static_cast<int>(::profiler_gui::ChronoTextPosition_Bottom));
|
action->setData(static_cast<int>(profiler_gui::ChronoTextPosition_Bottom));
|
||||||
if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Bottom)
|
if (EASY_GLOBALS.chrono_text_position == profiler_gui::ChronoTextPosition_Bottom)
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
submenu->addAction(action);
|
submenu->addAction(action);
|
||||||
connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged);
|
connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged);
|
||||||
@ -674,32 +678,32 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
|
|||||||
actionGroup->setExclusive(true);
|
actionGroup->setExclusive(true);
|
||||||
action = new QAction("Auto", actionGroup);
|
action = new QAction("Auto", actionGroup);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setData(static_cast<int>(::profiler_gui::TimeUnits_auto));
|
action->setData(static_cast<int>(profiler_gui::TimeUnits_auto));
|
||||||
if (EASY_GLOBALS.time_units == ::profiler_gui::TimeUnits_auto)
|
if (EASY_GLOBALS.time_units == profiler_gui::TimeUnits_auto)
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
submenu->addAction(action);
|
submenu->addAction(action);
|
||||||
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
|
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
|
||||||
|
|
||||||
action = new QAction("Milliseconds", actionGroup);
|
action = new QAction("Milliseconds", actionGroup);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setData(static_cast<int>(::profiler_gui::TimeUnits_ms));
|
action->setData(static_cast<int>(profiler_gui::TimeUnits_ms));
|
||||||
if (EASY_GLOBALS.time_units == ::profiler_gui::TimeUnits_ms)
|
if (EASY_GLOBALS.time_units == profiler_gui::TimeUnits_ms)
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
submenu->addAction(action);
|
submenu->addAction(action);
|
||||||
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
|
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
|
||||||
|
|
||||||
action = new QAction("Microseconds", actionGroup);
|
action = new QAction("Microseconds", actionGroup);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setData(static_cast<int>(::profiler_gui::TimeUnits_us));
|
action->setData(static_cast<int>(profiler_gui::TimeUnits_us));
|
||||||
if (EASY_GLOBALS.time_units == ::profiler_gui::TimeUnits_us)
|
if (EASY_GLOBALS.time_units == profiler_gui::TimeUnits_us)
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
submenu->addAction(action);
|
submenu->addAction(action);
|
||||||
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
|
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
|
||||||
|
|
||||||
action = new QAction("Nanoseconds", actionGroup);
|
action = new QAction("Nanoseconds", actionGroup);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setData(static_cast<int>(::profiler_gui::TimeUnits_ns));
|
action->setData(static_cast<int>(profiler_gui::TimeUnits_ns));
|
||||||
if (EASY_GLOBALS.time_units == ::profiler_gui::TimeUnits_ns)
|
if (EASY_GLOBALS.time_units == profiler_gui::TimeUnits_ns)
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
submenu->addAction(action);
|
submenu->addAction(action);
|
||||||
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
|
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
|
||||||
@ -789,13 +793,14 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
|
|||||||
m_frameTimeEdit->setValidator(val);
|
m_frameTimeEdit->setValidator(val);
|
||||||
m_frameTimeEdit->setText(QString::number(EASY_GLOBALS.frame_time * 1e-3));
|
m_frameTimeEdit->setText(QString::number(EASY_GLOBALS.frame_time * 1e-3));
|
||||||
connect(m_frameTimeEdit, &QLineEdit::editingFinished, this, &This::onFrameTimeEditFinish);
|
connect(m_frameTimeEdit, &QLineEdit::editingFinished, this, &This::onFrameTimeEditFinish);
|
||||||
connect(&EASY_GLOBALS.events, &::profiler_gui::GlobalSignals::expectedFrameTimeChanged, this, &This::onFrameTimeChanged);
|
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::expectedFrameTimeChanged, this, &This::onFrameTimeChanged);
|
||||||
toolbar->addWidget(m_frameTimeEdit);
|
toolbar->addWidget(m_frameTimeEdit);
|
||||||
|
|
||||||
lbl = new QLabel("ms", toolbar);
|
lbl = new QLabel("ms", toolbar);
|
||||||
lbl->setContentsMargins(5, 2, 1, 1);
|
lbl->setContentsMargins(5, 2, 1, 1);
|
||||||
toolbar->addWidget(lbl);
|
toolbar->addWidget(lbl);
|
||||||
|
|
||||||
|
m_readerTimer.setInterval(LOADER_TIMER_INTERVAL);
|
||||||
|
|
||||||
connect(graphicsView->view(), &BlocksGraphicsView::intervalChanged, treeWidget->tree(), &BlocksTreeWidget::setTreeBlocks);
|
connect(graphicsView->view(), &BlocksGraphicsView::intervalChanged, treeWidget->tree(), &BlocksTreeWidget::setTreeBlocks);
|
||||||
connect(&m_readerTimer, &QTimer::timeout, this, &This::onFileReaderTimeout);
|
connect(&m_readerTimer, &QTimer::timeout, this, &This::onFileReaderTimeout);
|
||||||
@ -962,14 +967,14 @@ void MainWindow::loadFile(const QString& filename)
|
|||||||
|
|
||||||
createProgressDialog(QString("Loading %1...").arg(filename.mid(std::max(i, j) + 1)));
|
createProgressDialog(QString("Loading %1...").arg(filename.mid(std::max(i, j) + 1)));
|
||||||
|
|
||||||
m_readerTimer.start(LOADER_TIMER_INTERVAL);
|
m_readerTimer.start();
|
||||||
m_reader.load(filename);
|
m_reader.load(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::readStream(std::stringstream& _data)
|
void MainWindow::readStream(std::stringstream& _data)
|
||||||
{
|
{
|
||||||
createProgressDialog(tr("Reading from stream..."));
|
createProgressDialog(tr("Reading from stream..."));
|
||||||
m_readerTimer.start(LOADER_TIMER_INTERVAL);
|
m_readerTimer.start();
|
||||||
m_reader.load(_data);
|
m_reader.load(_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1117,8 +1122,8 @@ void MainWindow::clear()
|
|||||||
emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
|
emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
|
||||||
|
|
||||||
EASY_GLOBALS.selected_thread = 0;
|
EASY_GLOBALS.selected_thread = 0;
|
||||||
::profiler_gui::set_max(EASY_GLOBALS.selected_block);
|
profiler_gui::set_max(EASY_GLOBALS.selected_block);
|
||||||
::profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
|
profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
|
||||||
EASY_GLOBALS.profiler_blocks.clear();
|
EASY_GLOBALS.profiler_blocks.clear();
|
||||||
EASY_GLOBALS.descriptors.clear();
|
EASY_GLOBALS.descriptors.clear();
|
||||||
EASY_GLOBALS.gui_blocks.clear();
|
EASY_GLOBALS.gui_blocks.clear();
|
||||||
@ -1181,14 +1186,14 @@ void MainWindow::onEncodingChanged(bool)
|
|||||||
void MainWindow::onChronoTextPosChanged(bool)
|
void MainWindow::onChronoTextPosChanged(bool)
|
||||||
{
|
{
|
||||||
auto _sender = qobject_cast<QAction*>(sender());
|
auto _sender = qobject_cast<QAction*>(sender());
|
||||||
EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(_sender->data().toInt());
|
EASY_GLOBALS.chrono_text_position = static_cast<profiler_gui::ChronometerTextPosition>(_sender->data().toInt());
|
||||||
refreshDiagram();
|
refreshDiagram();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onUnitsChanged(bool)
|
void MainWindow::onUnitsChanged(bool)
|
||||||
{
|
{
|
||||||
auto _sender = qobject_cast<QAction*>(sender());
|
auto _sender = qobject_cast<QAction*>(sender());
|
||||||
EASY_GLOBALS.time_units = static_cast<::profiler_gui::TimeUnits>(_sender->data().toInt());
|
EASY_GLOBALS.time_units = static_cast<profiler_gui::TimeUnits>(_sender->data().toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onEnableDisableStatistics(bool _checked)
|
void MainWindow::onEnableDisableStatistics(bool _checked)
|
||||||
@ -1379,7 +1384,7 @@ void MainWindow::closeEvent(QCloseEvent* close_event)
|
|||||||
|
|
||||||
void MainWindow::loadSettings()
|
void MainWindow::loadSettings()
|
||||||
{
|
{
|
||||||
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
|
QSettings settings(profiler_gui::ORGANAZATION_NAME, profiler_gui::APPLICATION_NAME);
|
||||||
settings.beginGroup("main");
|
settings.beginGroup("main");
|
||||||
|
|
||||||
auto last_files = settings.value("last_files");
|
auto last_files = settings.value("last_files");
|
||||||
@ -1400,11 +1405,11 @@ void MainWindow::loadSettings()
|
|||||||
|
|
||||||
auto val = settings.value("chrono_text_position");
|
auto val = settings.value("chrono_text_position");
|
||||||
if (!val.isNull())
|
if (!val.isNull())
|
||||||
EASY_GLOBALS.chrono_text_position = static_cast<::profiler_gui::ChronometerTextPosition>(val.toInt());
|
EASY_GLOBALS.chrono_text_position = static_cast<profiler_gui::ChronometerTextPosition>(val.toInt());
|
||||||
|
|
||||||
val = settings.value("time_units");
|
val = settings.value("time_units");
|
||||||
if (!val.isNull())
|
if (!val.isNull())
|
||||||
EASY_GLOBALS.time_units = static_cast<::profiler_gui::TimeUnits>(val.toInt());
|
EASY_GLOBALS.time_units = static_cast<profiler_gui::TimeUnits>(val.toInt());
|
||||||
|
|
||||||
|
|
||||||
val = settings.value("frame_time");
|
val = settings.value("frame_time");
|
||||||
@ -1529,7 +1534,7 @@ void MainWindow::loadSettings()
|
|||||||
|
|
||||||
void MainWindow::loadGeometry()
|
void MainWindow::loadGeometry()
|
||||||
{
|
{
|
||||||
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
|
QSettings settings(profiler_gui::ORGANAZATION_NAME, profiler_gui::APPLICATION_NAME);
|
||||||
settings.beginGroup("main");
|
settings.beginGroup("main");
|
||||||
|
|
||||||
auto geometry = settings.value("geometry").toByteArray();
|
auto geometry = settings.value("geometry").toByteArray();
|
||||||
@ -1559,7 +1564,7 @@ void MainWindow::loadGeometry()
|
|||||||
|
|
||||||
void MainWindow::saveSettingsAndGeometry()
|
void MainWindow::saveSettingsAndGeometry()
|
||||||
{
|
{
|
||||||
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
|
QSettings settings(profiler_gui::ORGANAZATION_NAME, profiler_gui::APPLICATION_NAME);
|
||||||
settings.beginGroup("main");
|
settings.beginGroup("main");
|
||||||
|
|
||||||
settings.setValue("geometry", this->saveGeometry());
|
settings.setValue("geometry", this->saveGeometry());
|
||||||
@ -1838,24 +1843,32 @@ void MainWindow::onListenerDialogClose(int _result)
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void MainWindow::onFileReaderTimeout()
|
void MainWindow::closeProgressDialogAndClearReader()
|
||||||
{
|
{
|
||||||
if (m_reader.done())
|
m_reader.interrupt();
|
||||||
|
m_readerTimer.stop();
|
||||||
|
destroyProgressDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
|
||||||
{
|
{
|
||||||
const auto nblocks = m_reader.size();
|
_nblocks = m_reader.size();
|
||||||
if (nblocks != 0)
|
if (_nblocks != 0)
|
||||||
{
|
{
|
||||||
emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
|
emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
|
||||||
|
|
||||||
::profiler::SerializedData serialized_blocks;
|
profiler::SerializedData serialized_blocks;
|
||||||
::profiler::SerializedData serialized_descriptors;
|
profiler::SerializedData serialized_descriptors;
|
||||||
::profiler::descriptors_list_t descriptors;
|
profiler::descriptors_list_t descriptors;
|
||||||
::profiler::blocks_t blocks;
|
profiler::blocks_t blocks;
|
||||||
::profiler::thread_blocks_tree_t threads_map;
|
profiler::thread_blocks_tree_t threads_map;
|
||||||
QString filename;
|
QString filename;
|
||||||
uint32_t descriptorsNumberInFile = 0;
|
uint32_t descriptorsNumberInFile = 0;
|
||||||
uint32_t version = 0;
|
uint32_t version = 0;
|
||||||
m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map, descriptorsNumberInFile, version, filename);
|
profiler::processid_t pid = 0;
|
||||||
|
|
||||||
|
m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map,
|
||||||
|
descriptorsNumberInFile, version, pid, filename);
|
||||||
|
|
||||||
if (threads_map.size() > 0xff)
|
if (threads_map.size() > 0xff)
|
||||||
{
|
{
|
||||||
@ -1907,19 +1920,22 @@ void MainWindow::onFileReaderTimeout()
|
|||||||
m_descriptorsNumberInFile = descriptorsNumberInFile;
|
m_descriptorsNumberInFile = descriptorsNumberInFile;
|
||||||
EASY_GLOBALS.selected_thread = 0;
|
EASY_GLOBALS.selected_thread = 0;
|
||||||
EASY_GLOBALS.version = version;
|
EASY_GLOBALS.version = version;
|
||||||
::profiler_gui::set_max(EASY_GLOBALS.selected_block);
|
EASY_GLOBALS.pid = pid;
|
||||||
::profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
|
profiler_gui::set_max(EASY_GLOBALS.selected_block);
|
||||||
|
profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
|
||||||
EASY_GLOBALS.profiler_blocks.swap(threads_map);
|
EASY_GLOBALS.profiler_blocks.swap(threads_map);
|
||||||
EASY_GLOBALS.descriptors.swap(descriptors);
|
EASY_GLOBALS.descriptors.swap(descriptors);
|
||||||
|
|
||||||
EASY_GLOBALS.gui_blocks.clear();
|
EASY_GLOBALS.gui_blocks.clear();
|
||||||
EASY_GLOBALS.gui_blocks.resize(nblocks);
|
EASY_GLOBALS.gui_blocks.resize(_nblocks);
|
||||||
memset(EASY_GLOBALS.gui_blocks.data(), 0, sizeof(::profiler_gui::EasyBlock) * nblocks);
|
memset(EASY_GLOBALS.gui_blocks.data(), 0, sizeof(profiler_gui::EasyBlock) * _nblocks);
|
||||||
for (std::remove_const<decltype(nblocks)>::type i = 0; i < nblocks; ++i) {
|
|
||||||
|
for (std::remove_reference<decltype(_nblocks)>::type i = 0; i < _nblocks; ++i)
|
||||||
|
{
|
||||||
auto& guiblock = EASY_GLOBALS.gui_blocks[i];
|
auto& guiblock = EASY_GLOBALS.gui_blocks[i];
|
||||||
guiblock.tree = std::move(blocks[i]);
|
guiblock.tree = std::move(blocks[i]);
|
||||||
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
#ifdef EASY_TREE_WIDGET__USE_VECTOR
|
||||||
::profiler_gui::set_max(guiblock.tree_item);
|
profiler_gui::set_max(guiblock.tree_item);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1944,11 +1960,23 @@ void MainWindow::onFileReaderTimeout()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_reader.interrupt();
|
void MainWindow::onSavingFinish()
|
||||||
|
{
|
||||||
|
|
||||||
m_readerTimer.stop();
|
}
|
||||||
destroyProgressDialog();
|
|
||||||
|
void MainWindow::onFileReaderTimeout()
|
||||||
|
{
|
||||||
|
if (m_reader.done())
|
||||||
|
{
|
||||||
|
if (m_reader.isLoading())
|
||||||
|
{
|
||||||
|
profiler::block_index_t nblocks = 0;
|
||||||
|
|
||||||
|
onLoadingFinish(nblocks);
|
||||||
|
closeProgressDialogAndClearReader();
|
||||||
|
|
||||||
if (nblocks != 0)
|
if (nblocks != 0)
|
||||||
{
|
{
|
||||||
@ -1957,6 +1985,16 @@ void MainWindow::onFileReaderTimeout()
|
|||||||
onExpandAllClicked(true);
|
onExpandAllClicked(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (m_reader.isSaving())
|
||||||
|
{
|
||||||
|
onSavingFinish();
|
||||||
|
closeProgressDialogAndClearReader();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
closeProgressDialogAndClearReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (m_progress != nullptr)
|
else if (m_progress != nullptr)
|
||||||
{
|
{
|
||||||
m_progress->setValue(m_reader.progress());
|
m_progress->setValue(m_reader.progress());
|
||||||
@ -1987,6 +2025,16 @@ const bool FileReader::isFile() const
|
|||||||
return m_isFile;
|
return m_isFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool FileReader::isSaving() const
|
||||||
|
{
|
||||||
|
return m_jobType == JobType::Saving;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool FileReader::isLoading() const
|
||||||
|
{
|
||||||
|
return m_jobType == JobType::Loading;
|
||||||
|
}
|
||||||
|
|
||||||
bool FileReader::done() const
|
bool FileReader::done() const
|
||||||
{
|
{
|
||||||
return m_bDone.load(std::memory_order_acquire);
|
return m_bDone.load(std::memory_order_acquire);
|
||||||
@ -2011,13 +2059,20 @@ void FileReader::load(const QString& _filename)
|
|||||||
{
|
{
|
||||||
interrupt();
|
interrupt();
|
||||||
|
|
||||||
|
m_jobType = JobType::Loading;
|
||||||
m_isFile = true;
|
m_isFile = true;
|
||||||
m_filename = _filename;
|
m_filename = _filename;
|
||||||
m_thread = std::thread([this](bool _enableStatistics) {
|
|
||||||
m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors,
|
m_thread = std::thread([this](bool _enableStatistics)
|
||||||
m_descriptors, m_blocks, m_blocksTree, m_descriptorsNumberInFile, m_version, _enableStatistics, m_errorMessage), std::memory_order_release);
|
{
|
||||||
|
m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks,
|
||||||
|
m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree,
|
||||||
|
m_descriptorsNumberInFile, m_version, m_pid, _enableStatistics,
|
||||||
|
m_errorMessage), std::memory_order_release);
|
||||||
|
|
||||||
m_progress.store(100, std::memory_order_release);
|
m_progress.store(100, std::memory_order_release);
|
||||||
m_bDone.store(true, std::memory_order_release);
|
m_bDone.store(true, std::memory_order_release);
|
||||||
|
|
||||||
}, EASY_GLOBALS.enable_statistics);
|
}, EASY_GLOBALS.enable_statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2025,6 +2080,7 @@ void FileReader::load(std::stringstream& _stream)
|
|||||||
{
|
{
|
||||||
interrupt();
|
interrupt();
|
||||||
|
|
||||||
|
m_jobType = JobType::Loading;
|
||||||
m_isFile = false;
|
m_isFile = false;
|
||||||
m_filename.clear();
|
m_filename.clear();
|
||||||
|
|
||||||
@ -2038,19 +2094,47 @@ void FileReader::load(std::stringstream& _stream)
|
|||||||
m_stream.swap(_stream);
|
m_stream.swap(_stream);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_thread = std::thread([this](bool _enableStatistics) {
|
m_thread = std::thread([this](bool _enableStatistics)
|
||||||
|
{
|
||||||
std::ofstream cache_file(NETWORK_CACHE_FILE, std::fstream::binary);
|
std::ofstream cache_file(NETWORK_CACHE_FILE, std::fstream::binary);
|
||||||
if (cache_file.is_open()) {
|
if (cache_file.is_open())
|
||||||
|
{
|
||||||
cache_file << m_stream.str();
|
cache_file << m_stream.str();
|
||||||
cache_file.close();
|
cache_file.close();
|
||||||
}
|
}
|
||||||
m_size.store(fillTreesFromStream(m_progress, m_stream, m_serializedBlocks, m_serializedDescriptors, m_descriptors,
|
|
||||||
m_blocks, m_blocksTree, m_descriptorsNumberInFile, m_version, _enableStatistics, m_errorMessage), std::memory_order_release);
|
m_size.store(fillTreesFromStream(m_progress, m_stream, m_serializedBlocks, m_serializedDescriptors,
|
||||||
|
m_descriptors, m_blocks, m_blocksTree, m_descriptorsNumberInFile,
|
||||||
|
m_version, m_pid, _enableStatistics, m_errorMessage), std::memory_order_release);
|
||||||
|
|
||||||
m_progress.store(100, std::memory_order_release);
|
m_progress.store(100, std::memory_order_release);
|
||||||
m_bDone.store(true, std::memory_order_release);
|
m_bDone.store(true, std::memory_order_release);
|
||||||
|
|
||||||
}, EASY_GLOBALS.enable_statistics);
|
}, EASY_GLOBALS.enable_statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileReader::save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
|
||||||
|
const profiler::SerializedData& _serializedDescriptors, profiler::block_id_t descriptors_count,
|
||||||
|
const profiler::thread_blocks_tree_t& _trees, profiler::block_getter_fn block_getter,
|
||||||
|
profiler::processid_t _pid)
|
||||||
|
{
|
||||||
|
interrupt();
|
||||||
|
|
||||||
|
m_jobType = JobType::Saving;
|
||||||
|
m_isFile = true;
|
||||||
|
m_filename = _filename;
|
||||||
|
|
||||||
|
auto serializedDescriptors = std::ref(_serializedDescriptors);
|
||||||
|
auto trees = std::ref(_trees);
|
||||||
|
|
||||||
|
m_thread = std::thread([=] (profiler::block_getter_fn getter) {
|
||||||
|
writeTreesToFile(m_progress, m_filename.toStdString().c_str(), serializedDescriptors, descriptors_count, trees,
|
||||||
|
getter, _beginTime, _endTime, _pid, m_errorMessage);
|
||||||
|
m_progress.store(100, std::memory_order_release);
|
||||||
|
m_bDone.store(true, std::memory_order_release);
|
||||||
|
}, std::move(block_getter));
|
||||||
|
}
|
||||||
|
|
||||||
void FileReader::interrupt()
|
void FileReader::interrupt()
|
||||||
{
|
{
|
||||||
join();
|
join();
|
||||||
@ -2064,25 +2148,29 @@ void FileReader::interrupt()
|
|||||||
m_blocksTree.clear();
|
m_blocksTree.clear();
|
||||||
m_descriptorsNumberInFile = 0;
|
m_descriptorsNumberInFile = 0;
|
||||||
m_version = 0;
|
m_version = 0;
|
||||||
|
m_pid = 0;
|
||||||
|
m_jobType = JobType::Idle;
|
||||||
|
|
||||||
clear_stream(m_stream);
|
clear_stream(m_stream);
|
||||||
clear_stream(m_errorMessage);
|
clear_stream(m_errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors,
|
void FileReader::get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
|
||||||
::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks,
|
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks,
|
||||||
::profiler::thread_blocks_tree_t& _tree, uint32_t& _descriptorsNumberInFile, uint32_t& _version, QString& _filename)
|
profiler::thread_blocks_tree_t& _trees, uint32_t& _descriptorsNumberInFile, uint32_t& _version,
|
||||||
|
profiler::processid_t& _pid, QString& _filename)
|
||||||
{
|
{
|
||||||
if (done())
|
if (done())
|
||||||
{
|
{
|
||||||
m_serializedBlocks.swap(_serializedBlocks);
|
m_serializedBlocks.swap(_serializedBlocks);
|
||||||
m_serializedDescriptors.swap(_serializedDescriptors);
|
m_serializedDescriptors.swap(_serializedDescriptors);
|
||||||
::profiler::descriptors_list_t(std::move(m_descriptors)).swap(_descriptors);
|
profiler::descriptors_list_t(std::move(m_descriptors)).swap(_descriptors);
|
||||||
m_blocks.swap(_blocks);
|
m_blocks.swap(_blocks);
|
||||||
m_blocksTree.swap(_tree);
|
m_blocksTree.swap(_trees);
|
||||||
m_filename.swap(_filename);
|
m_filename.swap(_filename);
|
||||||
_descriptorsNumberInFile = m_descriptorsNumberInFile;
|
_descriptorsNumberInFile = m_descriptorsNumberInFile;
|
||||||
_version = m_version;
|
_version = m_version;
|
||||||
|
_pid = m_pid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2126,12 +2214,12 @@ void MainWindow::onFrameTimeEditFinish()
|
|||||||
|
|
||||||
EASY_GLOBALS.frame_time = text.toFloat() * 1e3f;
|
EASY_GLOBALS.frame_time = text.toFloat() * 1e3f;
|
||||||
|
|
||||||
disconnect(&EASY_GLOBALS.events, &::profiler_gui::GlobalSignals::expectedFrameTimeChanged,
|
disconnect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::expectedFrameTimeChanged,
|
||||||
this, &This::onFrameTimeChanged);
|
this, &This::onFrameTimeChanged);
|
||||||
|
|
||||||
emit EASY_GLOBALS.events.expectedFrameTimeChanged();
|
emit EASY_GLOBALS.events.expectedFrameTimeChanged();
|
||||||
|
|
||||||
connect(&EASY_GLOBALS.events, &::profiler_gui::GlobalSignals::expectedFrameTimeChanged,
|
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::expectedFrameTimeChanged,
|
||||||
this, &This::onFrameTimeChanged);
|
this, &This::onFrameTimeChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2142,6 +2230,36 @@ void MainWindow::onFrameTimeChanged()
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void MainWindow::onCropAndSaveClicked(bool)
|
||||||
|
{
|
||||||
|
profiler::timestamp_t beginTime = 0, endTime = 0;
|
||||||
|
const bool hasSelection = static_cast<DiagramWidget*>(m_graphicsView->widget())->view()->getSelectionRegionForSaving(beginTime, endTime);
|
||||||
|
if (!hasSelection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString lastFile = m_lastFiles.empty() ? QString() : m_lastFiles.front();
|
||||||
|
|
||||||
|
const auto i = lastFile.lastIndexOf(QChar('/'));
|
||||||
|
const auto j = lastFile.lastIndexOf(QChar('\\'));
|
||||||
|
auto k = std::max(i, j);
|
||||||
|
|
||||||
|
QString dir;
|
||||||
|
if (k > 0)
|
||||||
|
dir = lastFile.mid(0, ++k);
|
||||||
|
|
||||||
|
auto filename = QFileDialog::getSaveFileName(this, "Save cropped area to EasyProfiler File", dir,
|
||||||
|
"EasyProfiler File (*.prof);;All Files (*.*)");
|
||||||
|
if (filename.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
createProgressDialog(tr("Saving selected region..."));
|
||||||
|
m_readerTimer.start();
|
||||||
|
m_reader.save(filename, beginTime, endTime, m_serializedDescriptors, m_descriptorsNumberInFile,
|
||||||
|
EASY_GLOBALS.profiler_blocks, easyBlocksTree, EASY_GLOBALS.pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void MainWindow::onConnectClicked(bool)
|
void MainWindow::onConnectClicked(bool)
|
||||||
{
|
{
|
||||||
if (EASY_GLOBALS.connected)
|
if (EASY_GLOBALS.connected)
|
||||||
@ -2428,7 +2546,7 @@ void MainWindow::onGetBlockDescriptionsClicked(bool)
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void MainWindow::onBlockStatusChange(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status)
|
void MainWindow::onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status)
|
||||||
{
|
{
|
||||||
if (EASY_GLOBALS.connected)
|
if (EASY_GLOBALS.connected)
|
||||||
m_listener.send(profiler::net::BlockStatusMessage(_id, static_cast<uint8_t>(_status)));
|
m_listener.send(profiler::net::BlockStatusMessage(_id, static_cast<uint8_t>(_status)));
|
||||||
@ -2613,7 +2731,7 @@ bool SocketListener::connect(const char* _ipaddress, uint16_t _port, profiler::n
|
|||||||
seek += bytes;
|
seek += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto message = reinterpret_cast<const ::profiler::net::EasyProfilerStatus*>(buffer);
|
auto message = reinterpret_cast<const profiler::net::EasyProfilerStatus*>(buffer);
|
||||||
if (message->isEasyNetMessage() && message->type == profiler::net::MessageType::Connection_Accepted)
|
if (message->isEasyNetMessage() && message->type == profiler::net::MessageType::Connection_Accepted)
|
||||||
_reply = *message;
|
_reply = *message;
|
||||||
|
|
||||||
@ -2625,7 +2743,7 @@ bool SocketListener::connect(const char* _ipaddress, uint16_t _port, profiler::n
|
|||||||
return isConnected;
|
return isConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketListener::reconnect(const char* _ipaddress, uint16_t _port, ::profiler::net::EasyProfilerStatus& _reply)
|
bool SocketListener::reconnect(const char* _ipaddress, uint16_t _port, profiler::net::EasyProfilerStatus& _reply)
|
||||||
{
|
{
|
||||||
return connect(_ipaddress, _port, _reply, true);
|
return connect(_ipaddress, _port, _reply, true);
|
||||||
}
|
}
|
||||||
@ -2820,7 +2938,7 @@ void SocketListener::listenCapture()
|
|||||||
|
|
||||||
if (bytes > 0)
|
if (bytes > 0)
|
||||||
{
|
{
|
||||||
auto message = reinterpret_cast<const ::profiler::net::Message*>(buf);
|
auto message = reinterpret_cast<const profiler::net::Message*>(buf);
|
||||||
if (!message->isEasyNetMessage())
|
if (!message->isEasyNetMessage())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -2978,7 +3096,7 @@ void SocketListener::listenDescription()
|
|||||||
|
|
||||||
if (bytes > 0)
|
if (bytes > 0)
|
||||||
{
|
{
|
||||||
auto message = reinterpret_cast<const ::profiler::net::Message*>(buf);
|
auto message = reinterpret_cast<const profiler::net::Message*>(buf);
|
||||||
if (!message->isEasyNetMessage())
|
if (!message->isEasyNetMessage())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -3069,7 +3187,7 @@ void SocketListener::listenDescription()
|
|||||||
|
|
||||||
void SocketListener::listenFrameTime()
|
void SocketListener::listenFrameTime()
|
||||||
{
|
{
|
||||||
EASY_STATIC_CONSTEXPR size_t buffer_size = sizeof(::profiler::net::TimestampMessage) << 2;
|
EASY_STATIC_CONSTEXPR size_t buffer_size = sizeof(profiler::net::TimestampMessage) << 2;
|
||||||
|
|
||||||
char buffer[buffer_size] = {};
|
char buffer[buffer_size] = {};
|
||||||
int seek = 0, bytes = 0;
|
int seek = 0, bytes = 0;
|
||||||
@ -3108,7 +3226,7 @@ void SocketListener::listenFrameTime()
|
|||||||
|
|
||||||
if (bytes > 0)
|
if (bytes > 0)
|
||||||
{
|
{
|
||||||
auto message = reinterpret_cast<const ::profiler::net::Message*>(buf);
|
auto message = reinterpret_cast<const profiler::net::Message*>(buf);
|
||||||
if (!message->isEasyNetMessage())
|
if (!message->isEasyNetMessage())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -54,10 +54,10 @@
|
|||||||
#ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H
|
#ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H
|
||||||
#define EASY_PROFILER_GUI__MAIN_WINDOW__H
|
#define EASY_PROFILER_GUI__MAIN_WINDOW__H
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
@ -85,6 +85,13 @@ namespace profiler { namespace net { struct EasyProfilerStatus; } }
|
|||||||
|
|
||||||
class FileReader Q_DECL_FINAL
|
class FileReader Q_DECL_FINAL
|
||||||
{
|
{
|
||||||
|
enum class JobType : int8_t
|
||||||
|
{
|
||||||
|
Idle=0,
|
||||||
|
Loading,
|
||||||
|
Saving,
|
||||||
|
};
|
||||||
|
|
||||||
profiler::SerializedData m_serializedBlocks; ///<
|
profiler::SerializedData m_serializedBlocks; ///<
|
||||||
profiler::SerializedData m_serializedDescriptors; ///<
|
profiler::SerializedData m_serializedDescriptors; ///<
|
||||||
profiler::descriptors_list_t m_descriptors; ///<
|
profiler::descriptors_list_t m_descriptors; ///<
|
||||||
@ -93,12 +100,14 @@ class FileReader Q_DECL_FINAL
|
|||||||
std::stringstream m_stream; ///<
|
std::stringstream m_stream; ///<
|
||||||
std::stringstream m_errorMessage; ///<
|
std::stringstream m_errorMessage; ///<
|
||||||
QString m_filename; ///<
|
QString m_filename; ///<
|
||||||
|
profiler::processid_t m_pid = 0; ///<
|
||||||
uint32_t m_descriptorsNumberInFile = 0; ///<
|
uint32_t m_descriptorsNumberInFile = 0; ///<
|
||||||
uint32_t m_version = 0; ///<
|
uint32_t m_version = 0; ///<
|
||||||
std::thread m_thread; ///<
|
std::thread m_thread; ///<
|
||||||
std::atomic_bool m_bDone; ///<
|
std::atomic_bool m_bDone; ///<
|
||||||
std::atomic<int> m_progress; ///<
|
std::atomic<int> m_progress; ///<
|
||||||
std::atomic<unsigned int> m_size; ///<
|
std::atomic<unsigned int> m_size; ///<
|
||||||
|
JobType m_jobType = JobType::Idle; ///<
|
||||||
bool m_isFile = false; ///<
|
bool m_isFile = false; ///<
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -107,6 +116,9 @@ public:
|
|||||||
~FileReader();
|
~FileReader();
|
||||||
|
|
||||||
const bool isFile() const;
|
const bool isFile() const;
|
||||||
|
const bool isSaving() const;
|
||||||
|
const bool isLoading() const;
|
||||||
|
|
||||||
bool done() const;
|
bool done() const;
|
||||||
int progress() const;
|
int progress() const;
|
||||||
unsigned int size() const;
|
unsigned int size() const;
|
||||||
@ -114,10 +126,17 @@ public:
|
|||||||
|
|
||||||
void load(const QString& _filename);
|
void load(const QString& _filename);
|
||||||
void load(std::stringstream& _stream);
|
void load(std::stringstream& _stream);
|
||||||
|
|
||||||
|
/** \brief Save data to file.
|
||||||
|
*/
|
||||||
|
void save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
|
||||||
|
const profiler::SerializedData& _serializedDescriptors, profiler::block_id_t descriptors_count,
|
||||||
|
const profiler::thread_blocks_tree_t& _trees, profiler::block_getter_fn block_getter, profiler::processid_t _pid);
|
||||||
|
|
||||||
void interrupt();
|
void interrupt();
|
||||||
void get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
|
void get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
|
||||||
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _tree,
|
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _trees,
|
||||||
uint32_t& _descriptorsNumberInFile, uint32_t& _version, QString& _filename);
|
uint32_t& _descriptorsNumberInFile, uint32_t& _version, profiler::processid_t& _pid, QString& _filename);
|
||||||
|
|
||||||
void join();
|
void join();
|
||||||
|
|
||||||
@ -238,6 +257,7 @@ protected:
|
|||||||
QStringList m_lastFiles;
|
QStringList m_lastFiles;
|
||||||
QString m_theme;
|
QString m_theme;
|
||||||
QString m_lastAddress;
|
QString m_lastAddress;
|
||||||
|
|
||||||
QDockWidget* m_treeWidget = nullptr;
|
QDockWidget* m_treeWidget = nullptr;
|
||||||
QDockWidget* m_graphicsView = nullptr;
|
QDockWidget* m_graphicsView = nullptr;
|
||||||
QDockWidget* m_fpsViewer = nullptr;
|
QDockWidget* m_fpsViewer = nullptr;
|
||||||
@ -326,6 +346,7 @@ protected slots:
|
|||||||
void onEventTracingEnableChange(bool _checked);
|
void onEventTracingEnableChange(bool _checked);
|
||||||
void onFrameTimeEditFinish();
|
void onFrameTimeEditFinish();
|
||||||
void onFrameTimeChanged();
|
void onFrameTimeChanged();
|
||||||
|
void onCropAndSaveClicked(bool);
|
||||||
|
|
||||||
void onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
|
void onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
|
||||||
|
|
||||||
@ -339,6 +360,10 @@ private:
|
|||||||
|
|
||||||
// Private non-virtual methods
|
// Private non-virtual methods
|
||||||
|
|
||||||
|
void closeProgressDialogAndClearReader();
|
||||||
|
void onLoadingFinish(profiler::block_index_t& _nblocks);
|
||||||
|
void onSavingFinish();
|
||||||
|
|
||||||
void configureSizes();
|
void configureSizes();
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void printTree(TreePrinter& printer, const ::profiler::BlocksTree& tree, int level = 0, profiler::timestamp_t parent_dur = 0, profiler::timestamp_t root_dur = 0)
|
void printTree(TreePrinter& printer, const profiler::BlocksTree& tree, int level = 0, profiler::timestamp_t parent_dur = 0, profiler::timestamp_t root_dur = 0)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
//if (tree.node){
|
//if (tree.node){
|
||||||
@ -72,7 +72,7 @@ void printTree(TreePrinter& printer, const ::profiler::BlocksTree& tree, int lev
|
|||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
::profiler::thread_blocks_tree_t threaded_trees;
|
profiler::thread_blocks_tree_t threaded_trees;
|
||||||
|
|
||||||
::std::string filename;// = "test.prof";
|
::std::string filename;// = "test.prof";
|
||||||
if (argc > 1 && argv[1])
|
if (argc > 1 && argv[1])
|
||||||
@ -110,14 +110,15 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
::profiler::SerializedData serialized_blocks, serialized_descriptors;
|
profiler::SerializedData serialized_blocks, serialized_descriptors;
|
||||||
::profiler::descriptors_list_t descriptors;
|
profiler::descriptors_list_t descriptors;
|
||||||
::profiler::blocks_t blocks;
|
profiler::blocks_t blocks;
|
||||||
::std::stringstream errorMessage;
|
std::stringstream errorMessage;
|
||||||
uint32_t descriptorsNumberInFile = 0;
|
uint32_t descriptorsNumberInFile = 0;
|
||||||
uint32_t version = 0;
|
uint32_t version = 0;
|
||||||
|
profiler::processid_t pid = 0;
|
||||||
auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks,
|
auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks,
|
||||||
threaded_trees, descriptorsNumberInFile, version, true, errorMessage);
|
threaded_trees, descriptorsNumberInFile, version, pid, true, errorMessage);
|
||||||
if (blocks_counter == 0)
|
if (blocks_counter == 0)
|
||||||
std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str();
|
std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user