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

Merge branch 'event_tracing' into develop

This commit is contained in:
Sergey Yagovtsev 2016-09-07 22:03:13 +03:00
commit 2cff79886d
37 changed files with 4650 additions and 2854 deletions

View File

@ -2,8 +2,8 @@ project(profiling_tool)
cmake_minimum_required(VERSION 2.8)
set(
ROOT
${CMAKE_CURRENT_LIST_DIR}
ROOT
${CMAKE_CURRENT_LIST_DIR}
)
set(OUTPUT_DIR
@ -23,16 +23,16 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
)
include_directories(
include
include
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-reorder -pedantic -O3" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-reorder -pedantic -O3" )
else()
add_definitions(
-D_CRT_SECURE_NO_WARNINGS
)
add_definitions(
-D_CRT_SECURE_NO_WARNINGS
)
endif(UNIX)
add_subdirectory(src)

View File

@ -0,0 +1,27 @@
#ifndef EASY_PROFILER__EVENT_TRACE_STATUS__H_
#define EASY_PROFILER__EVENT_TRACE_STATUS__H_
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler {
enum EventTracingEnableStatus : unsigned char
{
EVENT_TRACING_LAUNCHED_SUCCESSFULLY = 0,
EVENT_TRACING_NOT_ENOUGH_ACCESS_RIGHTS,
EVENT_TRACING_WAS_LAUNCHED_BY_SOMEBODY_ELSE,
EVENT_TRACING_BAD_PROPERTIES_SIZE,
EVENT_TRACING_OPEN_TRACE_ERROR,
EVENT_TRACING_MISTERIOUS_ERROR,
};
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__EVENT_TRACE_STATUS__H_

View File

@ -16,379 +16,338 @@ You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef ____PROFILER____H_______
#define ____PROFILER____H_______
#ifndef EASY_PROFILER____H_______
#define EASY_PROFILER____H_______
#define TOKEN_JOIN(x, y) x ## y
#define TOKEN_CONCATENATE(x, y) TOKEN_JOIN(x, y)
#ifdef _WIN32
# define __func__ __FUNCTION__
# if defined(_MSC_VER) && _MSC_VER <= 1800
// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead.
# define EASY_THREAD_LOCAL __declspec(thread)
# endif
#elif defined(__GNUC__)
#ifndef __clang__
# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4)
// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead.
# define EASY_THREAD_LOCAL __thread
#endif
# endif
#if defined ( __clang__ )
# if (__clang_major__ == 3 && __clang_minor__ < 3) || (__clang_major__ < 3)
# define EASY_THREAD_LOCAL __thread
#endif
#endif
#if defined ( WIN32 )
#define __func__ __FUNCTION__
#endif
// TODO: Check thread local support for clanv earlier than 3.3
#ifndef EASY_THREAD_LOCAL
# define EASY_THREAD_LOCAL thread_local
# define EASY_THREAD_LOCAL_CPP11
#endif
#if defined ( __clang__ )
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
#ifndef FULL_DISABLE_PROFILER
#include <type_traits>
#define EASY_TOKEN_JOIN(x, y) x ## y
#define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y)
#define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x)
#define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x)
/**
\defgroup profiler Profiler
*/
/** Macro of beginning of block with custom name and default identification
namespace profiler {
template <const bool IS_REF> struct NameSwitch final {
static const char* runtime_name(const char* name) { return name; }
static const char* compiletime_name(const char*) { return ""; }
};
template <> struct NameSwitch<true> final {
static const char* runtime_name(const char*) { return ""; }
static const char* compiletime_name(const char* name) { return name; }
};
} // END of namespace profiler.
#define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::compiletime_name(name)
#define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::runtime_name(name)
/** Macro of beginning of block with custom name and color.
\code
#include "profiler/profiler.h"
void foo()
{
// some code ...
if(something){
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()");
someThirdPartyLongFunction();
return;
}
}
#include "profiler/profiler.h"
void foo()
{
// some code ...
if(something){
EASY_BLOCK("Calling bar()"); // Block with default color
bar();
}
else{
EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block
baz();
}
}
\endcode
Block will be automatically completed by destructor
Block will be automatically completed by destructor.
\ingroup profiler
*/
#define PROFILER_BEGIN_BLOCK(name)\
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,profiler::colors::Clay,profiler::BLOCK_TYPE_BLOCK,\
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
#define EASY_BLOCK(name, ...)\
static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
/** Macro of beginning of block with custom name and custom identification
/** Macro of beginning of block with function name and custom color.
\code
#include "profiler/profiler.h"
void foo()
{
// some code ...
if(something){
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()",profiler::colors::Red);
someThirdPartyLongFunction();
return;
}
}
#include "profiler/profiler.h"
void foo(){
EASY_FUNCTION(); // Block with name="foo" and default color
//some code...
}
void bar(){
EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar"
//some code...
}
\endcode
Block will be automatically completed by destructor
Name of the block automatically created with function name.
\ingroup profiler
*/
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)\
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_BLOCK,\
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
#define EASY_FUNCTION(...)\
static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(__func__, __FILE__, __LINE__,\
::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), "");\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
/** Macro of beginning of function block with default identification
\code
#include "profiler/profiler.h"
void foo()
{
PROFILER_BEGIN_FUNCTION_BLOCK;
//some code...
}
\endcode
Name of block automatically created with function name
\ingroup profiler
*/
#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__)
/** Macro of beginning of function block with custom identification
\code
#include "profiler/profiler.h"
void foo()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
//some code...
}
\endcode
Name of block automatically created with function name
\ingroup profiler
*/
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_color) PROFILER_BEGIN_BLOCK_GROUPED(__func__,block_color)
/** Macro of completion of last nearest open block
/** Macro of completion of last nearest open block.
\code
#include "profiler/profiler.h"
void foo()
int foo()
{
// some code ...
int sum = 0;
PROFILER_BEGIN_BLOCK("Calculating summ");
for(int i = 0; i < 10; i++){
sum += i;
}
PROFILER_END_BLOCK;
// some code ...
int sum = 0;
EASY_BLOCK("Calculating sum");
for (int i = 0; i < 10; ++i){
sum += i;
}
EASY_END_BLOCK;
// some antoher code here ...
return sum;
}
\endcode
\ingroup profiler
*/
#define PROFILER_END_BLOCK profiler::endBlock();
#define EASY_END_BLOCK ::profiler::endBlock();
#define PROFILER_ADD_EVENT(name) \
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,0,profiler::BLOCK_TYPE_EVENT,\
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
/** Macro of creating event with custom name and color.
#define PROFILER_ADD_EVENT_GROUPED(name,block_group)\
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_EVENT,\
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
Event is a block with zero duration and special type.
\warning Event ends immidiately and calling EASY_END_BLOCK after EASY_EVENT
will end previously opened EASY_BLOCK or EASY_FUNCTION.
\ingroup profiler
*/
#define EASY_EVENT(name, ...)\
static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
::profiler::BLOCK_TYPE_EVENT , ## __VA_ARGS__);\
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
/** Macro enabling profiler
\ingroup profiler
*/
#define PROFILER_ENABLE profiler::setEnabled(true);
#define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
/** Macro disabling profiler
\ingroup profiler
*/
#define PROFILER_DISABLE profiler::setEnabled(false);
#define EASY_PROFILER_DISABLE ::profiler::setEnabled(false);
#ifdef WIN32
#define PROFILER_SET_THREAD_NAME(name) profiler::setThreadName(name);
#else
#define PROFILER_SET_THREAD_NAME(name) thread_local static const profiler::ThreadNameSetter TOKEN_CONCATENATE(unique_profiler_thread_name_setter_,__LINE__)(name);
#endif
/** Macro of naming current thread.
#define PROFILER_SET_MAIN_THREAD PROFILER_SET_THREAD_NAME("Main")
If this thread has been already named then nothing changes.
\ingroup profiler
*/
#define EASY_THREAD(name)\
EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\
if (EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) == nullptr)\
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::setThreadName(name, __FILE__, __func__, __LINE__);
/** Macro of naming main thread.
This is only for user comfort. There is no difference for EasyProfiler GUI between different threads.
\ingroup profiler
*/
#define EASY_MAIN_THREAD EASY_THREAD("Main")
#else
#define PROFILER_ADD_MARK(name)
#define PROFILER_ADD_MARK_GROUPED(name,block_group)
#define PROFILER_BEGIN_BLOCK(name)
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)
#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__)
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_group) PROFILER_BEGIN_BLOCK_GROUPED(__func__,block_group)
#define PROFILER_END_BLOCK profiler::endBlock();
#define PROFILER_ENABLE profiler::setEnabled(true);
#define PROFILER_DISABLE profiler::setEnabled(false);
#define PROFILER_ADD_EVENT(name)
#define PROFILER_ADD_EVENT_GROUPED(name,block_group)
#define PROFILER_SET_THREAD_NAME(name)
#define PROFILER_SET_MAIN_THREAD
#define EASY_BLOCK(...)
#define EASY_FUNCTION(...)
#define EASY_END_BLOCK
#define EASY_PROFILER_ENABLE
#define EASY_PROFILER_DISABLE
#define EASY_EVENT(...)
#define EASY_THREAD(...)
#define EASY_MAIN_THREAD
#endif
#include <stdint.h>
#include <cstddef>
#include "profiler/profiler_colors.h"
#ifdef _WIN32
#ifdef _BUILD_PROFILER
#define PROFILER_API __declspec(dllexport)
#ifdef _BUILD_PROFILER
#define PROFILER_API __declspec(dllexport)
#else
#define PROFILER_API __declspec(dllimport)
#define PROFILER_API __declspec(dllimport)
#endif
#else
#define PROFILER_API
#endif
class ProfileManager;
class ThreadStorage;
namespace profiler
{
typedef uint8_t color_t; //RRR-GGG-BB
namespace profiler {
namespace colors{
class Block;
const color_t Black = 0x00;
const color_t Lightgray = 0x6E;
const color_t Darkgray = 0x25;
const color_t White = 0xFF;
const color_t Red = 0xE0;
const color_t Green = 0x1C;
const color_t Blue = 0x03;
const color_t Magenta = (Red | Blue);
const color_t Cyan = (Green | Blue);
const color_t Yellow = (Red | Green);
const color_t Darkred = 0x60;
const color_t Darkgreen = 0x0C;
const color_t Darkblue = 0x01;
const color_t Darkmagenta = (Darkred | Darkblue);
const color_t Darkcyan = (Darkgreen | Darkblue);
const color_t Darkyellow = (Darkred | Darkgreen);
const color_t Navy = 0x02;
const color_t Teal = 0x12;
const color_t Maroon = 0x80;
const color_t Purple = 0x82;
const color_t Olive = 0x90;
const color_t Grey = 0x92;
const color_t Silver = 0xDB;
const color_t Orange = 0xF4;
const color_t Coral = 0xF6;
const color_t Brick = 0xED;
const color_t Clay = 0xD6;
const color_t Skin = 0xFA;
const color_t Palegold = 0xFE;
typedef uint64_t timestamp_t;
typedef uint32_t thread_id_t;
typedef uint32_t block_id_t;
inline int get_red(color_t color){
return (color >> 5) * 0x20;
}
inline int get_green(color_t color){
return ((color & 0x1C) >> 2) * 0x20;
}
inline int get_blue(color_t color){
return (color & 3) * 0x40;
}
inline int convert_to_rgb(color_t color){
return ((get_red(color) & 0xFF) << 16) | ((get_green(color) & 0xFF) << 8) | (get_blue(color) & 0xFF);
}
}
class Block;
class BlockSourceInfo;
extern "C"{
void PROFILER_API beginBlock(Block& _block);
void PROFILER_API endBlock();
void PROFILER_API setEnabled(bool isEnable);
unsigned int PROFILER_API dumpBlocksToFile(const char* filename);
void PROFILER_API setThreadName(const char* name);
}
typedef uint8_t block_type_t;
typedef uint64_t timestamp_t;
typedef uint32_t thread_id_t;
typedef uint32_t source_id_t;
const block_type_t BLOCK_TYPE_EVENT = 1;
const block_type_t BLOCK_TYPE_BLOCK = 2;
const block_type_t BLOCK_TYPE_THREAD_SIGN = 3;
#define EASY_USE_OLD_FILE_FORMAT
#pragma pack(push,1)
class PROFILER_API BaseBlockData
{
protected:
#ifdef EASY_USE_OLD_FILE_FORMAT
block_type_t type;
color_t color;
timestamp_t begin;
timestamp_t end;
thread_id_t thread_id;
#else
timestamp_t begin;
timestamp_t end;
thread_id_t thread_id;
source_id_t source_id;
block_type_t type;
color_t color;
#endif
void tick(timestamp_t& stamp);
public:
BaseBlockData(source_id_t _source_id, color_t _color, block_type_t _type, thread_id_t _thread_id = 0);
inline block_type_t getType() const { return type; }
inline color_t getColor() const { return color; }
inline timestamp_t getBegin() const { return begin; }
inline thread_id_t getThreadId() const { return thread_id; }
#ifdef EASY_USE_OLD_FILE_FORMAT
inline source_id_t getSourceId() const { return -1; }
#else
inline source_id_t getSourceId() const { return source_id; }
#endif
inline timestamp_t getEnd() const { return end; }
inline bool isFinished() const { return end != 0; }
inline bool isCleared() const { return end >= begin; }
inline void finish(){ tick(end); }
timestamp_t duration() const { return (end - begin); }
inline bool startsEarlierThan(const BaseBlockData& another) const {return this->begin < another.begin;}
inline bool endsEarlierThan(const BaseBlockData& another) const {return this->end < another.end;}
inline bool startsLaterThan(const BaseBlockData& another) const {return !this->startsEarlierThan(another);}
inline bool endsLaterThan(const BaseBlockData& another) const {return !this->endsEarlierThan(another);}
};
#pragma pack(pop)
class PROFILER_API Block final : public BaseBlockData
{
const char* m_name;
public:
Block(const char* _name, color_t _color, block_type_t _type, source_id_t _source_id);
Block(const char* _name, thread_id_t _thread_id, color_t _color, block_type_t _type, source_id_t _source_id);
~Block();
inline const char* getName() const { return m_name; }
};
class PROFILER_API SourceBlock final
enum BlockType : uint8_t
{
const char* m_filename;
int m_line;
BLOCK_TYPE_EVENT = 0,
BLOCK_TYPE_THREAD_SIGN,
BLOCK_TYPE_BLOCK,
BLOCK_TYPE_CONTEXT_SWITCH,
BLOCK_TYPES_NUMBER
};
typedef BlockType block_type_t;
extern "C" {
PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor);
PROFILER_API void beginBlock(Block& _block);
PROFILER_API void endBlock();
PROFILER_API void setEnabled(bool isEnable);
PROFILER_API uint32_t dumpBlocksToFile(const char* filename);
PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line);
PROFILER_API void setContextSwitchLogFilename(const char* name);
PROFILER_API const char* getContextSwitchLogFilename();
}
#pragma pack(push,1)
class PROFILER_API BaseBlockDescriptor
{
protected:
int m_line; ///< Line number in the source file
color_t m_color; ///< Color of the block packed into 1-byte structure
block_type_t m_type; ///< Type of the block (See BlockType)
BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color);
public:
SourceBlock(const char* _filename, int _line);
const char* file() const { return m_filename; }
int line() const { return m_line; }
inline int line() const { return m_line; }
inline block_type_t type() const { return m_type; }
inline color_t color() const { return m_color; }
};
class PROFILER_API SerializedBlock final : public BaseBlockData
class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor
{
const char* m_name; ///< Static name of all blocks of the same type (blocks can have dynamic name) which is, in pair with descriptor id, a unique block identifier
const char* m_filename; ///< Source file name where this block is declared
public:
BlockDescriptor(uint64_t& _used_mem, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color);
inline const char* name() const { return m_name; }
inline const char* file() const { return m_filename; }
};
class PROFILER_API BaseBlockData
{
friend ::ProfileManager;
protected:
timestamp_t m_begin;
timestamp_t m_end;
block_id_t m_id;
public:
///< Deprecated. For backward compatibility.
inline const BaseBlockData* block() const { return this; }
BaseBlockData(const BaseBlockData&) = default;
BaseBlockData(timestamp_t _begin_time, block_id_t _id);
inline const char* data() const { return reinterpret_cast<const char*>(this); }
inline const char* getName() const { return data() + sizeof(BaseBlockData); }
inline timestamp_t begin() const { return m_begin; }
inline timestamp_t end() const { return m_end; }
inline block_id_t id() const { return m_id; }
inline timestamp_t duration() const { return m_end - m_begin; }
inline void setId(block_id_t _id) { m_id = _id; }
private:
static SerializedBlock* create(const Block &block, uint64_t& memory_size);
static void destroy(SerializedBlock* that);
SerializedBlock(const profiler::Block& block, uint16_t name_length);
SerializedBlock(const SerializedBlock&) = delete;
SerializedBlock& operator = (const SerializedBlock&) = delete;
~SerializedBlock() = delete;
BaseBlockData() = delete;
};
#pragma pack(pop)
struct PROFILER_API ThreadNameSetter final
class PROFILER_API Block final : public BaseBlockData
{
ThreadNameSetter(const char* _name)
{
setThreadName(_name);
}
};
friend ::ProfileManager;
class PROFILER_API BlockSourceInfo final
{
unsigned int m_id;
const char* m_name;
private:
void finish();
void finish(timestamp_t _end_time);
inline bool isFinished() const { return m_end >= m_begin; }
public:
BlockSourceInfo(const char* _filename, int _linenumber);
Block(Block&& that);
Block(block_type_t _block_type, block_id_t _id, const char* _name);
Block(timestamp_t _begin_time, block_type_t _block_type, block_id_t _id, const char* _name);
~Block();
unsigned int id() const { return m_id; }
inline const char* name() const { return m_name; }
};
//////////////////////////////////////////////////////////////////////
} // END of namespace profiler.
#if defined ( __clang__ )
#pragma clang diagnostic pop
#endif
#endif // EASY_PROFILER____H_______

View File

