0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-26 16:11: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::thread_blocks_tree_t threaded_trees;
profiler::processid_t pid = 0;
uint32_t total_descriptors_number = 0;
EASY_CONSTEXPR bool DoNotGatherStats = false;
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)
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 <cstring>
#include <cstddef>
#include <stdint.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>
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/details/arbitrary_value_public_types.h>
#include <easy/utility.h>
#include <unordered_map>
#include <vector>
#include <string>
#include <atomic>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace profiler {
using processid_t = uint64_t;
using calls_number_t = uint32_t;
using block_index_t = uint32_t;
#pragma pack(push, 1)
struct BlockStatistics EASY_FINAL
{
::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::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 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::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::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 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
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_children_duration(0)
, min_duration_block(_block_index)
@ -82,7 +86,7 @@ namespace profiler {
//BlockStatistics() = default;
inline ::profiler::timestamp_t average_duration() const
inline profiler::timestamp_t average_duration() const
{
return total_duration / calls_number;
}
@ -100,20 +104,20 @@ namespace profiler {
public:
using blocks_t = ::std::vector<This>;
using children_t = ::std::vector<::profiler::block_index_t>;
using blocks_t = std::vector<This>;
using children_t = std::vector<profiler::block_index_t>;
children_t children; ///< List of children blocks. May be empty.
union {
::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::ArbitraryValue* value; ///< Pointer to serialized data for arbitrary value
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::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_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_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_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)
BlocksTree(const This&) = delete;
@ -132,12 +136,12 @@ namespace profiler {
BlocksTree(This&& that) EASY_NOEXCEPT
: BlocksTree()
{
make_move(::std::forward<This&&>(that));
make_move(std::forward<This&&>(that));
}
This& operator = (This&& that) EASY_NOEXCEPT
{
make_move(::std::forward<This&&>(that));
make_move(std::forward<This&&>(that));
return *this;
}
@ -166,7 +170,7 @@ namespace profiler {
// shrink version 2:
//children_t new_children;
//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);
}
@ -183,7 +187,7 @@ namespace profiler {
if (per_frame_stats != that.per_frame_stats)
release_stats(per_frame_stats);
children = ::std::move(that.children);
children = std::move(that.children);
node = that.node;
per_parent_stats = that.per_parent_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 events; ///< List of events indexes
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 wait_time; ///< Wait time of this thread (sum of all context switches)
::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 blocks_number; ///< Total blocks number including their children
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::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 blocks_number; ///< Total blocks number including their children
uint8_t depth; ///< Maximum stack depth (number of levels)
BlocksTreeRoot(const This&) = delete;
@ -226,10 +230,10 @@ namespace profiler {
}
BlocksTreeRoot(This&& that) EASY_NOEXCEPT
: children(::std::move(that.children))
, sync(::std::move(that.sync))
, events(::std::move(that.events))
, thread_name(::std::move(that.thread_name))
: children(std::move(that.children))
, sync(std::move(that.sync))
, events(std::move(that.events))
, thread_name(std::move(that.thread_name))
, profiled_time(that.profiled_time)
, wait_time(that.wait_time)
, thread_id(that.thread_id)
@ -241,10 +245,10 @@ namespace profiler {
This& operator = (This&& that) EASY_NOEXCEPT
{
children = ::std::move(that.children);
sync = ::std::move(that.sync);
events = ::std::move(that.events);
thread_name = ::std::move(that.thread_name);
children = std::move(that.children);
sync = std::move(that.sync);
events = std::move(that.events);
thread_name = std::move(that.thread_name);
profiled_time = that.profiled_time;
wait_time = that.wait_time;
thread_id = that.thread_id;
@ -271,93 +275,49 @@ namespace profiler {
}; // END of class BlocksTreeRoot.
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 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 block_getter_fn = std::function<const profiler::BlocksTree&(profiler::block_index_t)>;
//////////////////////////////////////////////////////////////////////////
class PROFILER_API SerializedData EASY_FINAL
{
char* m_data;
size_t m_size;
uint64_t m_size;
char* m_data;
public:
SerializedData(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)
{
that.m_data = nullptr;
that.m_size = 0;
}
SerializedData(SerializedData&& that);
~SerializedData()
{
clear();
}
~SerializedData();
void set(uint64_t _size);
void extend(uint64_t _size);
SerializedData& operator = (SerializedData&& that)
{
set(that.m_data, that.m_size);
that.m_data = nullptr;
that.m_size = 0;
return *this;
}
SerializedData& operator = (SerializedData&& that);
char* operator [] (uint64_t i)
{
return m_data + i;
}
char* operator [] (uint64_t i);
const char* operator [] (uint64_t i) const
{
return m_data + i;
}
const char* operator [] (uint64_t i) const;
bool empty() const
{
return m_size == 0;
}
bool empty() const;
uint64_t size() const
{
return m_size;
}
uint64_t size() const;
char* data()
{
return m_data;
}
char* data();
const char* data() const
{
return m_data;
}
const char* data() const;
void clear()
{
set(nullptr, 0);
}
void clear();
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;
}
void swap(SerializedData& other);
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.
extern "C" {
PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
::profiler::SerializedData& serialized_blocks,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors,
profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
uint32_t& version,
profiler::processid_t& pid,
bool gather_statistics,
std::ostream& _log);
PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& str,
profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors,
profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
uint32_t& version,
profiler::processid_t& pid,
bool gather_statistics,
::std::stringstream& _log);
std::ostream& _log);
PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
::profiler::SerializedData& serialized_blocks,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
uint32_t& version,
bool gather_statistics,
::std::stringstream& _log);
PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& str,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors,
std::ostream& _log);
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::std::stringstream& _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,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
uint32_t& version,
bool gather_statistics,
::std::stringstream& _log)
inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors, profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees,
uint32_t& total_descriptors_number,
uint32_t& version,
profiler::processid_t& pid,
bool gather_statistics,
std::ostream& _log)
{
::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);
std::atomic<int> progress = ATOMIC_VAR_INIT(0);
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,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::std::stringstream& _log)
inline profiler::block_index_t writeTreesToFile(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)
{
::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);
}

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;
@ -79,14 +79,15 @@ class ProfileManager
ProfileManager();
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
typedef std::map<profiler::thread_id_t, ThreadStorage> map_of_threads_stacks;
typedef std::vector<BlockDescriptor*> block_descriptors_t;
using atomic_timestamp_t = std::atomic<profiler::timestamp_t>;
using guard_lock_t = profiler::guard_lock<profiler::spin_lock>;
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
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
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
const processid_t m_processId;
@ -97,9 +98,9 @@ class ProfileManager
uint64_t m_descriptorsMemorySize;
profiler::timestamp_t m_beginTime;
profiler::timestamp_t m_endTime;
std::atomic<profiler::timestamp_t> m_frameMax;
std::atomic<profiler::timestamp_t> m_frameAvg;
std::atomic<profiler::timestamp_t> m_frameCur;
atomic_timestamp_t m_frameMax;
atomic_timestamp_t m_frameAvg;
atomic_timestamp_t m_frameCur;
profiler::spin_lock m_spin;
profiler::spin_lock m_storedSpin;
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;
emit EASY_GLOBALS.events.selectedThreadChanged(0);
emit EASY_GLOBALS.events.rulerVisible(false);
}
void BlocksGraphicsView::notifySceneSizeChange()
@ -438,7 +440,10 @@ void BlocksGraphicsView::notifyVisibleRegionPosChange()
void BlocksGraphicsView::notifyVisibleRegionPosChange(qreal _pos)
{
m_offset = estd::clamp(0., _pos, m_sceneWidth - m_visibleRegionWidth);
if (m_sceneWidth < m_visibleRegionWidth)
m_offset = 0;
else
m_offset = estd::clamp(0., _pos, m_sceneWidth - m_visibleRegionWidth);
notifyVisibleRegionPosChange();
}
@ -614,6 +619,21 @@ const BlocksGraphicsView::Items &BlocksGraphicsView::getItems() const
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)
{
if (_children.empty())
@ -898,7 +918,10 @@ void BlocksGraphicsView::onWheel(qreal _scenePos, int _wheelDelta)
notifyVisibleRegionSizeChange();
// Calculate new offset to simulate QGraphicsView::AnchorUnderMouse scaling behavior
m_offset = clamp(0., initialPosition - _scenePos / m_scale, m_sceneWidth - m_visibleRegionWidth);
if (m_sceneWidth < m_visibleRegionWidth)
m_offset = 0;
else
m_offset = clamp(0., initialPosition - _scenePos / m_scale, m_sceneWidth - m_visibleRegionWidth);
// Update slider position
profiler_gui::BoolFlagGuard guard(m_bUpdatingRect, true); // To be sure that updateVisibleSceneRect will not be called by scrollbar change
@ -955,6 +978,7 @@ void BlocksGraphicsView::mousePressEvent(QMouseEvent* _event)
m_selectionItem->setLeftRight(mouseX, mouseX);
m_selectionItem->hide();
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->hide();
emit sceneUpdated();
emit EASY_GLOBALS.events.rulerVisible(m_selectionItem->isVisible());
}
_event->accept();
@ -1010,6 +1035,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
{
m_selectionItem->hide();
m_pScrollbar->hideSelectionIndicator();
emit EASY_GLOBALS.events.rulerVisible(m_rulerItem->isVisible());
}
if (!m_selectedBlocks.empty())
@ -1046,6 +1072,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
{
chronoHidden = true;
m_rulerItem->hide();
emit EASY_GLOBALS.events.rulerVisible(m_selectionItem->isVisible());
}
else if (m_selectionItem->isVisible() && m_selectionItem->hoverIndicator())
{
@ -1191,6 +1218,9 @@ void BlocksGraphicsView::addSelectionToHierarchy()
void BlocksGraphicsView::onZoomSelection()
{
if (m_selectionItem->width() < 1e-6)
return;
auto deltaScale = m_visibleRegionWidth / m_selectionItem->width();
if (fabs(deltaScale - 1) < 1e-6)
@ -1229,6 +1259,9 @@ void BlocksGraphicsView::onInspectCurrentView(bool _strict)
m_selectionItem->show();
m_pScrollbar->setSelectionPos(m_selectionItem->left(), m_selectionItem->right());
m_pScrollbar->showSelectionIndicator();
emit EASY_GLOBALS.events.rulerVisible(true);
addSelectionToHierarchy();
}
else
@ -1281,6 +1314,7 @@ bool BlocksGraphicsView::moveChrono(GraphicsRulerItem* _chronometerItem, qreal _
if (!_chronometerItem->isVisible() && _chronometerItem->width() > 1e-6)
{
_chronometerItem->show();
emit EASY_GLOBALS.events.rulerVisible(true);
return true;
}

View File

@ -190,6 +190,8 @@ public:
const Items& getItems() const;
bool getSelectionRegionForSaving(profiler::timestamp_t& _beginTime, profiler::timestamp_t& _endTime) const;
void inspectCurrentView(bool _strict) {
onInspectCurrentView(_strict);
}

View File

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

View File

@ -79,6 +79,7 @@ namespace profiler_gui {
Globals::Globals()
: theme("default")
, pid(0)
, begin_time(0)
, selected_thread(0U)
, 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
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::thread_id_t selected_thread; ///< Current selected thread id
::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];
}
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) {
return easyBlock(i).tree;
}

