0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-28 17:28:14 +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) cmake_minimum_required(VERSION 2.8)
set( set(
ROOT ROOT
${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}
) )
set(OUTPUT_DIR set(OUTPUT_DIR
@ -23,16 +23,16 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
) )
include_directories( include_directories(
include include
) )
if(UNIX) if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 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" ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-reorder -pedantic -O3" )
else() else()
add_definitions( add_definitions(
-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS
) )
endif(UNIX) endif(UNIX)
add_subdirectory(src) 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/>. along with this program.If not, see <http://www.gnu.org/licenses/>.
**/ **/
#ifndef ____PROFILER____H_______ #ifndef EASY_PROFILER____H_______
#define ____PROFILER____H_______ #define EASY_PROFILER____H_______
#define TOKEN_JOIN(x, y) x ## y #ifdef _WIN32
#define TOKEN_CONCATENATE(x, y) TOKEN_JOIN(x, y) # 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 ) #endif
#define __func__ __FUNCTION__
// 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 #endif
#ifndef FULL_DISABLE_PROFILER #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 \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 \code
#include "profiler/profiler.h" #include "profiler/profiler.h"
void foo() void foo()
{ {
// some code ... // some code ...
if(something){ if(something){
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()"); EASY_BLOCK("Calling bar()"); // Block with default color
someThirdPartyLongFunction(); bar();
return; }
} else{
} EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block
baz();
}
}
\endcode \endcode
Block will be automatically completed by destructor Block will be automatically completed by destructor.
\ingroup profiler \ingroup profiler
*/ */
#define PROFILER_BEGIN_BLOCK(name)\ #define EASY_BLOCK(name, ...)\
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\ static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,profiler::colors::Clay,profiler::BLOCK_TYPE_BLOCK,\ ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\ ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)); ::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 \code
#include "profiler/profiler.h" #include "profiler/profiler.h"
void foo() void foo(){
{ EASY_FUNCTION(); // Block with name="foo" and default color
// some code ... //some code...
if(something){ }
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()",profiler::colors::Red);
someThirdPartyLongFunction(); void bar(){
return; EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar"
} //some code...
} }
\endcode \endcode
Block will be automatically completed by destructor Name of the block automatically created with function name.
\ingroup profiler \ingroup profiler
*/ */
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)\ #define EASY_FUNCTION(...)\
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\ static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(__func__, __FILE__, __LINE__,\
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_BLOCK,\ ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\ ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), "");\
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__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 /** Macro of completion of last nearest open block.
\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
\code \code
#include "profiler/profiler.h" #include "profiler/profiler.h"
void foo() int foo()
{ {
// some code ... // some code ...
int sum = 0;
PROFILER_BEGIN_BLOCK("Calculating summ"); int sum = 0;
for(int i = 0; i < 10; i++){ EASY_BLOCK("Calculating sum");
sum += i; for (int i = 0; i < 10; ++i){
} sum += i;
PROFILER_END_BLOCK; }
EASY_END_BLOCK;
// some antoher code here ...
return sum;
} }
\endcode \endcode
\ingroup profiler \ingroup profiler
*/ */
#define PROFILER_END_BLOCK profiler::endBlock(); #define EASY_END_BLOCK ::profiler::endBlock();
#define PROFILER_ADD_EVENT(name) \ /** Macro of creating event with custom name and color.
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__));
#define PROFILER_ADD_EVENT_GROUPED(name,block_group)\ Event is a block with zero duration and special type.
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,\ \warning Event ends immidiately and calling EASY_END_BLOCK after EASY_EVENT
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\ will end previously opened EASY_BLOCK or EASY_FUNCTION.
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
\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 /** Macro enabling profiler
\ingroup profiler \ingroup profiler
*/ */
#define PROFILER_ENABLE profiler::setEnabled(true); #define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
/** Macro disabling profiler /** Macro disabling profiler
\ingroup profiler \ingroup profiler
*/ */
#define PROFILER_DISABLE profiler::setEnabled(false); #define EASY_PROFILER_DISABLE ::profiler::setEnabled(false);
#ifdef WIN32 /** Macro of naming current thread.
#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
#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 #else
#define PROFILER_ADD_MARK(name) #define EASY_BLOCK(...)
#define PROFILER_ADD_MARK_GROUPED(name,block_group) #define EASY_FUNCTION(...)
#define PROFILER_BEGIN_BLOCK(name) #define EASY_END_BLOCK
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group) #define EASY_PROFILER_ENABLE
#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__) #define EASY_PROFILER_DISABLE
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_group) PROFILER_BEGIN_BLOCK_GROUPED(__func__,block_group) #define EASY_EVENT(...)
#define PROFILER_END_BLOCK profiler::endBlock(); #define EASY_THREAD(...)
#define PROFILER_ENABLE profiler::setEnabled(true); #define EASY_MAIN_THREAD
#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
#endif #endif
#include <stdint.h> #include <stdint.h>
#include <cstddef> #include <cstddef>
#include "profiler/profiler_colors.h"
#ifdef _WIN32 #ifdef _WIN32
#ifdef _BUILD_PROFILER #ifdef _BUILD_PROFILER
#define PROFILER_API __declspec(dllexport) #define PROFILER_API __declspec(dllexport)
#else #else
#define PROFILER_API __declspec(dllimport) #define PROFILER_API __declspec(dllimport)
#endif #endif
#else #else
#define PROFILER_API #define PROFILER_API
#endif #endif
class ProfileManager; class ProfileManager;
class ThreadStorage;
namespace profiler namespace profiler {
{
typedef uint8_t color_t; //RRR-GGG-BB
namespace colors{ class Block;
const color_t Black = 0x00; typedef uint64_t timestamp_t;
const color_t Lightgray = 0x6E; typedef uint32_t thread_id_t;
const color_t Darkgray = 0x25; typedef uint32_t block_id_t;
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;
inline int get_red(color_t color){ enum BlockType : uint8_t
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
{ {
const char* m_filename; BLOCK_TYPE_EVENT = 0,
int m_line; 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: public:
SourceBlock(const char* _filename, int _line); inline int line() const { return m_line; }
inline block_type_t type() const { return m_type; }
const char* file() const { return m_filename; } inline color_t color() const { return m_color; }
int line() const { return m_line; }
}; };
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; friend ::ProfileManager;
protected:
timestamp_t m_begin;
timestamp_t m_end;
block_id_t m_id;
public: public:
///< Deprecated. For backward compatibility. BaseBlockData(const BaseBlockData&) = default;
inline const BaseBlockData* block() const { return this; } BaseBlockData(timestamp_t _begin_time, block_id_t _id);
inline const char* data() const { return reinterpret_cast<const char*>(this); } inline timestamp_t begin() const { return m_begin; }
inline const char* getName() const { return data() + sizeof(BaseBlockData); } 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: private:
static SerializedBlock* create(const Block &block, uint64_t& memory_size); BaseBlockData() = delete;
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;
}; };
#pragma pack(pop)
struct PROFILER_API ThreadNameSetter final class PROFILER_API Block final : public BaseBlockData
{ {
ThreadNameSetter(const char* _name) friend ::ProfileManager;
{
setThreadName(_name);
}
};
class PROFILER_API BlockSourceInfo final const char* m_name;
{
unsigned int m_id; private:
void finish();
void finish(timestamp_t _end_time);
inline bool isFinished() const { return m_end >= m_begin; }
public: 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. } // END of namespace profiler.
#if defined ( __clang__ )
#pragma clang diagnostic pop
#endif #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 <vector>
#include <atomic> #include <atomic>
#include "profiler/profiler.h" #include "profiler/profiler.h"
#include "profiler/serialized_block.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -61,46 +62,31 @@ namespace profiler {
}; // END of struct BlockStatistics. }; // END of struct BlockStatistics.
#pragma pack(pop) #pragma pack(pop)
inline void release(BlockStatistics*& _stats) extern "C" void PROFILER_API release_stats(BlockStatistics*& _stats);
{
if (!_stats)
{
return;
}
if (--_stats->calls_number == 0)
{
delete _stats;
}
_stats = nullptr;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
class BlocksTree class BlocksTree final
{ {
typedef BlocksTree This; typedef BlocksTree This;
public: 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. children_t children; ///< List of children blocks. May be empty.
::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.) ::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_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks) ::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks)
::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread ::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread
uint16_t depth; ///< Maximum number of sublevels (maximum children depth)
::profiler::block_index_t block_index; ///< Index of this block
unsigned short depth; ///< Maximum number of sublevels (maximum children depth)
BlocksTree() BlocksTree()
: node(nullptr) : node(nullptr)
, per_parent_stats(nullptr) , per_parent_stats(nullptr)
, per_frame_stats(nullptr) , per_frame_stats(nullptr)
, per_thread_stats(nullptr) , per_thread_stats(nullptr)
, block_index(0)
, depth(0) , depth(0)
{ {
@ -119,14 +105,9 @@ namespace profiler {
~BlocksTree() ~BlocksTree()
{ {
//if (node) release_stats(per_thread_stats);
//{ release_stats(per_parent_stats);
// delete node; release_stats(per_frame_stats);
//}
release(per_thread_stats);
release(per_parent_stats);
release(per_frame_stats);
} }
bool operator < (const This& other) const bool operator < (const This& other) const
@ -135,7 +116,7 @@ namespace profiler {
{ {
return false; return false;
} }
return node->block()->getBegin() < other.node->block()->getBegin(); return node->begin() < other.node->begin();
} }
void shrink_to_fit() void shrink_to_fit()
@ -160,33 +141,20 @@ namespace profiler {
void makeMove(This&& that) void makeMove(This&& that)
{ {
//if (node && node != that.node)
//{
// delete node;
//}
if (per_thread_stats != that.per_thread_stats) if (per_thread_stats != that.per_thread_stats)
{ release_stats(per_thread_stats);
release(per_thread_stats);
}
if (per_parent_stats != that.per_parent_stats) if (per_parent_stats != that.per_parent_stats)
{ release_stats(per_parent_stats);
release(per_parent_stats);
}
if (per_frame_stats != that.per_frame_stats) if (per_frame_stats != that.per_frame_stats)
{ release_stats(per_frame_stats);
release(per_frame_stats);
}
children = ::std::move(that.children); children = ::std::move(that.children);
node = that.node; node = that.node;
per_parent_stats = that.per_parent_stats; per_parent_stats = that.per_parent_stats;
per_frame_stats = that.per_frame_stats; per_frame_stats = that.per_frame_stats;
per_thread_stats = that.per_thread_stats; per_thread_stats = that.per_thread_stats;
block_index = that.block_index;
depth = that.depth; depth = that.depth;
that.node = nullptr; that.node = nullptr;
@ -199,35 +167,53 @@ namespace profiler {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#define EASY_STORE_CSWITCH_SEPARATELY
//#undef EASY_STORE_CSWITCH_SEPARATELY
class BlocksTreeRoot final class BlocksTreeRoot final
{ {
typedef BlocksTreeRoot This; typedef BlocksTreeRoot This;
public: public:
BlocksTree tree; BlocksTree::children_t children;
#ifdef EASY_STORE_CSWITCH_SEPARATELY
BlocksTree::children_t sync;
#endif
const char* thread_name; const char* thread_name;
::profiler::thread_id_t thread_id; ::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) 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_name = that.thread_name;
thread_id = that.thread_id; thread_id = that.thread_id;
depth = that.depth;
return *this; return *this;
} }
bool operator < (const This& other) const bool operator < (const This& other) const
{ {
return tree < other.tree; return thread_id < other.thread_id;
} }
private: private:
@ -237,11 +223,12 @@ namespace profiler {
}; // END of class BlocksTreeRoot. }; // END of class BlocksTreeRoot.
typedef ::profiler::BlocksTree::blocks_t blocks_t;
typedef ::std::map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot> thread_blocks_tree_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; char* m_data;
@ -261,10 +248,11 @@ namespace profiler {
clear(); clear();
} }
void set(char* _data);
SerializedData& operator = (SerializedData&& that) SerializedData& operator = (SerializedData&& that)
{ {
clear(); set(that.m_data);
m_data = that.m_data;
that.m_data = nullptr; that.m_data = nullptr;
return *this; return *this;
} }
@ -276,17 +264,7 @@ namespace profiler {
void clear() void clear()
{ {
if (m_data) set(nullptr);
{
delete[] m_data;
m_data = nullptr;
}
}
void set(char* _data)
{
clear();
m_data = _data;
} }
void swap(SerializedData& other) void swap(SerializedData& other)
@ -305,15 +283,25 @@ namespace profiler {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
typedef ::std::vector<SerializedBlockDescriptor*> descriptors_list_t;
} // END of namespace profiler. } // END of namespace profiler.
extern "C"{ extern "C" ::profiler::block_index_t PROFILER_API fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
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); ::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); ::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 * file name : blocks_graphics_view.cpp
* ----------------- : * ----------------- :
* creation time : 2016/06/26 * creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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> #include <QGraphicsScene>
@ -54,8 +67,8 @@ enum BlockItemState
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
const qreal MIN_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 70); 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, 30); // ~800 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 qreal BASE_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 25); // ~0.003
const unsigned short GRAPHICS_ROW_SIZE = 18; const unsigned short GRAPHICS_ROW_SIZE = 18;
@ -71,11 +84,11 @@ const QRgb TIMELINE_BACKGROUND = 0x20303030;
const QRgb SELECTED_ITEM_COLOR = 0x000050a0; const QRgb SELECTED_ITEM_COLOR = 0x000050a0;
const QColor CHRONOMETER_COLOR2 = QColor::fromRgba(0x40408040); 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 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); 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) : QGraphicsItem(nullptr)
, m_pRoot(_root) , m_pRoot(_root)
, m_index(_index) , m_index(_index)
@ -139,7 +152,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
QRectF rect; QRectF rect;
QBrush brush; QBrush brush;
QRgb previousColor = 0, inverseColor = 0x00ffffff; QRgb previousColor = 0, inverseColor = 0xffffffff, textColor = 0;
Qt::PenStyle previousPenStyle = Qt::NoPen; Qt::PenStyle previousPenStyle = Qt::NoPen;
brush.setStyle(Qt::SolidPattern); brush.setStyle(Qt::SolidPattern);
@ -148,12 +161,12 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
// Reset indices of first visible item for each layer // Reset indices of first visible item for each layer
const auto levelsNumber = levels(); 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 // Search for first visible top-level item
auto& level0 = m_levels.front(); 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; 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 // This is to make _painter->drawText() work properly
// (it seems there is a bug in Qt5.6 when drawText called for big coordinates, // (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 // drawRect at the same time called for actually same coordinates
// works fine without using this additional shifting) // 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 // 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; previousPenStyle = Qt::SolidLine;
_painter->setPen(BORDERS_COLOR); _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)>(); 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::ProfBlockItem::children_begin) 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 // Mark that we would not paint children of current item
if (next_level < levelsNumber && children_begin != MAX_CHILD_INDEX) 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 // Iterate through layers and draw visible items
bool selectedItemsWasPainted = false; bool selectedItemsWasPainted = false;
const auto visibleBottom = visibleSceneRect.bottom() - 1; 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]; auto& level = m_levels[l];
const short next_level = l + 1; const short next_level = l + 1;
@ -243,8 +276,9 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
continue; continue;
} }
const auto& itemBlock = easyBlock(item.block);
int h = 0, flags = 0; 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 // 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; h -= dh;
bool changepen = false; bool changepen = false;
if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block) if (item.block == EASY_GLOBALS.selected_block)
{ {
selectedItemsWasPainted = true; selectedItemsWasPainted = true;
changepen = true; changepen = true;
@ -265,7 +299,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
_painter->setPen(pen); _painter->setPen(pen);
previousColor = SELECTED_ITEM_COLOR; previousColor = SELECTED_ITEM_COLOR;
inverseColor = 0x00ffffff - previousColor; inverseColor = 0xffffffff - previousColor;
textColor = ::profiler_gui::textColorForRgb(previousColor);
brush.setColor(previousColor); brush.setColor(previousColor);
_painter->setBrush(brush); _painter->setBrush(brush);
} }
@ -276,12 +311,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
{ {
// Set background color brush for rectangle // Set background color brush for rectangle
previousColor = item.color; previousColor = item.color;
inverseColor = 0x00ffffff - previousColor; inverseColor = 0xffffffff - previousColor;
textColor = ::profiler_gui::textColorForRgb(previousColor);
brush.setColor(previousColor); brush.setColor(previousColor);
_painter->setBrush(brush); _painter->setBrush(brush);
} }
if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders) if (EASY_GLOBALS.draw_graphics_items_borders)
{ {
//if (w < 2) //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; 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; selectedItemsWasPainted = true;
QPen pen(Qt::SolidLine); QPen pen(Qt::SolidLine);
@ -358,7 +394,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
_painter->setPen(pen); _painter->setPen(pen);
previousColor = SELECTED_ITEM_COLOR; previousColor = SELECTED_ITEM_COLOR;
inverseColor = 0x00ffffff - previousColor; inverseColor = 0xffffffff - previousColor;
textColor = ::profiler_gui::textColorForRgb(previousColor);
brush.setColor(previousColor); brush.setColor(previousColor);
_painter->setBrush(brush); _painter->setBrush(brush);
} }
@ -369,12 +406,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
{ {
// Set background color brush for rectangle // Set background color brush for rectangle
previousColor = item.color; previousColor = item.color;
inverseColor = 0x00ffffff - previousColor; inverseColor = 0xffffffff - previousColor;
textColor = ::profiler_gui::textColorForRgb(previousColor);
brush.setColor(previousColor); brush.setColor(previousColor);
_painter->setBrush(brush); _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 // Restore pen for item which is wide enough to paint borders
previousPenStyle = Qt::SolidLine; previousPenStyle = Qt::SolidLine;
@ -417,12 +455,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
rect.setRect(xtext + 1, top, w - 1, h); rect.setRect(xtext + 1, top, w - 1, h);
// text will be painted with inverse color // text will be painted with inverse color
auto textColor = inverseColor; //auto textColor = inverseColor < 0x00808080 ? profiler::colors::Black : profiler::colors::White;
if (textColor == previousColor) textColor = 0; //if (textColor == previousColor) textColor = 0;
_painter->setPen(textColor); _painter->setPen(QColor::fromRgb(textColor));
// drawing text // 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 // restore previous pen color
if (previousPenStyle == Qt::NoPen) 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) if (guiblock.graphics_item == m_index)
{ {
const auto& item = m_levels[guiblock.graphics_item_level][guiblock.graphics_item_index]; const auto& item = m_levels[guiblock.graphics_item_level][guiblock.graphics_item_index];
if (item.left() < sceneRight && item.right() > sceneLeft) 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 top = levelY(guiblock.graphics_item_level);
auto x = item.left() * currentScale - dx; decltype(top) h = item.totalHeight;
auto w = ::std::max(item.width() * currentScale, 1.0);
rect.setRect(x, top, w, item.totalHeight);
_painter->drawRect(rect);
if (w > 20) auto dh = top + h - visibleBottom;
if (dh < h)
{ {
// Draw text----------------------------------- if (dh > 0)
// calculating text coordinates h -= dh;
auto xtext = x;
if (item.left() < sceneLeft) 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 // Draw text-----------------------------------
// to ensure text is always visible for items presenting on the screen. // calculating text coordinates
w += (item.left() - sceneLeft) * currentScale; auto xtext = x;
xtext = sceneLeft * currentScale - dx; 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(); _painter->restore();
} }
@ -509,7 +609,7 @@ void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree
// Search for first visible top-level item // Search for first visible top-level item
auto& level0 = m_levels.front(); 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; 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()) 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]; const auto& level = m_levels[i];
// Search for first visible item // 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; return _item.left() < _value;
}); });
@ -618,7 +718,7 @@ const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF&
} }
const auto w = item.width() * currentScale; 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; 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); 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; typedef decltype(m_levelsIndexes) IndexesT;
static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max<IndexesT::value_type>(); 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); 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); 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]; 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]; 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]; return m_levels[_level][_index];
} }
unsigned int EasyGraphicsItem::addItem(unsigned char _level) unsigned int EasyGraphicsItem::addItem(uint8_t _level)
{ {
m_levels[_level].emplace_back(); m_levels[_level].emplace_back();
return static_cast<unsigned int>(m_levels[_level].size() - 1); 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 // instead of scrollbar we're using manual offset
_painter->setTransform(QTransform::fromTranslate(-x(), -y()), true); _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 // draw transparent rectangle
auto vcenter = rect.top() + rect.height() * 0.5; auto vcenter = rect.top() + rect.height() * 0.5;
QLinearGradient g(rect.left(), vcenter, rect.right(), vcenter); QLinearGradient g(rect.left(), vcenter, rect.right(), vcenter);
g.setColorAt(0, m_color); g.setColorAt(0, m_color);
g.setColorAt(0.15, QColor::fromRgba(0x14000000 | rgb)); g.setColorAt(0.25, QColor::fromRgba(0x20000000 | rgb));
g.setColorAt(0.85, QColor::fromRgba(0x14000000 | rgb)); g.setColorAt(0.75, QColor::fromRgba(0x20000000 | rgb));
g.setColorAt(1, m_color); g.setColorAt(1, m_color);
_painter->setBrush(g); _painter->setBrush(g);
_painter->setPen(Qt::NoPen); _painter->setPen(Qt::NoPen);
@ -850,21 +956,12 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
// draw text // draw text
_painter->setCompositionMode(QPainter::CompositionMode_Difference); // This lets the text to be visible on every background _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); _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; int textFlags = 0;
switch (::profiler_gui::EASY_GLOBALS.chrono_text_position) switch (EASY_GLOBALS.chrono_text_position)
{ {
case ::profiler_gui::ChronoTextPosition_Top: case ::profiler_gui::ChronoTextPosition_Top:
textFlags = Qt::AlignTop | Qt::AlignHCenter; textFlags = Qt::AlignTop | Qt::AlignHCenter;
@ -890,14 +987,15 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
return; 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 // Text will be drawed to the right of rectangle
rect.translate(rect.width(), 0); rect.translate(rect.width(), 0);
textFlags &= ~Qt::AlignHCenter; textFlags &= ~Qt::AlignHCenter;
textFlags |= Qt::AlignLeft; 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 // Text will be drawed to the left of rectangle
rect.translate(-rect.width(), 0); rect.translate(-rect.width(), 0);
@ -1002,7 +1100,7 @@ void EasyBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte
if (top > h || bottom < 0) if (top > h || bottom < 0)
continue; 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))); _painter->setBrush(QBrush(QColor::fromRgb(::profiler_gui::SELECTED_THREAD_BACKGROUND)));
else else
_painter->setBrush(brushes[i & 1]); _painter->setBrush(brushes[i & 1]);
@ -1092,13 +1190,10 @@ void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap
// Draw scale indicator // Draw scale indicator
_painter->save(); _painter->save();
_painter->setTransform(QTransform::fromTranslate(-x(), -y())); _painter->setTransform(QTransform::fromTranslate(-x(), -y()));
_painter->setCompositionMode(QPainter::CompositionMode_Difference); //_painter->setCompositionMode(QPainter::CompositionMode_Difference);
_painter->setBrush(Qt::NoBrush); _painter->setBrush(Qt::NoBrush);
//_painter->setBrush(Qt::white); QPen pen(Qt::black);
//_painter->setPen(Qt::NoPen);
QPen pen(Qt::white);
pen.setWidth(2); pen.setWidth(2);
pen.setJoinStyle(Qt::MiterJoin); pen.setJoinStyle(Qt::MiterJoin);
_painter->setPen(pen); _painter->setPen(pen);
@ -1107,7 +1202,6 @@ void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap
const auto rect_right = rect.right(); 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}}; 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->drawPolyline(points, sizeof(points) / sizeof(QPointF));
//_painter->drawRect(rect);
rect.translate(0, 3); rect.translate(0, 3);
_painter->drawText(rect, Qt::AlignRight | Qt::TextDontClip, text); _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 X_BEGIN = 50;
static const qreal Y_BEGIN = 0; static const qreal Y_BEGIN = 0;
@ -1201,9 +1295,9 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
clearSilent(); // Clear scene clearSilent(); // Clear scene
// Calculate items number for first level // 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 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); 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); ::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); auto item = new EasyGraphicsItem(i, true);
thread_items[i] = item; 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 // Calculate items number for each sublevel
auto chldrn = first_level_children_count; 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]; auto item = thread_items[j];
item->reserve(i, chldrn * _frames_number); 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; unsigned int total_items = 0;
qreal maxX = 0; qreal maxX = 0;
const EasyGraphicsItem* longestItem = nullptr; 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]; auto item = thread_items[i];
qreal x = X_BEGIN, y = item->y(); 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) if (longestItem != nullptr)
{ {
m_pScrollbar->setMinimapFrom(0, longestItem->items(0)); m_pScrollbar->setMinimapFrom(0, longestItem->items(0));
::profiler_gui::EASY_GLOBALS.selected_thread = 0; EASY_GLOBALS.selected_thread = 0;
emit::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0); emitEASY_GLOBALS.events.selectedThreadChanged(0);
} }
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()). // 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 // Calculating start and end time
::profiler::timestamp_t finish = 0; ::profiler::timestamp_t finish = 0;
const ::profiler::BlocksTree* longestTree = nullptr; ::profiler::thread_id_t longestTree = 0;
const EasyGraphicsItem* longestItem = nullptr; const EasyGraphicsItem* longestItem = nullptr;
const EasyGraphicsItem* mainThreadItem = nullptr;
for (const auto& threadTree : _blocksTree) for (const auto& threadTree : _blocksTree)
{ {
const auto& tree = threadTree.second.tree; const auto& tree = threadTree.second.children;
const auto timestart = tree.children.front().node->block()->getBegin(); auto timestart = blocksTree(tree.front()).node->begin();
const auto timefinish = tree.children.back().node->block()->getEnd();
#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) if (m_beginTime > timestart)
{ {
@ -1376,7 +1477,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
if (finish < timefinish) if (finish < timefinish)
{ {
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 // fill scene with new items
const auto& tree = threadTree.second.tree; const auto& tree = threadTree.second.children;
qreal h = 0, x = time2position(tree.children.front().node->block()->getBegin()); qreal h = 0, x = time2position(blocksTree(tree.front()).node->begin());
auto item = new EasyGraphicsItem(static_cast<unsigned char>(m_items.size()), &threadTree.second); auto item = new EasyGraphicsItem(static_cast<uint8_t>(m_items.size()), &threadTree.second);
item->setLevels(tree.depth); item->setLevels(threadTree.second.depth);
item->setPos(0, y); 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); item->setBoundingRect(0, 0, children_duration + x, h);
m_items.push_back(item); m_items.push_back(item);
@ -1406,10 +1507,11 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
y += h + THREADS_ROW_SPACING; y += h + THREADS_ROW_SPACING;
if (longestTree == &tree) if (longestTree == threadTree.first)
{
longestItem = item; longestItem = item;
}
if (mainThreadItem == nullptr && !strcmp(threadTree.second.thread_name, "Main"))
mainThreadItem = item;
} }
// Calculating scene rect // Calculating scene rect
@ -1422,11 +1524,14 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
updateVisibleSceneRect(); updateVisibleSceneRect();
setScrollbar(m_pScrollbar); setScrollbar(m_pScrollbar);
if (mainThreadItem != nullptr)
longestItem = mainThreadItem;
if (longestItem != nullptr) if (longestItem != nullptr)
{ {
m_pScrollbar->setMinimapFrom(longestItem->threadId(), longestItem->items(0)); m_pScrollbar->setMinimapFrom(longestItem->threadId(), longestItem->items(0));
::profiler_gui::EASY_GLOBALS.selected_thread = longestItem->threadId(); EASY_GLOBALS.selected_thread = longestItem->threadId();
emit::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(longestItem->threadId()); emit EASY_GLOBALS.events.selectedThreadChanged(longestItem->threadId());
} }
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()). // 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; 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())); _item->reserve(level, static_cast<unsigned int>(_children.size()));
const short next_level = _level + 1; const short next_level = _level + 1;
bool warned = false; bool warned = false;
qreal total_duration = 0, prev_end = 0, maxh = 0; qreal total_duration = 0, prev_end = 0, maxh = 0;
qreal start_time = -1; 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) if (start_time < 0)
{ {
start_time = xbegin; start_time = xbegin;
} }
auto duration = time2position(child.node->block()->getEnd()) - xbegin; auto duration = time2position(child.node->end()) - xbegin;
//const auto dt = xbegin - prev_end; //const auto dt = xbegin - prev_end;
//if (dt < 0) //if (dt < 0)
@ -1492,14 +1600,13 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block
auto i = _item->addItem(level); auto i = _item->addItem(level);
auto& b = _item->getItem(level, i); 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 = _item->index();
gui_block.graphics_item_level = level; gui_block.graphics_item_level = level;
gui_block.graphics_item_index = i; gui_block.graphics_item_index = i;
if (next_level < 256 && next_level < _item->levels() && !child.children.empty()) 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 else
{ {
@ -1529,9 +1636,8 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block
maxh = h; maxh = h;
} }
const auto color = child.node->block()->getColor(); b.block = child_index;// &child;
b.block = &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.color = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
b.setPos(xbegin, duration); b.setPos(xbegin, duration);
b.totalHeight = GRAPHICS_ROW_SIZE + h; b.totalHeight = GRAPHICS_ROW_SIZE + h;
b.state = BLOCK_ITEM_UNCHANGED; b.state = BLOCK_ITEM_UNCHANGED;
@ -1571,8 +1677,8 @@ void EasyGraphicsView::setScrollbar(EasyGraphicsScrollbar* _scrollbar)
connect(m_pScrollbar, &EasyGraphicsScrollbar::wheeled, this, &This::onGraphicsScrollbarWheel); connect(m_pScrollbar, &EasyGraphicsScrollbar::wheeled, this, &This::onGraphicsScrollbarWheel);
} }
::profiler_gui::EASY_GLOBALS.selected_thread = 0; EASY_GLOBALS.selected_thread = 0;
emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0); emit EASY_GLOBALS.events.selectedThreadChanged(0);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -1647,7 +1753,7 @@ void EasyGraphicsView::onGraphicsScrollbarWheel(qreal _mouseX, int _wheelDelta)
{ {
for (auto item : m_items) for (auto item : m_items)
{ {
if (item->threadId() == ::profiler_gui::EASY_GLOBALS.selected_thread) if (item->threadId() == EASY_GLOBALS.selected_thread)
{ {
m_bUpdatingRect = true; m_bUpdatingRect = true;
auto vbar = verticalScrollBar(); auto vbar = verticalScrollBar();
@ -1780,8 +1886,8 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
} }
} }
const ::profiler_gui::ProfBlockItem* selectedBlock = nullptr; const ::profiler_gui::EasyBlockItem* selectedBlock = nullptr;
const auto previouslySelectedBlock = ::profiler_gui::EASY_GLOBALS.selected_block; const auto previouslySelectedBlock = EASY_GLOBALS.selected_block;
if (m_mouseButtons & Qt::LeftButton) if (m_mouseButtons & Qt::LeftButton)
{ {
bool clicked = false; bool clicked = false;
@ -1814,15 +1920,15 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
{ {
changedSelectedItem = true; changedSelectedItem = true;
selectedBlock = block; selectedBlock = block;
::profiler_gui::EASY_GLOBALS.selected_block = block->block->block_index; EASY_GLOBALS.selected_block = block->block;
break; 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; 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) if (changedSelectedItem)
{ {
m_bUpdatingRect = true; 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; EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded;
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); 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; m_bUpdatingRect = false;
updateScene(); updateScene();
@ -1999,7 +2105,7 @@ void EasyGraphicsView::initMode()
connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &This::onScrollbarValueChange); connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &This::onScrollbarValueChange);
connect(&m_flickerTimer, &QTimer::timeout, this, &This::onFlickerTimeout); 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::selectedThreadChanged, this, &This::onSelectedThreadChange);
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::itemsExpandStateChanged, this, &This::onItemsEspandStateChange); connect(globalSignals, &::profiler_gui::EasyGlobalSignals::itemsExpandStateChanged, this, &This::onItemsEspandStateChange);
@ -2102,11 +2208,11 @@ void EasyGraphicsView::onSelectedBlockChange(unsigned int _block_index)
{ {
if (!m_bUpdatingRect) if (!m_bUpdatingRect)
{ {
if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size()) if (_block_index < EASY_GLOBALS.gui_blocks.size())
{ {
// Scroll to item // 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 thread_item = m_items[guiblock.graphics_item];
const auto& item = thread_item->items(guiblock.graphics_item_level)[guiblock.graphics_item_index]; 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); //m_layout->addWidget(m_label);
//setLayout(m_layout); //setLayout(m_layout);
//show(); //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() EasyThreadViewWidget::~EasyThreadViewWidget()
@ -2192,14 +2298,14 @@ EasyThreadViewWidget::~EasyThreadViewWidget()
void EasyThreadViewWidget::onSelectedThreadChange(::profiler::thread_id_t _id) 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) if(threadName[0]!=0)
{ {
m_label->setText(threadName); m_label->setText(threadName);
} }
else 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; QLayoutItem *ditem;

View File

@ -2,7 +2,6 @@
* file name : blocks_graphics_view.h * file name : blocks_graphics_view.h
* ----------------- : * ----------------- :
* creation time : 2016/06/26 * creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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_ #ifndef EASY__GRAPHICS_VIEW__H_
@ -58,7 +71,7 @@ inline qreal microseconds2units(qreal _value)
class EasyGraphicsItem : public QGraphicsItem class EasyGraphicsItem : public QGraphicsItem
{ {
typedef ::profiler_gui::ProfItems Children; typedef ::profiler_gui::EasyItems Children;
typedef ::std::vector<unsigned int> DrawIndexes; typedef ::std::vector<unsigned int> DrawIndexes;
typedef ::std::vector<Children> Sublevels; typedef ::std::vector<Children> Sublevels;
@ -67,11 +80,11 @@ class EasyGraphicsItem : public QGraphicsItem
QRectF m_boundingRect; ///< boundingRect (see 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. 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: public:
EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root); EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot* _root);
virtual ~EasyGraphicsItem(); virtual ~EasyGraphicsItem();
// Public virtual methods // Public virtual methods
@ -92,46 +105,46 @@ public:
::profiler::thread_id_t threadId() const; ::profiler::thread_id_t threadId() const;
///< Returns number of levels ///< 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. /** \brief Sets number of levels.
\note Must be set before doing anything else. \note Must be set before doing anything else.
\param _levels Desired number of levels */ \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. /** \brief Reserves memory for desired number of items on specified level.
\param _level Index of the level \param _level Index of the level
\param _items Desired number of items on this 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. /**\brief Returns reference to the array of items of specified level.
\param _level Index of the 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. /**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level \param _level Index of the level
\param _index Index of required item */ \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. /**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level \param _level Index of the level
\param _index Index of required item */ \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. /** \brief Adds new item to required level.
\param _level Index of the level \param _level Index of the level
\retval Index of the new created item */ \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. /** \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 */ \param _blocks Reference to the array of selected blocks */
void getBlocks(qreal _left, qreal _right, ::profiler_gui::TreeBlocks& _blocks) const; 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: private:
@ -154,7 +167,7 @@ public:
// Public inline methods // Public inline methods
///< Returns this item's index in the list of graphics items of EasyGraphicsView ///< 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; return m_index;
} }
@ -198,7 +211,7 @@ public:
void setHover(bool _hover); void setHover(bool _hover);
bool contains(const QPointF& _pos) const; bool contains(const QPointF& _pos) const override;
inline bool hoverIndicator() const inline bool hoverIndicator() const
{ {
@ -363,7 +376,7 @@ public:
return m_timelineStep; return m_timelineStep;
} }
private: //private:
// Private inline methods // Private inline methods

View File

@ -2,7 +2,6 @@
* file name : blocks_tree_widget.cpp * file name : blocks_tree_widget.cpp
* ----------------- : * ----------------- :
* creation time : 2016/06/26 * creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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 * : * 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> #include <QMenu>
@ -31,6 +44,7 @@
#include <QProgressDialog> #include <QProgressDialog>
#include <QResizeEvent> #include <QResizeEvent>
#include <QMoveEvent> #include <QMoveEvent>
#include <QDebug>
#include "blocks_tree_widget.h" #include "blocks_tree_widget.h"
#include "tree_widget_item.h" #include "tree_widget_item.h"
#include "globals.h" #include "globals.h"
@ -103,8 +117,8 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
setHeaderItem(header); setHeaderItem(header);
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange); connect(&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::selectedBlockChanged, this, &This::onSelectedBlockChange);
connect(&m_fillTimer, &QTimer::timeout, this, &This::onFillTimerTimeout); connect(&m_fillTimer, &QTimer::timeout, this, &This::onFillTimerTimeout);
loadSettings(); loadSettings();
@ -115,12 +129,12 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
m_progress->setValue(100); m_progress->setValue(100);
//m_progress->hide(); //m_progress->hide();
QTimer::singleShot(40, this, &This::alignProgressBar); QTimer::singleShot(1500, this, &This::alignProgressBar);
} }
EasyTreeWidget::~EasyTreeWidget() EasyTreeWidget::~EasyTreeWidget()
{ {
saveSettings(); saveSettings();
delete m_progress; delete m_progress;
} }
@ -162,8 +176,8 @@ void EasyTreeWidget::onFillTimerTimeout()
connect(this, &Parent::itemExpanded, this, &This::onItemExpand); connect(this, &Parent::itemExpanded, this, &This::onItemExpand);
connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse); connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse);
connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange); connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange);
onSelectedThreadChange(::profiler_gui::EASY_GLOBALS.selected_thread); onSelectedThreadChange(EASY_GLOBALS.selected_thread);
onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block); onSelectedBlockChange(EASY_GLOBALS.selected_block);
} }
else else
{ {
@ -193,7 +207,7 @@ void EasyTreeWidget::setTree(const unsigned int _blocksNumber, const ::profiler:
// { // {
// addTopLevelItem(item.second); // addTopLevelItem(item.second);
// m_roots[item.first] = 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); // item.second->colorize(true);
// } // }
//} //}
@ -226,7 +240,7 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::
// { // {
// addTopLevelItem(item.second); // addTopLevelItem(item.second);
// m_roots[item.first] = 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); // 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::itemExpanded, this, &This::onItemExpand);
//connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse); //connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse);
//onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block); //onSelectedBlockChange(EASY_GLOBALS.selected_block);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void EasyTreeWidget::clearSilent(bool _global) void EasyTreeWidget::clearSilent(bool _global)
{ {
const QSignalBlocker b(this);
m_hierarchyBuilder.interrupt(); m_hierarchyBuilder.interrupt();
if (m_progress) if (m_progress)
@ -262,25 +278,36 @@ void EasyTreeWidget::clearSilent(bool _global)
if (!_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); ::profiler_gui::set_max(gui_block.tree_item);
gui_block.expanded = false; gui_block.expanded = false;
} }
else for (auto item : m_items) 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_items.clear();
m_roots.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) 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); action->setChecked(m_bColorRows);
connect(action, &QAction::triggered, this, &This::onColorizeRowsTriggered); 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); //auto itemAction = new EasyItemAction("Show this item on scene", item->block()->block_index);
//itemAction->setToolTip("Scroll graphics scene to current item in the tree"); //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_PARENT:
case COL_MAX_PER_FRAME: case COL_MAX_PER_FRAME:
{ {
auto block = item->block(); auto& block = item->block();
auto i = ::profiler_gui::numeric_max<unsigned int>(); auto i = ::profiler_gui::numeric_max<uint32_t>();
switch (col) switch (col)
{ {
case COL_MIN_PER_THREAD: i = block->per_thread_stats->min_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_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_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_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_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_MAX_PER_FRAME: i = block.per_frame_stats->max_duration_block; break;
} }
if (i != ::profiler_gui::numeric_max(i)) if (i != ::profiler_gui::numeric_max(i))
{ {
menu.addSeparator(); 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)"); 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); menu.addAction(itemAction);
} }
@ -375,12 +403,13 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
auto hidemenu = menu.addMenu("Select columns"); auto hidemenu = menu.addMenu("Select columns");
auto hdr = headerItem(); 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->setCheckable(true);
columnAction->setChecked(!isColumnHidden(i)); columnAction->setChecked(!isColumnHidden(i));
connect(columnAction, &EasyHideShowColumnAction::clicked, this, &This::onHideShowColumn); connect(columnAction, &QAction::triggered, this, &This::onHideShowColumn);
hidemenu->addAction(columnAction); hidemenu->addAction(columnAction);
} }
@ -405,16 +434,21 @@ void EasyTreeWidget::moveEvent(QMoveEvent* _event)
void EasyTreeWidget::alignProgressBar() 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)); 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; auto action = qobject_cast<QAction*>(sender());
emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(_block_index); 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) void EasyTreeWidget::onCollapseAllClicked(bool)
@ -425,11 +459,11 @@ void EasyTreeWidget::onCollapseAllClicked(bool)
collapseAll(); collapseAll();
m_bSilentExpandCollapse = false; 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) for (auto item : m_items)
::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = false; item->guiBlock().expanded = false;
emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); emit EASY_GLOBALS.events.itemsExpandStateChanged();
} }
} }
@ -442,11 +476,15 @@ void EasyTreeWidget::onExpandAllClicked(bool)
resizeColumnsToContents(); resizeColumnsToContents();
m_bSilentExpandCollapse = false; 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) 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(); current->collapseAll();
m_bSilentExpandCollapse = false; m_bSilentExpandCollapse = false;
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); emit EASY_GLOBALS.events.itemsExpandStateChanged();
} }
} }
@ -477,7 +515,7 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool)
resizeColumnsToContents(); resizeColumnsToContents();
m_bSilentExpandCollapse = false; 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) 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(); resizeColumnsToContents();
return; 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) if (!m_bSilentExpandCollapse)
{ {
resizeColumnsToContents(); resizeColumnsToContents();
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); emit EASY_GLOBALS.events.itemsExpandStateChanged();
} }
} }
void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item) 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; 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) 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*) void EasyTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem*)
{ {
if (_item == nullptr) if (_item == nullptr)
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block); ::profiler_gui::set_max(EASY_GLOBALS.selected_block);
else 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); disconnect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(::profiler_gui::EASY_GLOBALS.selected_block); emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block);
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange); 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; 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()) if (i < m_items.size())
item = m_items[i]; item = m_items[i];
} }
@ -578,19 +616,19 @@ void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index)
{ {
//const QSignalBlocker b(this); //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; m_bSilentExpandCollapse = true;
setCurrentItem(item); setCurrentItem(item);
scrollToItem(item, QAbstractItemView::PositionAtCenter); scrollToItem(item, QAbstractItemView::PositionAtCenter);
if (::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded) if (item->guiBlock().expanded)
expandItem(item); expandItem(item);
else else
collapseItem(item); collapseItem(item);
resizeColumnsToContents(); resizeColumnsToContents();
m_bSilentExpandCollapse = false; m_bSilentExpandCollapse = false;
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged(); emit EASY_GLOBALS.events.itemsExpandStateChanged();
} }
else else
{ {
@ -621,16 +659,17 @@ void EasyTreeWidget::resizeColumnsToContents()
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void EasyTreeWidget::onHideShowColumn(int _column) void EasyTreeWidget::onHideShowColumn(bool)
{ {
if (isColumnHidden(_column)) auto action = qobject_cast<QAction*>(sender());
{ if (action == nullptr)
showColumn(_column); return;
}
auto col = action->data().toInt();
if (isColumnHidden(col))
showColumn(col);
else else
{ hideColumn(col);
hideColumn(_column);
}
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -655,17 +694,17 @@ void EasyTreeWidget::loadSettings()
void EasyTreeWidget::saveSettings() void EasyTreeWidget::saveSettings()
{ {
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("tree_widget"); settings.beginGroup("tree_widget");
settings.setValue("color_rows", m_bColorRows); settings.setValue("color_rows", m_bColorRows);
for (int i = 0; i < columnCount(); i++) for (int i = 0; i < columnCount(); i++)
{ {
settings.setValue(QString("Column") + QString::number(i) , isColumnHidden(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 * file name : blocks_tree_widget.h
* ----------------- : * ----------------- :
* creation time : 2016/06/26 * creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * email : v.s.zarubkin@gmail.com
* ----------------- : * ----------------- :
@ -20,7 +19,21 @@
* : * 2016/08/18 Victor Zarubkin: Added loading blocks hierarchy in separate thread; * : * 2016/08/18 Victor Zarubkin: Added loading blocks hierarchy in separate thread;
* : Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp * : 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_ #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 class EasyTreeWidget : public QTreeWidget
{ {
Q_OBJECT Q_OBJECT
@ -96,7 +88,7 @@ protected:
private slots: private slots:
void onJumpToItemClicked(unsigned int _block_index); void onJumpToItemClicked(bool);
void onCollapseAllClicked(bool); void onCollapseAllClicked(bool);
@ -118,14 +110,14 @@ private slots:
void resizeColumnsToContents(); void resizeColumnsToContents();
void onHideShowColumn(int _column); void onHideShowColumn(bool);
void onFillTimerTimeout(); void onFillTimerTimeout();
protected: protected:
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
void alignProgressBar(); void alignProgressBar();
}; // END of class EasyTreeWidget. }; // END of class EasyTreeWidget.

View File

@ -2,7 +2,6 @@
* file name : common_types.h * file name : common_types.h
* ----------------- : * ----------------- :
* creation time : 2016/07/31 * creation time : 2016/07/31
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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 #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) 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; 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) #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) 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 float w; ///< Width of the item
QRgb color; ///< Background color of the item QRgb color; ///< Background color of the item
unsigned int children_begin; ///< Index of first child item on the next sublevel ::profiler::block_index_t block; ///< Index of profiler block
unsigned short totalHeight; ///< Total height of the item including heights of all it's children 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 char state; ///< 0 = no change, 1 = paint, -1 = do not paint
// Possible optimizations: // Possible optimizations:
@ -125,31 +145,58 @@ struct ProfBlockItem final
inline qreal right() const { return x + w; } inline qreal right() const { return x + w; }
inline float width() const { return w; } inline float width() const { return w; }
}; // END of struct ProfBlockItem. }; // END of struct EasyBlockItem.
#pragma pack(pop)
typedef ::std::vector<ProfBlockItem> ProfItems; struct EasyBlock final
//////////////////////////////////////////////////////////////////////////
struct ProfSelectedBlock final
{ {
const ::profiler::BlocksTreeRoot* root; ::profiler::BlocksTree tree;
const ::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) : root(_root)
, tree(_tree) , 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 * file name : globals.cpp
* ----------------- : * ----------------- :
* creation time : 2016/08/03 * creation time : 2016/08/03
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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 #define IGNORE_GLOBALS_DECLARATION

View File

@ -2,7 +2,6 @@
* file name : globals.h * file name : globals.h
* ----------------- : * ----------------- :
* creation time : 2016/08/03 * creation time : 2016/08/03
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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 #ifndef EASY_PROFILER__GUI_GLOBALS_H
@ -30,8 +43,8 @@
namespace profiler_gui { namespace profiler_gui {
const QString ORGANAZATION_NAME = "EasyProfiler"; const QString ORGANAZATION_NAME = "EasyProfiler";
const QString APPLICATION_NAME = "Easy profiler gui application"; const QString APPLICATION_NAME = "Easy profiler gui application";
const QColor CHRONOMETER_COLOR = QColor::fromRgba(0x402020c0); const QColor CHRONOMETER_COLOR = QColor::fromRgba(0x402020c0);
const QRgb SELECTED_THREAD_BACKGROUND = 0x00e0e060; 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> template <class T>
inline auto toUnicode(const T& _inputString) -> decltype(QTextCodec::codecForLocale()->toUnicode(_inputString)) inline auto toUnicode(const T& _inputString) -> decltype(QTextCodec::codecForLocale()->toUnicode(_inputString))
{ {
@ -79,6 +79,7 @@ namespace profiler_gui {
EasyGlobalSignals events; ///< Global signals EasyGlobalSignals events; ///< Global signals
::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file ::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 EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI
::profiler::thread_id_t selected_thread; ///< Current selected thread id ::profiler::thread_id_t selected_thread; ///< Current selected thread id
unsigned int selected_block; ///< Current selected profiler block index unsigned int selected_block; ///< Current selected profiler block index
@ -96,13 +97,26 @@ namespace profiler_gui {
}; // END of struct EasyGlobals. }; // END of struct EasyGlobals.
#ifndef IGNORE_GLOBALS_DECLARATION
static EasyGlobals& EASY_GLOBALS = EasyGlobals::instance();
#endif
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
} // END of namespace profiler_gui. } // 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 * file name : globals_qobjects.cpp
* ----------------- : * ----------------- :
* creation time : 2016/08/08 * creation time : 2016/08/08
* copyright : (c) 2016 Victor Zarubkin, Sergey Yagovtsev * authors : Victor Zarubkin, Sergey Yagovtsev
* author : Victor Zarubkin * email : v.s.zarubkin@gmail.com, yse.sey@gmail.com
* email : v.s.zarubkin@gmail.com
* ----------------- : * ----------------- :
* description : The file contains implementation of EasyGlobalSignals QObject class. * 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" #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 <QObject>
#include "profiler/profiler.h" #include "profiler/profiler.h"
@ -27,4 +57,4 @@ namespace profiler_gui {
} // END of 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 * file name : graphics_scrollbar.cpp
* ----------------- : * ----------------- :
* creation time : 2016/07/04 * creation time : 2016/07/04
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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> #include <algorithm>
@ -28,7 +41,7 @@
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
const qreal SCALING_COEFFICIENT = 1.25; 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_TOP = -40;
const int DEFAULT_HEIGHT = 80; const int DEFAULT_HEIGHT = 80;
const int INDICATOR_SIZE = 8; 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); 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_pSource = _items;
m_threadId = _thread_id; 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_minimap->setSource(_thread_id, _items);
m_slider->setVisible(m_minimap->isVisible()); m_slider->setVisible(m_minimap->isVisible());
@ -477,7 +490,6 @@ void EasyGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event)
void EasyGraphicsScrollbar::wheelEvent(QWheelEvent* _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); 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); setValue(mapToScene(_event->pos()).x() - m_minimumValue - w);
emit wheeled(w * m_windowScale, _event->delta()); emit wheeled(w * m_windowScale, _event->delta());
@ -493,14 +505,14 @@ void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event)
void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event) void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
{ {
if (::profiler_gui::EASY_GLOBALS.profiler_blocks.empty()) if (EASY_GLOBALS.profiler_blocks.empty())
{ {
return; return;
} }
QMenu menu; QMenu menu;
for (const auto& it : ::profiler_gui::EASY_GLOBALS.profiler_blocks) for (const auto& it : EASY_GLOBALS.profiler_blocks)
{ {
QString label; QString label;
if (it.second.thread_name && it.second.thread_name[0] != 0) 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)); 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->setCheckable(true);
action->setChecked(it.first == ::profiler_gui::EASY_GLOBALS.selected_thread); action->setChecked(it.first == EASY_GLOBALS.selected_thread);
connect(action, &EasyIdAction::clicked, this, &This::onThreadActionClicked); connect(action, &QAction::triggered, this, &This::onThreadActionClicked);
menu.addAction(action); 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; EASY_GLOBALS.selected_thread = thread_id;
emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(_id); emit EASY_GLOBALS.events.selectedThreadChanged(thread_id);
} }
} }

View File

@ -2,17 +2,30 @@
* file name : graphics_scrollbar.h * file name : graphics_scrollbar.h
* ----------------- : * ----------------- :
* creation time : 2016/07/04 * creation time : 2016/07/04
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * email : v.s.zarubkin@gmail.com
* ----------------- : * ----------------- :
* description : . * description : This file contains declaration of
* ----------------- : * ----------------- :
* change log : * 2016/07/04 Victor Zarubkin: Initial commit. * 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 #ifndef EASY__GRAPHICS_SCROLLBAR__H
@ -66,7 +79,7 @@ class EasyMinimapItem : public QGraphicsItem
QRectF m_boundingRect; QRectF m_boundingRect;
qreal m_maxDuration; qreal m_maxDuration;
qreal m_minDuration; qreal m_minDuration;
const ::profiler_gui::ProfItems* m_pSource; const ::profiler_gui::EasyItems* m_pSource;
::profiler::thread_id_t m_threadId; ::profiler::thread_id_t m_threadId;
public: public:
@ -88,53 +101,12 @@ public:
void setBoundingRect(const QRectF& _rect); void setBoundingRect(const QRectF& _rect);
void setBoundingRect(qreal x, qreal y, qreal w, qreal h); 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. }; // 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 class EasyGraphicsScrollbar : public QGraphicsView
{ {
Q_OBJECT Q_OBJECT
@ -190,9 +162,9 @@ public:
void showChrono(); void showChrono();
void hideChrono(); 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); setMinimapFrom(_thread_id, &_items);
} }
@ -205,7 +177,7 @@ signals:
private slots: private slots:
void onThreadActionClicked(::profiler::thread_id_t _id); void onThreadActionClicked(bool);
void onWindowWidthChange(qreal _width); void onWindowWidthChange(qreal _width);
}; // END of class EasyGraphicsScrollbar. }; // END of class EasyGraphicsScrollbar.

View File

@ -1,38 +1,65 @@
#include <QApplication> /************************************************************************
#include <QTreeView> * file name : main.cpp
#include <QFileSystemModel> * ----------------- :
* 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 <chrono>
#include <QApplication>
//#include <QTreeView>
//#include <QFileSystemModel>
//#include "treemodel.h" //#include "treemodel.h"
#include "main_window.h" #include "main_window.h"
#include "profiler/reader.h" #include "profiler/reader.h"
//#ifdef WIN32
//#ifdef _WIN32
//#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup") //#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
//#endif //#endif
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
QApplication app(argc, argv); QApplication app(argc, argv);
//QFileSystemModel *model = new QFileSystemModel; //QFileSystemModel *model = new QFileSystemModel;
//model->setRootPath(QDir::currentPath()); //model->setRootPath(QDir::currentPath());
// const char* filename = 0; // const char* filename = 0;
// if(argc > 1 && argv[1]){ // if(argc > 1 && argv[1]){
// filename = argv[1]; // filename = argv[1];
// }else{ // }else{
// return 255; // return 255;
// } // }
// QFile file(filename); // QFile file(filename);
// file.open(QIODevice::ReadOnly); // file.open(QIODevice::ReadOnly);
// TreeModel model(file.readAll()); // TreeModel model(file.readAll());
// file.close(); // file.close();
// QTreeView *tree = new QTreeView(); // QTreeView *tree = new QTreeView();
// tree->setModel(&model); // 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; auto now = ::std::chrono::duration_cast<std::chrono::seconds>(::std::chrono::system_clock::now().time_since_epoch()).count() >> 1;
srand((unsigned int)now); 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 * file name : main_window.h
* ----------------- : * ----------------- :
* creation time : 2016/06/26 * creation time : 2016/06/26
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * email : v.s.zarubkin@gmail.com
* ----------------- : * ----------------- :
@ -11,7 +10,21 @@
* change log : * 2016/06/26 Victor Zarubkin: initial commit. * 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 #ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H
@ -32,13 +45,16 @@ class QDockWidget;
class EasyFileReader final class EasyFileReader final
{ {
::profiler::SerializedData m_serializedData; ///< ::profiler::SerializedData m_serializedBlocks; ///<
::profiler::thread_blocks_tree_t m_blocksTree; ///< ::profiler::SerializedData m_serializedDescriptors; ///<
QString m_filename; ///< ::profiler::descriptors_list_t m_descriptors; ///<
::std::thread m_thread; ///< ::profiler::blocks_t m_blocks; ///<
::std::atomic_bool m_bDone; ///< ::profiler::thread_blocks_tree_t m_blocksTree; ///<
::std::atomic<int> m_progress; ///< QString m_filename; ///<
::std::atomic<unsigned int> m_size; ///< ::std::thread m_thread; ///<
::std::atomic_bool m_bDone; ///<
::std::atomic<int> m_progress; ///<
::std::atomic<unsigned int> m_size; ///<
public: public:
@ -52,7 +68,9 @@ public:
void load(const QString& _filename); void load(const QString& _filename);
void interrupt(); 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. }; // END of class EasyFileReader.
@ -67,13 +85,14 @@ protected:
typedef EasyMainWindow This; typedef EasyMainWindow This;
typedef QMainWindow Parent; typedef QMainWindow Parent;
QString m_lastFile; QString m_lastFile;
QDockWidget* m_treeWidget; QDockWidget* m_treeWidget;
QDockWidget* m_graphicsView; QDockWidget* m_graphicsView;
class QProgressDialog* m_progress; class QProgressDialog* m_progress;
QTimer m_readerTimer; QTimer m_readerTimer;
::profiler::SerializedData m_serializedData; ::profiler::SerializedData m_serializedBlocks;
EasyFileReader m_reader; ::profiler::SerializedData m_serializedDescriptors;
EasyFileReader m_reader;
public: public:
@ -108,7 +127,7 @@ private:
void loadSettings(); void loadSettings();
void loadGeometry(); void loadGeometry();
void saveSettingsAndGeometry(); void saveSettingsAndGeometry();
}; // END of class EasyMainWindow. }; // END of class EasyMainWindow.

View File

@ -2,7 +2,6 @@
* file name : tree_widget_item.cpp * file name : tree_widget_item.cpp
* ----------------- : * ----------------- :
* creation time : 2016/08/18 * creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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" #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) : Parent(_parent)
, m_block(_treeBlock) , m_block(_treeBlock)
, m_customBGColor(0) , m_customBGColor(0)
@ -75,15 +88,25 @@ bool EasyTreeWidgetItem::operator < (const Parent& _other) const
return false; return false;
} }
const ::profiler::BlocksTree* EasyTreeWidgetItem::block() const ::profiler::block_index_t EasyTreeWidgetItem::block_index() const
{ {
return m_block; 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 ::profiler::timestamp_t EasyTreeWidgetItem::duration() const
{ {
if (m_block->node) if (parent() != nullptr)
return m_block->node->block()->duration(); return block().node->duration();
return data(COL_DURATION, Qt::UserRole).toULongLong(); return data(COL_DURATION, Qt::UserRole).toULongLong();
} }
@ -173,7 +196,8 @@ void EasyTreeWidgetItem::collapseAll()
} }
setExpanded(false); setExpanded(false);
::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = false; if (parent() != nullptr)
guiBlock().expanded = false;
} }
void EasyTreeWidgetItem::expandAll() void EasyTreeWidgetItem::expandAll()
@ -184,7 +208,8 @@ void EasyTreeWidgetItem::expandAll()
} }
setExpanded(true); 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 * file name : tree_widget_item.h
* ----------------- : * ----------------- :
* creation time : 2016/08/18 * creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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_ #ifndef EASY__TREE_WIDGET_ITEM__H_
@ -75,7 +88,7 @@ class EasyTreeWidgetItem : public QTreeWidgetItem
typedef QTreeWidgetItem Parent; typedef QTreeWidgetItem Parent;
typedef EasyTreeWidgetItem This; typedef EasyTreeWidgetItem This;
const ::profiler::BlocksTree* m_block; const ::profiler::block_index_t m_block;
QRgb m_customBGColor; QRgb m_customBGColor;
QRgb m_customTextColor; QRgb m_customTextColor;
@ -84,14 +97,16 @@ public:
using Parent::setBackgroundColor; using Parent::setBackgroundColor;
using Parent::setTextColor; 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(); virtual ~EasyTreeWidgetItem();
bool operator < (const Parent& _other) const override; bool operator < (const Parent& _other) const override;
public: 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 duration() const;
::profiler::timestamp_t selfDuration() 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 * file name : tree_widget_loader.h
* ----------------- : * ----------------- :
* creation time : 2016/08/18 * creation time : 2016/08/18
* copyright : (c) 2016 Victor Zarubkin
* author : Victor Zarubkin * author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com * 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_ #ifndef EASY__TREE_WIDGET_LOADER__H_