@ -0,0 +1,439 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_PROFILER__COLORS__H_______
#define EASY_PROFILER__COLORS__H_______
#include <stdint.h>
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
namespace profiler {
//////////////////////////////////////////////////////////////////////
typedef uint32_t color_t; // Standard four-byte ARGB color format
//typedef uint8_t color_t; // One-byte RGB color format: RRR-GGG-BB
//typedef uint32_t rgb32_t; // Standard four-byte ARGB color format
//////////////////////////////////////////////////////////////////////
namespace colors {
// ///< Extracts [0 .. 224] Red value from one-byte RGB format. Possible values are: [0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xe0].
// inline rgb32_t get_red(color_t color) { return color & 0xe0; }
//
// ///< Extracts [0 .. 224] Green value from one-byte RGB format. Possible values are: [0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xe0].
// inline rgb32_t get_green(color_t color) { return (color & 0x1c) << 3; }
//
// ///< Extracts [0 .. 192] Blue value from one-byte RGB format. Possible values are: [0x0, 0x40, 0x80, 0xc0]
// inline rgb32_t get_blue(color_t color) { return (color & 3) << 6; }
//
//
// ///< Extracts [0 .. 255] Red value from four-byte RGB format.
// inline rgb32_t rgb_red(rgb32_t color) { return (color & 0x00ff0000) >> 16; }
//
// ///< Extracts [0 .. 255] Green value from four-byte RGB format.
// inline rgb32_t rgb_green(rgb32_t color) { return (color & 0x0000ff00) >> 8; }
//
// ///< Extracts [0 .. 255] Blue value from four-byte RGB format.
// inline rgb32_t rgb_blue(rgb32_t color) { return color & 0x000000ff; }
//
// ///< Unpacks one-byte RGB value into standard four-byte RGB value.
// inline rgb32_t convert_to_rgb(color_t color) { return (get_red(color) << 16) | ((color & 0x1c) << 11) | get_blue(color); }
//
// ///< Packs standard four-byte RGB value into one-byte RGB value. R & G values packed with 0x20 (32) step, B value is packed with 0x40 (64) step.
// inline color_t from_rgb(rgb32_t color) { return (rgb_red(color) & 0xe0) | (((color & 0x0000ff00) >> 11) & 0x1c) | (rgb_blue(color) >> 6); }
//
// ///< Packs standard four-byte RGB value into one-byte RGB value. R & G values packed with 0x20 (32) step, B value is packed with 0x40 (64) step.
// inline color_t from_rgb(color_t red, color_t green, color_t blue) { return (red & 0xe0) | ((green >> 3) & 0x1c) | (blue >> 6); }
// const color_t Black = 0x00; // 0x00000000
// const color_t Random = Black; // Black // Currently GUI interprets Black color as permission to select random color for block
// const color_t Lightgray = 0x6E; // 0x00606080
// const color_t Darkgray = 0x25; // 0x00202040
// const color_t White = 0xFF; // 0x00E0E0C0
// const color_t Red = 0xE0; // 0x00E00000
// const color_t Green = 0x1C; // 0x0000E000
// const color_t Blue = 0x03; // 0x000000C0
// const color_t Magenta = (Red | Blue); // 0x00E000C0
// const color_t Cyan = (Green | Blue); // 0x0000E0C0
// const color_t Yellow = (Red | Green); // 0x00E0E000
// const color_t Darkred = 0x60; // 0x00600000
// const color_t Darkgreen = 0x0C; // 0x00006000
// const color_t Darkblue = 0x01; // 0x00000040
// const color_t Darkmagenta = (Darkred | Darkblue); // 0x00600040
// const color_t Darkcyan = (Darkgreen | Darkblue); // 0x00006040
// const color_t Darkyellow = (Darkred | Darkgreen); // 0x00606000
// const color_t Navy = 0x02; // 0x00000080
// const color_t Teal = 0x12; // 0x00008080
// const color_t Maroon = 0x80; // 0x00800000
// const color_t Purple = 0x82; // 0x00800080
// const color_t Olive = 0x90; // 0x00808000
// const color_t Grey = 0x92; // 0x00808080
// const color_t Silver = 0xDB; // 0x00C0C0C0
// const color_t Orange = 0xF4; // 0x00E0A000
// const color_t Coral = 0xF6; // 0x00E0A080
// const color_t Brick = 0xED; // 0x00E06040
// const color_t Clay = 0xD6; // 0x00C0A080
// const color_t Skin = 0xFA; // 0x00E0C080
// const color_t Palegold = 0xFE; // 0x00E0E080
// Google Material Design colors
// See https://material.google.com/style/color.html
const color_t Red50 = 0xffffebee;
const color_t Red100 = 0xffffcdd2;
const color_t Red200 = 0xffef9a9a;
const color_t Red300 = 0xffe57373;
const color_t Red400 = 0xffef5350;
const color_t Red500 = 0xfff44336;
const color_t Red600 = 0xffe53935;
const color_t Red700 = 0xffd32f2f;
const color_t Red800 = 0xffc62828;
const color_t Red900 = 0xffb71c1c;
const color_t RedA100 = 0xffff8a80;
const color_t RedA200 = 0xffff5252;
const color_t RedA400 = 0xffff1744;
const color_t RedA700 = 0xffd50000;
const color_t Pink50 = 0xfffce4ec;
const color_t Pink100 = 0xfff8bbd0;
const color_t Pink200 = 0xfff48fb1;
const color_t Pink300 = 0xfff06292;
const color_t Pink400 = 0xffec407a;
const color_t Pink500 = 0xffe91e63;
const color_t Pink600 = 0xffd81b60;
const color_t Pink700 = 0xffc2185b;
const color_t Pink800 = 0xffad1457;
const color_t Pink900 = 0xff880e4f;
const color_t PinkA100 = 0xffff80ab;
const color_t PinkA200 = 0xffff4081;
const color_t PinkA400 = 0xfff50057;
const color_t PinkA700 = 0xffc51162;
const color_t Purple50 = 0xfff3e5f5;
const color_t Purple100 = 0xffe1bee7;
const color_t Purple200 = 0xffce93d8;
const color_t Purple300 = 0xffba68c8;
const color_t Purple400 = 0xffab47bc;
const color_t Purple500 = 0xff9c27b0;
const color_t Purple600 = 0xff8e24aa;
const color_t Purple700 = 0xff7b1fa2;
const color_t Purple800 = 0xff6a1b9a;
const color_t Purple900 = 0xff4a148c;
const color_t PurpleA100 = 0xffea80fc;
const color_t PurpleA200 = 0xffe040fb;
const color_t PurpleA400 = 0xffd500f9;
const color_t PurpleA700 = 0xffaa00ff;
const color_t DeepPurple50 = 0xffede7f6;
const color_t DeepPurple100 = 0xffd1c4e9;
const color_t DeepPurple200 = 0xffb39ddb;
const color_t DeepPurple300 = 0xff9575cd;
const color_t DeepPurple400 = 0xff7e57c2;
const color_t DeepPurple500 = 0xff673ab7;
const color_t DeepPurple600 = 0xff5e35b1;
const color_t DeepPurple700 = 0xff512da8;
const color_t DeepPurple800 = 0xff4527a0;
const color_t DeepPurple900 = 0xff311b92;
const color_t DeepPurpleA100 = 0xffb388ff;
const color_t DeepPurpleA200 = 0xff7c4dff;
const color_t DeepPurpleA400 = 0xff651fff;
const color_t DeepPurpleA700 = 0xff6200ea;
const color_t Indigo50 = 0xffe8eaf6;
const color_t Indigo100 = 0xffc5cae9;
const color_t Indigo200 = 0xff9fa8da;
const color_t Indigo300 = 0xff7986cb;
const color_t Indigo400 = 0xff5c6bc0;
const color_t Indigo500 = 0xff3f51b5;
const color_t Indigo600 = 0xff3949ab;
const color_t Indigo700 = 0xff303f9f;
const color_t Indigo800 = 0xff283593;
const color_t Indigo900 = 0xff1a237e;
const color_t IndigoA100 = 0xff8c9eff;
const color_t IndigoA200 = 0xff536dfe;
const color_t IndigoA400 = 0xff3d5afe;
const color_t IndigoA700 = 0xff304ffe;
const color_t Blue50 = 0xffe3f2fd;
const color_t Blue100 = 0xffbbdefb;
const color_t Blue200 = 0xff90caf9;
const color_t Blue300 = 0xff64b5f6;
const color_t Blue400 = 0xff42a5f5;
const color_t Blue500 = 0xff2196f3;
const color_t Blue600 = 0xff1e88e5;
const color_t Blue700 = 0xff1976d2;
const color_t Blue800 = 0xff1565c0;
const color_t Blue900 = 0xff0d47a1;
const color_t BlueA100 = 0xff82b1ff;
const color_t BlueA200 = 0xff448aff;
const color_t BlueA400 = 0xff2979ff;
const color_t BlueA700 = 0xff2962ff;
const color_t LightBlue50 = 0xffe1f5fe;
const color_t LightBlue100 = 0xffb3e5fc;
const color_t LightBlue200 = 0xff81d4fa;
const color_t LightBlue300 = 0xff4fc3f7;
const color_t LightBlue400 = 0xff29b6f6;
const color_t LightBlue500 = 0xff03a9f4;
const color_t LightBlue600 = 0xff039be5;
const color_t LightBlue700 = 0xff0288d1;
const color_t LightBlue800 = 0xff0277bd;
const color_t LightBlue900 = 0xff01579b;
const color_t LightBlueA100 = 0xff80d8ff;
const color_t LightBlueA200 = 0xff40c4ff;
const color_t LightBlueA400 = 0xff00b0ff;
const color_t LightBlueA700 = 0xff0091ea;
const color_t Cyan50 = 0xffe0f7fa;
const color_t Cyan100 = 0xffb2ebf2;
const color_t Cyan200 = 0xff80deea;
const color_t Cyan300 = 0xff4dd0e1;
const color_t Cyan400 = 0xff26c6da;
const color_t Cyan500 = 0xff00bcd4;
const color_t Cyan600 = 0xff00acc1;
const color_t Cyan700 = 0xff0097a7;
const color_t Cyan800 = 0xff00838f;
const color_t Cyan900 = 0xff006064;
const color_t CyanA100 = 0xff84ffff;
const color_t CyanA200 = 0xff18ffff;
const color_t CyanA400 = 0xff00e5ff;
const color_t CyanA700 = 0xff00b8d4;
const color_t Teal50 = 0xffe0f2f1;
const color_t Teal100 = 0xffb2dfdb;
const color_t Teal200 = 0xff80cbc4;
const color_t Teal300 = 0xff4db6ac;
const color_t Teal400 = 0xff26a69a;
const color_t Teal500 = 0xff009688;
const color_t Teal600 = 0xff00897b;
const color_t Teal700 = 0xff00796b;
const color_t Teal800 = 0xff00695c;
const color_t Teal900 = 0xff004d40;
const color_t TealA100 = 0xffa7ffeb;
const color_t TealA200 = 0xff64ffda;
const color_t TealA400 = 0xff1de9b6;
const color_t TealA700 = 0xff00bfa5;
const color_t Green50 = 0xffe8f5e9;
const color_t Green100 = 0xffc8e6c9;
const color_t Green200 = 0xffa5d6a7;
const color_t Green300 = 0xff81c784;
const color_t Green400 = 0xff66bb6a;
const color_t Green500 = 0xff4caf50;
const color_t Green600 = 0xff43a047;
const color_t Green700 = 0xff388e3c;
const color_t Green800 = 0xff2e7d32;
const color_t Green900 = 0xff1b5e20;
const color_t GreenA100 = 0xffb9f6ca;
const color_t GreenA200 = 0xff69f0ae;
const color_t GreenA400 = 0xff00e676;
const color_t GreenA700 = 0xff00c853;
const color_t LightGreen50 = 0xfff1f8e9;
const color_t LightGreen100 = 0xffdcedc8;
const color_t LightGreen200 = 0xffc5e1a5;
const color_t LightGreen300 = 0xffaed581;
const color_t LightGreen400 = 0xff9ccc65;
const color_t LightGreen500 = 0xff8bc34a;
const color_t LightGreen600 = 0xff7cb342;
const color_t LightGreen700 = 0xff689f38;
const color_t LightGreen800 = 0xff558b2f;
const color_t LightGreen900 = 0xff33691e;
const color_t LightGreenA100 = 0xffccff90;
const color_t LightGreenA200 = 0xffb2ff59;
const color_t LightGreenA400 = 0xff76ff03;
const color_t LightGreenA700 = 0xff64dd17;
const color_t Lime50 = 0xfff9ebe7;
const color_t Lime100 = 0xfff0f4c3;
const color_t Lime200 = 0xffe6ee9c;
const color_t Lime300 = 0xffdce775;
const color_t Lime400 = 0xffd4e157;
const color_t Lime500 = 0xffcddc39;
const color_t Lime600 = 0xffc0ca33;
const color_t Lime700 = 0xffafb42b;
const color_t Lime800 = 0xff9e9d24;
const color_t Lime900 = 0xff827717;
const color_t LimeA100 = 0xfff4ff81;
const color_t LimeA200 = 0xffeeff41;
const color_t LimeA400 = 0xffc6ff00;
const color_t LimeA700 = 0xffaeea00;
const color_t Yellow50 = 0xfffffde7;
const color_t Yellow100 = 0xfffff9c4;
const color_t Yellow200 = 0xfffff59d;
const color_t Yellow300 = 0xfffff176;
const color_t Yellow400 = 0xffffee58;
const color_t Yellow500 = 0xffffeb3b;
const color_t Yellow600 = 0xfffdd835;
const color_t Yellow700 = 0xfffbc02d;
const color_t Yellow800 = 0xfff9a825;
const color_t Yellow900 = 0xfff57f17;
const color_t YellowA100 = 0xffffff8d;
const color_t YellowA200 = 0xffffff00;
const color_t YellowA400 = 0xffffea00;
const color_t YellowA700 = 0xffffd600;
const color_t Amber50 = 0xfffff8e1;
const color_t Amber100 = 0xffffecb3;
const color_t Amber200 = 0xffffe082;
const color_t Amber300 = 0xffffd54f;
const color_t Amber400 = 0xffffca28;
const color_t Amber500 = 0xffffc107;
const color_t Amber600 = 0xffffb300;
const color_t Amber700 = 0xffffa000;
const color_t Amber800 = 0xffff8f00;
const color_t Amber900 = 0xffff6f00;
const color_t AmberA100 = 0xffffe57f;
const color_t AmberA200 = 0xffffd740;
const color_t AmberA400 = 0xffffc400;
const color_t AmberA700 = 0xffffab00;
const color_t Orange50 = 0xfffff3e0;
const color_t Orange100 = 0xffffe0b2;
const color_t Orange200 = 0xffffcc80;
const color_t Orange300 = 0xffffb74d;
const color_t Orange400 = 0xffffa726;
const color_t Orange500 = 0xffff9800;
const color_t Orange600 = 0xfffb8c00;
const color_t Orange700 = 0xfff57c00;
const color_t Orange800 = 0xffef6c00;
const color_t Orange900 = 0xffe65100;
const color_t OrangeA100 = 0xffffd180;
const color_t OrangeA200 = 0xffffab40;
const color_t OrangeA400 = 0xffff9100;
const color_t OrangeA700 = 0xffff6d00;
const color_t DeepOrange50 = 0xfffbe9e7;
const color_t DeepOrange100 = 0xffffccbc;
const color_t DeepOrange200 = 0xffffab91;
const color_t DeepOrange300 = 0xffff8a65;
const color_t DeepOrange400 = 0xffff7043;
const color_t DeepOrange500 = 0xffff5722;
const color_t DeepOrange600 = 0xfff4511e;
const color_t DeepOrange700 = 0xffe64a19;
const color_t DeepOrange800 = 0xffd84315;
const color_t DeepOrange900 = 0xffbf360c;
const color_t DeepOrangeA100 = 0xffff9e80;
const color_t DeepOrangeA200 = 0xffff6e40;
const color_t DeepOrangeA400 = 0xffff3d00;
const color_t DeepOrangeA700 = 0xffdd2c00;
const color_t Brown50 = 0xffefebe9;
const color_t Brown100 = 0xffd7ccc8;
const color_t Brown200 = 0xffbcaaa4;
const color_t Brown300 = 0xffa1887f;
const color_t Brown400 = 0xff8d6e63;
const color_t Brown500 = 0xff795548;
const color_t Brown600 = 0xff6d4c41;
const color_t Brown700 = 0xff5d4037;
const color_t Brown800 = 0xff4e342e;
const color_t Brown900 = 0xff3e2723;
const color_t Grey50 = 0xfffafafa;
const color_t Grey100 = 0xfff5f5f5;
const color_t Grey200 = 0xffeeeeee;
const color_t Grey300 = 0xffe0e0e0;
const color_t Grey400 = 0xffbdbdbd;
const color_t Grey500 = 0xff9e9e9e;
const color_t Grey600 = 0xff757575;
const color_t Grey700 = 0xff616161;
const color_t Grey800 = 0xff424242;
const color_t Grey900 = 0xff212121;
const color_t BlueGrey50 = 0xffeceff1;
const color_t BlueGrey100 = 0xffcfd8dc;
const color_t BlueGrey200 = 0xffb0bec5;
const color_t BlueGrey300 = 0xff90a4ae;
const color_t BlueGrey400 = 0xff78909c;
const color_t BlueGrey500 = 0xff607d8b;
const color_t BlueGrey600 = 0xff546e7a;
const color_t BlueGrey700 = 0xff455a64;
const color_t BlueGrey800 = 0xff37474f;
const color_t BlueGrey900 = 0xff263238;
const color_t Black = 0xff000000;
const color_t White = 0xffffffff;
const color_t Null = 0x00000000;
const color_t Red = Red500;
const color_t DarkRed = Red900;
const color_t RichRed = 0xffff0000;
const color_t Pink = Pink500;
const color_t Rose = PinkA100;
const color_t Purple = Purple500;
const color_t Magenta = PurpleA200;
const color_t DarkMagenta = PurpleA700;
const color_t DeepPurple = DeepPurple500;
const color_t Indigo = Indigo500;
const color_t Blue = Blue500;
const color_t DarkBlue = Blue900;
const color_t RichBlue = 0xff0000ff;
const color_t LightBlue = LightBlue500;
const color_t SkyBlue = LightBlueA100;
const color_t Navy = LightBlue800;
const color_t Cyan = Cyan500;
const color_t DarkCyan = Cyan900;
const color_t Teal = Teal500;
const color_t DarkTeal = Teal900;
const color_t Green = Green500;
const color_t DarkGreen = Green900;
const color_t RichGreen = 0xff00ff00;
const color_t LightGreen = LightGreen500;
const color_t Mint = LightGreen900;
const color_t Lime = Lime500;
const color_t Olive = Lime900;
const color_t Yellow = Yellow500;
const color_t DarkYellow = DarkRed | DarkGreen;
const color_t RichYellow = YellowA200;
const color_t Amber = Amber500;
const color_t Gold = Amber300;
const color_t PaleGold = AmberA100;
const color_t Orange = Orange500;
const color_t Skin = Orange100;
const color_t DeepOrange = DeepOrange500;
const color_t Brick = DeepOrange900;
const color_t Coral = DeepOrange200;
const color_t Brown = Brown500;
const color_t DarkBrown = Brown900;
const color_t CreamWhite = Brown50;
const color_t Grey = Grey500;
const color_t Silver = Grey300;
const color_t BlueGrey = BlueGrey500;
} // END of namespace colors.
const color_t DefaultBlockColor = colors::OrangeA100;
//////////////////////////////////////////////////////////////////////
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__COLORS__H_______

View File

@ -25,6 +25,7 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
#include <vector>
#include <atomic>
#include "profiler/profiler.h"
#include "profiler/serialized_block.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -61,46 +62,31 @@ namespace profiler {
}; // END of struct BlockStatistics.
#pragma pack(pop)
inline void release(BlockStatistics*& _stats)
{
if (!_stats)
{
return;
}
if (--_stats->calls_number == 0)
{
delete _stats;
}
_stats = nullptr;
}
extern "C" void PROFILER_API release_stats(BlockStatistics*& _stats);
//////////////////////////////////////////////////////////////////////////
class BlocksTree
class BlocksTree final
{
typedef BlocksTree This;
public:
typedef ::std::vector<BlocksTree> children_t;
typedef ::std::vector<This> blocks_t;
typedef ::std::vector<::profiler::block_index_t> children_t;
children_t children; ///< List of children blocks. May be empty.
::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.)
::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::block_index_t block_index; ///< Index of this block
unsigned short depth; ///< Maximum number of sublevels (maximum children depth)
uint16_t depth; ///< Maximum number of sublevels (maximum children depth)
BlocksTree()
: node(nullptr)
, per_parent_stats(nullptr)
, per_frame_stats(nullptr)
, per_thread_stats(nullptr)
, block_index(0)
, depth(0)
{
@ -119,14 +105,9 @@ namespace profiler {
~BlocksTree()
{
//if (node)
//{
// delete node;
//}
release(per_thread_stats);
release(per_parent_stats);
release(per_frame_stats);
release_stats(per_thread_stats);
release_stats(per_parent_stats);
release_stats(per_frame_stats);
}
bool operator < (const This& other) const
@ -135,7 +116,7 @@ namespace profiler {
{
return false;
}
return node->block()->getBegin() < other.node->block()->getBegin();
return node->begin() < other.node->begin();
}
void shrink_to_fit()
@ -160,33 +141,20 @@ namespace profiler {
void makeMove(This&& that)
{
//if (node && node != that.node)
//{
// delete node;
//}
if (per_thread_stats != that.per_thread_stats)
{
release(per_thread_stats);
}
release_stats(per_thread_stats);
if (per_parent_stats != that.per_parent_stats)
{
release(per_parent_stats);
}
release_stats(per_parent_stats);
if (per_frame_stats != that.per_frame_stats)
{
release(per_frame_stats);
}
release_stats(per_frame_stats);
children = ::std::move(that.children);
node = that.node;
per_parent_stats = that.per_parent_stats;
per_frame_stats = that.per_frame_stats;
per_thread_stats = that.per_thread_stats;
block_index = that.block_index;
depth = that.depth;
that.node = nullptr;
@ -199,35 +167,53 @@ namespace profiler {
//////////////////////////////////////////////////////////////////////////
#define EASY_STORE_CSWITCH_SEPARATELY
//#undef EASY_STORE_CSWITCH_SEPARATELY
class BlocksTreeRoot final
{
typedef BlocksTreeRoot This;
public:
BlocksTree tree;
BlocksTree::children_t children;
#ifdef EASY_STORE_CSWITCH_SEPARATELY
BlocksTree::children_t sync;
#endif
const char* thread_name;
::profiler::thread_id_t thread_id;
uint16_t depth;
BlocksTreeRoot() : thread_name(""), thread_id(0)
BlocksTreeRoot() : thread_name(""), thread_id(0), depth(0)
{
}
BlocksTreeRoot(This&& that) : tree(::std::move(that.tree)), thread_name(that.thread_name), thread_id(that.thread_id)
BlocksTreeRoot(This&& that)
: children(::std::move(that.children))
#ifdef EASY_STORE_CSWITCH_SEPARATELY
, sync(::std::move(that.sync))
#endif
, thread_name(that.thread_name)
, thread_id(that.thread_id)
, depth(that.depth)
{
}
This& operator = (This&& that)
{
tree = ::std::move(that.tree);
children = ::std::move(that.children);
#ifdef EASY_STORE_CSWITCH_SEPARATELY
sync = ::std::move(that.sync);
#endif
thread_name = that.thread_name;
thread_id = that.thread_id;
depth = that.depth;
return *this;
}
bool operator < (const This& other) const
{
return tree < other.tree;
return thread_id < other.thread_id;
}
private:
@ -237,11 +223,12 @@ namespace profiler {
}; // END of class BlocksTreeRoot.
typedef ::profiler::BlocksTree::blocks_t blocks_t;
typedef ::std::map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot> thread_blocks_tree_t;
//////////////////////////////////////////////////////////////////////////
class SerializedData final
class PROFILER_API SerializedData final
{
char* m_data;
@ -261,10 +248,11 @@ namespace profiler {
clear();
}
void set(char* _data);
SerializedData& operator = (SerializedData&& that)
{
clear();
m_data = that.m_data;
set(that.m_data);
that.m_data = nullptr;
return *this;
}
@ -276,17 +264,7 @@ namespace profiler {
void clear()
{
if (m_data)
{
delete[] m_data;
m_data = nullptr;
}
}
void set(char* _data)
{
clear();
m_data = _data;
set(nullptr);
}
void swap(SerializedData& other)
@ -305,15 +283,25 @@ namespace profiler {
//////////////////////////////////////////////////////////////////////////
typedef ::std::vector<SerializedBlockDescriptor*> descriptors_list_t;
} // END of namespace profiler.
extern "C"{
unsigned int PROFILER_API fillTreesFromFile(::std::atomic<int>& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false);
}
extern "C" ::profiler::block_index_t PROFILER_API 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,
bool gather_statistics = false);
inline unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false) {
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,
bool gather_statistics = false)
{
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return fillTreesFromFile(progress, filename, serialized_blocks, threaded_trees, gather_statistics);
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, gather_statistics);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,83 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef EASY_PROFILER_SERIALIZED_BLOCK__H_______
#define EASY_PROFILER_SERIALIZED_BLOCK__H_______
#include "profiler/profiler.h"
namespace profiler {
//////////////////////////////////////////////////////////////////////////
class PROFILER_API SerializedBlock final : public BaseBlockData
{
friend ::ProfileManager;
friend ::ThreadStorage;
public:
inline const char* data() const { return reinterpret_cast<const char*>(this); }
inline const char* name() const { return data() + sizeof(BaseBlockData); }
private:
SerializedBlock(const ::profiler::Block& block, uint16_t name_length);
SerializedBlock(const SerializedBlock&) = delete;
SerializedBlock& operator = (const SerializedBlock&) = delete;
~SerializedBlock() = delete;
}; // END of SerializedBlock.
//////////////////////////////////////////////////////////////////////////
#pragma pack(push, 1)
class PROFILER_API SerializedBlockDescriptor final : public BaseBlockDescriptor
{
uint16_t m_nameLength;
public:
inline const char* data() const {
return reinterpret_cast<const char*>(this);
}
inline const char* name() const {
static const auto shift = sizeof(BaseBlockDescriptor) + sizeof(decltype(m_nameLength));
return data() + shift;
}
inline const char* file() const {
return name() + m_nameLength;
}
private:
SerializedBlockDescriptor(const SerializedBlockDescriptor&) = delete;
SerializedBlockDescriptor& operator = (const SerializedBlockDescriptor&) = delete;
~SerializedBlockDescriptor() = delete;
}; // END of SerializedBlockDescriptor.
#pragma pack(pop)
//////////////////////////////////////////////////////////////////////////
} // END of namespace profiler.
#endif // EASY_PROFILER_SERIALIZED_BLOCK__H_______

View File

@ -2,7 +2,6 @@
* file name : blocks_graphics_view.cpp
* ----------------- :
* creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -22,7 +21,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include <QGraphicsScene>
@ -54,8 +67,8 @@ enum BlockItemState
//////////////////////////////////////////////////////////////////////////
const qreal MIN_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 70);
const qreal MAX_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT, 30); // ~800
const qreal MIN_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 70); // Up to 1000 sec scale
const qreal MAX_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT, 45); // ~23000 --- Up to 10 ns scale
const qreal BASE_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 25); // ~0.003
const unsigned short GRAPHICS_ROW_SIZE = 18;
@ -71,11 +84,11 @@ const QRgb TIMELINE_BACKGROUND = 0x20303030;
const QRgb SELECTED_ITEM_COLOR = 0x000050a0;
const QColor CHRONOMETER_COLOR2 = QColor::fromRgba(0x40408040);
const unsigned int TEST_PROGRESSION_BASE = 4;
//const unsigned int TEST_PROGRESSION_BASE = 4;
const int FLICKER_INTERVAL = 16; // 60Hz
const auto CHRONOMETER_FONT = QFont("CourierNew", 16, 2);
const auto CHRONOMETER_FONT = QFont("CourierNew", 18, 2);
const auto ITEMS_FONT = QFont("CourierNew", 10);// , 2);
//////////////////////////////////////////////////////////////////////////
@ -95,7 +108,7 @@ inline T logn(T _value)
//////////////////////////////////////////////////////////////////////////
EasyGraphicsItem::EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root)
EasyGraphicsItem::EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot* _root)
: QGraphicsItem(nullptr)
, m_pRoot(_root)
, m_index(_index)
@ -139,7 +152,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
QRectF rect;
QBrush brush;
QRgb previousColor = 0, inverseColor = 0x00ffffff;
QRgb previousColor = 0, inverseColor = 0xffffffff, textColor = 0;
Qt::PenStyle previousPenStyle = Qt::NoPen;
brush.setStyle(Qt::SolidPattern);
@ -148,12 +161,12 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
// Reset indices of first visible item for each layer
const auto levelsNumber = levels();
for (unsigned char i = 1; i < levelsNumber; ++i) ::profiler_gui::set_max(m_levelsIndexes[i]);
for (uint8_t i = 1; i < levelsNumber; ++i) ::profiler_gui::set_max(m_levelsIndexes[i]);
// Search for first visible top-level item
auto& level0 = m_levels.front();
auto first = ::std::lower_bound(level0.begin(), level0.end(), sceneLeft, [](const ::profiler_gui::ProfBlockItem& _item, qreal _value)
auto first = ::std::lower_bound(level0.begin(), level0.end(), sceneLeft, [](const ::profiler_gui::EasyBlockItem& _item, qreal _value)
{
return _item.left() < _value;
});
@ -170,20 +183,40 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
}
#ifdef EASY_STORE_CSWITCH_SEPARATELY
auto firstSync = ::std::lower_bound(m_pRoot->sync.begin(), m_pRoot->sync.end(), sceneLeft, [&sceneView](::profiler::block_index_t _index, qreal _value)
{
return sceneView->time2position(easyBlock(_index).tree.node->begin()) < _value;
});
if (firstSync != m_pRoot->sync.end())
{
if (firstSync != m_pRoot->sync.begin())
--firstSync;
}
else if (!m_pRoot->sync.empty())
{
firstSync = m_pRoot->sync.begin() + m_pRoot->sync.size() - 1;
}
firstSync = m_pRoot->sync.begin();
#endif
// This is to make _painter->drawText() work properly
// (it seems there is a bug in Qt5.6 when drawText called for big coordinates,
// drawRect at the same time called for actually same coordinates
// works fine without using this additional shifting)
auto dx = level0[m_levelsIndexes[0]].left() * currentScale;
//const auto dx = level0[m_levelsIndexes[0]].left() * currentScale;
const auto dx = offset * currentScale;
// Shifting coordinates to current screen offset
_painter->setTransform(QTransform::fromTranslate(dx - offset * currentScale, -y()), true);
//_painter->setTransform(QTransform::fromTranslate(dx - offset * currentScale, -y()), true);
_painter->setTransform(QTransform::fromTranslate(0, -y()), true);
if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders)
if (EASY_GLOBALS.draw_graphics_items_borders)
{
previousPenStyle = Qt::SolidLine;
_painter->setPen(BORDERS_COLOR);
@ -194,8 +227,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
}
static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max<decltype(::profiler_gui::ProfBlockItem::children_begin)>();
auto const skip_children = [this, &levelsNumber](short next_level, decltype(::profiler_gui::ProfBlockItem::children_begin) children_begin)
static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max<decltype(::profiler_gui::EasyBlockItem::children_begin)>();
auto const skip_children = [this, &levelsNumber](short next_level, decltype(::profiler_gui::EasyBlockItem::children_begin) children_begin)
{
// Mark that we would not paint children of current item
if (next_level < levelsNumber && children_begin != MAX_CHILD_INDEX)
@ -206,7 +239,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
// Iterate through layers and draw visible items
bool selectedItemsWasPainted = false;
const auto visibleBottom = visibleSceneRect.bottom() - 1;
for (unsigned char l = 0; l < levelsNumber; ++l)
for (uint8_t l = 0; l < levelsNumber; ++l)
{
auto& level = m_levels[l];
const short next_level = l + 1;
@ -243,8 +276,9 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
continue;
}
const auto& itemBlock = easyBlock(item.block);
int h = 0, flags = 0;
if (w < 20 || !::profiler_gui::EASY_GLOBALS.gui_blocks[item.block->block_index].expanded)
if (w < 20 || !itemBlock.expanded)
{
// Items which width is less than 20 will be painted as big rectangles which are hiding it's children
@ -255,7 +289,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
h -= dh;
bool changepen = false;
if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block)
if (item.block == EASY_GLOBALS.selected_block)
{
selectedItemsWasPainted = true;
changepen = true;
@ -265,7 +299,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
_painter->setPen(pen);
previousColor = SELECTED_ITEM_COLOR;
inverseColor = 0x00ffffff - previousColor;
inverseColor = 0xffffffff - previousColor;
textColor = ::profiler_gui::textColorForRgb(previousColor);
brush.setColor(previousColor);
_painter->setBrush(brush);
}
@ -276,12 +311,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
{
// Set background color brush for rectangle
previousColor = item.color;
inverseColor = 0x00ffffff - previousColor;
inverseColor = 0xffffffff - previousColor;
textColor = ::profiler_gui::textColorForRgb(previousColor);
brush.setColor(previousColor);
_painter->setBrush(brush);
}
if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders)
if (EASY_GLOBALS.draw_graphics_items_borders)
{
//if (w < 2)
//{
@ -349,7 +385,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
m_levels[next_level][item.children_begin].state = BLOCK_ITEM_DO_PAINT;
}
if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block)
if (item.block == EASY_GLOBALS.selected_block)
{
selectedItemsWasPainted = true;
QPen pen(Qt::SolidLine);
@ -358,7 +394,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
_painter->setPen(pen);
previousColor = SELECTED_ITEM_COLOR;
inverseColor = 0x00ffffff - previousColor;
inverseColor = 0xffffffff - previousColor;
textColor = ::profiler_gui::textColorForRgb(previousColor);
brush.setColor(previousColor);
_painter->setBrush(brush);
}
@ -369,12 +406,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
{
// Set background color brush for rectangle
previousColor = item.color;
inverseColor = 0x00ffffff - previousColor;
inverseColor = 0xffffffff - previousColor;
textColor = ::profiler_gui::textColorForRgb(previousColor);
brush.setColor(previousColor);
_painter->setBrush(brush);
}
if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders && (previousPenStyle != Qt::SolidLine || colorChange))
if (EASY_GLOBALS.draw_graphics_items_borders && (previousPenStyle != Qt::SolidLine || colorChange))
{
// Restore pen for item which is wide enough to paint borders
previousPenStyle = Qt::SolidLine;
@ -417,12 +455,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
rect.setRect(xtext + 1, top, w - 1, h);
// text will be painted with inverse color
auto textColor = inverseColor;
if (textColor == previousColor) textColor = 0;
_painter->setPen(textColor);
//auto textColor = inverseColor < 0x00808080 ? profiler::colors::Black : profiler::colors::White;
//if (textColor == previousColor) textColor = 0;
_painter->setPen(QColor::fromRgb(textColor));
// drawing text
_painter->drawText(rect, flags, ::profiler_gui::toUnicode(item.block->node->getName()));
auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name();
_painter->drawText(rect, flags, ::profiler_gui::toUnicode(name));
// restore previous pen color
if (previousPenStyle == Qt::NoPen)
@ -433,61 +472,122 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
}
}
if (!selectedItemsWasPainted && ::profiler_gui::EASY_GLOBALS.selected_block < ::profiler_gui::EASY_GLOBALS.gui_blocks.size())
if (!selectedItemsWasPainted && EASY_GLOBALS.selected_block < EASY_GLOBALS.gui_blocks.size())
{
const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[::profiler_gui::EASY_GLOBALS.selected_block];
const auto& guiblock = EASY_GLOBALS.gui_blocks[EASY_GLOBALS.selected_block];
if (guiblock.graphics_item == m_index)
{
const auto& item = m_levels[guiblock.graphics_item_level][guiblock.graphics_item_index];
if (item.left() < sceneRight && item.right() > sceneLeft)
{
QPen pen(Qt::SolidLine);
pen.setColor(Qt::red);
pen.setWidth(2);
_painter->setPen(pen);
brush.setColor(SELECTED_ITEM_COLOR);
_painter->setBrush(brush);
auto top = levelY(guiblock.graphics_item_level);
auto x = item.left() * currentScale - dx;
auto w = ::std::max(item.width() * currentScale, 1.0);
rect.setRect(x, top, w, item.totalHeight);
_painter->drawRect(rect);
decltype(top) h = item.totalHeight;
if (w > 20)
auto dh = top + h - visibleBottom;
if (dh < h)
{
// Draw text-----------------------------------
// calculating text coordinates
auto xtext = x;
if (item.left() < sceneLeft)
if (dh > 0)
h -= dh;
QPen pen(Qt::SolidLine);
pen.setColor(Qt::red);
pen.setWidth(2);
_painter->setPen(pen);
brush.setColor(SELECTED_ITEM_COLOR);
_painter->setBrush(brush);
auto x = item.left() * currentScale - dx;
auto w = ::std::max(item.width() * currentScale, 1.0);
rect.setRect(x, top, w, h);
_painter->drawRect(rect);
if (w > 20)
{
// if item left border is out of screen then attach text to the left border of the screen
// to ensure text is always visible for items presenting on the screen.
w += (item.left() - sceneLeft) * currentScale;
xtext = sceneLeft * currentScale - dx;
// Draw text-----------------------------------
// calculating text coordinates
auto xtext = x;
if (item.left() < sceneLeft)
{
// if item left border is out of screen then attach text to the left border of the screen
// to ensure text is always visible for items presenting on the screen.
w += (item.left() - sceneLeft) * currentScale;
xtext = sceneLeft * currentScale - dx;
}
if (item.right() > sceneRight)
{
w -= (item.right() - sceneRight) * currentScale;
}
rect.setRect(xtext + 1, top, w - 1, h);
// text will be painted with inverse color
//auto textColor = 0x00ffffff - previousColor;
//if (textColor == previousColor) textColor = 0;
textColor = ::profiler_gui::textColorForRgb(SELECTED_ITEM_COLOR);
_painter->setPen(textColor);
// drawing text
const auto& itemBlock = easyBlock(item.block);
auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name();
_painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(name));
// END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
if (item.right() > sceneRight)
{
w -= (item.right() - sceneRight) * currentScale;
}
rect.setRect(xtext + 1, top, w - 1, item.totalHeight);
// text will be painted with inverse color
auto textColor = 0x00ffffff - previousColor;
if (textColor == previousColor) textColor = 0;
_painter->setPen(textColor);
// drawing text
_painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(item.block->node->getName()));
// END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
}
}
}
#ifdef EASY_STORE_CSWITCH_SEPARATELY
if (!m_pRoot->sync.empty())
{
_painter->setBrush(QColor::fromRgba(0xfffe6030));
_painter->setPen(QColor::fromRgb(0x00505050));
qreal prevRight = -1e100, top = y() - 4, h = 3;
if (top + h < visibleBottom)
{
for (auto it = firstSync, end = m_pRoot->sync.end(); it != end; ++it)
{
const auto& item = easyBlock(*it).tree;
auto begin = sceneView->time2position(item.node->begin());
if (begin > sceneRight)
break; // This is first totally invisible item. No need to check other items.
decltype(begin) width = sceneView->time2position(item.node->end()) - begin;
auto r = begin + width;
if (r < sceneLeft) // This item is not visible
continue;
begin *= currentScale;
begin -= dx;
width *= currentScale;
r = begin + width;
if (r <= prevRight) // This item is not visible
continue;
if (begin < prevRight)
{
width -= prevRight - begin;
begin = prevRight;
}
if (width < 2)
width = 2;
//_painter->drawLine(QLineF(::std::max(begin, prevRight), top, begin + width, top));
rect.setRect(begin, top, width, h);
_painter->drawRect(rect);
prevRight = begin + width;
}
}
}
#endif
_painter->restore();
}
@ -509,7 +609,7 @@ void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree
// Search for first visible top-level item
auto& level0 = m_levels.front();
auto first = ::std::lower_bound(level0.begin(), level0.end(), _left, [](const ::profiler_gui::ProfBlockItem& _item, qreal _value)
auto first = ::std::lower_bound(level0.begin(), level0.end(), _left, [](const ::profiler_gui::EasyBlockItem& _item, qreal _value)
{
return _item.left() < _value;
});
@ -550,7 +650,7 @@ void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree
//////////////////////////////////////////////////////////////////////////
const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF& _pos) const
const ::profiler_gui::EasyBlockItem* EasyGraphicsItem::intersect(const QPointF& _pos) const
{
if (m_levels.empty() || m_levels.front().empty())
{
@ -586,7 +686,7 @@ const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF&
const auto& level = m_levels[i];
// Search for first visible item
auto first = ::std::lower_bound(level.begin() + firstItem, level.begin() + lastItem, _pos.x(), [](const ::profiler_gui::ProfBlockItem& _item, qreal _value)
auto first = ::std::lower_bound(level.begin() + firstItem, level.begin() + lastItem, _pos.x(), [](const ::profiler_gui::EasyBlockItem& _item, qreal _value)
{
return _item.left() < _value;
});
@ -618,7 +718,7 @@ const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF&
}
const auto w = item.width() * currentScale;
if (i == levelIndex || w < 20 || !::profiler_gui::EASY_GLOBALS.gui_blocks[item.block->block_index].expanded)
if (i == levelIndex || w < 20 || !easyBlock(item.block).expanded)
{
return &item;
}
@ -692,17 +792,17 @@ void EasyGraphicsItem::setBoundingRect(const QRectF& _rect)
//////////////////////////////////////////////////////////////////////////
unsigned char EasyGraphicsItem::levels() const
uint8_t EasyGraphicsItem::levels() const
{
return static_cast<unsigned char>(m_levels.size());
return static_cast<uint8_t>(m_levels.size());
}
float EasyGraphicsItem::levelY(unsigned char _level) const
float EasyGraphicsItem::levelY(uint8_t _level) const
{
return y() + static_cast<int>(_level) * static_cast<int>(GRAPHICS_ROW_SIZE_FULL);
}
void EasyGraphicsItem::setLevels(unsigned char _levels)
void EasyGraphicsItem::setLevels(uint8_t _levels)
{
typedef decltype(m_levelsIndexes) IndexesT;
static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max<IndexesT::value_type>();
@ -711,29 +811,29 @@ void EasyGraphicsItem::setLevels(unsigned char _levels)
m_levelsIndexes.resize(_levels, MAX_CHILD_INDEX);
}
void EasyGraphicsItem::reserve(unsigned char _level, unsigned int _items)
void EasyGraphicsItem::reserve(uint8_t _level, unsigned int _items)
{
m_levels[_level].reserve(_items);
}
//////////////////////////////////////////////////////////////////////////
const EasyGraphicsItem::Children& EasyGraphicsItem::items(unsigned char _level) const
const EasyGraphicsItem::Children& EasyGraphicsItem::items(uint8_t _level) const
{
return m_levels[_level];
}
const ::profiler_gui::ProfBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) const
const ::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(uint8_t _level, unsigned int _index) const
{
return m_levels[_level][_index];
}
::profiler_gui::ProfBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index)
::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(uint8_t _level, unsigned int _index)
{
return m_levels[_level][_index];
}
unsigned int EasyGraphicsItem::addItem(unsigned char _level)
unsigned int EasyGraphicsItem::addItem(uint8_t _level)
{
m_levels[_level].emplace_back();
return static_cast<unsigned int>(m_levels[_level].size() - 1);
@ -829,12 +929,18 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
// instead of scrollbar we're using manual offset
_painter->setTransform(QTransform::fromTranslate(-x(), -y()), true);
if (m_left < sceneLeft)
rect.setLeft(0);
if (m_right > sceneRight)
rect.setWidth((sceneRight - offset) * currentScale - rect.left());
// draw transparent rectangle
auto vcenter = rect.top() + rect.height() * 0.5;
QLinearGradient g(rect.left(), vcenter, rect.right(), vcenter);
g.setColorAt(0, m_color);
g.setColorAt(0.15, QColor::fromRgba(0x14000000 | rgb));
g.setColorAt(0.85, QColor::fromRgba(0x14000000 | rgb));
g.setColorAt(0.25, QColor::fromRgba(0x20000000 | rgb));
g.setColorAt(0.75, QColor::fromRgba(0x20000000 | rgb));
g.setColorAt(1, m_color);
_painter->setBrush(g);
_painter->setPen(Qt::NoPen);
@ -850,21 +956,12 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
// draw text
_painter->setCompositionMode(QPainter::CompositionMode_Difference); // This lets the text to be visible on every background
_painter->setPen(0xffffffff - rgb);
_painter->setRenderHint(QPainter::TextAntialiasing);
_painter->setPen(0x00ffffff - rgb);
_painter->setFont(CHRONOMETER_FONT);
if (m_left < sceneLeft)
{
rect.setLeft(0);
}
if (m_right > sceneRight)
{
rect.setWidth((sceneRight - offset) * currentScale - rect.left());
}
int textFlags = 0;
switch (::profiler_gui::EASY_GLOBALS.chrono_text_position)
switch (EASY_GLOBALS.chrono_text_position)
{
case ::profiler_gui::ChronoTextPosition_Top:
textFlags = Qt::AlignTop | Qt::AlignHCenter;
@ -890,14 +987,15 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
return;
}
if (m_right + textRect.width() < sceneRight)
const auto w = textRect.width() / currentScale;
if (m_right + w < sceneRight)
{
// Text will be drawed to the right of rectangle
rect.translate(rect.width(), 0);
textFlags &= ~Qt::AlignHCenter;
textFlags |= Qt::AlignLeft;
}
else if (m_left - textRect.width() > sceneLeft)
else if (m_left - w > sceneLeft)
{
// Text will be drawed to the left of rectangle
rect.translate(-rect.width(), 0);
@ -1002,7 +1100,7 @@ void EasyBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte
if (top > h || bottom < 0)
continue;
if (item->threadId() == ::profiler_gui::EASY_GLOBALS.selected_thread)
if (item->threadId() == EASY_GLOBALS.selected_thread)
_painter->setBrush(QBrush(QColor::fromRgb(::profiler_gui::SELECTED_THREAD_BACKGROUND)));
else
_painter->setBrush(brushes[i & 1]);
@ -1092,13 +1190,10 @@ void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap
// Draw scale indicator
_painter->save();
_painter->setTransform(QTransform::fromTranslate(-x(), -y()));
_painter->setCompositionMode(QPainter::CompositionMode_Difference);
//_painter->setCompositionMode(QPainter::CompositionMode_Difference);
_painter->setBrush(Qt::NoBrush);
//_painter->setBrush(Qt::white);
//_painter->setPen(Qt::NoPen);
QPen pen(Qt::white);
QPen pen(Qt::black);
pen.setWidth(2);
pen.setJoinStyle(Qt::MiterJoin);
_painter->setPen(pen);
@ -1107,7 +1202,6 @@ void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap
const auto rect_right = rect.right();
const QPointF points[] = {{rect.left(), rect.bottom()}, {rect.left(), rect.top()}, {rect_right, rect.top()}, {rect_right, rect.top() + 5}};
_painter->drawPolyline(points, sizeof(points) / sizeof(QPointF));
//_painter->drawRect(rect);
rect.translate(0, 3);
_painter->drawText(rect, Qt::AlignRight | Qt::TextDontClip, text);
@ -1193,7 +1287,7 @@ EasyChronometerItem* EasyGraphicsView::createChronometer(bool _main)
}
}
void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows)
void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, uint8_t _rows)
{
static const qreal X_BEGIN = 50;
static const qreal Y_BEGIN = 0;
@ -1201,9 +1295,9 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
clearSilent(); // Clear scene
// Calculate items number for first level
_rows = ::std::max((unsigned char)1, _rows);
_rows = ::std::max((uint8_t)1, _rows);
const auto children_per_frame = static_cast<unsigned int>(0.5 + static_cast<double>(_total_items_number_estimate) / static_cast<double>(_rows * _frames_number));
const unsigned char max_depth = ::std::min(254, static_cast<int>(logn<TEST_PROGRESSION_BASE>(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1)));
const uint8_t max_depth = ::std::min(254, static_cast<int>(logn<TEST_PROGRESSION_BASE>(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1)));
const auto first_level_children_count = static_cast<unsigned int>(static_cast<double>(children_per_frame) * (1.0 - TEST_PROGRESSION_BASE) / (1.0 - pow(TEST_PROGRESSION_BASE, max_depth)) + 0.5);
@ -1212,7 +1306,7 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
::std::vector<EasyGraphicsItem*> thread_items(_rows);
for (unsigned char i = 0; i < _rows; ++i)
for (uint8_t i = 0; i < _rows; ++i)
{
auto item = new EasyGraphicsItem(i, true);
thread_items[i] = item;
@ -1225,9 +1319,9 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
// Calculate items number for each sublevel
auto chldrn = first_level_children_count;
for (unsigned char i = 1; i <= max_depth; ++i)
for (uint8_t i = 1; i <= max_depth; ++i)
{
for (unsigned char j = 0; j < _rows; ++j)
for (uint8_t j = 0; j < _rows; ++j)
{
auto item = thread_items[j];
item->reserve(i, chldrn * _frames_number);
@ -1240,7 +1334,7 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
unsigned int total_items = 0;
qreal maxX = 0;
const EasyGraphicsItem* longestItem = nullptr;
for (unsigned char i = 0; i < _rows; ++i)
for (uint8_t i = 0; i < _rows; ++i)
{
auto item = thread_items[i];
qreal x = X_BEGIN, y = item->y();
@ -1292,8 +1386,8 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
if (longestItem != nullptr)
{
m_pScrollbar->setMinimapFrom(0, longestItem->items(0));
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
emit::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0);
EASY_GLOBALS.selected_thread = 0;
emitEASY_GLOBALS.events.selectedThreadChanged(0);
}
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()).
@ -1360,13 +1454,20 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
// Calculating start and end time
::profiler::timestamp_t finish = 0;
const ::profiler::BlocksTree* longestTree = nullptr;
::profiler::thread_id_t longestTree = 0;
const EasyGraphicsItem* longestItem = nullptr;
const EasyGraphicsItem* mainThreadItem = nullptr;
for (const auto& threadTree : _blocksTree)
{
const auto& tree = threadTree.second.tree;
const auto timestart = tree.children.front().node->block()->getBegin();
const auto timefinish = tree.children.back().node->block()->getEnd();
const auto& tree = threadTree.second.children;
auto timestart = blocksTree(tree.front()).node->begin();
#ifdef EASY_STORE_CSWITCH_SEPARATELY
if (!threadTree.second.sync.empty())
timestart = ::std::min(timestart, blocksTree(threadTree.second.sync.front()).node->begin());
#endif
const auto timefinish = blocksTree(tree.back()).node->end();
if (m_beginTime > timestart)
{
@ -1376,7 +1477,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
if (finish < timefinish)
{
finish = timefinish;
longestTree = &tree;
longestTree = threadTree.first;
}
}
@ -1392,13 +1493,13 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
}
// fill scene with new items
const auto& tree = threadTree.second.tree;
qreal h = 0, x = time2position(tree.children.front().node->block()->getBegin());
auto item = new EasyGraphicsItem(static_cast<unsigned char>(m_items.size()), &threadTree.second);
item->setLevels(tree.depth);
const auto& tree = threadTree.second.children;
qreal h = 0, x = time2position(blocksTree(tree.front()).node->begin());
auto item = new EasyGraphicsItem(static_cast<uint8_t>(m_items.size()), &threadTree.second);
item->setLevels(threadTree.second.depth);
item->setPos(0, y);
const auto children_duration = setTree(item, tree.children, h, y, 0);
const auto children_duration = setTree(item, tree, h, y, 0);
item->setBoundingRect(0, 0, children_duration + x, h);
m_items.push_back(item);
@ -1406,10 +1507,11 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
y += h + THREADS_ROW_SPACING;
if (longestTree == &tree)
{
if (longestTree == threadTree.first)
longestItem = item;
}
if (mainThreadItem == nullptr && !strcmp(threadTree.second.thread_name, "Main"))
mainThreadItem = item;
}
// Calculating scene rect
@ -1422,11 +1524,14 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
updateVisibleSceneRect();
setScrollbar(m_pScrollbar);
if (mainThreadItem != nullptr)
longestItem = mainThreadItem;
if (longestItem != nullptr)
{
m_pScrollbar->setMinimapFrom(longestItem->threadId(), longestItem->items(0));
::profiler_gui::EASY_GLOBALS.selected_thread = longestItem->threadId();
emit::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(longestItem->threadId());
EASY_GLOBALS.selected_thread = longestItem->threadId();
emit EASY_GLOBALS.events.selectedThreadChanged(longestItem->threadId());
}
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()).
@ -1460,22 +1565,25 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block
return 0;
}
const auto level = static_cast<unsigned char>(_level);
const auto level = static_cast<uint8_t>(_level);
_item->reserve(level, static_cast<unsigned int>(_children.size()));
const short next_level = _level + 1;
bool warned = false;
qreal total_duration = 0, prev_end = 0, maxh = 0;
qreal start_time = -1;
for (const auto& child : _children)
for (auto child_index : _children)
{
auto xbegin = time2position(child.node->block()->getBegin());
auto& gui_block = easyBlock(child_index);
const auto& child = gui_block.tree;
auto xbegin = time2position(child.node->begin());
if (start_time < 0)
{
start_time = xbegin;
}
auto duration = time2position(child.node->block()->getEnd()) - xbegin;
auto duration = time2position(child.node->end()) - xbegin;
//const auto dt = xbegin - prev_end;
//if (dt < 0)
@ -1492,14 +1600,13 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block
auto i = _item->addItem(level);
auto& b = _item->getItem(level, i);
auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index];
gui_block.graphics_item = _item->index();
gui_block.graphics_item_level = level;
gui_block.graphics_item_index = i;
if (next_level < 256 && next_level < _item->levels() && !child.children.empty())
{
b.children_begin = static_cast<unsigned int>(_item->items(static_cast<unsigned char>(next_level)).size());
b.children_begin = static_cast<unsigned int>(_item->items(static_cast<uint8_t>(next_level)).size());
}
else
{
@ -1529,9 +1636,8 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block
maxh = h;
}
const auto color = child.node->block()->getColor();
b.block = &child;
b.color = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
b.block = child_index;// &child;
b.color = EASY_GLOBALS.descriptors[child.node->id()]->color();// ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
b.setPos(xbegin, duration);
b.totalHeight = GRAPHICS_ROW_SIZE + h;
b.state = BLOCK_ITEM_UNCHANGED;
@ -1571,8 +1677,8 @@ void EasyGraphicsView::setScrollbar(EasyGraphicsScrollbar* _scrollbar)
connect(m_pScrollbar, &EasyGraphicsScrollbar::wheeled, this, &This::onGraphicsScrollbarWheel);
}
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0);
EASY_GLOBALS.selected_thread = 0;
emit EASY_GLOBALS.events.selectedThreadChanged(0);
}
//////////////////////////////////////////////////////////////////////////
@ -1647,7 +1753,7 @@ void EasyGraphicsView::onGraphicsScrollbarWheel(qreal _mouseX, int _wheelDelta)
{
for (auto item : m_items)
{
if (item->threadId() == ::profiler_gui::EASY_GLOBALS.selected_thread)
if (item->threadId() == EASY_GLOBALS.selected_thread)
{
m_bUpdatingRect = true;
auto vbar = verticalScrollBar();
@ -1780,8 +1886,8 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
}
}
const ::profiler_gui::ProfBlockItem* selectedBlock = nullptr;
const auto previouslySelectedBlock = ::profiler_gui::EASY_GLOBALS.selected_block;
const ::profiler_gui::EasyBlockItem* selectedBlock = nullptr;
const auto previouslySelectedBlock = EASY_GLOBALS.selected_block;
if (m_mouseButtons & Qt::LeftButton)
{
bool clicked = false;
@ -1814,15 +1920,15 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
{
changedSelectedItem = true;
selectedBlock = block;
::profiler_gui::EASY_GLOBALS.selected_block = block->block->block_index;
EASY_GLOBALS.selected_block = block->block;
break;
}
}
if (!changedSelectedItem && ::profiler_gui::EASY_GLOBALS.selected_block != ::profiler_gui::numeric_max(::profiler_gui::EASY_GLOBALS.selected_block))
if (!changedSelectedItem && EASY_GLOBALS.selected_block != ::profiler_gui::numeric_max(EASY_GLOBALS.selected_block))
{
changedSelectedItem = true;
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
::profiler_gui::set_max(EASY_GLOBALS.selected_block);
}
}
}
@ -1842,12 +1948,12 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
if (changedSelectedItem)
{
m_bUpdatingRect = true;
if (selectedBlock != nullptr && previouslySelectedBlock == ::profiler_gui::EASY_GLOBALS.selected_block && !selectedBlock->block->children.empty())
if (selectedBlock != nullptr && previouslySelectedBlock == EASY_GLOBALS.selected_block && !blocksTree(selectedBlock->block).children.empty())
{
::profiler_gui::EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !::profiler_gui::EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded;
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded;
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(::profiler_gui::EASY_GLOBALS.selected_block);
emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block);
m_bUpdatingRect = false;
updateScene();
@ -1999,7 +2105,7 @@ void EasyGraphicsView::initMode()
connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &This::onScrollbarValueChange);
connect(&m_flickerTimer, &QTimer::timeout, this, &This::onFlickerTimeout);
auto globalSignals = &::profiler_gui::EASY_GLOBALS.events;
auto globalSignals = &EASY_GLOBALS.events;
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::itemsExpandStateChanged, this, &This::onItemsEspandStateChange);
@ -2102,11 +2208,11 @@ void EasyGraphicsView::onSelectedBlockChange(unsigned int _block_index)
{
if (!m_bUpdatingRect)
{
if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size())
if (_block_index < EASY_GLOBALS.gui_blocks.size())
{
// Scroll to item
const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index];
const auto& guiblock = EASY_GLOBALS.gui_blocks[_block_index];
const auto thread_item = m_items[guiblock.graphics_item];
const auto& item = thread_item->items(guiblock.graphics_item_level)[guiblock.graphics_item_index];
@ -2181,7 +2287,7 @@ EasyThreadViewWidget::EasyThreadViewWidget(QWidget *parent, EasyGraphicsView* vi
//m_layout->addWidget(m_label);
//setLayout(m_layout);
//show();
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
}
EasyThreadViewWidget::~EasyThreadViewWidget()
@ -2192,14 +2298,14 @@ EasyThreadViewWidget::~EasyThreadViewWidget()
void EasyThreadViewWidget::onSelectedThreadChange(::profiler::thread_id_t _id)
{
/*
auto threadName = ::profiler_gui::EASY_GLOBALS.profiler_blocks[::profiler_gui::EASY_GLOBALS.selected_thread].thread_name;
auto threadName = EASY_GLOBALS.profiler_blocks[EASY_GLOBALS.selected_thread].thread_name;
if(threadName[0]!=0)
{
m_label->setText(threadName);
}
else
{
m_label->setText(QString("Thread %1").arg(::profiler_gui::EASY_GLOBALS.selected_thread));
m_label->setText(QString("Thread %1").arg(EASY_GLOBALS.selected_thread));
}
*/
QLayoutItem *ditem;

View File

@ -2,7 +2,6 @@
* file name : blocks_graphics_view.h
* ----------------- :
* creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -18,7 +17,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__GRAPHICS_VIEW__H_
@ -58,7 +71,7 @@ inline qreal microseconds2units(qreal _value)
class EasyGraphicsItem : public QGraphicsItem
{
typedef ::profiler_gui::ProfItems Children;
typedef ::profiler_gui::EasyItems Children;
typedef ::std::vector<unsigned int> DrawIndexes;
typedef ::std::vector<Children> Sublevels;
@ -67,11 +80,11 @@ class EasyGraphicsItem : public QGraphicsItem
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy.
unsigned char m_index; ///< This item's index in the list of items of EasyGraphicsView
uint8_t m_index; ///< This item's index in the list of items of EasyGraphicsView
public:
EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root);
EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot* _root);
virtual ~EasyGraphicsItem();
// Public virtual methods
@ -92,46 +105,46 @@ public:
::profiler::thread_id_t threadId() const;
///< Returns number of levels
unsigned char levels() const;
uint8_t levels() const;
float levelY(unsigned char _level) const;
float levelY(uint8_t _level) const;
/** \brief Sets number of levels.
\note Must be set before doing anything else.
\param _levels Desired number of levels */
void setLevels(unsigned char _levels);
void setLevels(uint8_t _levels);
/** \brief Reserves memory for desired number of items on specified level.
\param _level Index of the level
\param _items Desired number of items on this level */
void reserve(unsigned char _level, unsigned int _items);
void reserve(uint8_t _level, unsigned int _items);
/**\brief Returns reference to the array of items of specified level.
\param _level Index of the level */
const Children& items(unsigned char _level) const;
const Children& items(uint8_t _level) const;
/**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level
\param _index Index of required item */
const ::profiler_gui::ProfBlockItem& getItem(unsigned char _level, unsigned int _index) const;
const ::profiler_gui::EasyBlockItem& getItem(uint8_t _level, unsigned int _index) const;
/**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level
\param _index Index of required item */
::profiler_gui::ProfBlockItem& getItem(unsigned char _level, unsigned int _index);
::profiler_gui::EasyBlockItem& getItem(uint8_t _level, unsigned int _index);
/** \brief Adds new item to required level.
\param _level Index of the level
\retval Index of the new created item */
unsigned int addItem(unsigned char _level);
unsigned int addItem(uint8_t _level);
/** \brief Finds top-level blocks which are intersects with required selection zone.
@ -142,7 +155,7 @@ public:
\param _blocks Reference to the array of selected blocks */
void getBlocks(qreal _left, qreal _right, ::profiler_gui::TreeBlocks& _blocks) const;
const ::profiler_gui::ProfBlockItem* intersect(const QPointF& _pos) const;
const ::profiler_gui::EasyBlockItem* intersect(const QPointF& _pos) const;
private:
@ -154,7 +167,7 @@ public:
// Public inline methods
///< Returns this item's index in the list of graphics items of EasyGraphicsView
inline unsigned char index() const
inline uint8_t index() const
{
return m_index;
}
@ -198,7 +211,7 @@ public:
void setHover(bool _hover);
bool contains(const QPointF& _pos) const;
bool contains(const QPointF& _pos) const override;
inline bool hoverIndicator() const
{
@ -363,7 +376,7 @@ public:
return m_timelineStep;
}
private:
//private:
// Private inline methods

View File

@ -2,7 +2,6 @@
* file name : blocks_tree_widget.cpp
* ----------------- :
* creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -21,7 +20,21 @@
* :
* : * 2016/08/18 Victor Zarubkin: Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include <QMenu>
@ -31,6 +44,7 @@
#include <QProgressDialog>
#include <QResizeEvent>
#include <QMoveEvent>
#include <QDebug>
#include "blocks_tree_widget.h"
#include "tree_widget_item.h"
#include "globals.h"
@ -103,8 +117,8 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
setHeaderItem(header);
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
connect(&m_fillTimer, &QTimer::timeout, this, &This::onFillTimerTimeout);
loadSettings();
@ -115,12 +129,12 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
m_progress->setValue(100);
//m_progress->hide();
QTimer::singleShot(40, this, &This::alignProgressBar);
QTimer::singleShot(1500, this, &This::alignProgressBar);
}
EasyTreeWidget::~EasyTreeWidget()
{
saveSettings();
saveSettings();
delete m_progress;
}
@ -162,8 +176,8 @@ void EasyTreeWidget::onFillTimerTimeout()
connect(this, &Parent::itemExpanded, this, &This::onItemExpand);
connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse);
connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange);
onSelectedThreadChange(::profiler_gui::EASY_GLOBALS.selected_thread);
onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block);
onSelectedThreadChange(EASY_GLOBALS.selected_thread);
onSelectedBlockChange(EASY_GLOBALS.selected_block);
}
else
{
@ -193,7 +207,7 @@ void EasyTreeWidget::setTree(const unsigned int _blocksNumber, const ::profiler:
// {
// addTopLevelItem(item.second);
// m_roots[item.first] = item.second;
// if (item.first == ::profiler_gui::EASY_GLOBALS.selected_thread)
// if (item.first == EASY_GLOBALS.selected_thread)
// item.second->colorize(true);
// }
//}
@ -226,7 +240,7 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::
// {
// addTopLevelItem(item.second);
// m_roots[item.first] = item.second;
// if (item.first == ::profiler_gui::EASY_GLOBALS.selected_thread)
// if (item.first == EASY_GLOBALS.selected_thread)
// item.second->colorize(true);
// }
//}
@ -237,13 +251,15 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::
//connect(this, &Parent::itemExpanded, this, &This::onItemExpand);
//connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse);
//onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block);
//onSelectedBlockChange(EASY_GLOBALS.selected_block);
}
//////////////////////////////////////////////////////////////////////////
void EasyTreeWidget::clearSilent(bool _global)
{
const QSignalBlocker b(this);
m_hierarchyBuilder.interrupt();
if (m_progress)
@ -262,25 +278,36 @@ void EasyTreeWidget::clearSilent(bool _global)
if (!_global)
{
if (::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close) for (auto item : m_items)
if (EASY_GLOBALS.collapse_items_on_tree_close) for (auto item : m_items)
{
auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index];
auto& gui_block = item->guiBlock();
::profiler_gui::set_max(gui_block.tree_item);
gui_block.expanded = false;
}
else for (auto item : m_items)
{
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].tree_item);
::profiler_gui::set_max(item->guiBlock().tree_item);
}
}
m_items.clear();
m_roots.clear();
{ const QSignalBlocker b(this); clear(); } // clear without emitting any signals
::std::vector<QTreeWidgetItem*> topLevelItems;
topLevelItems.reserve(topLevelItemCount());
for (int i = topLevelItemCount() - 1; i >= 0; --i)
topLevelItems.push_back(takeTopLevelItem(i));
auto deleter_thread = ::std::thread([](decltype(topLevelItems) _items) {
for (auto item : _items)
delete item;
}, ::std::move(topLevelItems));
deleter_thread.detach();
//clear();
if (!_global)
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
//////////////////////////////////////////////////////////////////////////
@ -325,7 +352,7 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
action->setChecked(m_bColorRows);
connect(action, &QAction::triggered, this, &This::onColorizeRowsTriggered);
if (item != nullptr)
if (item != nullptr && item->parent() != nullptr)
{
//auto itemAction = new EasyItemAction("Show this item on scene", item->block()->block_index);
//itemAction->setToolTip("Scroll graphics scene to current item in the tree");
@ -343,24 +370,25 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
case COL_MAX_PER_PARENT:
case COL_MAX_PER_FRAME:
{
auto block = item->block();
auto i = ::profiler_gui::numeric_max<unsigned int>();
auto& block = item->block();
auto i = ::profiler_gui::numeric_max<uint32_t>();
switch (col)
{
case COL_MIN_PER_THREAD: i = block->per_thread_stats->min_duration_block; break;
case COL_MIN_PER_PARENT: i = block->per_parent_stats->min_duration_block; break;
case COL_MIN_PER_FRAME: i = block->per_frame_stats->min_duration_block; break;
case COL_MAX_PER_THREAD: i = block->per_thread_stats->max_duration_block; break;
case COL_MAX_PER_PARENT: i = block->per_parent_stats->max_duration_block; break;
case COL_MAX_PER_FRAME: i = block->per_frame_stats->max_duration_block; break;
case COL_MIN_PER_THREAD: i = block.per_thread_stats->min_duration_block; break;
case COL_MIN_PER_PARENT: i = block.per_parent_stats->min_duration_block; break;
case COL_MIN_PER_FRAME: i = block.per_frame_stats->min_duration_block; break;
case COL_MAX_PER_THREAD: i = block.per_thread_stats->max_duration_block; break;
case COL_MAX_PER_PARENT: i = block.per_parent_stats->max_duration_block; break;
case COL_MAX_PER_FRAME: i = block.per_frame_stats->max_duration_block; break;
}
if (i != ::profiler_gui::numeric_max(i))
{
menu.addSeparator();
auto itemAction = new EasyItemAction("Jump to such item", i);
auto itemAction = new QAction("Jump to such item", nullptr);
itemAction->setData(i);
itemAction->setToolTip("Jump to item with min/max duration (depending on clicked column)");
connect(itemAction, &EasyItemAction::clicked, this, &This::onJumpToItemClicked);
connect(itemAction, &QAction::triggered, this, &This::onJumpToItemClicked);
menu.addAction(itemAction);
}
@ -375,12 +403,13 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
auto hidemenu = menu.addMenu("Select columns");
auto hdr = headerItem();
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
{
auto columnAction = new EasyHideShowColumnAction(hdr->text(i), i);
auto columnAction = new QAction(hdr->text(i), nullptr);
columnAction->setData(i);
columnAction->setCheckable(true);
columnAction->setChecked(!isColumnHidden(i));
connect(columnAction, &EasyHideShowColumnAction::clicked, this, &This::onHideShowColumn);
columnAction->setChecked(!isColumnHidden(i));
connect(columnAction, &QAction::triggered, this, &This::onHideShowColumn);
hidemenu->addAction(columnAction);
}
@ -405,16 +434,21 @@ void EasyTreeWidget::moveEvent(QMoveEvent* _event)
void EasyTreeWidget::alignProgressBar()
{
auto pos = mapToGlobal(rect().center());
auto pos = mapToGlobal(rect().center());
m_progress->move(pos.x() - (m_progress->width() >> 1), pos.y() - (m_progress->height() >> 1));
}
//////////////////////////////////////////////////////////////////////////
void EasyTreeWidget::onJumpToItemClicked(unsigned int _block_index)
void EasyTreeWidget::onJumpToItemClicked(bool)
{
::profiler_gui::EASY_GLOBALS.selected_block = _block_index;
emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(_block_index);
auto action = qobject_cast<QAction*>(sender());
if (action == nullptr)
return;
auto block_index = action->data().toUInt();
EASY_GLOBALS.selected_block = block_index;
emit EASY_GLOBALS.events.selectedBlockChanged(block_index);
}
void EasyTreeWidget::onCollapseAllClicked(bool)
@ -425,11 +459,11 @@ void EasyTreeWidget::onCollapseAllClicked(bool)
collapseAll();
m_bSilentExpandCollapse = false;
if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
if (EASY_GLOBALS.bind_scene_and_tree_expand_status)
{
for (auto item : m_items)
::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = false;
emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
item->guiBlock().expanded = false;
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
}
@ -442,11 +476,15 @@ void EasyTreeWidget::onExpandAllClicked(bool)
resizeColumnsToContents();
m_bSilentExpandCollapse = false;
if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
if (EASY_GLOBALS.bind_scene_and_tree_expand_status)
{
for (auto item : m_items)
::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = !item->block()->children.empty();
emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
{
auto& b = item->guiBlock();
b.expanded = !b.tree.children.empty();
}
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
}
@ -461,7 +499,7 @@ void EasyTreeWidget::onCollapseAllChildrenClicked(bool)
current->collapseAll();
m_bSilentExpandCollapse = false;
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
}
@ -477,7 +515,7 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool)
resizeColumnsToContents();
m_bSilentExpandCollapse = false;
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
}
@ -485,30 +523,30 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool)
void EasyTreeWidget::onItemExpand(QTreeWidgetItem* _item)
{
if (!::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
if (!EASY_GLOBALS.bind_scene_and_tree_expand_status)
{
resizeColumnsToContents();
return;
}
::profiler_gui::EASY_GLOBALS.gui_blocks[static_cast<EasyTreeWidgetItem*>(_item)->block()->block_index].expanded = true;
static_cast<EasyTreeWidgetItem*>(_item)->guiBlock().expanded = true;
if (!m_bSilentExpandCollapse)
{
resizeColumnsToContents();
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
}
void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item)
{
if (!::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
if (!EASY_GLOBALS.bind_scene_and_tree_expand_status)
return;
::profiler_gui::EASY_GLOBALS.gui_blocks[static_cast<EasyTreeWidgetItem*>(_item)->block()->block_index].expanded = false;
static_cast<EasyTreeWidgetItem*>(_item)->guiBlock().expanded = false;
if (!m_bSilentExpandCollapse)
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
//////////////////////////////////////////////////////////////////////////
@ -516,13 +554,13 @@ void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item)
void EasyTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem*)
{
if (_item == nullptr)
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
::profiler_gui::set_max(EASY_GLOBALS.selected_block);
else
::profiler_gui::EASY_GLOBALS.selected_block = static_cast<EasyTreeWidgetItem*>(_item)->block()->block_index;
EASY_GLOBALS.selected_block = static_cast<EasyTreeWidgetItem*>(_item)->block_index();
disconnect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(::profiler_gui::EASY_GLOBALS.selected_block);
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
disconnect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
}
//////////////////////////////////////////////////////////////////////////
@ -567,9 +605,9 @@ void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index)
EasyTreeWidgetItem* item = nullptr;
if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size())
if (_block_index < EASY_GLOBALS.gui_blocks.size())
{
const auto i = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index].tree_item;
const auto i = easyBlock(_block_index).tree_item;
if (i < m_items.size())
item = m_items[i];
}
@ -578,19 +616,19 @@ void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index)
{
//const QSignalBlocker b(this);
if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
if (EASY_GLOBALS.bind_scene_and_tree_expand_status)
{
m_bSilentExpandCollapse = true;
setCurrentItem(item);
scrollToItem(item, QAbstractItemView::PositionAtCenter);
if (::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded)
if (item->guiBlock().expanded)
expandItem(item);
else
collapseItem(item);
resizeColumnsToContents();
m_bSilentExpandCollapse = false;
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
emit EASY_GLOBALS.events.itemsExpandStateChanged();
}
else
{
@ -621,16 +659,17 @@ void EasyTreeWidget::resizeColumnsToContents()
//////////////////////////////////////////////////////////////////////////
void EasyTreeWidget::onHideShowColumn(int _column)
void EasyTreeWidget::onHideShowColumn(bool)
{
if (isColumnHidden(_column))
{
showColumn(_column);
}
auto action = qobject_cast<QAction*>(sender());
if (action == nullptr)
return;
auto col = action->data().toInt();
if (isColumnHidden(col))
showColumn(col);
else
{
hideColumn(_column);
}
hideColumn(col);
}
//////////////////////////////////////////////////////////////////////////
@ -655,17 +694,17 @@ void EasyTreeWidget::loadSettings()
void EasyTreeWidget::saveSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("tree_widget");
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("tree_widget");
settings.setValue("color_rows", m_bColorRows);
settings.setValue("color_rows", m_bColorRows);
for (int i = 0; i < columnCount(); i++)
{
settings.setValue(QString("Column") + QString::number(i) , isColumnHidden(i));
}
for (int i = 0; i < columnCount(); i++)
{
settings.setValue(QString("Column") + QString::number(i) , isColumnHidden(i));
}
settings.endGroup();
settings.endGroup();
}
//////////////////////////////////////////////////////////////////////////

View File

@ -2,7 +2,6 @@
* file name : blocks_tree_widget.h
* ----------------- :
* creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -20,7 +19,21 @@
* : * 2016/08/18 Victor Zarubkin: Added loading blocks hierarchy in separate thread;
* : Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__TREE_WIDGET__H_
@ -34,27 +47,6 @@
//////////////////////////////////////////////////////////////////////////
#define DECLARE_QACTION(ClassName, DataType) \
class ClassName : public QAction { \
Q_OBJECT \
private: \
DataType m_item; \
public: \
ClassName(const char* _label, DataType _item) : QAction(_label, nullptr), m_item(_item) { \
connect(this, &QAction::triggered, this, &ClassName::onToggle); } \
ClassName(const QString& _label, DataType _item) : QAction(_label, nullptr), m_item(_item) { \
connect(this, &QAction::triggered, this, &ClassName::onToggle); } \
virtual ~ClassName() {} \
private: \
void onToggle(bool) { emit clicked(m_item); }
DECLARE_QACTION(EasyItemAction, unsigned int) signals: void clicked(unsigned int _item); };
DECLARE_QACTION(EasyHideShowColumnAction, int) signals: void clicked(int _item); };
#undef DECLARE_QACTION
//////////////////////////////////////////////////////////////////////////
class EasyTreeWidget : public QTreeWidget
{
Q_OBJECT
@ -96,7 +88,7 @@ protected:
private slots:
void onJumpToItemClicked(unsigned int _block_index);
void onJumpToItemClicked(bool);
void onCollapseAllClicked(bool);
@ -118,14 +110,14 @@ private slots:
void resizeColumnsToContents();
void onHideShowColumn(int _column);
void onHideShowColumn(bool);
void onFillTimerTimeout();
protected:
void loadSettings();
void saveSettings();
void saveSettings();
void alignProgressBar();
}; // END of class EasyTreeWidget.