View File

@ -93,6 +93,7 @@ namespace profiler_gui {
void hexThreadIdChanged();
void refreshRequired();
void blocksTreeModeChanged();
void rulerVisible(bool);
void sceneCleared();
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-left.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/svg2.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();
}
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); }
@ -378,6 +378,12 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
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();
auto menu = new QMenu("Settings", this);
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->setToolTip("Draw duration of selected interval\nat the top of the screen.");
action->setCheckable(true);
action->setData(static_cast<int>(::profiler_gui::ChronoTextPosition_Top));
if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Top)
action->setData(static_cast<int>(profiler_gui::ChronoTextPosition_Top));
if (EASY_GLOBALS.chrono_text_position == profiler_gui::ChronoTextPosition_Top)
action->setChecked(true);
submenu->addAction(action);
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->setToolTip("Draw duration of selected interval\nat the center of the screen.");
action->setCheckable(true);
action->setData(static_cast<int>(::profiler_gui::ChronoTextPosition_Center));
if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Center)
action->setData(static_cast<int>(profiler_gui::ChronoTextPosition_Center));
if (EASY_GLOBALS.chrono_text_position == profiler_gui::ChronoTextPosition_Center)
action->setChecked(true);
submenu->addAction(action);
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->setToolTip("Draw duration of selected interval\nat the bottom of the screen.");
action->setCheckable(true);
action->setData(static_cast<int>(::profiler_gui::ChronoTextPosition_Bottom));
if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Bottom)
action->setData(static_cast<int>(profiler_gui::ChronoTextPosition_Bottom));
if (EASY_GLOBALS.chrono_text_position == profiler_gui::ChronoTextPosition_Bottom)
action->setChecked(true);
submenu->addAction(action);
connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged);
@ -674,32 +680,32 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos
actionGroup->setExclusive(true);
action = new QAction("Auto", actionGroup);
action->setCheckable(true);
action->setData(static_cast<int>(::profiler_gui::TimeUnits_auto));
if (EASY_GLOBALS.time_units == ::profiler_gui::TimeUnits_auto)
action->setData(static_cast<int>(profiler_gui::TimeUnits_auto));
if (EASY_GLOBALS.time_units == profiler_gui::TimeUnits_auto)
action->setChecked(true);
submenu->addAction(action);
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
action = new QAction("Milliseconds", actionGroup);
action->setCheckable(true);
action->setData(static_cast<int>(::profiler_gui::TimeUnits_ms));
if (EASY_GLOBALS.time_units == ::profiler_gui::TimeUnits_ms)
action->setData(static_cast<int>(profiler_gui::TimeUnits_ms));
if (EASY_GLOBALS.time_units == profiler_gui::TimeUnits_ms)
action->setChecked(true);
submenu->addAction(action);
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
action = new QAction("Microseconds", actionGroup);
action->setCheckable(true);
action->setData(static_cast<int>(::profiler_gui::TimeUnits_us));
if (EASY_GLOBALS.time_units == ::profiler_gui::TimeUnits_us)
action->setData(static_cast<int>(profiler_gui::TimeUnits_us));
if (EASY_GLOBALS.time_units == profiler_gui::TimeUnits_us)
action->setChecked(true);
submenu->addAction(action);
connect(action, &QAction::triggered, this, &This::onUnitsChanged);
action = new QAction("Nanoseconds", actionGroup);
action->setCheckable(true);
action->setData(static_cast<int>(::profiler_gui::TimeUnits_ns));
if (EASY_GLOBALS.time_units == ::profiler_gui::TimeUnits_ns)
action->setData(static_cast<int>(profiler_gui::TimeUnits_ns));
if (EASY_GLOBALS.time_units == profiler_gui::TimeUnits_ns)
action->setChecked(true);
submenu->addAction(action);
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->setText(QString::number(EASY_GLOBALS.frame_time * 1e-3));
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);
lbl = new QLabel("ms", toolbar);
lbl->setContentsMargins(5, 2, 1, 1);
toolbar->addWidget(lbl);
m_readerTimer.setInterval(LOADER_TIMER_INTERVAL);
connect(graphicsView->view(), &BlocksGraphicsView::intervalChanged, treeWidget->tree(), &BlocksTreeWidget::setTreeBlocks);
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)));
m_readerTimer.start(LOADER_TIMER_INTERVAL);
m_readerTimer.start();
m_reader.load(filename);
}
void MainWindow::readStream(std::stringstream& _data)
{
createProgressDialog(tr("Reading from stream..."));
m_readerTimer.start(LOADER_TIMER_INTERVAL);
m_readerTimer.start();
m_reader.load(_data);
}
@ -1117,8 +1124,8 @@ void MainWindow::clear()
emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
EASY_GLOBALS.selected_thread = 0;
::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);
profiler_gui::set_max(EASY_GLOBALS.selected_block_id);
EASY_GLOBALS.profiler_blocks.clear();
EASY_GLOBALS.descriptors.clear();
EASY_GLOBALS.gui_blocks.clear();
@ -1181,14 +1188,14 @@ void MainWindow::onEncodingChanged(bool)
void MainWindow::onChronoTextPosChanged(bool)
{
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();
}
void MainWindow::onUnitsChanged(bool)
{
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)
@ -1379,7 +1386,7 @@ void MainWindow::closeEvent(QCloseEvent* close_event)
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");
auto last_files = settings.value("last_files");
@ -1400,11 +1407,11 @@ void MainWindow::loadSettings()
auto val = settings.value("chrono_text_position");
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");
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");
@ -1529,7 +1536,7 @@ void MainWindow::loadSettings()
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");
auto geometry = settings.value("geometry").toByteArray();
@ -1559,7 +1566,7 @@ void MainWindow::loadGeometry()
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.setValue("geometry", this->saveGeometry());
@ -1838,123 +1845,162 @@ void MainWindow::onListenerDialogClose(int _result)
//////////////////////////////////////////////////////////////////////////
void MainWindow::closeProgressDialogAndClearReader()
{
m_reader.interrupt();
m_readerTimer.stop();
destroyProgressDialog();
}
void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks)
{
_nblocks = m_reader.size();
if (_nblocks != 0)
{
emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
profiler::SerializedData serialized_blocks;
profiler::SerializedData serialized_descriptors;
profiler::descriptors_list_t descriptors;
profiler::blocks_t blocks;
profiler::thread_blocks_tree_t threads_map;
QString filename;
uint32_t descriptorsNumberInFile = 0;
uint32_t version = 0;
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 (m_reader.isFile())
qWarning() << "Warning: file " << filename << " contains " << threads_map.size() << " threads!";
else
qWarning() << "Warning: input stream contains " << threads_map.size() << " threads!";
qWarning() << "Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed.";
}
m_bNetworkFileRegime = !m_reader.isFile();
if (!m_bNetworkFileRegime)
{
auto index = m_lastFiles.indexOf(filename, 0);
if (index == -1)
{
// This file is totally new. Add it to the list.
addFileToList(filename);
}
else
{
if (index != 0)
{
// This file has been already loaded. Move it to the front.
m_lastFiles.move(index, 0);
auto fileActions = m_loadActionMenu->actions();
auto action = fileActions.at(index);
m_loadActionMenu->removeAction(action);
m_loadActionMenu->insertAction(fileActions.front(), action);
validateLastDir();
}
m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE);
if (m_bOpenedCacheFile)
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(filename));
else
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(filename));
}
}
else
{
m_bOpenedCacheFile = false;
setWindowTitle(EASY_DEFAULT_WINDOW_TITLE " - UNSAVED network cache");
}
m_serializedBlocks = std::move(serialized_blocks);
m_serializedDescriptors = std::move(serialized_descriptors);
m_descriptorsNumberInFile = descriptorsNumberInFile;
EASY_GLOBALS.selected_thread = 0;
EASY_GLOBALS.version = version;
EASY_GLOBALS.pid = pid;
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.descriptors.swap(descriptors);
EASY_GLOBALS.gui_blocks.clear();
EASY_GLOBALS.gui_blocks.resize(_nblocks);
memset(EASY_GLOBALS.gui_blocks.data(), 0, sizeof(profiler_gui::EasyBlock) * _nblocks);
for (std::remove_reference<decltype(_nblocks)>::type i = 0; i < _nblocks; ++i)
{
auto& guiblock = EASY_GLOBALS.gui_blocks[i];
guiblock.tree = std::move(blocks[i]);
#ifdef EASY_TREE_WIDGET__USE_VECTOR
profiler_gui::set_max(guiblock.tree_item);
#endif
}
m_saveAction->setEnabled(true);
m_deleteAction->setEnabled(true);
}
else
{
QMessageBox::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1")
.arg(m_reader.getError()), QMessageBox::Close);
if (m_reader.isFile())
{
auto index = m_lastFiles.indexOf(m_reader.filename(), 0);
if (index >= 0)
{
// Remove unexisting file from list
m_lastFiles.removeAt(index);
auto action = m_loadActionMenu->actions().at(index);
m_loadActionMenu->removeAction(action);
delete action;
validateLastDir();
}
}
}
}
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);
}
}
void MainWindow::onFileReaderTimeout()
{
if (m_reader.done())
{
const auto nblocks = m_reader.size();
if (nblocks != 0)
if (m_reader.isLoading())
{
emit EASY_GLOBALS.events.allDataGoingToBeDeleted();
profiler::block_index_t nblocks = 0;
::profiler::SerializedData serialized_blocks;
::profiler::SerializedData serialized_descriptors;
::profiler::descriptors_list_t descriptors;
::profiler::blocks_t blocks;
::profiler::thread_blocks_tree_t threads_map;
QString filename;
uint32_t descriptorsNumberInFile = 0;
uint32_t version = 0;
m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map, descriptorsNumberInFile, version, filename);
onLoadingFinish(nblocks);
closeProgressDialogAndClearReader();
if (threads_map.size() > 0xff)
if (nblocks != 0)
{
if (m_reader.isFile())
qWarning() << "Warning: file " << filename << " contains " << threads_map.size() << " threads!";
else
qWarning() << "Warning: input stream contains " << threads_map.size() << " threads!";
qWarning() << "Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed.";
emit EASY_GLOBALS.events.fileOpened();
if (EASY_GLOBALS.all_items_expanded_by_default)
onExpandAllClicked(true);
}
m_bNetworkFileRegime = !m_reader.isFile();
if (!m_bNetworkFileRegime)
{
auto index = m_lastFiles.indexOf(filename, 0);
if (index == -1)
{
// This file is totally new. Add it to the list.
addFileToList(filename);
}
else
{
if (index != 0)
{
// This file has been already loaded. Move it to the front.
m_lastFiles.move(index, 0);
auto fileActions = m_loadActionMenu->actions();
auto action = fileActions.at(index);
m_loadActionMenu->removeAction(action);
m_loadActionMenu->insertAction(fileActions.front(), action);
validateLastDir();
}
m_bOpenedCacheFile = filename.contains(NETWORK_CACHE_FILE);
if (m_bOpenedCacheFile)
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1] - UNSAVED network cache file").arg(filename));
else
setWindowTitle(QString(EASY_DEFAULT_WINDOW_TITLE " - [%1]").arg(filename));
}
}
else
{
m_bOpenedCacheFile = false;
setWindowTitle(EASY_DEFAULT_WINDOW_TITLE " - UNSAVED network cache");
}
m_serializedBlocks = std::move(serialized_blocks);
m_serializedDescriptors = std::move(serialized_descriptors);
m_descriptorsNumberInFile = descriptorsNumberInFile;
EASY_GLOBALS.selected_thread = 0;
EASY_GLOBALS.version = version;
::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.descriptors.swap(descriptors);
EASY_GLOBALS.gui_blocks.clear();
EASY_GLOBALS.gui_blocks.resize(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) {
auto& guiblock = EASY_GLOBALS.gui_blocks[i];
guiblock.tree = std::move(blocks[i]);
#ifdef EASY_TREE_WIDGET__USE_VECTOR
::profiler_gui::set_max(guiblock.tree_item);
#endif
}
m_saveAction->setEnabled(true);
m_deleteAction->setEnabled(true);
}
else if (m_reader.isSaving())
{
onSavingFinish();
closeProgressDialogAndClearReader();
}
else
{
QMessageBox::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1").arg(m_reader.getError()), QMessageBox::Close);
if (m_reader.isFile())
{
auto index = m_lastFiles.indexOf(m_reader.filename(), 0);
if (index >= 0)
{
// Remove unexisting file from list
m_lastFiles.removeAt(index);
auto action = m_loadActionMenu->actions().at(index);
m_loadActionMenu->removeAction(action);
delete action;
validateLastDir();
}
}
}
m_reader.interrupt();
m_readerTimer.stop();
destroyProgressDialog();
if (nblocks != 0)
{
emit EASY_GLOBALS.events.fileOpened();
if (EASY_GLOBALS.all_items_expanded_by_default)
onExpandAllClicked(true);
closeProgressDialogAndClearReader();
}
}
else if (m_progress != nullptr)
@ -1987,6 +2033,16 @@ const bool FileReader::isFile() const
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
{
return m_bDone.load(std::memory_order_acquire);
@ -2011,13 +2067,20 @@ void FileReader::load(const QString& _filename)
{
interrupt();
m_jobType = JobType::Loading;
m_isFile = true;
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_descriptors, m_blocks, m_blocksTree, m_descriptorsNumberInFile, m_version, _enableStatistics, m_errorMessage), std::memory_order_release);
m_thread = std::thread([this](bool _enableStatistics)
{
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_bDone.store(true, std::memory_order_release);
}, EASY_GLOBALS.enable_statistics);
}
@ -2025,6 +2088,7 @@ void FileReader::load(std::stringstream& _stream)
{
interrupt();
m_jobType = JobType::Loading;
m_isFile = false;
m_filename.clear();
@ -2038,19 +2102,72 @@ void FileReader::load(std::stringstream& _stream)
m_stream.swap(_stream);
#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);
if (cache_file.is_open()) {
if (cache_file.is_open())
{
cache_file << m_stream.str();
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_bDone.store(true, std::memory_order_release);
}, 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()
{
join();
@ -2064,25 +2181,29 @@ void FileReader::interrupt()
m_blocksTree.clear();
m_descriptorsNumberInFile = 0;
m_version = 0;
m_pid = 0;
m_jobType = JobType::Idle;
clear_stream(m_stream);
clear_stream(m_errorMessage);
}
void FileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors,
::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& _tree, uint32_t& _descriptorsNumberInFile, uint32_t& _version, QString& _filename)
void FileReader::get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& _trees, uint32_t& _descriptorsNumberInFile, uint32_t& _version,
profiler::processid_t& _pid, QString& _filename)
{
if (done())
{
m_serializedBlocks.swap(_serializedBlocks);
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_blocksTree.swap(_tree);
m_blocksTree.swap(_trees);
m_filename.swap(_filename);
_descriptorsNumberInFile = m_descriptorsNumberInFile;
_version = m_version;
_pid = m_pid;
}
}
@ -2126,12 +2247,12 @@ void MainWindow::onFrameTimeEditFinish()
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);
emit EASY_GLOBALS.events.expectedFrameTimeChanged();
connect(&EASY_GLOBALS.events, &::profiler_gui::GlobalSignals::expectedFrameTimeChanged,
connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::expectedFrameTimeChanged,
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)
{
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)
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;
}
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)
_reply = *message;
@ -2625,7 +2777,7 @@ bool SocketListener::connect(const char* _ipaddress, uint16_t _port, profiler::n
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);
}
@ -2820,7 +2972,7 @@ void SocketListener::listenCapture()
if (bytes > 0)
{
auto message = reinterpret_cast<const ::profiler::net::Message*>(buf);
auto message = reinterpret_cast<const profiler::net::Message*>(buf);
if (!message->isEasyNetMessage())
continue;
@ -2978,7 +3130,7 @@ void SocketListener::listenDescription()
if (bytes > 0)
{
auto message = reinterpret_cast<const ::profiler::net::Message*>(buf);
auto message = reinterpret_cast<const profiler::net::Message*>(buf);
if (!message->isEasyNetMessage())
continue;
@ -3069,7 +3221,7 @@ void SocketListener::listenDescription()
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] = {};
int seek = 0, bytes = 0;
@ -3108,7 +3260,7 @@ void SocketListener::listenFrameTime()
if (bytes > 0)
{
auto message = reinterpret_cast<const ::profiler::net::Message*>(buf);
auto message = reinterpret_cast<const profiler::net::Message*>(buf);
if (!message->isEasyNetMessage())
continue;

View File

@ -54,10 +54,10 @@
#ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H
#define EASY_PROFILER_GUI__MAIN_WINDOW__H
#include <string>
#include <thread>
#include <atomic>
#include <sstream>
#include <string>
#include <thread>
#include <QMainWindow>
#include <QDockWidget>
@ -85,6 +85,13 @@ namespace profiler { namespace net { struct EasyProfilerStatus; } }
class FileReader Q_DECL_FINAL
{
enum class JobType : int8_t
{
Idle=0,
Loading,
Saving,
};
profiler::SerializedData m_serializedBlocks; ///<
profiler::SerializedData m_serializedDescriptors; ///<
profiler::descriptors_list_t m_descriptors; ///<
@ -93,12 +100,14 @@ class FileReader Q_DECL_FINAL
std::stringstream m_stream; ///<
std::stringstream m_errorMessage; ///<
QString m_filename; ///<
profiler::processid_t m_pid = 0; ///<
uint32_t m_descriptorsNumberInFile = 0; ///<
uint32_t m_version = 0; ///<
std::thread m_thread; ///<
std::atomic_bool m_bDone; ///<
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; ///<
public:
@ -107,6 +116,9 @@ public:
~FileReader();
const bool isFile() const;
const bool isSaving() const;
const bool isLoading() const;
bool done() const;
int progress() const;
unsigned int size() const;
@ -114,10 +126,18 @@ public:
void load(const QString& _filename);
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 get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _tree,
uint32_t& _descriptorsNumberInFile, uint32_t& _version, QString& _filename);
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _trees,
uint32_t& _descriptorsNumberInFile, uint32_t& _version, profiler::processid_t& _pid, QString& _filename);
void join();
@ -238,42 +258,43 @@ protected:
QStringList m_lastFiles;
QString m_theme;
QString m_lastAddress;
QDockWidget* m_treeWidget = nullptr;
QDockWidget* m_graphicsView = nullptr;
QDockWidget* m_fpsViewer = nullptr;
QDockWidget* m_treeWidget = nullptr;
QDockWidget* m_graphicsView = nullptr;
QDockWidget* m_fpsViewer = nullptr;
#if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
QDockWidget* m_descTreeWidget = nullptr;
#endif
class QProgressDialog* m_progress = nullptr;
class BlockDescriptorsWidget* m_dialogDescTree = nullptr;
class QMessageBox* m_listenerDialog = nullptr;
class QProgressDialog* m_progress = nullptr;
class BlockDescriptorsWidget* m_dialogDescTree = nullptr;
class QMessageBox* m_listenerDialog = nullptr;
QTimer m_readerTimer;
QTimer m_listenerTimer;
QTimer m_fpsRequestTimer;
profiler::SerializedData m_serializedBlocks;
profiler::SerializedData m_serializedDescriptors;
FileReader m_reader;
SocketListener m_listener;
profiler::SerializedData m_serializedBlocks;
profiler::SerializedData m_serializedDescriptors;
FileReader m_reader;
SocketListener m_listener;
class QLineEdit* m_addressEdit = nullptr;
class QLineEdit* m_portEdit = nullptr;
class QLineEdit* m_addressEdit = nullptr;
class QLineEdit* m_portEdit = nullptr;
class QLineEdit* m_frameTimeEdit = nullptr;
class QMenu* m_loadActionMenu = nullptr;
class QAction* m_saveAction = nullptr;
class QAction* m_deleteAction = nullptr;
class QAction* m_saveAction = nullptr;
class QAction* m_deleteAction = nullptr;
class QAction* m_captureAction = nullptr;
class QAction* m_connectAction = nullptr;
class QAction* m_eventTracingEnableAction = nullptr;
class QAction* m_captureAction = nullptr;
class QAction* m_connectAction = nullptr;
class QAction* m_eventTracingEnableAction = nullptr;
class QAction* m_eventTracingPriorityAction = nullptr;
uint32_t m_descriptorsNumberInFile = 0;
uint16_t m_lastPort = 0;
bool m_bNetworkFileRegime = false;
bool m_bOpenedCacheFile = false;
uint16_t m_lastPort = 0;
bool m_bNetworkFileRegime = false;
bool m_bOpenedCacheFile = false;
public:
@ -326,6 +347,7 @@ protected slots:
void onEventTracingEnableChange(bool _checked);
void onFrameTimeEditFinish();
void onFrameTimeChanged();
void onSnapshotClicked(bool);
void onBlockStatusChange(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
@ -339,6 +361,10 @@ private:
// Private non-virtual methods
void closeProgressDialogAndClearReader();
void onLoadingFinish(profiler::block_index_t& _nblocks);
void onSavingFinish();
void configureSizes();
void clear();

View File

@ -7,6 +7,7 @@
</qresource>
<qresource prefix="/images/default">
<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="open">images/default/open-folder2.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){
@ -72,7 +72,7 @@ void printTree(TreePrinter& printer, const ::profiler::BlocksTree& tree, int lev
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";
if (argc > 1 && argv[1])
@ -110,14 +110,15 @@ int main(int argc, char* argv[])
auto start = std::chrono::system_clock::now();
::profiler::SerializedData serialized_blocks, serialized_descriptors;
::profiler::descriptors_list_t descriptors;
::profiler::blocks_t blocks;
::std::stringstream errorMessage;
profiler::SerializedData serialized_blocks, serialized_descriptors;
profiler::descriptors_list_t descriptors;
profiler::blocks_t blocks;
std::stringstream errorMessage;
uint32_t descriptorsNumberInFile = 0;
uint32_t version = 0;
profiler::processid_t pid = 0;
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)
std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str();