View File

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

View File

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

View File

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

View File

@ -26,22 +26,22 @@ void localSleep(int magic=200000)
} }
void loadingResources(){ void loadingResources(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkcyan); EASY_FUNCTION(profiler::colors::DarkCyan);
localSleep(); localSleep();
// std::this_thread::sleep_for(std::chrono::milliseconds(50)); // std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }
void prepareMath(){ void prepareMath(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); EASY_FUNCTION(profiler::colors::Blue);
int* intarray = new int[OBJECTS]; int* intarray = new int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i) for (int i = 0; i < OBJECTS; ++i)
intarray[i] = i * i; intarray[i] = i * i;
delete[] intarray; delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(3)); //std::this_thread::sleep_for(std::chrono::milliseconds(3));
} }
void calcIntersect(){ 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 * OBJECTS];
int* intarray = new int[OBJECTS]; int* intarray = new int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i) for (int i = 0; i < OBJECTS; ++i)
@ -51,17 +51,17 @@ void calcIntersect(){
intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5; intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5;
} }
delete[] intarray; delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(4)); //std::this_thread::sleep_for(std::chrono::milliseconds(4));
} }
double multModel(double i) double multModel(double i)
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); EASY_FUNCTION(profiler::colors::Blue);
return i * sin(i) * cos(i); return i * sin(i) * cos(i);
} }
void calcPhys(){ void calcPhys(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); EASY_FUNCTION(profiler::colors::Blue);
double* intarray = new double[OBJECTS]; double* intarray = new double[OBJECTS];
for (int i = 0; i < OBJECTS; ++i) for (int i = 0; i < OBJECTS; ++i)
intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2); intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2);
@ -71,213 +71,218 @@ void calcPhys(){
double calcSubbrain(int i) 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 ; return i * i * i - i / 10 + (OBJECTS - i) * 7 ;
} }
void calcBrain(){ void calcBrain(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue); EASY_FUNCTION(profiler::colors::Blue);
double* intarray = new double[OBJECTS]; double* intarray = new double[OBJECTS];
for (int i = 0; i < OBJECTS; ++i) for (int i = 0; i < OBJECTS; ++i)
intarray[i] = calcSubbrain(i) + double(i * 180 / 3); intarray[i] = calcSubbrain(i) + double(i * 180 / 3);
delete[] intarray; delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(3)); //std::this_thread::sleep_for(std::chrono::milliseconds(3));
} }
void calculateBehavior(){ void calculateBehavior(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkblue); EASY_FUNCTION(profiler::colors::DarkBlue);
calcPhys(); calcPhys();
calcBrain(); calcBrain();
} }
void modellingStep(){ void modellingStep(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Navy); EASY_FUNCTION(profiler::colors::Navy);
prepareMath(); prepareMath();
calculateBehavior(); calculateBehavior();
} }
void prepareRender(){ void prepareRender(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkred); EASY_FUNCTION(profiler::colors::DarkRed);
localSleep(); localSleep();
//std::this_thread::sleep_for(std::chrono::milliseconds(8)); //std::this_thread::sleep_for(std::chrono::milliseconds(8));
} }
int multPhys(int i) int multPhys(int i)
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
return i * i * i * i / 100; return i * i * i * i / 100;
} }
int calcPhysicForObject(int i) 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; return multPhys(i) + i / 3 - (OBJECTS - i) * 15;
} }
void calculatePhysics(){ void calculatePhysics(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
unsigned int* intarray = new unsigned int[OBJECTS]; unsigned int* intarray = new unsigned int[OBJECTS];
for (int i = 0; i < OBJECTS; ++i) for (int i = 0; i < OBJECTS; ++i)
intarray[i] = calcPhysicForObject(i); intarray[i] = calcPhysicForObject(i);
delete[] intarray; delete[] intarray;
//std::this_thread::sleep_for(std::chrono::milliseconds(8)); //std::this_thread::sleep_for(std::chrono::milliseconds(8));
} }
void frame(){ void frame(){
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Magenta); EASY_FUNCTION(profiler::colors::Magenta);
prepareRender(); prepareRender();
calculatePhysics(); calculatePhysics();
} }
void loadingResourcesThread(){ void loadingResourcesThread(){
//std::unique_lock<std::mutex> lk(cv_m); //std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; }); //cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Resource loading") EASY_THREAD("Resource loading");
for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){ for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){
loadingResources(); loadingResources();
PROFILER_ADD_EVENT_GROUPED("Resources Loading!",profiler::colors::Cyan); EASY_EVENT("Resources Loading!", profiler::colors::Cyan);
localSleep(1200000); localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20)); //std::this_thread::sleep_for(std::chrono::milliseconds(20));
} }
} }
void modellingThread(){ void modellingThread(){
//std::unique_lock<std::mutex> lk(cv_m); //std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; }); //cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Modelling") EASY_THREAD("Modelling");
for (int i = 0; i < RENDER_SPEPS; i++){ for (int i = 0; i < RENDER_SPEPS; i++){
modellingStep(); modellingStep();
localSleep(1200000); localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20)); //std::this_thread::sleep_for(std::chrono::milliseconds(20));
} }
} }
void renderThread(){ void renderThread(){
//std::unique_lock<std::mutex> lk(cv_m); //std::unique_lock<std::mutex> lk(cv_m);
//cv.wait(lk, []{return g_i == 1; }); //cv.wait(lk, []{return g_i == 1; });
PROFILER_SET_THREAD_NAME("Render") EASY_THREAD("Render");
for (int i = 0; i < MODELLING_STEPS; i++){ for (int i = 0; i < MODELLING_STEPS; i++){
frame(); frame();
localSleep(1200000); localSleep(1200000);
//std::this_thread::sleep_for(std::chrono::milliseconds(20)); //std::this_thread::sleep_for(std::chrono::milliseconds(20));
} }
} }
void four() void four()
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(37)); std::this_thread::sleep_for(std::chrono::milliseconds(37));
} }
void five() void five()
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::this_thread::sleep_for(std::chrono::milliseconds(20));
} }
void six() void six()
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(42)); std::this_thread::sleep_for(std::chrono::milliseconds(42));
} }
void three() void three()
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
four(); four();
five(); five();
six(); six();
} }
void seven() void seven()
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(147)); std::this_thread::sleep_for(std::chrono::milliseconds(147));
} }
void two() void two()
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
std::this_thread::sleep_for(std::chrono::milliseconds(26)); std::this_thread::sleep_for(std::chrono::milliseconds(26));
} }
void one() void one()
{ {
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red); EASY_FUNCTION(profiler::colors::Red);
two(); two();
three(); three();
seven(); seven();
} }
/* /*
one one
two two
three three
four four
five five
six six
seven seven
*/ */
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
if (argc > 1 && argv[1]){ if (argc > 1 && argv[1]){
OBJECTS = std::atoi(argv[1]); OBJECTS = std::atoi(argv[1]);
} }
if (argc > 2 && argv[2]){ if (argc > 2 && argv[2]){
RENDER_SPEPS = std::atoi(argv[2]); RENDER_SPEPS = std::atoi(argv[2]);
} }
if (argc > 3 && argv[3]){ if (argc > 3 && argv[3]){
MODELLING_STEPS = std::atoi(argv[3]); MODELLING_STEPS = std::atoi(argv[3]);
} }
if (argc > 4 && argv[4]){ if (argc > 4 && argv[4]){
RESOURCE_LOADING_COUNT = std::atoi(argv[4]); RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
} }
std::cout << "Objects count: " << OBJECTS << std::endl; std::cout << "Objects count: " << OBJECTS << std::endl;
std::cout << "Render steps: " << RENDER_SPEPS << std::endl; std::cout << "Render steps: " << RENDER_SPEPS << std::endl;
std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl; std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl;
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl; std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
auto start = std::chrono::system_clock::now(); auto start = std::chrono::system_clock::now();
PROFILER_ENABLE; EASY_PROFILER_ENABLE;
PROFILER_SET_MAIN_THREAD; EASY_MAIN_THREAD;
//one(); //one();
//one(); //one();
/**/ /**/
std::vector<std::thread> threads; std::vector<std::thread> threads;
std::thread render = std::thread(renderThread); std::thread render = std::thread(renderThread);
std::thread modelling = std::thread(modellingThread); std::thread modelling = std::thread(modellingThread);
for(int i=0; i < 3; i++){ for(int i=0; i < 3; i++){
threads.emplace_back(std::thread(loadingResourcesThread)); threads.emplace_back(std::thread(loadingResourcesThread));
threads.emplace_back(std::thread(renderThread)); threads.emplace_back(std::thread(renderThread));
threads.emplace_back(std::thread(modellingThread)); threads.emplace_back(std::thread(modellingThread));
} }
{ {
std::lock_guard<std::mutex> lk(cv_m); std::lock_guard<std::mutex> lk(cv_m);
g_i = 1; g_i = 1;
} }
cv.notify_all(); cv.notify_all();
render.join(); for (int i = 0; i < RENDER_SPEPS; ++i) {
modelling.join(); modellingStep();
for(auto& t : threads){ localSleep(1200000);
t.join(); }
}
/**/
auto end = std::chrono::system_clock::now(); render.join();
auto elapsed = modelling.join();
std::chrono::duration_cast<std::chrono::microseconds>(end - start); 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) project(easy_profiler)
set(CPP_FILES set(CPP_FILES
block.cpp block.cpp
profile_manager.cpp profile_manager.cpp
reader.cpp reader.cpp
event_trace_win.cpp
) )
set(H_FILES set(H_FILES
${ROOT}/include/profiler/profiler.h ${ROOT}/include/profiler/profiler.h
${ROOT}/include/profiler/reader.h ${ROOT}/include/profiler/reader.h
profile_manager.h ${ROOT}/include/profiler/event_trace_status.h
spin_lock.h profile_manager.h
spin_lock.h
event_trace_win.h
) )
set(SOURCES set(SOURCES
${CPP_FILES} ${CPP_FILES}
${H_FILES} ${H_FILES}
) )
add_definitions( add_definitions(
-D_BUILD_PROFILER -D_BUILD_PROFILER
) )
add_library(${PROJECT_NAME} SHARED ${SOURCES}) 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 "profiler/profiler.h"
#include "profile_manager.h" #include "profile_manager.h"
#include <ctime> #include <ctime>
@ -6,73 +31,69 @@
using namespace profiler; using namespace profiler;
#ifdef WIN32 #ifdef _WIN32
struct ProfPerformanceFrequency { decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY = ([](){ LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return freq.QuadPart; })();
LARGE_INTEGER frequency;
ProfPerformanceFrequency() { QueryPerformanceFrequency(&frequency); }
} const WINDOWS_CPU_INFO;
#endif #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() inline timestamp_t getCurrentTime()
{ {
#ifdef WIN32 #ifdef _WIN32
//see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx //see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx
LARGE_INTEGER elapsedMicroseconds; LARGE_INTEGER elapsedMicroseconds;
if (!QueryPerformanceCounter(&elapsedMicroseconds)) if (!QueryPerformanceCounter(&elapsedMicroseconds))
return 0; return 0;
elapsedMicroseconds.QuadPart *= 1000000000LL; //elapsedMicroseconds.QuadPart *= 1000000000LL;
elapsedMicroseconds.QuadPart /= WINDOWS_CPU_INFO.frequency.QuadPart; //elapsedMicroseconds.QuadPart /= CPU_FREQUENCY;
return (timestamp_t)elapsedMicroseconds.QuadPart; return (timestamp_t)elapsedMicroseconds.QuadPart;
#else #else
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time_point; 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()); time_point = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now());
return time_point.time_since_epoch().count(); return time_point.time_since_epoch().count();
#endif #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() Block::~Block()
{ {
if (this->type == BLOCK_TYPE_BLOCK) if (!isFinished())
{ ::profiler::endBlock();
if (this->isCleared())//this block was cleared by END_BLOCK macros
return;
if (!this->isFinished())
this->finish();
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" /************************************************************************
* file name : profile_manager.cpp
#include <thread> * ----------------- :
#include <string.h> * creation time : 2016/02/16
* authors : Sergey Yagovtsev, Victor Zarubkin
#include <fstream> * emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
using namespace profiler; * description : The file contains implementation of Profile manager and implement access c-function
* :
auto& MANAGER = ProfileManager::instance(); * license : Lightweight profiler library for c++
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
extern "C"{ * :
* : This program is free software : you can redistribute it and / or modify
void PROFILER_API endBlock() * : it under the terms of the GNU General Public License as published by
{ * : the Free Software Foundation, either version 3 of the License, or
MANAGER.endBlock(); * : (at your option) any later version.
} * :
* : This program is distributed in the hope that it will be useful,
void PROFILER_API setEnabled(bool isEnable) * : but WITHOUT ANY WARRANTY; without even the implied warranty of
{ * : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
MANAGER.setEnabled(isEnable); * : GNU General Public License for more details.
} * :
void PROFILER_API beginBlock(Block& _block) * : You should have received a copy of the GNU General Public License
{ * : along with this program.If not, see <http://www.gnu.org/licenses/>.
MANAGER.beginBlock(_block); ************************************************************************/
} #include "profile_manager.h"
#include "profiler/serialized_block.h"
unsigned int PROFILER_API dumpBlocksToFile(const char* filename) #include "event_trace_win.h"
{
return MANAGER.dumpBlocksToFile(filename); #include <thread>
} #include <string.h>
void PROFILER_API setThreadName(const char* name) #include <fstream>
{
return MANAGER.setThreadName(name); //////////////////////////////////////////////////////////////////////////
} //////////////////////////////////////////////////////////////////////////
}
using namespace profiler;
SerializedBlock* SerializedBlock::create(const Block& block, uint64_t& memory_size)
{ #ifdef _WIN32
auto name_length = static_cast<uint16_t>(strlen(block.getName())); extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY;
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1); #endif
auto data = ::new char[size];
::new (static_cast<void*>(data)) SerializedBlock(block, name_length); //auto& MANAGER = ProfileManager::instance();
memory_size += size; #define MANAGER ProfileManager::instance()
return reinterpret_cast<SerializedBlock*>(data);
} extern "C" {
void SerializedBlock::destroy(SerializedBlock* that) PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
{ {
::delete[] reinterpret_cast<char*>(that); return MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color);
} }
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) PROFILER_API void endBlock()
: BaseBlockData(block) {
{ MANAGER.endBlock();
auto name = const_cast<char*>(getName()); }
strncpy(name, block.getName(), name_length);
name[name_length] = 0; PROFILER_API void setEnabled(bool isEnable)
} {
MANAGER.setEnabled(isEnable);
////////////////////////////////////////////////////////////////////////// #ifdef _WIN32
if (isEnable)
BlockSourceInfo::BlockSourceInfo(const char* _filename, int _linenumber) : m_id(MANAGER.addSource(_filename, _linenumber)) EasyEventTracer::instance().enable(true);
{ else
EasyEventTracer::instance().disable();
} #endif
}
SourceBlock::SourceBlock(const char* _filename, int _line) : m_filename(_filename), m_line(_line)
{ PROFILER_API void beginBlock(Block& _block)
{
} MANAGER.beginBlock(_block);
}
//////////////////////////////////////////////////////////////////////////
PROFILER_API uint32_t dumpBlocksToFile(const char* filename)
ProfileManager::ProfileManager() {
{ return MANAGER.dumpBlocksToFile(filename);
}
}
PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line)
ProfileManager::~ProfileManager() {
{ return MANAGER.setThreadName(name, filename, _funcname, line);
//dumpBlocksToFile("test.prof"); }
}
PROFILER_API void setContextSwitchLogFilename(const char* name)
ProfileManager& ProfileManager::instance() {
{ return MANAGER.setContextSwitchLogFilename(name);
///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; PROFILER_API const char* getContextSwitchLogFilename()
return m_profileManager; {
} return MANAGER.getContextSwitchLogFilename();
}
void ProfileManager::beginBlock(Block& _block)
{ }
if (!m_isEnabled)
return; SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
: BaseBlockData(block)
if (BLOCK_TYPE_BLOCK == _block.getType()){ {
guard_lock_t lock(m_spin); auto pName = const_cast<char*>(name());
m_openedBracketsMap[_block.getThreadId()].emplace(_block); if (name_length) strncpy(pName, block.name(), name_length);
} pName[name_length] = 0;
else{ }
_internalInsertBlock(_block);
} //////////////////////////////////////////////////////////////////////////
} BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color)
void ProfileManager::endBlock() : m_line(_line)
{ , m_type(_block_type)
, m_color(_color)
if (!m_isEnabled) {
return;
}
uint32_t threadId = getCurrentThreadId();
BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
guard_lock_t lock(m_spin); : BaseBlockDescriptor(_line, _block_type, _color)
auto& stackOfOpenedBlocks = m_openedBracketsMap[threadId]; , m_name(_name)
, m_filename(_filename)
if (stackOfOpenedBlocks.empty()) {
return; _used_mem += sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2;
}
Block& lastBlock = stackOfOpenedBlocks.top();
if(!lastBlock.isFinished()) //////////////////////////////////////////////////////////////////////////
lastBlock.finish();
_internalInsertBlock(lastBlock); void ThreadStorage::storeBlock(const profiler::Block& block)
{
stackOfOpenedBlocks.pop(); 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);
void ProfileManager::setEnabled(bool isEnable) ::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
{ blocks.usedMemorySize += size;
m_isEnabled = isEnable; blocks.closedList.emplace_back(reinterpret_cast<SerializedBlock*>(data));
} }
void ProfileManager::_internalInsertBlock(const profiler::Block& _block) void ThreadStorage::storeCSwitch(const profiler::Block& block)
{ {
guard_lock_t lock(m_storedSpin); auto name_length = static_cast<uint16_t>(strlen(block.name()));
m_blocks.emplace_back(SerializedBlock::create(_block, m_blocksMemorySize)); 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);
unsigned int ProfileManager::dumpBlocksToFile(const char* filename) sync.usedMemorySize += size;
{ sync.closedList.emplace_back(reinterpret_cast<SerializedBlock*>(data));
::std::ofstream of(filename, std::fstream::binary); }
auto blocks_number = static_cast<uint32_t>(m_blocks.size()); void ThreadStorage::clearClosed()
//of.write((const char*)&blocks_number, sizeof(uint32_t)); {
of.write((const char*)&m_blocksMemorySize, sizeof(uint64_t)); blocks.clearClosed();
sync.clearClosed();
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)); EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr;
of.write(b->data(), sz);
// #ifdef _WIN32
SerializedBlock::destroy(b); // LPTOP_LEVEL_EXCEPTION_FILTER PREVIOUS_FILTER = NULL;
} // LONG WINAPI easyTopLevelExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
// {
m_blocksMemorySize = 0; // std::ofstream testexp("TEST_EXP.txt", std::fstream::binary);
m_blocks.clear(); // testexp.write("APPLICATION CRASHED!", strlen("APPLICATION CRASHED!"));
//
return blocks_number; // EasyEventTracer::instance().disable();
} // if (PREVIOUS_FILTER)
// return PREVIOUS_FILTER(ExceptionInfo);
void ProfileManager::setThreadName(const char* name) // return EXCEPTION_CONTINUE_SEARCH;
{ // }
auto current_thread_id = getCurrentThreadId(); // #endif
guard_lock_t lock(m_storedSpin); ProfileManager::ProfileManager()
auto find_it = m_namedThreades.find(current_thread_id); {
if (find_it != m_namedThreades.end()) // #ifdef _WIN32
return; // PREVIOUS_FILTER = SetUnhandledExceptionFilter(easyTopLevelExceptionFilter);
// #endif
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); ProfileManager::~ProfileManager()
} {
//dumpBlocksToFile("test.prof");
////////////////////////////////////////////////////////////////////////// }
unsigned int ProfileManager::addSource(const char* _filename, int _line) ProfileManager& ProfileManager::instance()
{ {
guard_lock_t lock(m_storedSpin); ///C++11 makes possible to create Singleton without any warry about thread-safeness
const auto id = static_cast<unsigned int>(m_sources.size()); ///http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
m_sources.emplace_back(_filename, _line); static ProfileManager m_profileManager;
return id; 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 <stack>
#include <map> #include <map>
#include <list> #include <list>
#include <set>
#include <vector> #include <vector>
#include <string>
#include <functional> #include <functional>
#ifdef WIN32 //////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
#include <Windows.h> #include <Windows.h>
#else #else
#include <thread> #include <thread>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#endif #endif
inline uint32_t getCurrentThreadId() inline uint32_t getCurrentThreadId()
{ {
#ifdef WIN32 #ifdef _WIN32
return (uint32_t)::GetCurrentThreadId(); return (uint32_t)::GetCurrentThreadId();
#else #else
thread_local static uint32_t _id = (uint32_t)std::hash<std::thread::id>()(std::this_thread::get_id()); EASY_THREAD_LOCAL static const pid_t x = syscall(__NR_gettid);
return _id; EASY_THREAD_LOCAL static const uint32_t _id = (uint32_t)x;//std::hash<std::thread::id>()(std::this_thread::get_id());
return _id;
#endif #endif
} }
class ProfileManager namespace profiler { class SerializedBlock; }
//////////////////////////////////////////////////////////////////////////
template <class T, const uint16_t N>
class chunk_allocator final
{ {
ProfileManager(); struct chunk { T data[N]; };
ProfileManager(const ProfileManager& p) = delete;
ProfileManager& operator=(const ProfileManager&) = delete;
static ProfileManager m_profileManager;
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; public:
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;
map_of_threads_stacks m_openedBracketsMap; chunk_allocator() : m_size(0)
{
m_chunks.emplace_back();
}
profiler::spin_lock m_spin; T* allocate(uint16_t n)
profiler::spin_lock m_storedSpin; {
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t; 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: public:
static ProfileManager& instance(); 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 beginBlock(profiler::Block& _block);
void endBlock(); void endBlock();
void setEnabled(bool isEnable); void setEnabled(bool isEnable);
unsigned int dumpBlocksToFile(const char* filename); uint32_t dumpBlocksToFile(const char* filename);
void setThreadName(const char* name); const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line);
unsigned int addSource(const char* _filename, 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 #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/>. along with this program.If not, see <http://www.gnu.org/licenses/>.
**/ **/
#ifndef ________SPIN_LOCK__________H______ #ifndef EASY_PROFILER__SPIN_LOCK__________H______
#define ________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> #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 #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______