View File

@ -2,7 +2,6 @@
* file name : common_types.h
* ----------------- :
* creation time : 2016/07/31
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -13,7 +12,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__GUI_COMMON_TYPES_H
@ -88,7 +101,7 @@ struct do_no_hash {
//////////////////////////////////////////////////////////////////////////
const QRgb DEFAULT_COLOR = 0x00d4b494;//0x00f0e094;
const QRgb DEFAULT_COLOR = profiler::DefaultBlockColor;// 0x00d4b494;
inline QRgb toRgb(unsigned int _red, unsigned int _green, unsigned int _blue)
{
@ -102,17 +115,24 @@ inline QRgb fromProfilerRgb(unsigned int _red, unsigned int _green, unsigned int
return toRgb(_red, _green, _blue) | 0x00141414;
}
inline QRgb textColorForRgb(QRgb _color)
{
const QRgb sum = 0xff - ((_color & 0xff000000) >> 24) + ((_color & 0x00ff0000) >> 16) + ((_color & 0x0000ff00) >> 8) + (_color & 0x000000ff);
return sum > 0x215 ? ::profiler::colors::Black : ::profiler::colors::White;
}
//////////////////////////////////////////////////////////////////////////
#pragma pack(push, 1)
struct ProfBlockItem final
struct EasyBlockItem final
{
const ::profiler::BlocksTree* block; ///< Pointer to profiler block
//const ::profiler::BlocksTree* block; ///< Pointer to profiler block
qreal x; ///< x coordinate of the item (this is made qreal=double to avoid mistakes on very wide scene)
float w; ///< Width of the item
QRgb color; ///< Background color of the item
unsigned int children_begin; ///< Index of first child item on the next sublevel
unsigned short totalHeight; ///< Total height of the item including heights of all it's children
::profiler::block_index_t block; ///< Index of profiler block
uint32_t children_begin; ///< Index of first child item on the next sublevel
uint16_t totalHeight; ///< Total height of the item including heights of all it's children
char state; ///< 0 = no change, 1 = paint, -1 = do not paint
// Possible optimizations:
@ -125,31 +145,58 @@ struct ProfBlockItem final
inline qreal right() const { return x + w; }
inline float width() const { return w; }
}; // END of struct ProfBlockItem.
#pragma pack(pop)
}; // END of struct EasyBlockItem.
typedef ::std::vector<ProfBlockItem> ProfItems;
//////////////////////////////////////////////////////////////////////////
struct ProfSelectedBlock final
struct EasyBlock final
{
const ::profiler::BlocksTreeRoot* root;
const ::profiler::BlocksTree* tree;
::profiler::BlocksTree tree;
uint32_t tree_item;
uint32_t graphics_item_index;
uint8_t graphics_item_level;
uint8_t graphics_item;
bool expanded;
ProfSelectedBlock() : root(nullptr), tree(nullptr)
EasyBlock() = default;
EasyBlock(EasyBlock&& that)
: tree(::std::move(that.tree))
, tree_item(that.tree_item)
, graphics_item_index(that.graphics_item_index)
, graphics_item_level(that.graphics_item_level)
, graphics_item(that.graphics_item)
, expanded(that.expanded)
{
}
ProfSelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::BlocksTree* _tree)
private:
EasyBlock(const EasyBlock&) = delete;
};
#pragma pack(pop)
typedef ::std::vector<EasyBlockItem> EasyItems;
typedef ::std::vector<EasyBlock> EasyBlocks;
//////////////////////////////////////////////////////////////////////////
struct EasySelectedBlock final
{
const ::profiler::BlocksTreeRoot* root;
::profiler::block_index_t tree;
EasySelectedBlock() : root(nullptr), tree(0xffffffff)
{
}
EasySelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::block_index_t _tree)
: root(_root)
, tree(_tree)
{
}
}; // END of struct ProfSelectedBlock.
}; // END of struct EasySelectedBlock.
typedef ::std::vector<ProfSelectedBlock> TreeBlocks;
typedef ::std::vector<EasySelectedBlock> TreeBlocks;
//////////////////////////////////////////////////////////////////////////

