0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-27 08:41:02 +08:00

Merge remote-tracking branch 'origin/saving_file_develop' into develop

This commit is contained in:
Victor Zarubkin 2018-04-26 00:26:50 +03:00
commit ca80ca0ccb
18 changed files with 1865 additions and 1139 deletions

View File

@ -62,11 +62,12 @@ profiler::block_index_t FileReader::readFile(const std::string& filename)
profiler::blocks_t blocks; profiler::blocks_t blocks;
profiler::thread_blocks_tree_t threaded_trees; profiler::thread_blocks_tree_t threaded_trees;
profiler::processid_t pid = 0;
uint32_t total_descriptors_number = 0; uint32_t total_descriptors_number = 0;
EASY_CONSTEXPR bool DoNotGatherStats = false; EASY_CONSTEXPR bool DoNotGatherStats = false;
const auto blocks_number = ::fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, const auto blocks_number = ::fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors,
descriptors, blocks, threaded_trees, total_descriptors_number, m_version, DoNotGatherStats, m_errorMessage); descriptors, blocks, threaded_trees, total_descriptors_number, m_version, pid, DoNotGatherStats, m_errorMessage);
if (blocks_number == 0) if (blocks_number == 0)
return 0; return 0;

View File

@ -0,0 +1,274 @@
/************************************************
* creation time : 2017/08/20
* author : Blake Martin
* email : rationalcoder@gmail.com
************************************************/
/**
Lightweight profiler library for c++
Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
The MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_ALIGNMENT_HELPERS_H
#define EASY_PROFILER_ALIGNMENT_HELPERS_H
#include <cstddef>
#include <cstdint>
#include <easy/details/easy_compiler_support.h>
//! Checks if a pointer is aligned.
//! \param ptr The pointer to check.
//! \param alignment The alignement (must be a power of 2)
//! \returns true if the memory is aligned.
//!
template <uint32_t ALIGNMENT>
EASY_FORCE_INLINE bool is_aligned(void* ptr)
{
static_assert((ALIGNMENT & 1) == 0, "Alignment must be a power of two.");
return ((uintptr_t)ptr & (ALIGNMENT-1)) == 0;
}
EASY_FORCE_INLINE void unaligned_zero16(void* ptr)
{
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(uint16_t*)ptr = 0;
#else
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
#endif
}
EASY_FORCE_INLINE void unaligned_zero32(void* ptr)
{
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(uint32_t*)ptr = 0;
#else
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
((char*)ptr)[2] = 0;
((char*)ptr)[3] = 0;
#endif
}
EASY_FORCE_INLINE void unaligned_zero64(void* ptr)
{
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
// Assume unaligned is more common.
if (!is_aligned<alignof(uint64_t)>(ptr)) {
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
((char*)ptr)[2] = 0;
((char*)ptr)[3] = 0;
((char*)ptr)[4] = 0;
((char*)ptr)[5] = 0;
((char*)ptr)[6] = 0;
((char*)ptr)[7] = 0;
}
else
#endif
*(uint64_t*)ptr = 0;
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store16(void* ptr, T val)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(T*)ptr = val;
#else
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
#endif
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store32(void* ptr, T val)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(T*)ptr = val;
#else
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
((char*)ptr)[2] = temp[2];
((char*)ptr)[3] = temp[3];
#endif
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store64(void* ptr, T val)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
// Assume unaligned is more common.
if (!is_aligned<alignof(T)>(ptr)) {
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
((char*)ptr)[2] = temp[2];
((char*)ptr)[3] = temp[3];
((char*)ptr)[4] = temp[4];
((char*)ptr)[5] = temp[5];
((char*)ptr)[6] = temp[6];
((char*)ptr)[7] = temp[7];
}
else
#endif
*(T*)ptr = val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load16(const void* ptr)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
return *(const T*)ptr;
#else
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
return value;
#endif
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load16(const void* ptr, T* val)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*val = *(const T*)ptr;
#else
((char*)val)[0] = ((const char*)ptr)[0];
((char*)val)[1] = ((const char*)ptr)[1];
#endif
return *val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load32(const void* ptr)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
return *(const T*)ptr;
#else
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
((char*)&value)[2] = ((const char*)ptr)[2];
((char*)&value)[3] = ((const char*)ptr)[3];
return value;
#endif
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load32(const void* ptr, T* val)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*val = *(const T*)ptr;
#else
((char*)&val)[0] = ((const char*)ptr)[0];
((char*)&val)[1] = ((const char*)ptr)[1];
((char*)&val)[2] = ((const char*)ptr)[2];
((char*)&val)[3] = ((const char*)ptr)[3];
#endif
return *val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load64(const void* ptr)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
if (!is_aligned<alignof(T)>(ptr)) {
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
((char*)&value)[2] = ((const char*)ptr)[2];
((char*)&value)[3] = ((const char*)ptr)[3];
((char*)&value)[4] = ((const char*)ptr)[4];
((char*)&value)[5] = ((const char*)ptr)[5];
((char*)&value)[6] = ((const char*)ptr)[6];
((char*)&value)[7] = ((const char*)ptr)[7];
return value;
}
#endif
return *(const T*)ptr;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load64(const void* ptr, T* val)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
if (!is_aligned<alignof(T)>(ptr)) {
((char*)&val)[0] = ((const char*)ptr)[0];
((char*)&val)[1] = ((const char*)ptr)[1];
((char*)&val)[2] = ((const char*)ptr)[2];
((char*)&val)[3] = ((const char*)ptr)[3];
((char*)&val)[4] = ((const char*)ptr)[4];
((char*)&val)[5] = ((const char*)ptr)[5];
((char*)&val)[6] = ((const char*)ptr)[6];
((char*)&val)[7] = ((const char*)ptr)[7];
}
else
#endif
*val = *(const T*)ptr;
return *val;
}
#endif //EASY_PROFILER_ALIGNMENT_HELPERS_H

View File

@ -45,9 +45,8 @@ The Apache License, Version 2.0 (the "License");
#include <easy/details/easy_compiler_support.h> #include <easy/details/easy_compiler_support.h>
#include <cstring> #include <cstring>
#include <cstddef>
#include <stdint.h>
#include "outstream.h" #include "outstream.h"
#include "alignment_helpers.h"
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -83,226 +82,6 @@ The Apache License, Version 2.0 (the "License");
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
//! Checks if a pointer is aligned.
//! \param ptr The pointer to check.
//! \param alignment The alignement (must be a power of 2)
//! \returns true if the memory is aligned.
//!
template <uint32_t ALIGNMENT>
EASY_FORCE_INLINE bool is_aligned(void* ptr)
{
static_assert((ALIGNMENT & 1) == 0, "Alignment must be a power of two.");
return ((uintptr_t)ptr & (ALIGNMENT-1)) == 0;
}
EASY_FORCE_INLINE void unaligned_zero16(void* ptr)
{
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(uint16_t*)ptr = 0;
#else
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
#endif
}
EASY_FORCE_INLINE void unaligned_zero32(void* ptr)
{
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(uint32_t*)ptr = 0;
#else
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
((char*)ptr)[2] = 0;
((char*)ptr)[3] = 0;
#endif
}
EASY_FORCE_INLINE void unaligned_zero64(void* ptr)
{
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
// Assume unaligned is more common.
if (!is_aligned<alignof(uint64_t)>(ptr)) {
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
((char*)ptr)[2] = 0;
((char*)ptr)[3] = 0;
((char*)ptr)[4] = 0;
((char*)ptr)[5] = 0;
((char*)ptr)[6] = 0;
((char*)ptr)[7] = 0;
}
else
#endif
*(uint64_t*)ptr = 0;
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store16(void* ptr, T val)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(T*)ptr = val;
#else
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
#endif
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store32(void* ptr, T val)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(T*)ptr = val;
#else
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
((char*)ptr)[2] = temp[2];
((char*)ptr)[3] = temp[3];
#endif
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store64(void* ptr, T val)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
// Assume unaligned is more common.
if (!is_aligned<alignof(T)>(ptr)) {
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
((char*)ptr)[2] = temp[2];
((char*)ptr)[3] = temp[3];
((char*)ptr)[4] = temp[4];
((char*)ptr)[5] = temp[5];
((char*)ptr)[6] = temp[6];
((char*)ptr)[7] = temp[7];
}
else
#endif
*(T*)ptr = val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load16(const void* ptr)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
return *(const T*)ptr;
#else
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
return value;
#endif
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load16(const void* ptr, T* val)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*val = *(const T*)ptr;
#else
((char*)val)[0] = ((const char*)ptr)[0];
((char*)val)[1] = ((const char*)ptr)[1];
#endif
return *val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load32(const void* ptr)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
return *(const T*)ptr;
#else
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
((char*)&value)[2] = ((const char*)ptr)[2];
((char*)&value)[3] = ((const char*)ptr)[3];
return value;
#endif
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load32(const void* ptr, T* val)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*val = *(const T*)ptr;
#else
((char*)&val)[0] = ((const char*)ptr)[0];
((char*)&val)[1] = ((const char*)ptr)[1];
((char*)&val)[2] = ((const char*)ptr)[2];
((char*)&val)[3] = ((const char*)ptr)[3];
#endif
return *val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load64(const void* ptr)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
if (!is_aligned<alignof(T)>(ptr)) {
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
((char*)&value)[2] = ((const char*)ptr)[2];
((char*)&value)[3] = ((const char*)ptr)[3];
((char*)&value)[4] = ((const char*)ptr)[4];
((char*)&value)[5] = ((const char*)ptr)[5];
((char*)&value)[6] = ((const char*)ptr)[6];
((char*)&value)[7] = ((const char*)ptr)[7];
return value;
}
#endif
return *(const T*)ptr;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load64(const void* ptr, T* val)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
if (!is_aligned<alignof(T)>(ptr)) {
((char*)&val)[0] = ((const char*)ptr)[0];
((char*)&val)[1] = ((const char*)ptr)[1];
((char*)&val)[2] = ((const char*)ptr)[2];
((char*)&val)[3] = ((const char*)ptr)[3];
((char*)&val)[4] = ((const char*)ptr)[4];
((char*)&val)[5] = ((const char*)ptr)[5];
((char*)&val)[6] = ((const char*)ptr)[6];
((char*)&val)[7] = ((const char*)ptr)[7];
}
else
#endif
*val = *(const T*)ptr;
return *val;
}
//////////////////////////////////////////////////////////////////////////
template <const uint16_t N> template <const uint16_t N>
class chunk_allocator class chunk_allocator
{ {

View File

@ -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,93 +275,49 @@ 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)>;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
class PROFILER_API SerializedData EASY_FINAL class PROFILER_API SerializedData EASY_FINAL
{ {
uint64_t m_size;
char* m_data; char* m_data;
size_t m_size;
public: public:
SerializedData(const SerializedData&) = delete; SerializedData(const SerializedData&) = delete;
SerializedData& operator = (const SerializedData&) = delete; SerializedData& operator = (const SerializedData&) = delete;
SerializedData() : m_data(nullptr), m_size(0) SerializedData();
{
}
SerializedData(SerializedData&& that) : m_data(that.m_data), m_size(that.m_size) SerializedData(SerializedData&& that);
{
that.m_data = nullptr;
that.m_size = 0;
}
~SerializedData() ~SerializedData();
{
clear();
}
void set(uint64_t _size); void set(uint64_t _size);
void extend(uint64_t _size); void extend(uint64_t _size);
SerializedData& operator = (SerializedData&& that) SerializedData& operator = (SerializedData&& that);
{
set(that.m_data, that.m_size);
that.m_data = nullptr;
that.m_size = 0;
return *this;
}
char* operator [] (uint64_t i) char* operator [] (uint64_t i);
{
return m_data + i;
}
const char* operator [] (uint64_t i) const const char* operator [] (uint64_t i) const;
{
return m_data + i;
}
bool empty() const bool empty() const;
{
return m_size == 0;
}
uint64_t size() const uint64_t size() const;
{
return m_size;
}
char* data() char* data();
{
return m_data;
}
const char* data() const const char* data() const;
{
return m_data;
}
void clear() void clear();
{
set(nullptr, 0);
}
void swap(SerializedData& other) void swap(SerializedData& other);
{
char* d = other.m_data;
uint64_t sz = other.m_size;
other.m_data = m_data;
other.m_size = m_size;
m_data = d;
m_size = (size_t)sz;
}
private: private:
@ -367,59 +327,117 @@ 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,
const profiler::descriptors_list_t& 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,
const profiler::descriptors_list_t& 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, const profiler::descriptors_list_t& descriptors,
::std::stringstream& _log) 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); std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return writeTreesToFile(progress, filename, serialized_descriptors, 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,
const profiler::descriptors_list_t& 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, 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);
} }

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -407,6 +407,8 @@ void BlocksGraphicsView::clear()
EASY_GLOBALS.selected_thread = 0; EASY_GLOBALS.selected_thread = 0;
emit EASY_GLOBALS.events.selectedThreadChanged(0); emit EASY_GLOBALS.events.selectedThreadChanged(0);
emit EASY_GLOBALS.events.rulerVisible(false);
} }
void BlocksGraphicsView::notifySceneSizeChange() void BlocksGraphicsView::notifySceneSizeChange()
@ -438,6 +440,9 @@ void BlocksGraphicsView::notifyVisibleRegionPosChange()
void BlocksGraphicsView::notifyVisibleRegionPosChange(qreal _pos) void BlocksGraphicsView::notifyVisibleRegionPosChange(qreal _pos)
{ {
if (m_sceneWidth < m_visibleRegionWidth)
m_offset = 0;
else
m_offset = estd::clamp(0., _pos, m_sceneWidth - m_visibleRegionWidth); m_offset = estd::clamp(0., _pos, m_sceneWidth - m_visibleRegionWidth);
notifyVisibleRegionPosChange(); notifyVisibleRegionPosChange();
} }
@ -614,6 +619,21 @@ 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_bEmpty)
return false;
if (!m_selectionItem->isVisible() && !m_rulerItem->isVisible())
return false;
decltype(m_selectionItem) ruler = m_selectionItem->isVisible() ? m_selectionItem : m_rulerItem;
_beginTime = m_beginTime + position2time(ruler->left());
_endTime = m_beginTime + position2time(ruler->right());
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())
@ -898,6 +918,9 @@ void BlocksGraphicsView::onWheel(qreal _scenePos, int _wheelDelta)
notifyVisibleRegionSizeChange(); notifyVisibleRegionSizeChange();
// Calculate new offset to simulate QGraphicsView::AnchorUnderMouse scaling behavior // Calculate new offset to simulate QGraphicsView::AnchorUnderMouse scaling behavior
if (m_sceneWidth < m_visibleRegionWidth)
m_offset = 0;
else
m_offset = clamp(0., initialPosition - _scenePos / m_scale, m_sceneWidth - m_visibleRegionWidth); m_offset = clamp(0., initialPosition - _scenePos / m_scale, m_sceneWidth - m_visibleRegionWidth);
// Update slider position // Update slider position
@ -955,6 +978,7 @@ void BlocksGraphicsView::mousePressEvent(QMouseEvent* _event)
m_selectionItem->setLeftRight(mouseX, mouseX); m_selectionItem->setLeftRight(mouseX, mouseX);
m_selectionItem->hide(); m_selectionItem->hide();
m_pScrollbar->hideSelectionIndicator(); m_pScrollbar->hideSelectionIndicator();
emit EASY_GLOBALS.events.rulerVisible(m_rulerItem->isVisible());
} }
} }
@ -984,6 +1008,7 @@ void BlocksGraphicsView::mouseDoubleClickEvent(QMouseEvent* _event)
m_rulerItem->setLeftRight(mouseX, mouseX); m_rulerItem->setLeftRight(mouseX, mouseX);
m_rulerItem->hide(); m_rulerItem->hide();
emit sceneUpdated(); emit sceneUpdated();
emit EASY_GLOBALS.events.rulerVisible(m_selectionItem->isVisible());
} }
_event->accept(); _event->accept();
@ -1010,6 +1035,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
{ {
m_selectionItem->hide(); m_selectionItem->hide();
m_pScrollbar->hideSelectionIndicator(); m_pScrollbar->hideSelectionIndicator();
emit EASY_GLOBALS.events.rulerVisible(m_rulerItem->isVisible());
} }
if (!m_selectedBlocks.empty()) if (!m_selectedBlocks.empty())
@ -1046,6 +1072,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
{ {
chronoHidden = true; chronoHidden = true;
m_rulerItem->hide(); m_rulerItem->hide();
emit EASY_GLOBALS.events.rulerVisible(m_selectionItem->isVisible());
} }
else if (m_selectionItem->isVisible() && m_selectionItem->hoverIndicator()) else if (m_selectionItem->isVisible() && m_selectionItem->hoverIndicator())
{ {
@ -1191,6 +1218,9 @@ void BlocksGraphicsView::addSelectionToHierarchy()
void BlocksGraphicsView::onZoomSelection() void BlocksGraphicsView::onZoomSelection()
{ {
if (m_selectionItem->width() < 1e-6)
return;
auto deltaScale = m_visibleRegionWidth / m_selectionItem->width(); auto deltaScale = m_visibleRegionWidth / m_selectionItem->width();
if (fabs(deltaScale - 1) < 1e-6) if (fabs(deltaScale - 1) < 1e-6)
@ -1229,6 +1259,9 @@ void BlocksGraphicsView::onInspectCurrentView(bool _strict)
m_selectionItem->show(); m_selectionItem->show();
m_pScrollbar->setSelectionPos(m_selectionItem->left(), m_selectionItem->right()); m_pScrollbar->setSelectionPos(m_selectionItem->left(), m_selectionItem->right());
m_pScrollbar->showSelectionIndicator(); m_pScrollbar->showSelectionIndicator();
emit EASY_GLOBALS.events.rulerVisible(true);
addSelectionToHierarchy(); addSelectionToHierarchy();
} }
else else
@ -1281,6 +1314,7 @@ bool BlocksGraphicsView::moveChrono(GraphicsRulerItem* _chronometerItem, qreal _
if (!_chronometerItem->isVisible() && _chronometerItem->width() > 1e-6) if (!_chronometerItem->isVisible() && _chronometerItem->width() > 1e-6)
{ {
_chronometerItem->show(); _chronometerItem->show();
emit EASY_GLOBALS.events.rulerVisible(true);
return true; return true;
} }

View File

@ -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);
} }

View File

@ -122,8 +122,6 @@ struct EasyBlock Q_DECL_FINAL
{ {
} }
private:
EasyBlock(const EasyBlock&) = delete; EasyBlock(const EasyBlock&) = delete;
}; };
#pragma pack(pop) #pragma pack(pop)

View File

@ -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)>())

View File

@ -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;
} }

View File

@ -93,6 +93,7 @@ namespace profiler_gui {
void hexThreadIdChanged(); void hexThreadIdChanged();
void refreshRequired(); void refreshRequired();
void blocksTreeModeChanged(); void blocksTreeModeChanged();
void rulerVisible(bool);
void sceneCleared(); void sceneCleared();
void sceneSizeChanged(qreal left, qreal right); void sceneSizeChanged(qreal left, qreal right);

View File

@ -42,6 +42,7 @@ default/arrow-up-hover.svg - Icon made by Freepik from www.flaticon.com
default/arrow-up-disabled.svg - Icon made by Freepik from www.flaticon.com default/arrow-up-disabled.svg - Icon made by Freepik from www.flaticon.com
default/arrow-left.svg - Icon made by Freepik from www.flaticon.com default/arrow-left.svg - Icon made by Freepik from www.flaticon.com
default/arrow-right.svg - Icon made by Freepik from www.flaticon.com default/arrow-right.svg - Icon made by Freepik from www.flaticon.com
default/crop.svg - Icon made by Freepik from www.flaticon.com
default/yx.svg - Icon made by Freepik from www.flaticon.com default/yx.svg - Icon made by Freepik from www.flaticon.com
default/svg2.svg - Icon made by Freepik from www.flaticon.com default/svg2.svg - Icon made by Freepik from www.flaticon.com
default/svg3.svg - Icon made by Freepik from www.flaticon.com default/svg3.svg - Icon made by Freepik from www.flaticon.com

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="956.815px" height="956.815px" viewBox="0 0 956.815 956.815" style="enable-background:new 0 0 956.815 956.815;"
xml:space="preserve">
<g>
<path fill="#484848" d="M137.621,162.622H20c-11.046,0-20,8.954-20,20v72.919c0,11.046,8.954,20,20,20h117.622L137.621,162.622L137.621,162.622z"/>
<path fill="#484848" d="M774.193,956.815c11.046,0,20-8.954,20-20V819.193H681.274v117.621c0,11.046,8.954,20,20,20L774.193,956.815
L774.193,956.815z"/>
<path fill="#484848" d="M794.193,656.275V182.622c0-11.046-8.954-20-20-20H300.54v112.919h380.734v380.734H794.193z"/>
<path fill="#f44336" d="M936.814,681.275H794.193H681.274H275.54V275.541V162.622V20c0-11.046-8.954-20-20-20h-72.918c-11.046,0-20,8.954-20,20
v142.622v112.919v498.653c0,11.046,8.954,20,20,20h498.653h112.918h142.622c11.045,0,20-8.954,20-20v-72.918
C956.814,690.229,947.86,681.275,936.814,681.275z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -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,12 @@ 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")), "Snapshot");
action->setToolTip("Take a snapshot.\nSave selected area to\nseparate .prof file.");
action->setEnabled(false);
connect(action, &QAction::triggered, this, &This::onSnapshotClicked);
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::rulerVisible, action, &QAction::setEnabled);
toolbar->addSeparator(); toolbar->addSeparator();
auto menu = new QMenu("Settings", this); auto menu = new QMenu("Settings", this);
menu->setToolTipsVisible(true); menu->setToolTipsVisible(true);
@ -547,8 +553,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 +562,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 +571,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 +680,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 +795,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 +969,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 +1124,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 +1188,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 +1386,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 +1407,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 +1536,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 +1566,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 +1845,32 @@ void MainWindow::onListenerDialogClose(int _result)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void MainWindow::onFileReaderTimeout() void MainWindow::closeProgressDialogAndClearReader()
{ {
if (m_reader.done()) m_reader.interrupt();
{ m_readerTimer.stop();
const auto nblocks = m_reader.size(); destroyProgressDialog();
if (nblocks != 0) }
void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
{
_nblocks = m_reader.size();
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 +1922,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
} }
@ -1928,7 +1946,8 @@ void MainWindow::onFileReaderTimeout()
} }
else else
{ {
QMessageBox::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1").arg(m_reader.getError()), QMessageBox::Close); QMessageBox::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1")
.arg(m_reader.getError()), QMessageBox::Close);
if (m_reader.isFile()) if (m_reader.isFile())
{ {
@ -1944,11 +1963,28 @@ void MainWindow::onFileReaderTimeout()
} }
} }
} }
}
m_reader.interrupt(); void MainWindow::onSavingFinish()
{
const auto errorMessage = m_reader.getError();
if (!errorMessage.isEmpty())
{
QMessageBox::warning(this, "Warning", QString("Cannot save profiled blocks.\n\nReason:\n%1")
.arg(errorMessage), QMessageBox::Close);
}
}
m_readerTimer.stop(); void MainWindow::onFileReaderTimeout()
destroyProgressDialog(); {
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 +1993,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 +2033,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 +2067,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 +2088,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 +2102,72 @@ 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,
const profiler::descriptors_list_t& _descriptors, 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 descriptors = std::ref(_descriptors);
auto trees = std::ref(_trees);
m_thread = std::thread([=] (profiler::block_getter_fn getter)
{
const QString tmpFile = m_filename + ".tmp";
const auto result = writeTreesToFile(m_progress, tmpFile.toStdString().c_str(), serializedDescriptors,
descriptors, descriptors_count, trees, getter, _beginTime, _endTime,
_pid, m_errorMessage);
if (result == 0 || !m_errorMessage.str().empty())
{
// Remove temporary file in case of error
QFile::remove(tmpFile);
}
else
{
// Remove old file if exists
{
QFile out(m_filename);
if (out.exists())
out.remove();
}
QFile::rename(tmpFile, m_filename);
}
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 +2181,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 +2247,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 +2263,37 @@ void MainWindow::onFrameTimeChanged()
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void MainWindow::onSnapshotClicked(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, EASY_GLOBALS.descriptors,
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 +2580,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 +2765,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 +2777,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 +2972,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 +3130,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 +3221,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 +3260,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;

View File

@ -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,18 @@ 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, const profiler::descriptors_list_t& _descriptors,
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 +258,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 +347,7 @@ protected slots:
void onEventTracingEnableChange(bool _checked); void onEventTracingEnableChange(bool _checked);
void onFrameTimeEditFinish(); void onFrameTimeEditFinish();
void onFrameTimeChanged(); void onFrameTimeChanged();
void onSnapshotClicked(bool);
void onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status); void onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
@ -339,6 +361,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();

View File

@ -7,6 +7,7 @@
</qresource> </qresource>
<qresource prefix="/images/default"> <qresource prefix="/images/default">
<file alias="binoculars">images/default/binoculars.svg</file> <file alias="binoculars">images/default/binoculars.svg</file>
<file alias="crop">images/default/crop.svg</file>
<file alias="exit">images/default/off.svg</file> <file alias="exit">images/default/off.svg</file>
<file alias="open">images/default/open-folder2.svg</file> <file alias="open">images/default/open-folder2.svg</file>
<file alias="reload">images/default/reload.svg</file> <file alias="reload">images/default/reload.svg</file>

View File

@ -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();