View File

@ -2,7 +2,6 @@
* file name : globals.cpp
* ----------------- :
* creation time : 2016/08/03
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -12,7 +11,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#define IGNORE_GLOBALS_DECLARATION

View File

@ -2,7 +2,6 @@
* file name : globals.h
* ----------------- :
* creation time : 2016/08/03
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -12,7 +11,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER__GUI_GLOBALS_H
@ -30,8 +43,8 @@
namespace profiler_gui {
const QString ORGANAZATION_NAME = "EasyProfiler";
const QString APPLICATION_NAME = "Easy profiler gui application";
const QString ORGANAZATION_NAME = "EasyProfiler";
const QString APPLICATION_NAME = "Easy profiler gui application";
const QColor CHRONOMETER_COLOR = QColor::fromRgba(0x402020c0);
const QRgb SELECTED_THREAD_BACKGROUND = 0x00e0e060;
@ -42,19 +55,6 @@ namespace profiler_gui {
//////////////////////////////////////////////////////////////////////////
#pragma pack(push, 1)
struct EasyBlock final
{
unsigned int tree_item;
unsigned int graphics_item_index;
unsigned char graphics_item_level;
unsigned char graphics_item;
bool expanded;
};
#pragma pack(pop)
typedef ::std::vector<EasyBlock> EasyBlocks;
template <class T>
inline auto toUnicode(const T& _inputString) -> decltype(QTextCodec::codecForLocale()->toUnicode(_inputString))
{
@ -79,6 +79,7 @@ namespace profiler_gui {
EasyGlobalSignals events; ///< Global signals
::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file
::profiler::descriptors_list_t descriptors; ///< Profiler block descriptors list
EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI
::profiler::thread_id_t selected_thread; ///< Current selected thread id
unsigned int selected_block; ///< Current selected profiler block index
@ -96,13 +97,26 @@ namespace profiler_gui {
}; // END of struct EasyGlobals.
#ifndef IGNORE_GLOBALS_DECLARATION
static EasyGlobals& EASY_GLOBALS = EasyGlobals::instance();
#endif
//////////////////////////////////////////////////////////////////////////
} // END of namespace profiler_gui.
#ifndef IGNORE_GLOBALS_DECLARATION
static ::profiler_gui::EasyGlobals& EASY_GLOBALS = ::profiler_gui::EasyGlobals::instance();
inline ::profiler_gui::EasyBlock& easyBlock(::profiler::block_index_t i) {
return EASY_GLOBALS.gui_blocks[i];
}
inline ::profiler::SerializedBlockDescriptor& easyDescriptor(::profiler::block_id_t i) {
return *EASY_GLOBALS.descriptors[i];
}
inline ::profiler::BlocksTree& blocksTree(::profiler::block_index_t i) {
return easyBlock(i).tree;
}
#endif
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

View File

@ -2,9 +2,8 @@
* file name : globals_qobjects.cpp
* ----------------- :
* creation time : 2016/08/08
* copyright : (c) 2016 Victor Zarubkin, Sergey Yagovtsev
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* authors : Victor Zarubkin, Sergey Yagovtsev
* email : v.s.zarubkin@gmail.com, yse.sey@gmail.com
* ----------------- :
* description : The file contains implementation of EasyGlobalSignals QObject class.
* ----------------- :
@ -12,7 +11,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "globals_qobjects.h"

View File

@ -1,5 +1,35 @@
#ifndef GLOBALS_QOBJECTS_H
#define GLOBALS_QOBJECTS_H
/************************************************************************
* file name : globals_qobjects.h
* ----------------- :
* creation time : 2016/08/08
* authors : Victor Zarubkin, Sergey Yagovtsev
* email : v.s.zarubkin@gmail.com, yse.sey@gmail.com
* ----------------- :
* description : The file contains declaration of EasyGlobalSignals QObject class.
* ----------------- :
* change log : * 2016/08/08 Sergey Yagovtsev: moved sources from globals.h
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__GLOBALS_QOBJECTS_H___
#define EASY__GLOBALS_QOBJECTS_H___
#include <QObject>
#include "profiler/profiler.h"
@ -27,4 +57,4 @@ namespace profiler_gui {
} // END of namespace profiler_gui.
#endif // GLOBALS_QOBJECTS_H
#endif // EASY__GLOBALS_QOBJECTS_H___

View File

@ -2,7 +2,6 @@
* file name : graphics_scrollbar.cpp
* ----------------- :
* creation time : 2016/07/04
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -12,7 +11,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include <algorithm>
@ -28,7 +41,7 @@
//////////////////////////////////////////////////////////////////////////
const qreal SCALING_COEFFICIENT = 1.25;
const qreal SCALING_COEFFICIENT_INV = 1.0 / SCALING_COEFFICIENT;
//const qreal SCALING_COEFFICIENT_INV = 1.0 / SCALING_COEFFICIENT;
const int DEFAULT_TOP = -40;
const int DEFAULT_HEIGHT = 80;
const int INDICATOR_SIZE = 8;
@ -238,7 +251,7 @@ void EasyMinimapItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h)
m_boundingRect.setRect(x, y, w, h);
}
void EasyMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items)
void EasyMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items)
{
m_pSource = _items;
m_threadId = _thread_id;
@ -428,7 +441,7 @@ void EasyGraphicsScrollbar::hideChrono()
//////////////////////////////////////////////////////////////////////////
void EasyGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items)
void EasyGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items)
{
m_minimap->setSource(_thread_id, _items);
m_slider->setVisible(m_minimap->isVisible());
@ -477,7 +490,6 @@ void EasyGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event)
void EasyGraphicsScrollbar::wheelEvent(QWheelEvent* _event)
{
qreal deltaSign = _event->delta() < 0 ? -1 : 1;
auto w = m_slider->halfwidth() * (_event->delta() < 0 ? ::profiler_gui::SCALING_COEFFICIENT : ::profiler_gui::SCALING_COEFFICIENT_INV);
setValue(mapToScene(_event->pos()).x() - m_minimumValue - w);
emit wheeled(w * m_windowScale, _event->delta());
@ -493,14 +505,14 @@ void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event)
void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
{
if (::profiler_gui::EASY_GLOBALS.profiler_blocks.empty())
if (EASY_GLOBALS.profiler_blocks.empty())
{
return;
}
QMenu menu;
for (const auto& it : ::profiler_gui::EASY_GLOBALS.profiler_blocks)
for (const auto& it : EASY_GLOBALS.profiler_blocks)
{
QString label;
if (it.second.thread_name && it.second.thread_name[0] != 0)
@ -512,10 +524,11 @@ void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
label = ::std::move(QString("Thread %1").arg(it.first));
}
auto action = new EasyIdAction(label, it.first);
auto action = new QAction(label, nullptr);
action->setData(it.first);
action->setCheckable(true);
action->setChecked(it.first == ::profiler_gui::EASY_GLOBALS.selected_thread);
connect(action, &EasyIdAction::clicked, this, &This::onThreadActionClicked);
action->setChecked(it.first == EASY_GLOBALS.selected_thread);
connect(action, &QAction::triggered, this, &This::onThreadActionClicked);
menu.addAction(action);
}
@ -526,12 +539,17 @@ void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
//////////////////////////////////////////////////////////////////////////
void EasyGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id)
void EasyGraphicsScrollbar::onThreadActionClicked(bool)
{
if (_id != m_minimap->threadId())
auto action = qobject_cast<QAction*>(sender());
if (action == nullptr)
return;
const auto thread_id = action->data().toUInt();
if (thread_id != m_minimap->threadId())
{
::profiler_gui::EASY_GLOBALS.selected_thread = _id;
emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(_id);
EASY_GLOBALS.selected_thread = thread_id;
emit EASY_GLOBALS.events.selectedThreadChanged(thread_id);
}
}

View File

@ -2,17 +2,30 @@
* file name : graphics_scrollbar.h
* ----------------- :
* creation time : 2016/07/04
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : .
* description : This file contains declaration of
* ----------------- :
* change log : * 2016/07/04 Victor Zarubkin: Initial commit.
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__GRAPHICS_SCROLLBAR__H
@ -66,7 +79,7 @@ class EasyMinimapItem : public QGraphicsItem
QRectF m_boundingRect;
qreal m_maxDuration;
qreal m_minDuration;
const ::profiler_gui::ProfItems* m_pSource;
const ::profiler_gui::EasyItems* m_pSource;
::profiler::thread_id_t m_threadId;
public:
@ -88,53 +101,12 @@ public:
void setBoundingRect(const QRectF& _rect);
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items);
void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items);
}; // END of class EasyMinimapItem.
//////////////////////////////////////////////////////////////////////////
class EasyIdAction : public QAction
{
Q_OBJECT
private:
typedef QAction Parent;
typedef EasyIdAction This;
::profiler::thread_id_t m_id;
public:
EasyIdAction(const QString& _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id)
{
connect(this, &Parent::triggered, this, &This::onToggle);
}
EasyIdAction(const char* _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id)
{
connect(this, &Parent::triggered, this, &This::onToggle);
}
virtual ~EasyIdAction()
{
}
private:
void onToggle(bool)
{
emit clicked(m_id);
}
signals:
void clicked(::profiler::thread_id_t _id);
};
//////////////////////////////////////////////////////////////////////////
class EasyGraphicsScrollbar : public QGraphicsView
{
Q_OBJECT
@ -190,9 +162,9 @@ public:
void showChrono();
void hideChrono();
void setMinimapFrom(::profiler::thread_id_t _thread_id, const::profiler_gui::ProfItems* _items);
void setMinimapFrom(::profiler::thread_id_t _thread_id, const::profiler_gui::EasyItems* _items);
inline void setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems& _items)
inline void setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems& _items)
{
setMinimapFrom(_thread_id, &_items);
}
@ -205,7 +177,7 @@ signals:
private slots:
void onThreadActionClicked(::profiler::thread_id_t _id);
void onThreadActionClicked(bool);
void onWindowWidthChange(qreal _width);
}; // END of class EasyGraphicsScrollbar.

View File

@ -1,38 +1,65 @@
#include <QApplication>
#include <QTreeView>
#include <QFileSystemModel>
/************************************************************************
* file name : main.cpp
* ----------------- :
* creation time : 2016/04/29
* authors : Sergey Yagovtsev, Victor Zarubkin
* email : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : Main file for EasyProfiler GUI.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include <chrono>
#include <QApplication>
//#include <QTreeView>
//#include <QFileSystemModel>
//#include "treemodel.h"
#include "main_window.h"
#include "profiler/reader.h"
//#ifdef WIN32
//#ifdef _WIN32
//#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
//#endif
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QApplication app(argc, argv);
//QFileSystemModel *model = new QFileSystemModel;
//model->setRootPath(QDir::currentPath());
// const char* filename = 0;
//QFileSystemModel *model = new QFileSystemModel;
//model->setRootPath(QDir::currentPath());
// const char* filename = 0;
// if(argc > 1 && argv[1]){
// filename = argv[1];
// filename = argv[1];
// }else{
// return 255;
// }
// return 255;
// }
// QFile file(filename);
// file.open(QIODevice::ReadOnly);
// file.open(QIODevice::ReadOnly);
// TreeModel model(file.readAll());
// file.close();
// file.close();
// QTreeView *tree = new QTreeView();
// tree->setModel(&model);
// QTreeView *tree = new QTreeView();
// tree->setModel(&model);
//
// tree->show();
// tree->show();
auto now = ::std::chrono::duration_cast<std::chrono::seconds>(::std::chrono::system_clock::now().time_since_epoch()).count() >> 1;
srand((unsigned int)now);

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
* file name : main_window.h
* ----------------- :
* creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -11,7 +10,21 @@
* change log : * 2016/06/26 Victor Zarubkin: initial commit.
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H
@ -32,13 +45,16 @@ class QDockWidget;
class EasyFileReader final
{
::profiler::SerializedData m_serializedData; ///<
::profiler::thread_blocks_tree_t m_blocksTree; ///<
QString m_filename; ///<
::std::thread m_thread; ///<
::std::atomic_bool m_bDone; ///<
::std::atomic<int> m_progress; ///<
::std::atomic<unsigned int> m_size; ///<
::profiler::SerializedData m_serializedBlocks; ///<
::profiler::SerializedData m_serializedDescriptors; ///<
::profiler::descriptors_list_t m_descriptors; ///<
::profiler::blocks_t m_blocks; ///<
::profiler::thread_blocks_tree_t m_blocksTree; ///<
QString m_filename; ///<
::std::thread m_thread; ///<
::std::atomic_bool m_bDone; ///<
::std::atomic<int> m_progress; ///<
::std::atomic<unsigned int> m_size; ///<
public:
@ -52,7 +68,9 @@ public:
void load(const QString& _filename);
void interrupt();
void get(::profiler::SerializedData& _data, ::profiler::thread_blocks_tree_t& _tree, QString& _filename);
void get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors,
::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree,
QString& _filename);
}; // END of class EasyFileReader.
@ -67,13 +85,14 @@ protected:
typedef EasyMainWindow This;
typedef QMainWindow Parent;
QString m_lastFile;
QDockWidget* m_treeWidget;
QDockWidget* m_graphicsView;
class QProgressDialog* m_progress;
QTimer m_readerTimer;
::profiler::SerializedData m_serializedData;
EasyFileReader m_reader;
QString m_lastFile;
QDockWidget* m_treeWidget;
QDockWidget* m_graphicsView;
class QProgressDialog* m_progress;
QTimer m_readerTimer;
::profiler::SerializedData m_serializedBlocks;
::profiler::SerializedData m_serializedDescriptors;
EasyFileReader m_reader;
public:
@ -108,7 +127,7 @@ private:
void loadSettings();
void loadGeometry();
void saveSettingsAndGeometry();
void saveSettingsAndGeometry();
}; // END of class EasyMainWindow.

View File

@ -2,7 +2,6 @@
* file name : tree_widget_item.cpp
* ----------------- :
* creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -13,7 +12,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "tree_widget_item.h"
@ -21,7 +34,7 @@
//////////////////////////////////////////////////////////////////////////
EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent)
EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock, Parent* _parent)
: Parent(_parent)
, m_block(_treeBlock)
, m_customBGColor(0)
@ -75,15 +88,25 @@ bool EasyTreeWidgetItem::operator < (const Parent& _other) const
return false;
}
const ::profiler::BlocksTree* EasyTreeWidgetItem::block() const
::profiler::block_index_t EasyTreeWidgetItem::block_index() const
{
return m_block;
}
::profiler_gui::EasyBlock& EasyTreeWidgetItem::guiBlock()
{
return easyBlock(m_block);
}
const ::profiler::BlocksTree& EasyTreeWidgetItem::block() const
{
return blocksTree(m_block);
}
::profiler::timestamp_t EasyTreeWidgetItem::duration() const
{
if (m_block->node)
return m_block->node->block()->duration();
if (parent() != nullptr)
return block().node->duration();
return data(COL_DURATION, Qt::UserRole).toULongLong();
}
@ -173,7 +196,8 @@ void EasyTreeWidgetItem::collapseAll()
}
setExpanded(false);
::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = false;
if (parent() != nullptr)
guiBlock().expanded = false;
}
void EasyTreeWidgetItem::expandAll()
@ -184,7 +208,8 @@ void EasyTreeWidgetItem::expandAll()
}
setExpanded(true);
::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = true;
if (parent() != nullptr)
guiBlock().expanded = true;
}
//////////////////////////////////////////////////////////////////////////

View File

@ -2,7 +2,6 @@
* file name : tree_widget_item.h
* ----------------- :
* creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -14,7 +13,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__TREE_WIDGET_ITEM__H_
@ -75,7 +88,7 @@ class EasyTreeWidgetItem : public QTreeWidgetItem
typedef QTreeWidgetItem Parent;
typedef EasyTreeWidgetItem This;
const ::profiler::BlocksTree* m_block;
const ::profiler::block_index_t m_block;
QRgb m_customBGColor;
QRgb m_customTextColor;
@ -84,14 +97,16 @@ public:
using Parent::setBackgroundColor;
using Parent::setTextColor;
EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent = nullptr);
EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock = ::profiler_gui::numeric_max<decltype(m_block)>(), Parent* _parent = nullptr);
virtual ~EasyTreeWidgetItem();
bool operator < (const Parent& _other) const override;
public:
const ::profiler::BlocksTree* block() const;
::profiler::block_index_t block_index() const;
::profiler_gui::EasyBlock& guiBlock();
const ::profiler::BlocksTree& block() const;
::profiler::timestamp_t duration() const;
::profiler::timestamp_t selfDuration() const;

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
* file name : tree_widget_loader.h
* ----------------- :
* creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
@ -14,7 +13,21 @@
* :
* : *
* ----------------- :
* license : TODO: add license text
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#ifndef EASY__TREE_WIDGET_LOADER__H_

View File

@ -1,17 +1,17 @@
project(profiler_reader)
set(CPP_FILES
main.cpp
main.cpp
)
set(SOURCES
${CPP_FILES}
${CPP_FILES}
)
add_executable(${PROJECT_NAME} ${SOURCES})
if(UNIX)
set(SPEC_LIB pthread)
set(SPEC_LIB pthread)
endif(UNIX)
target_link_libraries(${PROJECT_NAME} easy_profiler ${SPEC_LIB})

View File

@ -16,57 +16,57 @@
class TreePrinter
{
struct Info{
std::string name;
std::string info;
};
std::vector<Info> m_rows;
struct Info{
std::string name;
std::string info;
};
std::vector<Info> m_rows;
public:
TreePrinter(){
TreePrinter(){
}
void addNewRow(int level)
{
}
void addNewRow(int level)
{
}
}
void printTree()
{
for (auto& row : m_rows){
std::cout << row.name << " " << row.info << std::endl;
}
}
void printTree()
{
for (auto& row : m_rows){
std::cout << row.name << " " << row.info << std::endl;
}
}
};
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){
auto duration = tree.node->block()->duration();
float duration_ms = duration / 1e6f;
float percent = parent_dur ? float(duration) / float(parent_dur)*100.0f : 100.0f;
float rpercent = root_dur ? float(duration) / float(root_dur)*100.0f : 100.0f;
std::cout << std::string(level, '\t') << tree.node->getName()
<< std::string(5 - level, '\t')
/*<< std::string(level, ' ')*/ << percent << "%| "
<< rpercent << "%| "
<< duration_ms << " ms"
<< std::endl;
if (root_dur == 0){
root_dur = tree.node->block()->duration();
}
}
else{
root_dur = 0;
}
//
//if (tree.node){
// auto duration = tree.node->block()->duration();
// float duration_ms = duration / 1e6f;
// float percent = parent_dur ? float(duration) / float(parent_dur)*100.0f : 100.0f;
// float rpercent = root_dur ? float(duration) / float(root_dur)*100.0f : 100.0f;
// std::cout << std::string(level, '\t') << tree.node->getName()
// << std::string(5 - level, '\t')
// /*<< std::string(level, ' ')*/ << percent << "%| "
// << rpercent << "%| "
// << duration_ms << " ms"
// << std::endl;
// if (root_dur == 0){
// root_dur = tree.node->block()->duration();
// }
//}
//else{
// root_dur = 0;
//}
//
for (const auto& i : tree.children){
//for (const auto& i : tree.children){
printTree(printer, i, level + 1, tree.node ? tree.node->block()->duration() : 0, root_dur);
}
// printTree(printer, i, level + 1, tree.node ? tree.node->block()->duration() : 0, root_dur);
//}
}
int main(int argc, char* argv[])
@ -99,7 +99,7 @@ int main(int argc, char* argv[])
if (dump_filename.size() > 2)
{
PROFILER_ENABLE
EASY_PROFILER_ENABLE;
std::cout << "Will dump reader prof file to " << dump_filename << std::endl;
}
else
@ -110,17 +110,19 @@ int main(int argc, char* argv[])
auto start = std::chrono::system_clock::now();
::profiler::SerializedData data;
auto blocks_counter = fillTreesFromFile(filename.c_str(), data, threaded_trees, true);
::profiler::SerializedData serialized_blocks, serialized_descriptors;
::profiler::descriptors_list_t descriptors;
::profiler::blocks_t blocks;
auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, true);
auto end = std::chrono::system_clock::now();
std::cout << "Blocks count: " << blocks_counter << std::endl;
std::cout << "dT = " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << " usec" << std::endl;
//for (const auto & i : threaded_trees){
// TreePrinter p;
// std::cout << std::string(20, '=') << " thread "<< i.first << " "<< std::string(20, '=') << std::endl;
// printTree(p, i.second.tree,-1);
// TreePrinter p;
// std::cout << std::string(20, '=') << " thread "<< i.first << " "<< std::string(20, '=') << std::endl;
// printTree(p, i.second.tree,-1);
//}
if (!dump_filename.empty())

View File

@ -1,22 +1,22 @@
project(profiler_sample)
set(CPP_FILES
main.cpp
main.cpp
)
set(SOURCES
${CPP_FILES}
${CPP_FILES}
)
add_executable(${PROJECT_NAME} ${SOURCES})
set(DISABLED_PROFILER_NAME
"${PROJECT_NAME}_disabled_profiler"
"${PROJECT_NAME}_disabled_profiler"
)
add_executable(${DISABLED_PROFILER_NAME} ${SOURCES})
if(UNIX)
set(SPEC_LIB pthread)
set(SPEC_LIB pthread)
endif(UNIX)
target_link_libraries(${PROJECT_NAME} easy_profiler ${SPEC_LIB})

View File

@ -26,22 +26,22 @@ void localSleep(int magic=200000)
}
void loadingResources(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkcyan);
EASY_FUNCTION(profiler::colors::DarkCyan);
localSleep();
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
void prepareMath(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
EASY_FUNCTION(profiler::colors::Blue);
int* intarray = new int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = i * i;
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
void calcIntersect(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
EASY_FUNCTION(profiler::colors::Blue);
//int* intarray = new int[OBJECTS * OBJECTS];
int* intarray = new int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
@ -51,17 +51,17 @@ void calcIntersect(){
intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5;
}
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(4));
//std::this_thread::sleep_for(std::chrono::milliseconds(4));
}
double multModel(double i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
EASY_FUNCTION(profiler::colors::Blue);
return i * sin(i) * cos(i);
}
void calcPhys(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
EASY_FUNCTION(profiler::colors::Blue);
double* intarray = new double[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2);
@ -71,213 +71,218 @@ void calcPhys(){
double calcSubbrain(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
EASY_FUNCTION(profiler::colors::Blue);
return i * i * i - i / 10 + (OBJECTS - i) * 7 ;
}
void calcBrain(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
EASY_FUNCTION(profiler::colors::Blue);
double* intarray = new double[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = calcSubbrain(i) + double(i * 180 / 3);
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
void calculateBehavior(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkblue);
EASY_FUNCTION(profiler::colors::DarkBlue);
calcPhys();
calcBrain();
}
void modellingStep(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Navy);
prepareMath();
calculateBehavior();
EASY_FUNCTION(profiler::colors::Navy);
prepareMath();
calculateBehavior();
}
void prepareRender(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkred);
EASY_FUNCTION(profiler::colors::DarkRed);
localSleep();
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
}
int multPhys(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
EASY_FUNCTION(profiler::colors::Red);
return i * i * i * i / 100;
}
int calcPhysicForObject(int i)
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
EASY_FUNCTION(profiler::colors::Red);
return multPhys(i) + i / 3 - (OBJECTS - i) * 15;
}
void calculatePhysics(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
EASY_FUNCTION(profiler::colors::Red);
unsigned int* intarray = new unsigned int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i)
intarray[i] = calcPhysicForObject(i);
delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
}
void frame(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Magenta);
prepareRender();
calculatePhysics();
EASY_FUNCTION(profiler::colors::Magenta);
prepareRender();
calculatePhysics();
}
void loadingResourcesThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Resource loading")
for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){
loadingResources();
PROFILER_ADD_EVENT_GROUPED("Resources Loading!",profiler::colors::Cyan);
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
EASY_THREAD("Resource loading");
for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){
loadingResources();
EASY_EVENT("Resources Loading!", profiler::colors::Cyan);
localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
}
void modellingThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Modelling")
for (int i = 0; i < RENDER_SPEPS; i++){
modellingStep();
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
EASY_THREAD("Modelling");
for (int i = 0; i < RENDER_SPEPS; i++){
modellingStep();
localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
}
void renderThread(){
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Render")
for (int i = 0; i < MODELLING_STEPS; i++){
frame();
//std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; });
EASY_THREAD("Render");
for (int i = 0; i < MODELLING_STEPS; i++){
frame();
localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
}
void four()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(37));
EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(37));
}
void five()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
void six()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(42));
EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(42));
}
void three()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
four();
five();
six();
EASY_FUNCTION(profiler::colors::Red);
four();
five();
six();
}
void seven()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(147));
EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(147));
}
void two()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(26));
EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(26));
}
void one()
{
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
two();
three();
seven();
EASY_FUNCTION(profiler::colors::Red);
two();
three();
seven();
}
/*
one
two
three
four
five
six
seven
two
three
four
five
six
seven
*/
int main(int argc, char* argv[])
{
if (argc > 1 && argv[1]){
OBJECTS = std::atoi(argv[1]);
}
if (argc > 2 && argv[2]){
RENDER_SPEPS = std::atoi(argv[2]);
}
if (argc > 3 && argv[3]){
MODELLING_STEPS = std::atoi(argv[3]);
}
if (argc > 4 && argv[4]){
RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
}
if (argc > 1 && argv[1]){
OBJECTS = std::atoi(argv[1]);
}
if (argc > 2 && argv[2]){
RENDER_SPEPS = std::atoi(argv[2]);
}
if (argc > 3 && argv[3]){
MODELLING_STEPS = std::atoi(argv[3]);
}
if (argc > 4 && argv[4]){
RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
}
std::cout << "Objects count: " << OBJECTS << std::endl;
std::cout << "Render steps: " << RENDER_SPEPS << std::endl;
std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl;
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
std::cout << "Objects count: " << OBJECTS << std::endl;
std::cout << "Render steps: " << RENDER_SPEPS << std::endl;
std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl;
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
auto start = std::chrono::system_clock::now();
PROFILER_ENABLE;
PROFILER_SET_MAIN_THREAD;
//one();
//one();
/**/
std::vector<std::thread> threads;
auto start = std::chrono::system_clock::now();
EASY_PROFILER_ENABLE;
EASY_MAIN_THREAD;
//one();
//one();
/**/
std::vector<std::thread> threads;
std::thread render = std::thread(renderThread);
std::thread modelling = std::thread(modellingThread);
std::thread render = std::thread(renderThread);
std::thread modelling = std::thread(modellingThread);
for(int i=0; i < 3; i++){
threads.emplace_back(std::thread(loadingResourcesThread));
threads.emplace_back(std::thread(renderThread));
threads.emplace_back(std::thread(modellingThread));
}
{
std::lock_guard<std::mutex> lk(cv_m);
g_i = 1;
}
cv.notify_all();
for(int i=0; i < 3; i++){
threads.emplace_back(std::thread(loadingResourcesThread));
threads.emplace_back(std::thread(renderThread));
threads.emplace_back(std::thread(modellingThread));
}
{
std::lock_guard<std::mutex> lk(cv_m);
g_i = 1;
}
cv.notify_all();
render.join();
modelling.join();
for(auto& t : threads){
t.join();
}
/**/
for (int i = 0; i < RENDER_SPEPS; ++i) {
modellingStep();
localSleep(1200000);
}
auto end = std::chrono::system_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
render.join();
modelling.join();
for(auto& t : threads){
t.join();
}
/**/
std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl;
auto end = std::chrono::system_clock::now();
auto elapsed =
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
auto blocks_count = profiler::dumpBlocksToFile("test.prof");
std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl;
std::cout << "Blocks count: " << blocks_count << std::endl;
auto blocks_count = profiler::dumpBlocksToFile("test.prof");
return 0;
std::cout << "Blocks count: " << blocks_count << std::endl;
return 0;
}

View File

@ -0,0 +1,36 @@
global target_pid
global target_name
probe scheduler.ctxswitch {
if (target_pid != 0
&& next_pid != target_pid
&& prev_pid != target_pid)
next
if (target_name != ""
&& prev_task_name != target_name
&& next_task_name != target_name)
next
//printf("Switch from %d(%s) to %d(%s) at %d\n",prev_tid, prev_task_name,next_tid,next_task_name, gettimeofday_ns())
printf("%d %d %d\n",gettimeofday_ns(),prev_tid, next_tid )
}
probe begin
{
target_pid = 0
target_name = ""
%( $# == 1 || $# > 2 %?
log("Wrong number of arguments, use none, 'pid nr' or 'name proc'")
exit()
%)
%( $# == 2 %?
if(@1 == "pid")
target_pid = strtol(@2, 10)
if(@1 == "name")
target_name = @2
%)
}

View File

@ -1,24 +1,27 @@
project(easy_profiler)
set(CPP_FILES
block.cpp
profile_manager.cpp
reader.cpp
block.cpp
profile_manager.cpp
reader.cpp
event_trace_win.cpp
)
set(H_FILES
${ROOT}/include/profiler/profiler.h
${ROOT}/include/profiler/reader.h
profile_manager.h
spin_lock.h
${ROOT}/include/profiler/profiler.h
${ROOT}/include/profiler/reader.h
${ROOT}/include/profiler/event_trace_status.h
profile_manager.h
spin_lock.h
event_trace_win.h
)
set(SOURCES
${CPP_FILES}
${H_FILES}
${CPP_FILES}
${H_FILES}
)
add_definitions(
-D_BUILD_PROFILER
-D_BUILD_PROFILER
)
add_library(${PROJECT_NAME} SHARED ${SOURCES})

View File

@ -1,3 +1,28 @@
/************************************************************************
* file name : block.cpp
* ----------------- :
* creation time : 2016/02/16
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of profiling blocks
* :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "profiler/profiler.h"
#include "profile_manager.h"
#include <ctime>
@ -6,73 +31,69 @@
using namespace profiler;
#ifdef WIN32
struct ProfPerformanceFrequency {
LARGE_INTEGER frequency;
ProfPerformanceFrequency() { QueryPerformanceFrequency(&frequency); }
} const WINDOWS_CPU_INFO;
#ifdef _WIN32
decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY = ([](){ LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return freq.QuadPart; })();
#endif
BaseBlockData::BaseBlockData(source_id_t _source_id, color_t _color, block_type_t _type, thread_id_t _thread_id)
: begin(0)
, end(0)
, thread_id(_thread_id)
#ifndef EASY_USE_OLD_FILE_FORMAT
, source_id(_source_id)
#endif
, type(_type)
, color(_color)
{
}
Block::Block(const char* _name, color_t _color, block_type_t _type, source_id_t _source_id)
: Block(_name, getCurrentThreadId(), _color, _type, _source_id)
{
}
Block::Block(const char* _name, thread_id_t _thread_id, color_t _color, block_type_t _type, source_id_t _source_id)
: BaseBlockData(_source_id, _color, _type, _thread_id)
, m_name(_name)
{
tick(begin);
if (BLOCK_TYPE_BLOCK != this->type)
{
end = begin;
}
}
inline timestamp_t getCurrentTime()
{
#ifdef WIN32
//see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx
LARGE_INTEGER elapsedMicroseconds;
if (!QueryPerformanceCounter(&elapsedMicroseconds))
return 0;
elapsedMicroseconds.QuadPart *= 1000000000LL;
elapsedMicroseconds.QuadPart /= WINDOWS_CPU_INFO.frequency.QuadPart;
return (timestamp_t)elapsedMicroseconds.QuadPart;
#ifdef _WIN32
//see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx
LARGE_INTEGER elapsedMicroseconds;
if (!QueryPerformanceCounter(&elapsedMicroseconds))
return 0;
//elapsedMicroseconds.QuadPart *= 1000000000LL;
//elapsedMicroseconds.QuadPart /= CPU_FREQUENCY;
return (timestamp_t)elapsedMicroseconds.QuadPart;
#else
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time_point;
time_point = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now());
return time_point.time_since_epoch().count();
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time_point;
time_point = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now());
return time_point.time_since_epoch().count();
#endif
}
void BaseBlockData::tick(timestamp_t& stamp)
BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id)
: m_begin(_begin_time)
, m_end(0)
, m_id(_descriptor_id)
{
stamp = getCurrentTime();
}
Block::Block(Block&& that)
: BaseBlockData(that.m_begin, that.m_id)
, m_name(that.m_name)
{
m_end = that.m_end;
}
Block::Block(block_type_t _block_type, block_id_t _descriptor_id, const char* _name)
: Block(getCurrentTime(), _block_type, _descriptor_id, _name)
{
}
Block::Block(timestamp_t _begin_time, block_type_t _block_type, block_id_t _descriptor_id, const char* _name)
: BaseBlockData(_begin_time, _descriptor_id)
, m_name(_name)
{
if (static_cast<uint8_t>(_block_type) < BLOCK_TYPE_BLOCK)
{
m_end = m_begin;
}
}
void Block::finish()
{
m_end = getCurrentTime();
}
void Block::finish(timestamp_t _end_time)
{
m_end = _end_time;
}
Block::~Block()
{
if (this->type == BLOCK_TYPE_BLOCK)
{
if (this->isCleared())//this block was cleared by END_BLOCK macros
return;
if (!this->isFinished())
this->finish();
endBlock();
}
if (!isFinished())
::profiler::endBlock();
}

177
src/event_trace_win.cpp Normal file
View File

@ -0,0 +1,177 @@
#ifdef _WIN32
#include <memory.h>
#include <chrono>
#include "event_trace_win.h"
#include "profiler/profiler.h"
#include "profile_manager.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//extern ProfileManager& MANAGER;
#define MANAGER ProfileManager::instance()
namespace profiler {
// CSwitch class
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa964744(v=vs.85).aspx
// EventType = 36
struct CSwitch final
{
uint32_t NewThreadId;
uint32_t OldThreadId;
int8_t NewThreadPriority;
int8_t OldThreadPriority;
uint8_t PreviousCState;
int8_t SpareByte;
int8_t OldThreadWaitReason;
int8_t OldThreadWaitMode;
int8_t OldThreadState;
int8_t OldThreadWaitIdealProcessor;
uint32_t NewThreadWaitTime;
uint32_t Reserved;
};
void WINAPI processTraceEvent(PEVENT_RECORD _traceEvent)
{
static const decltype(_traceEvent->EventHeader.EventDescriptor.Opcode) SWITCH_CONTEXT_OPCODE = 36;
if (_traceEvent->EventHeader.EventDescriptor.Opcode != SWITCH_CONTEXT_OPCODE)
return;
if (sizeof(CSwitch) != _traceEvent->UserDataLength)
return;
//EASY_FUNCTION(::profiler::colors::Red);
auto _contextSwitchEvent = reinterpret_cast<CSwitch*>(_traceEvent->UserData);
const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
static const auto desc = MANAGER.addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, desc);
MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, time);
}
//////////////////////////////////////////////////////////////////////////
EasyEventTracer& EasyEventTracer::instance()
{
static EasyEventTracer tracer;
return tracer;
}
EasyEventTracer::EasyEventTracer()
{
}
EasyEventTracer::~EasyEventTracer()
{
disable();
}
::profiler::EventTracingEnableStatus EasyEventTracer::startTrace(bool _force, int _step)
{
auto startTraceResult = StartTrace(&m_sessionHandle, KERNEL_LOGGER_NAME, props());
switch (startTraceResult)
{
case ERROR_SUCCESS:
return EVENT_TRACING_LAUNCHED_SUCCESSFULLY;
case ERROR_ALREADY_EXISTS:
{
if (_force)
{
// Try to stop another event tracing session to force launch self session.
if ((_step == 0 && 32 < (int)ShellExecute(NULL, NULL, "logman", "stop \"" KERNEL_LOGGER_NAME "\" -ets", NULL, SW_HIDE)) || (_step > 0 && _step < 6))
{
// Command executed successfully. Wait for a few time until tracing session finish.
::std::this_thread::sleep_for(::std::chrono::milliseconds(500));
return startTrace(true, ++_step);
}
}
return EVENT_TRACING_WAS_LAUNCHED_BY_SOMEBODY_ELSE;
}
case ERROR_ACCESS_DENIED:
return EVENT_TRACING_NOT_ENOUGH_ACCESS_RIGHTS;
case ERROR_BAD_LENGTH:
return EVENT_TRACING_BAD_PROPERTIES_SIZE;
}
return EVENT_TRACING_MISTERIOUS_ERROR;
}
::profiler::EventTracingEnableStatus EasyEventTracer::enable(bool _force)
{
static const decltype(m_properties.base.Wnode.ClientContext) RAW_TIMESTAMP_TIME_TYPE = 1;
if (m_bEnabled)
return EVENT_TRACING_LAUNCHED_SUCCESSFULLY;
// Clear properties
memset(&m_properties, 0, sizeof(m_properties));
m_properties.base.Wnode.BufferSize = sizeof(m_properties);
m_properties.base.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
m_properties.base.Wnode.ClientContext = RAW_TIMESTAMP_TIME_TYPE;
m_properties.base.Wnode.Guid = SystemTraceControlGuid;
m_properties.base.LoggerNameOffset = sizeof(m_properties.base);
m_properties.base.EnableFlags = EVENT_TRACE_FLAG_CSWITCH;
m_properties.base.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
auto res = startTrace(_force);
if (res != EVENT_TRACING_LAUNCHED_SUCCESSFULLY)
return res;
memset(&m_trace, 0, sizeof(m_trace));
m_trace.LoggerName = KERNEL_LOGGER_NAME;
m_trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP;
m_trace.EventRecordCallback = ::profiler::processTraceEvent;
m_openedHandle = OpenTrace(&m_trace);
if (m_openedHandle == INVALID_PROCESSTRACE_HANDLE)
return EVENT_TRACING_OPEN_TRACE_ERROR;
// Have to launch a thread to process events because according to MSDN documentation:
//
// The ProcessTrace function blocks the thread until it delivers all events, the BufferCallback function returns FALSE,
// or you call CloseTrace. If the consumer is consuming events in real time, the ProcessTrace function returns after
// the controller stops the trace session. (Note that there may be a several-second delay before the function returns.)
//
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364093(v=vs.85).aspx
m_stubThread = ::std::move(::std::thread([this]()
{
EASY_THREAD("EasyProfiler.EventTracing");
//EASY_BLOCK("ProcessTrace()", ::profiler::colors::Red);
ProcessTrace(&m_openedHandle, 1, 0, 0);
}));
m_bEnabled = true;
return EVENT_TRACING_LAUNCHED_SUCCESSFULLY;
}
void EasyEventTracer::disable()
{
if (!m_bEnabled)
return;
ControlTrace(m_openedHandle, KERNEL_LOGGER_NAME, props(), EVENT_TRACE_CONTROL_STOP);
CloseTrace(m_openedHandle);
// Wait for ProcessThread to finish
if (m_stubThread.joinable())
m_stubThread.join();
m_bEnabled = false;
}
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // _WIN32

66
src/event_trace_win.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef EASY_PROFILER__EVENT_TRACE_WINDOWS__H_
#define EASY_PROFILER__EVENT_TRACE_WINDOWS__H_
#ifdef _WIN32
#define INITGUID // This is to enable using SystemTraceControlGuid in evntrace.h.
#include <Windows.h>
//#include <Strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#include <evntcons.h>
#include <thread>
#include "profiler/event_trace_status.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler {
class EasyEventTracer final
{
#pragma pack(push, 1)
struct Properties final {
EVENT_TRACE_PROPERTIES base;
char sessionName[sizeof(KERNEL_LOGGER_NAME)];
};
#pragma pack(pop)
::std::thread m_stubThread;
Properties m_properties;
EVENT_TRACE_LOGFILE m_trace;
TRACEHANDLE m_sessionHandle = INVALID_PROCESSTRACE_HANDLE;
TRACEHANDLE m_openedHandle = INVALID_PROCESSTRACE_HANDLE;
bool m_bEnabled = false;
public:
static EasyEventTracer& instance();
~EasyEventTracer();
::profiler::EventTracingEnableStatus enable(bool _force = false);
void disable();
private:
EasyEventTracer();
inline EVENT_TRACE_PROPERTIES* props()
{
return reinterpret_cast<EVENT_TRACE_PROPERTIES*>(&m_properties);
}
::profiler::EventTracingEnableStatus startTrace(bool _force, int _step = 0);
}; // END of class EasyEventTracer.
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // _WIN32
#endif // EASY_PROFILER__EVENT_TRACE_WINDOWS__H_

View File

@ -1,190 +1,420 @@
#include "profile_manager.h"
#include <thread>
#include <string.h>
#include <fstream>
using namespace profiler;
auto& MANAGER = ProfileManager::instance();
extern "C"{
void PROFILER_API endBlock()
{
MANAGER.endBlock();
}
void PROFILER_API setEnabled(bool isEnable)
{
MANAGER.setEnabled(isEnable);
}
void PROFILER_API beginBlock(Block& _block)
{
MANAGER.beginBlock(_block);
}
unsigned int PROFILER_API dumpBlocksToFile(const char* filename)
{
return MANAGER.dumpBlocksToFile(filename);
}
void PROFILER_API setThreadName(const char* name)
{
return MANAGER.setThreadName(name);
}
}
SerializedBlock* SerializedBlock::create(const Block& block, uint64_t& memory_size)
{
auto name_length = static_cast<uint16_t>(strlen(block.getName()));
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
auto data = ::new char[size];
::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
memory_size += size;
return reinterpret_cast<SerializedBlock*>(data);
}
void SerializedBlock::destroy(SerializedBlock* that)
{
::delete[] reinterpret_cast<char*>(that);
}
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
: BaseBlockData(block)
{
auto name = const_cast<char*>(getName());
strncpy(name, block.getName(), name_length);
name[name_length] = 0;
}
//////////////////////////////////////////////////////////////////////////
BlockSourceInfo::BlockSourceInfo(const char* _filename, int _linenumber) : m_id(MANAGER.addSource(_filename, _linenumber))
{
}
SourceBlock::SourceBlock(const char* _filename, int _line) : m_filename(_filename), m_line(_line)
{
}
//////////////////////////////////////////////////////////////////////////
ProfileManager::ProfileManager()
{
}
ProfileManager::~ProfileManager()
{
//dumpBlocksToFile("test.prof");
}
ProfileManager& ProfileManager::instance()
{
///C++11 makes possible to create Singleton without any warry about thread-safeness
///http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
static ProfileManager m_profileManager;
return m_profileManager;
}
void ProfileManager::beginBlock(Block& _block)
{
if (!m_isEnabled)
return;
if (BLOCK_TYPE_BLOCK == _block.getType()){
guard_lock_t lock(m_spin);
m_openedBracketsMap[_block.getThreadId()].emplace(_block);
}
else{
_internalInsertBlock(_block);
}
}
void ProfileManager::endBlock()
{
if (!m_isEnabled)
return;
uint32_t threadId = getCurrentThreadId();
guard_lock_t lock(m_spin);
auto& stackOfOpenedBlocks = m_openedBracketsMap[threadId];
if (stackOfOpenedBlocks.empty())
return;
Block& lastBlock = stackOfOpenedBlocks.top();
if(!lastBlock.isFinished())
lastBlock.finish();
_internalInsertBlock(lastBlock);
stackOfOpenedBlocks.pop();
}
void ProfileManager::setEnabled(bool isEnable)
{
m_isEnabled = isEnable;
}
void ProfileManager::_internalInsertBlock(const profiler::Block& _block)
{
guard_lock_t lock(m_storedSpin);
m_blocks.emplace_back(SerializedBlock::create(_block, m_blocksMemorySize));
}
unsigned int ProfileManager::dumpBlocksToFile(const char* filename)
{
::std::ofstream of(filename, std::fstream::binary);
auto blocks_number = static_cast<uint32_t>(m_blocks.size());
//of.write((const char*)&blocks_number, sizeof(uint32_t));
of.write((const char*)&m_blocksMemorySize, sizeof(uint64_t));
for (auto b : m_blocks)
{
auto sz = static_cast<uint16_t>(sizeof(BaseBlockData) + strlen(b->getName()) + 1);
of.write((const char*)&sz, sizeof(uint16_t));
of.write(b->data(), sz);
SerializedBlock::destroy(b);
}
m_blocksMemorySize = 0;
m_blocks.clear();
return blocks_number;
}
void ProfileManager::setThreadName(const char* name)
{
auto current_thread_id = getCurrentThreadId();
guard_lock_t lock(m_storedSpin);
auto find_it = m_namedThreades.find(current_thread_id);
if (find_it != m_namedThreades.end())
return;
profiler::Block block(name, current_thread_id, 0, profiler::BLOCK_TYPE_THREAD_SIGN);
m_blocks.emplace_back(SerializedBlock::create(block, m_blocksMemorySize));
m_namedThreades.insert(current_thread_id);
}
//////////////////////////////////////////////////////////////////////////
unsigned int ProfileManager::addSource(const char* _filename, int _line)
{
guard_lock_t lock(m_storedSpin);
const auto id = static_cast<unsigned int>(m_sources.size());
m_sources.emplace_back(_filename, _line);
return id;
}
//////////////////////////////////////////////////////////////////////////
/************************************************************************
* file name : profile_manager.cpp
* ----------------- :
* creation time : 2016/02/16
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of Profile manager and implement access c-function
* :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
* :
* : This program is free software : you can redistribute it and / or modify
* : it under the terms of the GNU General Public License as published by
* : the Free Software Foundation, either version 3 of the License, or
* : (at your option) any later version.
* :
* : This program is distributed in the hope that it will be useful,
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* : GNU General Public License for more details.
* :
* : You should have received a copy of the GNU General Public License
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
************************************************************************/
#include "profile_manager.h"
#include "profiler/serialized_block.h"
#include "event_trace_win.h"
#include <thread>
#include <string.h>
#include <fstream>
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
using namespace profiler;
#ifdef _WIN32
extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY;
#endif
//auto& MANAGER = ProfileManager::instance();
#define MANAGER ProfileManager::instance()
extern "C" {
PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
{
return MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color);
}
PROFILER_API void endBlock()
{
MANAGER.endBlock();
}
PROFILER_API void setEnabled(bool isEnable)
{
MANAGER.setEnabled(isEnable);
#ifdef _WIN32
if (isEnable)
EasyEventTracer::instance().enable(true);
else
EasyEventTracer::instance().disable();
#endif
}
PROFILER_API void beginBlock(Block& _block)
{
MANAGER.beginBlock(_block);
}
PROFILER_API uint32_t dumpBlocksToFile(const char* filename)
{
return MANAGER.dumpBlocksToFile(filename);
}
PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line)
{
return MANAGER.setThreadName(name, filename, _funcname, line);
}
PROFILER_API void setContextSwitchLogFilename(const char* name)
{
return MANAGER.setContextSwitchLogFilename(name);
}
PROFILER_API const char* getContextSwitchLogFilename()
{
return MANAGER.getContextSwitchLogFilename();
}
}
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
: BaseBlockData(block)
{
auto pName = const_cast<char*>(name());
if (name_length) strncpy(pName, block.name(), name_length);
pName[name_length] = 0;
}
//////////////////////////////////////////////////////////////////////////
BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color)
: m_line(_line)
, m_type(_block_type)
, m_color(_color)
{
}
BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
: BaseBlockDescriptor(_line, _block_type, _color)
, m_name(_name)
, m_filename(_filename)
{
_used_mem += sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2;
}
//////////////////////////////////////////////////////////////////////////
void ThreadStorage::storeBlock(const profiler::Block& block)
{
auto name_length = static_cast<uint16_t>(strlen(block.name()));
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
auto data = blocks.alloc.allocate(size);
::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
blocks.usedMemorySize += size;
blocks.closedList.emplace_back(reinterpret_cast<SerializedBlock*>(data));
}
void ThreadStorage::storeCSwitch(const profiler::Block& block)
{
auto name_length = static_cast<uint16_t>(strlen(block.name()));
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
auto data = sync.alloc.allocate(size);
::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
sync.usedMemorySize += size;
sync.closedList.emplace_back(reinterpret_cast<SerializedBlock*>(data));
}
void ThreadStorage::clearClosed()
{
blocks.clearClosed();
sync.clearClosed();
}
//////////////////////////////////////////////////////////////////////////
EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr;
// #ifdef _WIN32
// LPTOP_LEVEL_EXCEPTION_FILTER PREVIOUS_FILTER = NULL;
// LONG WINAPI easyTopLevelExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
// {
// std::ofstream testexp("TEST_EXP.txt", std::fstream::binary);
// testexp.write("APPLICATION CRASHED!", strlen("APPLICATION CRASHED!"));
//
// EasyEventTracer::instance().disable();
// if (PREVIOUS_FILTER)
// return PREVIOUS_FILTER(ExceptionInfo);
// return EXCEPTION_CONTINUE_SEARCH;
// }
// #endif
ProfileManager::ProfileManager()
{
// #ifdef _WIN32
// PREVIOUS_FILTER = SetUnhandledExceptionFilter(easyTopLevelExceptionFilter);
// #endif
}
ProfileManager::~ProfileManager()
{
//dumpBlocksToFile("test.prof");
}
ProfileManager& ProfileManager::instance()
{
///C++11 makes possible to create Singleton without any warry about thread-safeness
///http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
static ProfileManager m_profileManager;
return m_profileManager;
}
void ProfileManager::beginBlock(Block& _block)
{
if (!m_isEnabled)
return;
if (THREAD_STORAGE == nullptr)
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
if (!_block.isFinished())
THREAD_STORAGE->blocks.openedList.emplace(_block);
else
THREAD_STORAGE->storeBlock(_block);
}
void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id)
{
auto ts = findThreadStorage(_thread_id);
if (ts != nullptr)
ts->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, "");
}
void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id)
{
auto ts = findThreadStorage(_thread_id);
if (ts != nullptr)
{
profiler::Block lastBlock(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, "");
lastBlock.finish(_time);
ts->storeCSwitch(lastBlock);
}
}
void ProfileManager::endBlock()
{
if (!m_isEnabled)
return;
if (THREAD_STORAGE->blocks.openedList.empty())
return;
Block& lastBlock = THREAD_STORAGE->blocks.openedList.top();
if (!lastBlock.isFinished())
lastBlock.finish();
THREAD_STORAGE->storeBlock(lastBlock);
THREAD_STORAGE->blocks.openedList.pop();
}
void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime)
{
auto ts = findThreadStorage(_thread_id);
if (ts == nullptr || ts->sync.openedList.empty())
return;
Block& lastBlock = ts->sync.openedList.top();
lastBlock.finish(_endtime);
ts->storeCSwitch(lastBlock);
ts->sync.openedList.pop();
}
void ProfileManager::setEnabled(bool isEnable)
{
m_isEnabled = isEnable;
}
//////////////////////////////////////////////////////////////////////////
class FileWriter final
{
std::ofstream m_file;
public:
FileWriter(const char* _filename) : m_file(_filename, std::fstream::binary) { }
template <typename T> void write(const char* _data, T _size) {
m_file.write(_data, _size);
}
template <class T> void write(const T& _data) {
m_file.write((const char*)&_data, sizeof(T));
}
void writeBlock(const profiler::SerializedBlock* _block)
{
auto sz = static_cast<uint16_t>(sizeof(BaseBlockData) + strlen(_block->name()) + 1);
write(sz);
write(_block->data(), sz);
}
};
//////////////////////////////////////////////////////////////////////////
#define STORE_CSWITCHES_SEPARATELY
uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
{
const bool wasEnabled = m_isEnabled;
if (wasEnabled)
::profiler::setEnabled(false);
#ifndef _WIN32
uint64_t timestamp;
uint32_t thread_from, thread_to;
std::ifstream infile(m_csInfoFilename.c_str());
if(infile.is_open())
{
static const auto desc = addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
while (infile >> timestamp >> thread_from >> thread_to)
{
beginContextSwitch(thread_from, timestamp, desc);
endContextSwitch(thread_to, timestamp);
}
}
#endif
FileWriter of(filename);
uint64_t usedMemorySize = 0;
uint32_t blocks_number = 0;
for (const auto& thread_storage : m_threads)
{
const auto& t = thread_storage.second;
usedMemorySize += t.blocks.usedMemorySize + t.sync.usedMemorySize;
blocks_number += static_cast<uint32_t>(t.blocks.closedList.size()) + static_cast<uint32_t>(t.sync.closedList.size());
}
#ifdef _WIN32
of.write(CPU_FREQUENCY);
#else
of.write(0LL);
#endif
of.write(blocks_number);
of.write(usedMemorySize);
of.write(static_cast<uint32_t>(m_descriptors.size()));
of.write(m_usedMemorySize);
for (const auto& descriptor : m_descriptors)
{
const auto name_size = static_cast<uint16_t>(strlen(descriptor.name()) + 1);
const auto filename_size = static_cast<uint16_t>(strlen(descriptor.file()) + 1);
const auto size = static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor) + name_size + filename_size);
of.write(size);
of.write<profiler::BaseBlockDescriptor>(descriptor);
of.write(name_size);
of.write(descriptor.name(), name_size);
of.write(descriptor.file(), filename_size);
}
for (auto& thread_storage : m_threads)
{
auto& t = thread_storage.second;
of.write(thread_storage.first);
#ifdef STORE_CSWITCHES_SEPARATELY
of.write(static_cast<uint32_t>(t.blocks.closedList.size()));
#else
of.write(static_cast<uint32_t>(t.blocks.closedList.size()) + static_cast<uint32_t>(t.sync.closedList.size()));
uint32_t i = 0;
#endif
for (auto b : t.blocks.closedList)
{
#ifndef STORE_CSWITCHES_SEPARATELY
if (i < t.sync.closedList.size())
{
auto s = t.sync.closedList[i];
if (s->end() <= b->end())// || s->begin() >= b->begin())
//if (((s->end() <= b->end() && s->end() >= b->begin()) || (s->begin() >= b->begin() && s->begin() <= b->end())))
{
if (s->m_begin < b->m_begin)
s->m_begin = b->m_begin;
if (s->m_end > b->m_end)
s->m_end = b->m_end;
of.writeBlock(s);
++i;
}
}
#endif
of.writeBlock(b);
}
#ifdef STORE_CSWITCHES_SEPARATELY
of.write(static_cast<uint32_t>(t.sync.closedList.size()));
for (auto b : t.sync.closedList)
{
#else
for (; i < t.sync.closedList.size(); ++i)
{
auto b = t.sync.closedList[i];
#endif
of.writeBlock(b);
}
t.clearClosed();
}
// if (wasEnabled)
// ::profiler::setEnabled(true);
return blocks_number;
}
const char* ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line)
{
if (THREAD_STORAGE == nullptr)
{
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
}
if (!THREAD_STORAGE->named)
{
const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Black);
THREAD_STORAGE->storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name));
THREAD_STORAGE->name = name;
THREAD_STORAGE->named = true;
}
return THREAD_STORAGE->name.c_str();
}
//////////////////////////////////////////////////////////////////////////

View File

@ -26,68 +26,212 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
#include <stack>
#include <map>
#include <list>
#include <set>
#include <vector>
#include <string>
#include <functional>
#ifdef WIN32
//////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
#include <Windows.h>
#else
#include <thread>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#endif
inline uint32_t getCurrentThreadId()
{
#ifdef WIN32
return (uint32_t)::GetCurrentThreadId();
#ifdef _WIN32
return (uint32_t)::GetCurrentThreadId();
#else
thread_local static uint32_t _id = (uint32_t)std::hash<std::thread::id>()(std::this_thread::get_id());
return _id;
EASY_THREAD_LOCAL static const pid_t x = syscall(__NR_gettid);
EASY_THREAD_LOCAL static const uint32_t _id = (uint32_t)x;//std::hash<std::thread::id>()(std::this_thread::get_id());
return _id;
#endif
}
class ProfileManager
namespace profiler { class SerializedBlock; }
//////////////////////////////////////////////////////////////////////////
template <class T, const uint16_t N>
class chunk_allocator final
{
ProfileManager();
ProfileManager(const ProfileManager& p) = delete;
ProfileManager& operator=(const ProfileManager&) = delete;
static ProfileManager m_profileManager;
struct chunk { T data[N]; };
bool m_isEnabled = false;
std::list<chunk> m_chunks;
uint16_t m_size;
typedef std::stack<::std::reference_wrapper<profiler::Block> > stack_of_blocks_t;
typedef std::map<size_t, stack_of_blocks_t> map_of_threads_stacks;
typedef std::set<size_t> set_of_thread_id;
typedef std::vector<profiler::SourceBlock> sources;
public:
map_of_threads_stacks m_openedBracketsMap;
chunk_allocator() : m_size(0)
{
m_chunks.emplace_back();
}
profiler::spin_lock m_spin;
profiler::spin_lock m_storedSpin;
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
T* allocate(uint16_t n)
{
if (m_size + n <= N)
{
T* data = m_chunks.back().data + m_size;
m_size += n;
return data;
}
void _internalInsertBlock(const profiler::Block &_block);
m_size = n;
m_chunks.emplace_back();
return m_chunks.back().data;
}
sources m_sources;
void clear()
{
m_size = 0;
m_chunks.clear();
m_chunks.emplace_back();
}
};
typedef std::list<profiler::SerializedBlock*> serialized_list_t;
serialized_list_t m_blocks;
//////////////////////////////////////////////////////////////////////////
set_of_thread_id m_namedThreades;
const uint16_t SIZEOF_CSWITCH = sizeof(profiler::BaseBlockData) + 1;
uint64_t m_blocksMemorySize = 0;
typedef std::vector<profiler::SerializedBlock*> serialized_list_t;
template <class T, const uint16_t N>
struct BlocksList final
{
BlocksList() = default;
class Stack final {
//std::stack<T> m_stack;
std::vector<T> m_stack;
public:
inline void clear() { m_stack.clear(); }
inline bool empty() const { return m_stack.empty(); }
inline void emplace(profiler::Block& _block) {
//m_stack.emplace(_block);
m_stack.emplace_back(_block);
}
template <class ... TArgs> inline void emplace(TArgs ... _args) {
//m_stack.emplace(_args);
m_stack.emplace_back(_args...);
}
inline T& top() {
//return m_stack.top();
return m_stack.back();
}
inline void pop() {
//m_stack.pop();
m_stack.pop_back();
}
};
chunk_allocator<char, N> alloc;
Stack openedList;
serialized_list_t closedList;
uint64_t usedMemorySize = 0;
void clearClosed() {
serialized_list_t().swap(closedList);
alloc.clear();
usedMemorySize = 0;
}
};
class ThreadStorage final
{
public:
BlocksList<std::reference_wrapper<profiler::Block>, SIZEOF_CSWITCH * (uint16_t)1024U> blocks;
BlocksList<profiler::Block, SIZEOF_CSWITCH * (uint16_t)128U> sync;
std::string name;
bool named = false;
void storeBlock(const profiler::Block& _block);
void storeCSwitch(const profiler::Block& _block);
void clearClosed();
ThreadStorage() = default;
};
//////////////////////////////////////////////////////////////////////////
class ProfileManager final
{
ProfileManager();
ProfileManager(const ProfileManager& p) = delete;
ProfileManager& operator=(const ProfileManager&) = delete;
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<profiler::BlockDescriptor> block_descriptors_t;
map_of_threads_stacks m_threads;
block_descriptors_t m_descriptors;
uint64_t m_usedMemorySize = 0;
profiler::spin_lock m_spin;
profiler::spin_lock m_storedSpin;
bool m_isEnabled = false;
std::string m_csInfoFilename = "/tmp/cs_profiling_info.log";
public:
static ProfileManager& instance();
~ProfileManager();
~ProfileManager();
template <class ... TArgs>
uint32_t addBlockDescriptor(TArgs ... _args)
{
guard_lock_t lock(m_storedSpin);
const auto id = static_cast<uint32_t>(m_descriptors.size());
m_descriptors.emplace_back(m_usedMemorySize, _args...);
return id;
}
void beginBlock(profiler::Block& _block);
void endBlock();
void setEnabled(bool isEnable);
unsigned int dumpBlocksToFile(const char* filename);
void setThreadName(const char* name);
unsigned int addSource(const char* _filename, int _line);
void endBlock();
void setEnabled(bool isEnable);
uint32_t dumpBlocksToFile(const char* filename);
const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line);
void setContextSwitchLogFilename(const char* name)
{
m_csInfoFilename = name;
}
const char* getContextSwitchLogFilename() const
{
return m_csInfoFilename.c_str();
}
void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id);
void storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id);
void endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime);
private:
ThreadStorage& threadStorage(profiler::thread_id_t _thread_id)
{
guard_lock_t lock(m_spin);
return m_threads[_thread_id];
}
ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id)
{
guard_lock_t lock(m_spin);
auto it = m_threads.find(_thread_id);
return it != m_threads.end() ? &it->second : nullptr;
}
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -16,53 +16,87 @@ You should have received a copy of the GNU General Public License
along with this program.If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef ________SPIN_LOCK__________H______
#define ________SPIN_LOCK__________H______
#ifndef EASY_PROFILER__SPIN_LOCK__________H______
#define EASY_PROFILER__SPIN_LOCK__________H______
#define EASY_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
#include <Windows.h>
#else
#include <atomic>
namespace profiler{
class spin_lock
{
std::atomic_flag m_lock;
public:
void lock()
{
while (m_lock.test_and_set(std::memory_order_acquire)){}
}
void unlock()
{
m_lock.clear(std::memory_order_release);
}
spin_lock(){
m_lock.clear();
}
};
template<class T>
class guard_lock
{
T& m_mutex;
bool m_isLocked = false;
public:
explicit guard_lock(T& m) :m_mutex(m){
m_mutex.lock();
m_isLocked = true;
}
~guard_lock(){
this->release();
}
inline void release(){
if (m_isLocked){
m_mutex.unlock();
m_isLocked = false;
}
}
};
}
#endif
namespace profiler {
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
// std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag...
// By the way, Windows critical sections are slower than std::atomic_flag on Unix.
class spin_lock final { CRITICAL_SECTION m_lock; public:
void lock() {
EnterCriticalSection(&m_lock);
}
void unlock() {
LeaveCriticalSection(&m_lock);
}
spin_lock() {
InitializeCriticalSection(&m_lock);
}
~spin_lock() {
DeleteCriticalSection(&m_lock);
}
};
#else
// std::atomic_flag on Unix works fine and very fast (almost instant!)
class spin_lock final { ::std::atomic_flag m_lock; public:
void lock() {
while (m_lock.test_and_set(::std::memory_order_acquire));
}
void unlock() {
m_lock.clear(::std::memory_order_release);
}
spin_lock() {
m_lock.clear();
}
};
#endif
template <class T>
class guard_lock final
{
T& m_lock;
bool m_isLocked = false;
public:
explicit guard_lock(T& m) : m_lock(m) {
m_lock.lock();
m_isLocked = true;
}
~guard_lock() {
unlock();
}
inline void unlock() {
if (m_isLocked) {
m_lock.unlock();
m_isLocked = false;
}
}
};
} // END of namespace profiler.
#ifdef EASY_USE_CRITICAL_SECTION
# undef EASY_USE_CRITICAL_SECTION
#endif
#endif // EASY_PROFILER__SPIN_LOCK__________H______