mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-28 01:04:41 +08:00
Merge branch 'event_tracing' into develop
This commit is contained in:
commit
2cff79886d
@ -2,8 +2,8 @@ project(profiling_tool)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set(
|
||||
ROOT
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
ROOT
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
set(OUTPUT_DIR
|
||||
@ -23,16 +23,16 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
|
||||
)
|
||||
|
||||
include_directories(
|
||||
include
|
||||
include
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-reorder -pedantic -O3" )
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-reorder -pedantic -O3" )
|
||||
else()
|
||||
add_definitions(
|
||||
-D_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
add_definitions(
|
||||
-D_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
endif(UNIX)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
27
include/profiler/event_trace_status.h
Normal file
27
include/profiler/event_trace_status.h
Normal 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_
|
@ -16,379 +16,338 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef ____PROFILER____H_______
|
||||
#define ____PROFILER____H_______
|
||||
#ifndef EASY_PROFILER____H_______
|
||||
#define EASY_PROFILER____H_______
|
||||
|
||||
#define TOKEN_JOIN(x, y) x ## y
|
||||
#define TOKEN_CONCATENATE(x, y) TOKEN_JOIN(x, y)
|
||||
#ifdef _WIN32
|
||||
# define __func__ __FUNCTION__
|
||||
# if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead.
|
||||
# define EASY_THREAD_LOCAL __declspec(thread)
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
#ifndef __clang__
|
||||
# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4)
|
||||
// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead.
|
||||
# define EASY_THREAD_LOCAL __thread
|
||||
#endif
|
||||
# endif
|
||||
#if defined ( __clang__ )
|
||||
# if (__clang_major__ == 3 && __clang_minor__ < 3) || (__clang_major__ < 3)
|
||||
# define EASY_THREAD_LOCAL __thread
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined ( WIN32 )
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
// TODO: Check thread local support for clanv earlier than 3.3
|
||||
|
||||
#ifndef EASY_THREAD_LOCAL
|
||||
# define EASY_THREAD_LOCAL thread_local
|
||||
# define EASY_THREAD_LOCAL_CPP11
|
||||
#endif
|
||||
|
||||
#if defined ( __clang__ )
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||
#endif
|
||||
|
||||
#ifndef FULL_DISABLE_PROFILER
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#define EASY_TOKEN_JOIN(x, y) x ## y
|
||||
#define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y)
|
||||
#define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x)
|
||||
#define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x)
|
||||
|
||||
/**
|
||||
\defgroup profiler Profiler
|
||||
*/
|
||||
|
||||
/** Macro of beginning of block with custom name and default identification
|
||||
namespace profiler {
|
||||
template <const bool IS_REF> struct NameSwitch final {
|
||||
static const char* runtime_name(const char* name) { return name; }
|
||||
static const char* compiletime_name(const char*) { return ""; }
|
||||
};
|
||||
|
||||
template <> struct NameSwitch<true> final {
|
||||
static const char* runtime_name(const char*) { return ""; }
|
||||
static const char* compiletime_name(const char* name) { return name; }
|
||||
};
|
||||
} // END of namespace profiler.
|
||||
|
||||
#define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::compiletime_name(name)
|
||||
#define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::runtime_name(name)
|
||||
|
||||
|
||||
/** Macro of beginning of block with custom name and color.
|
||||
|
||||
\code
|
||||
#include "profiler/profiler.h"
|
||||
void foo()
|
||||
{
|
||||
// some code ...
|
||||
if(something){
|
||||
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()");
|
||||
someThirdPartyLongFunction();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#include "profiler/profiler.h"
|
||||
void foo()
|
||||
{
|
||||
// some code ...
|
||||
if(something){
|
||||
EASY_BLOCK("Calling bar()"); // Block with default color
|
||||
bar();
|
||||
}
|
||||
else{
|
||||
EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block
|
||||
baz();
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
|
||||
Block will be automatically completed by destructor
|
||||
Block will be automatically completed by destructor.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_BEGIN_BLOCK(name)\
|
||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,profiler::colors::Clay,profiler::BLOCK_TYPE_BLOCK,\
|
||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
#define EASY_BLOCK(name, ...)\
|
||||
static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
|
||||
::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
|
||||
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
|
||||
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
|
||||
|
||||
/** Macro of beginning of block with custom name and custom identification
|
||||
/** Macro of beginning of block with function name and custom color.
|
||||
|
||||
\code
|
||||
#include "profiler/profiler.h"
|
||||
void foo()
|
||||
{
|
||||
// some code ...
|
||||
if(something){
|
||||
PROFILER_BEGIN_BLOCK("Calling someThirdPartyLongFunction()",profiler::colors::Red);
|
||||
someThirdPartyLongFunction();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#include "profiler/profiler.h"
|
||||
void foo(){
|
||||
EASY_FUNCTION(); // Block with name="foo" and default color
|
||||
//some code...
|
||||
}
|
||||
|
||||
void bar(){
|
||||
EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar"
|
||||
//some code...
|
||||
}
|
||||
\endcode
|
||||
|
||||
Block will be automatically completed by destructor
|
||||
Name of the block automatically created with function name.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)\
|
||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_BLOCK,\
|
||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
#define EASY_FUNCTION(...)\
|
||||
static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(__func__, __FILE__, __LINE__,\
|
||||
::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\
|
||||
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), "");\
|
||||
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
|
||||
|
||||
/** Macro of beginning of function block with default identification
|
||||
|
||||
\code
|
||||
#include "profiler/profiler.h"
|
||||
void foo()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK;
|
||||
//some code...
|
||||
}
|
||||
\endcode
|
||||
|
||||
Name of block automatically created with function name
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__)
|
||||
|
||||
/** Macro of beginning of function block with custom identification
|
||||
|
||||
\code
|
||||
#include "profiler/profiler.h"
|
||||
void foo()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
//some code...
|
||||
}
|
||||
\endcode
|
||||
|
||||
Name of block automatically created with function name
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_color) PROFILER_BEGIN_BLOCK_GROUPED(__func__,block_color)
|
||||
|
||||
/** Macro of completion of last nearest open block
|
||||
/** Macro of completion of last nearest open block.
|
||||
|
||||
\code
|
||||
#include "profiler/profiler.h"
|
||||
void foo()
|
||||
int foo()
|
||||
{
|
||||
// some code ...
|
||||
int sum = 0;
|
||||
PROFILER_BEGIN_BLOCK("Calculating summ");
|
||||
for(int i = 0; i < 10; i++){
|
||||
sum += i;
|
||||
}
|
||||
PROFILER_END_BLOCK;
|
||||
// some code ...
|
||||
|
||||
int sum = 0;
|
||||
EASY_BLOCK("Calculating sum");
|
||||
for (int i = 0; i < 10; ++i){
|
||||
sum += i;
|
||||
}
|
||||
EASY_END_BLOCK;
|
||||
|
||||
// some antoher code here ...
|
||||
|
||||
return sum;
|
||||
}
|
||||
\endcode
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_END_BLOCK profiler::endBlock();
|
||||
#define EASY_END_BLOCK ::profiler::endBlock();
|
||||
|
||||
#define PROFILER_ADD_EVENT(name) \
|
||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,0,profiler::BLOCK_TYPE_EVENT,\
|
||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
/** Macro of creating event with custom name and color.
|
||||
|
||||
#define PROFILER_ADD_EVENT_GROUPED(name,block_group)\
|
||||
static const profiler::BlockSourceInfo TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__)(__FILE__, __LINE__);\
|
||||
profiler::Block TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__)(name,block_group,profiler::BLOCK_TYPE_EVENT,\
|
||||
TOKEN_CONCATENATE(unique_profiler_source_name_,__LINE__).id());\
|
||||
profiler::beginBlock(TOKEN_CONCATENATE(unique_profiler_mark_name_,__LINE__));
|
||||
Event is a block with zero duration and special type.
|
||||
|
||||
\warning Event ends immidiately and calling EASY_END_BLOCK after EASY_EVENT
|
||||
will end previously opened EASY_BLOCK or EASY_FUNCTION.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define EASY_EVENT(name, ...)\
|
||||
static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\
|
||||
::profiler::BLOCK_TYPE_EVENT , ## __VA_ARGS__);\
|
||||
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
|
||||
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable
|
||||
|
||||
/** Macro enabling profiler
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_ENABLE profiler::setEnabled(true);
|
||||
#define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
|
||||
|
||||
/** Macro disabling profiler
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define PROFILER_DISABLE profiler::setEnabled(false);
|
||||
#define EASY_PROFILER_DISABLE ::profiler::setEnabled(false);
|
||||
|
||||
#ifdef WIN32
|
||||
#define PROFILER_SET_THREAD_NAME(name) profiler::setThreadName(name);
|
||||
#else
|
||||
#define PROFILER_SET_THREAD_NAME(name) thread_local static const profiler::ThreadNameSetter TOKEN_CONCATENATE(unique_profiler_thread_name_setter_,__LINE__)(name);
|
||||
#endif
|
||||
/** Macro of naming current thread.
|
||||
|
||||
#define PROFILER_SET_MAIN_THREAD PROFILER_SET_THREAD_NAME("Main")
|
||||
If this thread has been already named then nothing changes.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define EASY_THREAD(name)\
|
||||
EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\
|
||||
if (EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) == nullptr)\
|
||||
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::setThreadName(name, __FILE__, __func__, __LINE__);
|
||||
|
||||
/** Macro of naming main thread.
|
||||
|
||||
This is only for user comfort. There is no difference for EasyProfiler GUI between different threads.
|
||||
|
||||
\ingroup profiler
|
||||
*/
|
||||
#define EASY_MAIN_THREAD EASY_THREAD("Main")
|
||||
|
||||
#else
|
||||
#define PROFILER_ADD_MARK(name)
|
||||
#define PROFILER_ADD_MARK_GROUPED(name,block_group)
|
||||
#define PROFILER_BEGIN_BLOCK(name)
|
||||
#define PROFILER_BEGIN_BLOCK_GROUPED(name,block_group)
|
||||
#define PROFILER_BEGIN_FUNCTION_BLOCK PROFILER_BEGIN_BLOCK(__func__)
|
||||
#define PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(block_group) PROFILER_BEGIN_BLOCK_GROUPED(__func__,block_group)
|
||||
#define PROFILER_END_BLOCK profiler::endBlock();
|
||||
#define PROFILER_ENABLE profiler::setEnabled(true);
|
||||
#define PROFILER_DISABLE profiler::setEnabled(false);
|
||||
#define PROFILER_ADD_EVENT(name)
|
||||
#define PROFILER_ADD_EVENT_GROUPED(name,block_group)
|
||||
#define PROFILER_SET_THREAD_NAME(name)
|
||||
#define PROFILER_SET_MAIN_THREAD
|
||||
#define EASY_BLOCK(...)
|
||||
#define EASY_FUNCTION(...)
|
||||
#define EASY_END_BLOCK
|
||||
#define EASY_PROFILER_ENABLE
|
||||
#define EASY_PROFILER_DISABLE
|
||||
#define EASY_EVENT(...)
|
||||
#define EASY_THREAD(...)
|
||||
#define EASY_MAIN_THREAD
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
#include "profiler/profiler_colors.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _BUILD_PROFILER
|
||||
#define PROFILER_API __declspec(dllexport)
|
||||
#ifdef _BUILD_PROFILER
|
||||
#define PROFILER_API __declspec(dllexport)
|
||||
#else
|
||||
#define PROFILER_API __declspec(dllimport)
|
||||
#define PROFILER_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define PROFILER_API
|
||||
#endif
|
||||
|
||||
class ProfileManager;
|
||||
class ThreadStorage;
|
||||
|
||||
namespace profiler
|
||||
{
|
||||
typedef uint8_t color_t; //RRR-GGG-BB
|
||||
namespace profiler {
|
||||
|
||||
namespace colors{
|
||||
class Block;
|
||||
|
||||
const color_t Black = 0x00;
|
||||
const color_t Lightgray = 0x6E;
|
||||
const color_t Darkgray = 0x25;
|
||||
const color_t White = 0xFF;
|
||||
const color_t Red = 0xE0;
|
||||
const color_t Green = 0x1C;
|
||||
const color_t Blue = 0x03;
|
||||
const color_t Magenta = (Red | Blue);
|
||||
const color_t Cyan = (Green | Blue);
|
||||
const color_t Yellow = (Red | Green);
|
||||
const color_t Darkred = 0x60;
|
||||
const color_t Darkgreen = 0x0C;
|
||||
const color_t Darkblue = 0x01;
|
||||
const color_t Darkmagenta = (Darkred | Darkblue);
|
||||
const color_t Darkcyan = (Darkgreen | Darkblue);
|
||||
const color_t Darkyellow = (Darkred | Darkgreen);
|
||||
const color_t Navy = 0x02;
|
||||
const color_t Teal = 0x12;
|
||||
const color_t Maroon = 0x80;
|
||||
const color_t Purple = 0x82;
|
||||
const color_t Olive = 0x90;
|
||||
const color_t Grey = 0x92;
|
||||
const color_t Silver = 0xDB;
|
||||
const color_t Orange = 0xF4;
|
||||
const color_t Coral = 0xF6;
|
||||
const color_t Brick = 0xED;
|
||||
const color_t Clay = 0xD6;
|
||||
const color_t Skin = 0xFA;
|
||||
const color_t Palegold = 0xFE;
|
||||
typedef uint64_t timestamp_t;
|
||||
typedef uint32_t thread_id_t;
|
||||
typedef uint32_t block_id_t;
|
||||
|
||||
inline int get_red(color_t color){
|
||||
return (color >> 5) * 0x20;
|
||||
}
|
||||
inline int get_green(color_t color){
|
||||
return ((color & 0x1C) >> 2) * 0x20;
|
||||
}
|
||||
inline int get_blue(color_t color){
|
||||
return (color & 3) * 0x40;
|
||||
}
|
||||
|
||||
inline int convert_to_rgb(color_t color){
|
||||
return ((get_red(color) & 0xFF) << 16) | ((get_green(color) & 0xFF) << 8) | (get_blue(color) & 0xFF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class Block;
|
||||
class BlockSourceInfo;
|
||||
|
||||
extern "C"{
|
||||
void PROFILER_API beginBlock(Block& _block);
|
||||
void PROFILER_API endBlock();
|
||||
void PROFILER_API setEnabled(bool isEnable);
|
||||
unsigned int PROFILER_API dumpBlocksToFile(const char* filename);
|
||||
void PROFILER_API setThreadName(const char* name);
|
||||
}
|
||||
|
||||
typedef uint8_t block_type_t;
|
||||
typedef uint64_t timestamp_t;
|
||||
typedef uint32_t thread_id_t;
|
||||
typedef uint32_t source_id_t;
|
||||
|
||||
const block_type_t BLOCK_TYPE_EVENT = 1;
|
||||
const block_type_t BLOCK_TYPE_BLOCK = 2;
|
||||
const block_type_t BLOCK_TYPE_THREAD_SIGN = 3;
|
||||
|
||||
#define EASY_USE_OLD_FILE_FORMAT
|
||||
|
||||
#pragma pack(push,1)
|
||||
class PROFILER_API BaseBlockData
|
||||
{
|
||||
protected:
|
||||
|
||||
#ifdef EASY_USE_OLD_FILE_FORMAT
|
||||
block_type_t type;
|
||||
color_t color;
|
||||
timestamp_t begin;
|
||||
timestamp_t end;
|
||||
thread_id_t thread_id;
|
||||
#else
|
||||
timestamp_t begin;
|
||||
timestamp_t end;
|
||||
thread_id_t thread_id;
|
||||
source_id_t source_id;
|
||||
block_type_t type;
|
||||
color_t color;
|
||||
#endif
|
||||
|
||||
void tick(timestamp_t& stamp);
|
||||
public:
|
||||
|
||||
BaseBlockData(source_id_t _source_id, color_t _color, block_type_t _type, thread_id_t _thread_id = 0);
|
||||
|
||||
inline block_type_t getType() const { return type; }
|
||||
inline color_t getColor() const { return color; }
|
||||
inline timestamp_t getBegin() const { return begin; }
|
||||
inline thread_id_t getThreadId() const { return thread_id; }
|
||||
|
||||
#ifdef EASY_USE_OLD_FILE_FORMAT
|
||||
inline source_id_t getSourceId() const { return -1; }
|
||||
#else
|
||||
inline source_id_t getSourceId() const { return source_id; }
|
||||
#endif
|
||||
|
||||
inline timestamp_t getEnd() const { return end; }
|
||||
inline bool isFinished() const { return end != 0; }
|
||||
inline bool isCleared() const { return end >= begin; }
|
||||
inline void finish(){ tick(end); }
|
||||
timestamp_t duration() const { return (end - begin); }
|
||||
|
||||
inline bool startsEarlierThan(const BaseBlockData& another) const {return this->begin < another.begin;}
|
||||
inline bool endsEarlierThan(const BaseBlockData& another) const {return this->end < another.end;}
|
||||
inline bool startsLaterThan(const BaseBlockData& another) const {return !this->startsEarlierThan(another);}
|
||||
inline bool endsLaterThan(const BaseBlockData& another) const {return !this->endsEarlierThan(another);}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class PROFILER_API Block final : public BaseBlockData
|
||||
{
|
||||
const char* m_name;
|
||||
public:
|
||||
|
||||
Block(const char* _name, color_t _color, block_type_t _type, source_id_t _source_id);
|
||||
Block(const char* _name, thread_id_t _thread_id, color_t _color, block_type_t _type, source_id_t _source_id);
|
||||
~Block();
|
||||
|
||||
inline const char* getName() const { return m_name; }
|
||||
};
|
||||
|
||||
class PROFILER_API SourceBlock final
|
||||
enum BlockType : uint8_t
|
||||
{
|
||||
const char* m_filename;
|
||||
int m_line;
|
||||
BLOCK_TYPE_EVENT = 0,
|
||||
BLOCK_TYPE_THREAD_SIGN,
|
||||
BLOCK_TYPE_BLOCK,
|
||||
BLOCK_TYPE_CONTEXT_SWITCH,
|
||||
|
||||
BLOCK_TYPES_NUMBER
|
||||
};
|
||||
typedef BlockType block_type_t;
|
||||
|
||||
extern "C" {
|
||||
PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor);
|
||||
PROFILER_API void beginBlock(Block& _block);
|
||||
PROFILER_API void endBlock();
|
||||
PROFILER_API void setEnabled(bool isEnable);
|
||||
PROFILER_API uint32_t dumpBlocksToFile(const char* filename);
|
||||
PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line);
|
||||
PROFILER_API void setContextSwitchLogFilename(const char* name);
|
||||
PROFILER_API const char* getContextSwitchLogFilename();
|
||||
}
|
||||
|
||||
#pragma pack(push,1)
|
||||
class PROFILER_API BaseBlockDescriptor
|
||||
{
|
||||
protected:
|
||||
|
||||
int m_line; ///< Line number in the source file
|
||||
color_t m_color; ///< Color of the block packed into 1-byte structure
|
||||
block_type_t m_type; ///< Type of the block (See BlockType)
|
||||
|
||||
BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color);
|
||||
|
||||
public:
|
||||
|
||||
SourceBlock(const char* _filename, int _line);
|
||||
|
||||
const char* file() const { return m_filename; }
|
||||
int line() const { return m_line; }
|
||||
inline int line() const { return m_line; }
|
||||
inline block_type_t type() const { return m_type; }
|
||||
inline color_t color() const { return m_color; }
|
||||
};
|
||||
|
||||
class PROFILER_API SerializedBlock final : public BaseBlockData
|
||||
class PROFILER_API BlockDescriptor final : public BaseBlockDescriptor
|
||||
{
|
||||
const char* m_name; ///< Static name of all blocks of the same type (blocks can have dynamic name) which is, in pair with descriptor id, a unique block identifier
|
||||
const char* m_filename; ///< Source file name where this block is declared
|
||||
|
||||
public:
|
||||
|
||||
BlockDescriptor(uint64_t& _used_mem, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color);
|
||||
|
||||
inline const char* name() const { return m_name; }
|
||||
inline const char* file() const { return m_filename; }
|
||||
};
|
||||
|
||||
class PROFILER_API BaseBlockData
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
|
||||
protected:
|
||||
|
||||
timestamp_t m_begin;
|
||||
timestamp_t m_end;
|
||||
block_id_t m_id;
|
||||
|
||||
public:
|
||||
|
||||
///< Deprecated. For backward compatibility.
|
||||
inline const BaseBlockData* block() const { return this; }
|
||||
BaseBlockData(const BaseBlockData&) = default;
|
||||
BaseBlockData(timestamp_t _begin_time, block_id_t _id);
|
||||
|
||||
inline const char* data() const { return reinterpret_cast<const char*>(this); }
|
||||
inline const char* getName() const { return data() + sizeof(BaseBlockData); }
|
||||
inline timestamp_t begin() const { return m_begin; }
|
||||
inline timestamp_t end() const { return m_end; }
|
||||
inline block_id_t id() const { return m_id; }
|
||||
inline timestamp_t duration() const { return m_end - m_begin; }
|
||||
|
||||
inline void setId(block_id_t _id) { m_id = _id; }
|
||||
|
||||
private:
|
||||
|
||||
static SerializedBlock* create(const Block &block, uint64_t& memory_size);
|
||||
static void destroy(SerializedBlock* that);
|
||||
|
||||
SerializedBlock(const profiler::Block& block, uint16_t name_length);
|
||||
|
||||
SerializedBlock(const SerializedBlock&) = delete;
|
||||
SerializedBlock& operator = (const SerializedBlock&) = delete;
|
||||
~SerializedBlock() = delete;
|
||||
BaseBlockData() = delete;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct PROFILER_API ThreadNameSetter final
|
||||
class PROFILER_API Block final : public BaseBlockData
|
||||
{
|
||||
ThreadNameSetter(const char* _name)
|
||||
{
|
||||
setThreadName(_name);
|
||||
}
|
||||
};
|
||||
friend ::ProfileManager;
|
||||
|
||||
class PROFILER_API BlockSourceInfo final
|
||||
{
|
||||
unsigned int m_id;
|
||||
const char* m_name;
|
||||
|
||||
private:
|
||||
|
||||
void finish();
|
||||
void finish(timestamp_t _end_time);
|
||||
inline bool isFinished() const { return m_end >= m_begin; }
|
||||
|
||||
public:
|
||||
|
||||
BlockSourceInfo(const char* _filename, int _linenumber);
|
||||
Block(Block&& that);
|
||||
Block(block_type_t _block_type, block_id_t _id, const char* _name);
|
||||
Block(timestamp_t _begin_time, block_type_t _block_type, block_id_t _id, const char* _name);
|
||||
~Block();
|
||||
|
||||
unsigned int id() const { return m_id; }
|
||||
inline const char* name() const { return m_name; }
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
#if defined ( __clang__ )
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // EASY_PROFILER____H_______
|
||||
|
439
include/profiler/profiler_colors.h
Normal file
439
include/profiler/profiler_colors.h
Normal 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_______
|
@ -25,6 +25,7 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include "profiler/profiler.h"
|
||||
#include "profiler/serialized_block.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -61,46 +62,31 @@ namespace profiler {
|
||||
}; // END of struct BlockStatistics.
|
||||
#pragma pack(pop)
|
||||
|
||||
inline void release(BlockStatistics*& _stats)
|
||||
{
|
||||
if (!_stats)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (--_stats->calls_number == 0)
|
||||
{
|
||||
delete _stats;
|
||||
}
|
||||
|
||||
_stats = nullptr;
|
||||
}
|
||||
extern "C" void PROFILER_API release_stats(BlockStatistics*& _stats);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BlocksTree
|
||||
class BlocksTree final
|
||||
{
|
||||
typedef BlocksTree This;
|
||||
|
||||
public:
|
||||
|
||||
typedef ::std::vector<BlocksTree> children_t;
|
||||
typedef ::std::vector<This> blocks_t;
|
||||
typedef ::std::vector<::profiler::block_index_t> children_t;
|
||||
|
||||
children_t children; ///< List of children blocks. May be empty.
|
||||
::profiler::SerializedBlock* node; ///< Pointer to serilized data (type, name, begin, end etc.)
|
||||
::profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
|
||||
::profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks)
|
||||
::profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread
|
||||
|
||||
::profiler::block_index_t block_index; ///< Index of this block
|
||||
unsigned short depth; ///< Maximum number of sublevels (maximum children depth)
|
||||
uint16_t depth; ///< Maximum number of sublevels (maximum children depth)
|
||||
|
||||
BlocksTree()
|
||||
: node(nullptr)
|
||||
, per_parent_stats(nullptr)
|
||||
, per_frame_stats(nullptr)
|
||||
, per_thread_stats(nullptr)
|
||||
, block_index(0)
|
||||
, depth(0)
|
||||
{
|
||||
|
||||
@ -119,14 +105,9 @@ namespace profiler {
|
||||
|
||||
~BlocksTree()
|
||||
{
|
||||
//if (node)
|
||||
//{
|
||||
// delete node;
|
||||
//}
|
||||
|
||||
release(per_thread_stats);
|
||||
release(per_parent_stats);
|
||||
release(per_frame_stats);
|
||||
release_stats(per_thread_stats);
|
||||
release_stats(per_parent_stats);
|
||||
release_stats(per_frame_stats);
|
||||
}
|
||||
|
||||
bool operator < (const This& other) const
|
||||
@ -135,7 +116,7 @@ namespace profiler {
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return node->block()->getBegin() < other.node->block()->getBegin();
|
||||
return node->begin() < other.node->begin();
|
||||
}
|
||||
|
||||
void shrink_to_fit()
|
||||
@ -160,33 +141,20 @@ namespace profiler {
|
||||
|
||||
void makeMove(This&& that)
|
||||
{
|
||||
//if (node && node != that.node)
|
||||
//{
|
||||
// delete node;
|
||||
//}
|
||||
|
||||
if (per_thread_stats != that.per_thread_stats)
|
||||
{
|
||||
release(per_thread_stats);
|
||||
}
|
||||
release_stats(per_thread_stats);
|
||||
|
||||
if (per_parent_stats != that.per_parent_stats)
|
||||
{
|
||||
release(per_parent_stats);
|
||||
}
|
||||
release_stats(per_parent_stats);
|
||||
|
||||
if (per_frame_stats != that.per_frame_stats)
|
||||
{
|
||||
release(per_frame_stats);
|
||||
}
|
||||
release_stats(per_frame_stats);
|
||||
|
||||
children = ::std::move(that.children);
|
||||
node = that.node;
|
||||
per_parent_stats = that.per_parent_stats;
|
||||
per_frame_stats = that.per_frame_stats;
|
||||
per_thread_stats = that.per_thread_stats;
|
||||
|
||||
block_index = that.block_index;
|
||||
depth = that.depth;
|
||||
|
||||
that.node = nullptr;
|
||||
@ -199,35 +167,53 @@ namespace profiler {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define EASY_STORE_CSWITCH_SEPARATELY
|
||||
//#undef EASY_STORE_CSWITCH_SEPARATELY
|
||||
|
||||
class BlocksTreeRoot final
|
||||
{
|
||||
typedef BlocksTreeRoot This;
|
||||
|
||||
public:
|
||||
|
||||
BlocksTree tree;
|
||||
BlocksTree::children_t children;
|
||||
#ifdef EASY_STORE_CSWITCH_SEPARATELY
|
||||
BlocksTree::children_t sync;
|
||||
#endif
|
||||
const char* thread_name;
|
||||
::profiler::thread_id_t thread_id;
|
||||
uint16_t depth;
|
||||
|
||||
BlocksTreeRoot() : thread_name(""), thread_id(0)
|
||||
BlocksTreeRoot() : thread_name(""), thread_id(0), depth(0)
|
||||
{
|
||||
}
|
||||
|
||||
BlocksTreeRoot(This&& that) : tree(::std::move(that.tree)), thread_name(that.thread_name), thread_id(that.thread_id)
|
||||
BlocksTreeRoot(This&& that)
|
||||
: children(::std::move(that.children))
|
||||
#ifdef EASY_STORE_CSWITCH_SEPARATELY
|
||||
, sync(::std::move(that.sync))
|
||||
#endif
|
||||
, thread_name(that.thread_name)
|
||||
, thread_id(that.thread_id)
|
||||
, depth(that.depth)
|
||||
{
|
||||
}
|
||||
|
||||
This& operator = (This&& that)
|
||||
{
|
||||
tree = ::std::move(that.tree);
|
||||
children = ::std::move(that.children);
|
||||
#ifdef EASY_STORE_CSWITCH_SEPARATELY
|
||||
sync = ::std::move(that.sync);
|
||||
#endif
|
||||
thread_name = that.thread_name;
|
||||
thread_id = that.thread_id;
|
||||
depth = that.depth;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator < (const This& other) const
|
||||
{
|
||||
return tree < other.tree;
|
||||
return thread_id < other.thread_id;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -237,11 +223,12 @@ namespace profiler {
|
||||
|
||||
}; // END of class BlocksTreeRoot.
|
||||
|
||||
typedef ::profiler::BlocksTree::blocks_t blocks_t;
|
||||
typedef ::std::map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot> thread_blocks_tree_t;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SerializedData final
|
||||
class PROFILER_API SerializedData final
|
||||
{
|
||||
char* m_data;
|
||||
|
||||
@ -261,10 +248,11 @@ namespace profiler {
|
||||
clear();
|
||||
}
|
||||
|
||||
void set(char* _data);
|
||||
|
||||
SerializedData& operator = (SerializedData&& that)
|
||||
{
|
||||
clear();
|
||||
m_data = that.m_data;
|
||||
set(that.m_data);
|
||||
that.m_data = nullptr;
|
||||
return *this;
|
||||
}
|
||||
@ -276,17 +264,7 @@ namespace profiler {
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
delete[] m_data;
|
||||
m_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void set(char* _data)
|
||||
{
|
||||
clear();
|
||||
m_data = _data;
|
||||
set(nullptr);
|
||||
}
|
||||
|
||||
void swap(SerializedData& other)
|
||||
@ -305,15 +283,25 @@ namespace profiler {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef ::std::vector<SerializedBlockDescriptor*> descriptors_list_t;
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
extern "C"{
|
||||
unsigned int PROFILER_API fillTreesFromFile(::std::atomic<int>& progress, const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false);
|
||||
}
|
||||
extern "C" ::profiler::block_index_t PROFILER_API fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
|
||||
::profiler::SerializedData& serialized_blocks,
|
||||
::profiler::SerializedData& serialized_descriptors,
|
||||
::profiler::descriptors_list_t& descriptors,
|
||||
::profiler::blocks_t& _blocks,
|
||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
||||
bool gather_statistics = false);
|
||||
|
||||
inline unsigned int fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics = false) {
|
||||
inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks,
|
||||
::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors,
|
||||
::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& threaded_trees,
|
||||
bool gather_statistics = false)
|
||||
{
|
||||
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||
return fillTreesFromFile(progress, filename, serialized_blocks, threaded_trees, gather_statistics);
|
||||
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, gather_statistics);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
83
include/profiler/serialized_block.h
Normal file
83
include/profiler/serialized_block.h
Normal 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_______
|
@ -2,7 +2,6 @@
|
||||
* file name : blocks_graphics_view.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/06/26
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -22,7 +21,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#include <QGraphicsScene>
|
||||
@ -54,8 +67,8 @@ enum BlockItemState
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const qreal MIN_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 70);
|
||||
const qreal MAX_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT, 30); // ~800
|
||||
const qreal MIN_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 70); // Up to 1000 sec scale
|
||||
const qreal MAX_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT, 45); // ~23000 --- Up to 10 ns scale
|
||||
const qreal BASE_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 25); // ~0.003
|
||||
|
||||
const unsigned short GRAPHICS_ROW_SIZE = 18;
|
||||
@ -71,11 +84,11 @@ const QRgb TIMELINE_BACKGROUND = 0x20303030;
|
||||
const QRgb SELECTED_ITEM_COLOR = 0x000050a0;
|
||||
const QColor CHRONOMETER_COLOR2 = QColor::fromRgba(0x40408040);
|
||||
|
||||
const unsigned int TEST_PROGRESSION_BASE = 4;
|
||||
//const unsigned int TEST_PROGRESSION_BASE = 4;
|
||||
|
||||
const int FLICKER_INTERVAL = 16; // 60Hz
|
||||
|
||||
const auto CHRONOMETER_FONT = QFont("CourierNew", 16, 2);
|
||||
const auto CHRONOMETER_FONT = QFont("CourierNew", 18, 2);
|
||||
const auto ITEMS_FONT = QFont("CourierNew", 10);// , 2);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -95,7 +108,7 @@ inline T logn(T _value)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EasyGraphicsItem::EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root)
|
||||
EasyGraphicsItem::EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot* _root)
|
||||
: QGraphicsItem(nullptr)
|
||||
, m_pRoot(_root)
|
||||
, m_index(_index)
|
||||
@ -139,7 +152,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
|
||||
QRectF rect;
|
||||
QBrush brush;
|
||||
QRgb previousColor = 0, inverseColor = 0x00ffffff;
|
||||
QRgb previousColor = 0, inverseColor = 0xffffffff, textColor = 0;
|
||||
Qt::PenStyle previousPenStyle = Qt::NoPen;
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
|
||||
@ -148,12 +161,12 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
|
||||
// Reset indices of first visible item for each layer
|
||||
const auto levelsNumber = levels();
|
||||
for (unsigned char i = 1; i < levelsNumber; ++i) ::profiler_gui::set_max(m_levelsIndexes[i]);
|
||||
for (uint8_t i = 1; i < levelsNumber; ++i) ::profiler_gui::set_max(m_levelsIndexes[i]);
|
||||
|
||||
|
||||
// Search for first visible top-level item
|
||||
auto& level0 = m_levels.front();
|
||||
auto first = ::std::lower_bound(level0.begin(), level0.end(), sceneLeft, [](const ::profiler_gui::ProfBlockItem& _item, qreal _value)
|
||||
auto first = ::std::lower_bound(level0.begin(), level0.end(), sceneLeft, [](const ::profiler_gui::EasyBlockItem& _item, qreal _value)
|
||||
{
|
||||
return _item.left() < _value;
|
||||
});
|
||||
@ -170,20 +183,40 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
}
|
||||
|
||||
|
||||
#ifdef EASY_STORE_CSWITCH_SEPARATELY
|
||||
auto firstSync = ::std::lower_bound(m_pRoot->sync.begin(), m_pRoot->sync.end(), sceneLeft, [&sceneView](::profiler::block_index_t _index, qreal _value)
|
||||
{
|
||||
return sceneView->time2position(easyBlock(_index).tree.node->begin()) < _value;
|
||||
});
|
||||
|
||||
if (firstSync != m_pRoot->sync.end())
|
||||
{
|
||||
if (firstSync != m_pRoot->sync.begin())
|
||||
--firstSync;
|
||||
}
|
||||
else if (!m_pRoot->sync.empty())
|
||||
{
|
||||
firstSync = m_pRoot->sync.begin() + m_pRoot->sync.size() - 1;
|
||||
}
|
||||
firstSync = m_pRoot->sync.begin();
|
||||
#endif
|
||||
|
||||
|
||||
// This is to make _painter->drawText() work properly
|
||||
// (it seems there is a bug in Qt5.6 when drawText called for big coordinates,
|
||||
// drawRect at the same time called for actually same coordinates
|
||||
// works fine without using this additional shifting)
|
||||
auto dx = level0[m_levelsIndexes[0]].left() * currentScale;
|
||||
//const auto dx = level0[m_levelsIndexes[0]].left() * currentScale;
|
||||
const auto dx = offset * currentScale;
|
||||
|
||||
|
||||
|
||||
// Shifting coordinates to current screen offset
|
||||
_painter->setTransform(QTransform::fromTranslate(dx - offset * currentScale, -y()), true);
|
||||
//_painter->setTransform(QTransform::fromTranslate(dx - offset * currentScale, -y()), true);
|
||||
_painter->setTransform(QTransform::fromTranslate(0, -y()), true);
|
||||
|
||||
|
||||
if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders)
|
||||
if (EASY_GLOBALS.draw_graphics_items_borders)
|
||||
{
|
||||
previousPenStyle = Qt::SolidLine;
|
||||
_painter->setPen(BORDERS_COLOR);
|
||||
@ -194,8 +227,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
}
|
||||
|
||||
|
||||
static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max<decltype(::profiler_gui::ProfBlockItem::children_begin)>();
|
||||
auto const skip_children = [this, &levelsNumber](short next_level, decltype(::profiler_gui::ProfBlockItem::children_begin) children_begin)
|
||||
static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max<decltype(::profiler_gui::EasyBlockItem::children_begin)>();
|
||||
auto const skip_children = [this, &levelsNumber](short next_level, decltype(::profiler_gui::EasyBlockItem::children_begin) children_begin)
|
||||
{
|
||||
// Mark that we would not paint children of current item
|
||||
if (next_level < levelsNumber && children_begin != MAX_CHILD_INDEX)
|
||||
@ -206,7 +239,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
// Iterate through layers and draw visible items
|
||||
bool selectedItemsWasPainted = false;
|
||||
const auto visibleBottom = visibleSceneRect.bottom() - 1;
|
||||
for (unsigned char l = 0; l < levelsNumber; ++l)
|
||||
for (uint8_t l = 0; l < levelsNumber; ++l)
|
||||
{
|
||||
auto& level = m_levels[l];
|
||||
const short next_level = l + 1;
|
||||
@ -243,8 +276,9 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& itemBlock = easyBlock(item.block);
|
||||
int h = 0, flags = 0;
|
||||
if (w < 20 || !::profiler_gui::EASY_GLOBALS.gui_blocks[item.block->block_index].expanded)
|
||||
if (w < 20 || !itemBlock.expanded)
|
||||
{
|
||||
// Items which width is less than 20 will be painted as big rectangles which are hiding it's children
|
||||
|
||||
@ -255,7 +289,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
h -= dh;
|
||||
|
||||
bool changepen = false;
|
||||
if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block)
|
||||
if (item.block == EASY_GLOBALS.selected_block)
|
||||
{
|
||||
selectedItemsWasPainted = true;
|
||||
changepen = true;
|
||||
@ -265,7 +299,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
_painter->setPen(pen);
|
||||
|
||||
previousColor = SELECTED_ITEM_COLOR;
|
||||
inverseColor = 0x00ffffff - previousColor;
|
||||
inverseColor = 0xffffffff - previousColor;
|
||||
textColor = ::profiler_gui::textColorForRgb(previousColor);
|
||||
brush.setColor(previousColor);
|
||||
_painter->setBrush(brush);
|
||||
}
|
||||
@ -276,12 +311,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
{
|
||||
// Set background color brush for rectangle
|
||||
previousColor = item.color;
|
||||
inverseColor = 0x00ffffff - previousColor;
|
||||
inverseColor = 0xffffffff - previousColor;
|
||||
textColor = ::profiler_gui::textColorForRgb(previousColor);
|
||||
brush.setColor(previousColor);
|
||||
_painter->setBrush(brush);
|
||||
}
|
||||
|
||||
if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders)
|
||||
if (EASY_GLOBALS.draw_graphics_items_borders)
|
||||
{
|
||||
//if (w < 2)
|
||||
//{
|
||||
@ -349,7 +385,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
m_levels[next_level][item.children_begin].state = BLOCK_ITEM_DO_PAINT;
|
||||
}
|
||||
|
||||
if (item.block->block_index == ::profiler_gui::EASY_GLOBALS.selected_block)
|
||||
if (item.block == EASY_GLOBALS.selected_block)
|
||||
{
|
||||
selectedItemsWasPainted = true;
|
||||
QPen pen(Qt::SolidLine);
|
||||
@ -358,7 +394,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
_painter->setPen(pen);
|
||||
|
||||
previousColor = SELECTED_ITEM_COLOR;
|
||||
inverseColor = 0x00ffffff - previousColor;
|
||||
inverseColor = 0xffffffff - previousColor;
|
||||
textColor = ::profiler_gui::textColorForRgb(previousColor);
|
||||
brush.setColor(previousColor);
|
||||
_painter->setBrush(brush);
|
||||
}
|
||||
@ -369,12 +406,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
{
|
||||
// Set background color brush for rectangle
|
||||
previousColor = item.color;
|
||||
inverseColor = 0x00ffffff - previousColor;
|
||||
inverseColor = 0xffffffff - previousColor;
|
||||
textColor = ::profiler_gui::textColorForRgb(previousColor);
|
||||
brush.setColor(previousColor);
|
||||
_painter->setBrush(brush);
|
||||
}
|
||||
|
||||
if (::profiler_gui::EASY_GLOBALS.draw_graphics_items_borders && (previousPenStyle != Qt::SolidLine || colorChange))
|
||||
if (EASY_GLOBALS.draw_graphics_items_borders && (previousPenStyle != Qt::SolidLine || colorChange))
|
||||
{
|
||||
// Restore pen for item which is wide enough to paint borders
|
||||
previousPenStyle = Qt::SolidLine;
|
||||
@ -417,12 +455,13 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
rect.setRect(xtext + 1, top, w - 1, h);
|
||||
|
||||
// text will be painted with inverse color
|
||||
auto textColor = inverseColor;
|
||||
if (textColor == previousColor) textColor = 0;
|
||||
_painter->setPen(textColor);
|
||||
//auto textColor = inverseColor < 0x00808080 ? profiler::colors::Black : profiler::colors::White;
|
||||
//if (textColor == previousColor) textColor = 0;
|
||||
_painter->setPen(QColor::fromRgb(textColor));
|
||||
|
||||
// drawing text
|
||||
_painter->drawText(rect, flags, ::profiler_gui::toUnicode(item.block->node->getName()));
|
||||
auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name();
|
||||
_painter->drawText(rect, flags, ::profiler_gui::toUnicode(name));
|
||||
|
||||
// restore previous pen color
|
||||
if (previousPenStyle == Qt::NoPen)
|
||||
@ -433,61 +472,122 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedItemsWasPainted && ::profiler_gui::EASY_GLOBALS.selected_block < ::profiler_gui::EASY_GLOBALS.gui_blocks.size())
|
||||
if (!selectedItemsWasPainted && EASY_GLOBALS.selected_block < EASY_GLOBALS.gui_blocks.size())
|
||||
{
|
||||
const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[::profiler_gui::EASY_GLOBALS.selected_block];
|
||||
const auto& guiblock = EASY_GLOBALS.gui_blocks[EASY_GLOBALS.selected_block];
|
||||
if (guiblock.graphics_item == m_index)
|
||||
{
|
||||
const auto& item = m_levels[guiblock.graphics_item_level][guiblock.graphics_item_index];
|
||||
if (item.left() < sceneRight && item.right() > sceneLeft)
|
||||
{
|
||||
QPen pen(Qt::SolidLine);
|
||||
pen.setColor(Qt::red);
|
||||
pen.setWidth(2);
|
||||
_painter->setPen(pen);
|
||||
|
||||
brush.setColor(SELECTED_ITEM_COLOR);
|
||||
_painter->setBrush(brush);
|
||||
|
||||
auto top = levelY(guiblock.graphics_item_level);
|
||||
auto x = item.left() * currentScale - dx;
|
||||
auto w = ::std::max(item.width() * currentScale, 1.0);
|
||||
rect.setRect(x, top, w, item.totalHeight);
|
||||
_painter->drawRect(rect);
|
||||
decltype(top) h = item.totalHeight;
|
||||
|
||||
if (w > 20)
|
||||
auto dh = top + h - visibleBottom;
|
||||
if (dh < h)
|
||||
{
|
||||
// Draw text-----------------------------------
|
||||
// calculating text coordinates
|
||||
auto xtext = x;
|
||||
if (item.left() < sceneLeft)
|
||||
if (dh > 0)
|
||||
h -= dh;
|
||||
|
||||
QPen pen(Qt::SolidLine);
|
||||
pen.setColor(Qt::red);
|
||||
pen.setWidth(2);
|
||||
_painter->setPen(pen);
|
||||
|
||||
brush.setColor(SELECTED_ITEM_COLOR);
|
||||
_painter->setBrush(brush);
|
||||
|
||||
auto x = item.left() * currentScale - dx;
|
||||
auto w = ::std::max(item.width() * currentScale, 1.0);
|
||||
rect.setRect(x, top, w, h);
|
||||
_painter->drawRect(rect);
|
||||
|
||||
if (w > 20)
|
||||
{
|
||||
// if item left border is out of screen then attach text to the left border of the screen
|
||||
// to ensure text is always visible for items presenting on the screen.
|
||||
w += (item.left() - sceneLeft) * currentScale;
|
||||
xtext = sceneLeft * currentScale - dx;
|
||||
// Draw text-----------------------------------
|
||||
// calculating text coordinates
|
||||
auto xtext = x;
|
||||
if (item.left() < sceneLeft)
|
||||
{
|
||||
// if item left border is out of screen then attach text to the left border of the screen
|
||||
// to ensure text is always visible for items presenting on the screen.
|
||||
w += (item.left() - sceneLeft) * currentScale;
|
||||
xtext = sceneLeft * currentScale - dx;
|
||||
}
|
||||
|
||||
if (item.right() > sceneRight)
|
||||
{
|
||||
w -= (item.right() - sceneRight) * currentScale;
|
||||
}
|
||||
|
||||
rect.setRect(xtext + 1, top, w - 1, h);
|
||||
|
||||
// text will be painted with inverse color
|
||||
//auto textColor = 0x00ffffff - previousColor;
|
||||
//if (textColor == previousColor) textColor = 0;
|
||||
textColor = ::profiler_gui::textColorForRgb(SELECTED_ITEM_COLOR);
|
||||
_painter->setPen(textColor);
|
||||
|
||||
// drawing text
|
||||
const auto& itemBlock = easyBlock(item.block);
|
||||
auto name = *itemBlock.tree.node->name() != 0 ? itemBlock.tree.node->name() : easyDescriptor(itemBlock.tree.node->id()).name();
|
||||
_painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(name));
|
||||
// END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
}
|
||||
|
||||
if (item.right() > sceneRight)
|
||||
{
|
||||
w -= (item.right() - sceneRight) * currentScale;
|
||||
}
|
||||
|
||||
rect.setRect(xtext + 1, top, w - 1, item.totalHeight);
|
||||
|
||||
// text will be painted with inverse color
|
||||
auto textColor = 0x00ffffff - previousColor;
|
||||
if (textColor == previousColor) textColor = 0;
|
||||
_painter->setPen(textColor);
|
||||
|
||||
// drawing text
|
||||
_painter->drawText(rect, Qt::AlignCenter, ::profiler_gui::toUnicode(item.block->node->getName()));
|
||||
// END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef EASY_STORE_CSWITCH_SEPARATELY
|
||||
if (!m_pRoot->sync.empty())
|
||||
{
|
||||
_painter->setBrush(QColor::fromRgba(0xfffe6030));
|
||||
_painter->setPen(QColor::fromRgb(0x00505050));
|
||||
|
||||
qreal prevRight = -1e100, top = y() - 4, h = 3;
|
||||
if (top + h < visibleBottom)
|
||||
{
|
||||
for (auto it = firstSync, end = m_pRoot->sync.end(); it != end; ++it)
|
||||
{
|
||||
const auto& item = easyBlock(*it).tree;
|
||||
auto begin = sceneView->time2position(item.node->begin());
|
||||
|
||||
if (begin > sceneRight)
|
||||
break; // This is first totally invisible item. No need to check other items.
|
||||
|
||||
decltype(begin) width = sceneView->time2position(item.node->end()) - begin;
|
||||
auto r = begin + width;
|
||||
if (r < sceneLeft) // This item is not visible
|
||||
continue;
|
||||
|
||||
begin *= currentScale;
|
||||
begin -= dx;
|
||||
width *= currentScale;
|
||||
r = begin + width;
|
||||
if (r <= prevRight) // This item is not visible
|
||||
continue;
|
||||
|
||||
if (begin < prevRight)
|
||||
{
|
||||
width -= prevRight - begin;
|
||||
begin = prevRight;
|
||||
}
|
||||
|
||||
if (width < 2)
|
||||
width = 2;
|
||||
|
||||
//_painter->drawLine(QLineF(::std::max(begin, prevRight), top, begin + width, top));
|
||||
rect.setRect(begin, top, width, h);
|
||||
_painter->drawRect(rect);
|
||||
prevRight = begin + width;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
_painter->restore();
|
||||
}
|
||||
|
||||
@ -509,7 +609,7 @@ void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree
|
||||
|
||||
// Search for first visible top-level item
|
||||
auto& level0 = m_levels.front();
|
||||
auto first = ::std::lower_bound(level0.begin(), level0.end(), _left, [](const ::profiler_gui::ProfBlockItem& _item, qreal _value)
|
||||
auto first = ::std::lower_bound(level0.begin(), level0.end(), _left, [](const ::profiler_gui::EasyBlockItem& _item, qreal _value)
|
||||
{
|
||||
return _item.left() < _value;
|
||||
});
|
||||
@ -550,7 +650,7 @@ void EasyGraphicsItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tree
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF& _pos) const
|
||||
const ::profiler_gui::EasyBlockItem* EasyGraphicsItem::intersect(const QPointF& _pos) const
|
||||
{
|
||||
if (m_levels.empty() || m_levels.front().empty())
|
||||
{
|
||||
@ -586,7 +686,7 @@ const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF&
|
||||
const auto& level = m_levels[i];
|
||||
|
||||
// Search for first visible item
|
||||
auto first = ::std::lower_bound(level.begin() + firstItem, level.begin() + lastItem, _pos.x(), [](const ::profiler_gui::ProfBlockItem& _item, qreal _value)
|
||||
auto first = ::std::lower_bound(level.begin() + firstItem, level.begin() + lastItem, _pos.x(), [](const ::profiler_gui::EasyBlockItem& _item, qreal _value)
|
||||
{
|
||||
return _item.left() < _value;
|
||||
});
|
||||
@ -618,7 +718,7 @@ const ::profiler_gui::ProfBlockItem* EasyGraphicsItem::intersect(const QPointF&
|
||||
}
|
||||
|
||||
const auto w = item.width() * currentScale;
|
||||
if (i == levelIndex || w < 20 || !::profiler_gui::EASY_GLOBALS.gui_blocks[item.block->block_index].expanded)
|
||||
if (i == levelIndex || w < 20 || !easyBlock(item.block).expanded)
|
||||
{
|
||||
return &item;
|
||||
}
|
||||
@ -692,17 +792,17 @@ void EasyGraphicsItem::setBoundingRect(const QRectF& _rect)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned char EasyGraphicsItem::levels() const
|
||||
uint8_t EasyGraphicsItem::levels() const
|
||||
{
|
||||
return static_cast<unsigned char>(m_levels.size());
|
||||
return static_cast<uint8_t>(m_levels.size());
|
||||
}
|
||||
|
||||
float EasyGraphicsItem::levelY(unsigned char _level) const
|
||||
float EasyGraphicsItem::levelY(uint8_t _level) const
|
||||
{
|
||||
return y() + static_cast<int>(_level) * static_cast<int>(GRAPHICS_ROW_SIZE_FULL);
|
||||
}
|
||||
|
||||
void EasyGraphicsItem::setLevels(unsigned char _levels)
|
||||
void EasyGraphicsItem::setLevels(uint8_t _levels)
|
||||
{
|
||||
typedef decltype(m_levelsIndexes) IndexesT;
|
||||
static const auto MAX_CHILD_INDEX = ::profiler_gui::numeric_max<IndexesT::value_type>();
|
||||
@ -711,29 +811,29 @@ void EasyGraphicsItem::setLevels(unsigned char _levels)
|
||||
m_levelsIndexes.resize(_levels, MAX_CHILD_INDEX);
|
||||
}
|
||||
|
||||
void EasyGraphicsItem::reserve(unsigned char _level, unsigned int _items)
|
||||
void EasyGraphicsItem::reserve(uint8_t _level, unsigned int _items)
|
||||
{
|
||||
m_levels[_level].reserve(_items);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const EasyGraphicsItem::Children& EasyGraphicsItem::items(unsigned char _level) const
|
||||
const EasyGraphicsItem::Children& EasyGraphicsItem::items(uint8_t _level) const
|
||||
{
|
||||
return m_levels[_level];
|
||||
}
|
||||
|
||||
const ::profiler_gui::ProfBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index) const
|
||||
const ::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(uint8_t _level, unsigned int _index) const
|
||||
{
|
||||
return m_levels[_level][_index];
|
||||
}
|
||||
|
||||
::profiler_gui::ProfBlockItem& EasyGraphicsItem::getItem(unsigned char _level, unsigned int _index)
|
||||
::profiler_gui::EasyBlockItem& EasyGraphicsItem::getItem(uint8_t _level, unsigned int _index)
|
||||
{
|
||||
return m_levels[_level][_index];
|
||||
}
|
||||
|
||||
unsigned int EasyGraphicsItem::addItem(unsigned char _level)
|
||||
unsigned int EasyGraphicsItem::addItem(uint8_t _level)
|
||||
{
|
||||
m_levels[_level].emplace_back();
|
||||
return static_cast<unsigned int>(m_levels[_level].size() - 1);
|
||||
@ -829,12 +929,18 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
|
||||
// instead of scrollbar we're using manual offset
|
||||
_painter->setTransform(QTransform::fromTranslate(-x(), -y()), true);
|
||||
|
||||
if (m_left < sceneLeft)
|
||||
rect.setLeft(0);
|
||||
|
||||
if (m_right > sceneRight)
|
||||
rect.setWidth((sceneRight - offset) * currentScale - rect.left());
|
||||
|
||||
// draw transparent rectangle
|
||||
auto vcenter = rect.top() + rect.height() * 0.5;
|
||||
QLinearGradient g(rect.left(), vcenter, rect.right(), vcenter);
|
||||
g.setColorAt(0, m_color);
|
||||
g.setColorAt(0.15, QColor::fromRgba(0x14000000 | rgb));
|
||||
g.setColorAt(0.85, QColor::fromRgba(0x14000000 | rgb));
|
||||
g.setColorAt(0.25, QColor::fromRgba(0x20000000 | rgb));
|
||||
g.setColorAt(0.75, QColor::fromRgba(0x20000000 | rgb));
|
||||
g.setColorAt(1, m_color);
|
||||
_painter->setBrush(g);
|
||||
_painter->setPen(Qt::NoPen);
|
||||
@ -850,21 +956,12 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
|
||||
|
||||
// draw text
|
||||
_painter->setCompositionMode(QPainter::CompositionMode_Difference); // This lets the text to be visible on every background
|
||||
_painter->setPen(0xffffffff - rgb);
|
||||
_painter->setRenderHint(QPainter::TextAntialiasing);
|
||||
_painter->setPen(0x00ffffff - rgb);
|
||||
_painter->setFont(CHRONOMETER_FONT);
|
||||
|
||||
if (m_left < sceneLeft)
|
||||
{
|
||||
rect.setLeft(0);
|
||||
}
|
||||
|
||||
if (m_right > sceneRight)
|
||||
{
|
||||
rect.setWidth((sceneRight - offset) * currentScale - rect.left());
|
||||
}
|
||||
|
||||
int textFlags = 0;
|
||||
switch (::profiler_gui::EASY_GLOBALS.chrono_text_position)
|
||||
switch (EASY_GLOBALS.chrono_text_position)
|
||||
{
|
||||
case ::profiler_gui::ChronoTextPosition_Top:
|
||||
textFlags = Qt::AlignTop | Qt::AlignHCenter;
|
||||
@ -890,14 +987,15 @@ void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_right + textRect.width() < sceneRight)
|
||||
const auto w = textRect.width() / currentScale;
|
||||
if (m_right + w < sceneRight)
|
||||
{
|
||||
// Text will be drawed to the right of rectangle
|
||||
rect.translate(rect.width(), 0);
|
||||
textFlags &= ~Qt::AlignHCenter;
|
||||
textFlags |= Qt::AlignLeft;
|
||||
}
|
||||
else if (m_left - textRect.width() > sceneLeft)
|
||||
else if (m_left - w > sceneLeft)
|
||||
{
|
||||
// Text will be drawed to the left of rectangle
|
||||
rect.translate(-rect.width(), 0);
|
||||
@ -1002,7 +1100,7 @@ void EasyBackgroundItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte
|
||||
if (top > h || bottom < 0)
|
||||
continue;
|
||||
|
||||
if (item->threadId() == ::profiler_gui::EASY_GLOBALS.selected_thread)
|
||||
if (item->threadId() == EASY_GLOBALS.selected_thread)
|
||||
_painter->setBrush(QBrush(QColor::fromRgb(::profiler_gui::SELECTED_THREAD_BACKGROUND)));
|
||||
else
|
||||
_painter->setBrush(brushes[i & 1]);
|
||||
@ -1092,13 +1190,10 @@ void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap
|
||||
// Draw scale indicator
|
||||
_painter->save();
|
||||
_painter->setTransform(QTransform::fromTranslate(-x(), -y()));
|
||||
_painter->setCompositionMode(QPainter::CompositionMode_Difference);
|
||||
//_painter->setCompositionMode(QPainter::CompositionMode_Difference);
|
||||
_painter->setBrush(Qt::NoBrush);
|
||||
|
||||
//_painter->setBrush(Qt::white);
|
||||
//_painter->setPen(Qt::NoPen);
|
||||
|
||||
QPen pen(Qt::white);
|
||||
QPen pen(Qt::black);
|
||||
pen.setWidth(2);
|
||||
pen.setJoinStyle(Qt::MiterJoin);
|
||||
_painter->setPen(pen);
|
||||
@ -1107,7 +1202,6 @@ void EasyTimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGrap
|
||||
const auto rect_right = rect.right();
|
||||
const QPointF points[] = {{rect.left(), rect.bottom()}, {rect.left(), rect.top()}, {rect_right, rect.top()}, {rect_right, rect.top() + 5}};
|
||||
_painter->drawPolyline(points, sizeof(points) / sizeof(QPointF));
|
||||
//_painter->drawRect(rect);
|
||||
|
||||
rect.translate(0, 3);
|
||||
_painter->drawText(rect, Qt::AlignRight | Qt::TextDontClip, text);
|
||||
@ -1193,7 +1287,7 @@ EasyChronometerItem* EasyGraphicsView::createChronometer(bool _main)
|
||||
}
|
||||
}
|
||||
|
||||
void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, unsigned char _rows)
|
||||
void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_items_number_estimate, uint8_t _rows)
|
||||
{
|
||||
static const qreal X_BEGIN = 50;
|
||||
static const qreal Y_BEGIN = 0;
|
||||
@ -1201,9 +1295,9 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
|
||||
clearSilent(); // Clear scene
|
||||
|
||||
// Calculate items number for first level
|
||||
_rows = ::std::max((unsigned char)1, _rows);
|
||||
_rows = ::std::max((uint8_t)1, _rows);
|
||||
const auto children_per_frame = static_cast<unsigned int>(0.5 + static_cast<double>(_total_items_number_estimate) / static_cast<double>(_rows * _frames_number));
|
||||
const unsigned char max_depth = ::std::min(254, static_cast<int>(logn<TEST_PROGRESSION_BASE>(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1)));
|
||||
const uint8_t max_depth = ::std::min(254, static_cast<int>(logn<TEST_PROGRESSION_BASE>(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1)));
|
||||
const auto first_level_children_count = static_cast<unsigned int>(static_cast<double>(children_per_frame) * (1.0 - TEST_PROGRESSION_BASE) / (1.0 - pow(TEST_PROGRESSION_BASE, max_depth)) + 0.5);
|
||||
|
||||
|
||||
@ -1212,7 +1306,7 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
|
||||
|
||||
|
||||
::std::vector<EasyGraphicsItem*> thread_items(_rows);
|
||||
for (unsigned char i = 0; i < _rows; ++i)
|
||||
for (uint8_t i = 0; i < _rows; ++i)
|
||||
{
|
||||
auto item = new EasyGraphicsItem(i, true);
|
||||
thread_items[i] = item;
|
||||
@ -1225,9 +1319,9 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
|
||||
|
||||
// Calculate items number for each sublevel
|
||||
auto chldrn = first_level_children_count;
|
||||
for (unsigned char i = 1; i <= max_depth; ++i)
|
||||
for (uint8_t i = 1; i <= max_depth; ++i)
|
||||
{
|
||||
for (unsigned char j = 0; j < _rows; ++j)
|
||||
for (uint8_t j = 0; j < _rows; ++j)
|
||||
{
|
||||
auto item = thread_items[j];
|
||||
item->reserve(i, chldrn * _frames_number);
|
||||
@ -1240,7 +1334,7 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
|
||||
unsigned int total_items = 0;
|
||||
qreal maxX = 0;
|
||||
const EasyGraphicsItem* longestItem = nullptr;
|
||||
for (unsigned char i = 0; i < _rows; ++i)
|
||||
for (uint8_t i = 0; i < _rows; ++i)
|
||||
{
|
||||
auto item = thread_items[i];
|
||||
qreal x = X_BEGIN, y = item->y();
|
||||
@ -1292,8 +1386,8 @@ void EasyGraphicsView::test(unsigned int _frames_number, unsigned int _total_ite
|
||||
if (longestItem != nullptr)
|
||||
{
|
||||
m_pScrollbar->setMinimapFrom(0, longestItem->items(0));
|
||||
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
|
||||
emit::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0);
|
||||
EASY_GLOBALS.selected_thread = 0;
|
||||
emitEASY_GLOBALS.events.selectedThreadChanged(0);
|
||||
}
|
||||
|
||||
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()).
|
||||
@ -1360,13 +1454,20 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
|
||||
|
||||
// Calculating start and end time
|
||||
::profiler::timestamp_t finish = 0;
|
||||
const ::profiler::BlocksTree* longestTree = nullptr;
|
||||
::profiler::thread_id_t longestTree = 0;
|
||||
const EasyGraphicsItem* longestItem = nullptr;
|
||||
const EasyGraphicsItem* mainThreadItem = nullptr;
|
||||
for (const auto& threadTree : _blocksTree)
|
||||
{
|
||||
const auto& tree = threadTree.second.tree;
|
||||
const auto timestart = tree.children.front().node->block()->getBegin();
|
||||
const auto timefinish = tree.children.back().node->block()->getEnd();
|
||||
const auto& tree = threadTree.second.children;
|
||||
auto timestart = blocksTree(tree.front()).node->begin();
|
||||
|
||||
#ifdef EASY_STORE_CSWITCH_SEPARATELY
|
||||
if (!threadTree.second.sync.empty())
|
||||
timestart = ::std::min(timestart, blocksTree(threadTree.second.sync.front()).node->begin());
|
||||
#endif
|
||||
|
||||
const auto timefinish = blocksTree(tree.back()).node->end();
|
||||
|
||||
if (m_beginTime > timestart)
|
||||
{
|
||||
@ -1376,7 +1477,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
|
||||
if (finish < timefinish)
|
||||
{
|
||||
finish = timefinish;
|
||||
longestTree = &tree;
|
||||
longestTree = threadTree.first;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1392,13 +1493,13 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
|
||||
}
|
||||
|
||||
// fill scene with new items
|
||||
const auto& tree = threadTree.second.tree;
|
||||
qreal h = 0, x = time2position(tree.children.front().node->block()->getBegin());
|
||||
auto item = new EasyGraphicsItem(static_cast<unsigned char>(m_items.size()), &threadTree.second);
|
||||
item->setLevels(tree.depth);
|
||||
const auto& tree = threadTree.second.children;
|
||||
qreal h = 0, x = time2position(blocksTree(tree.front()).node->begin());
|
||||
auto item = new EasyGraphicsItem(static_cast<uint8_t>(m_items.size()), &threadTree.second);
|
||||
item->setLevels(threadTree.second.depth);
|
||||
item->setPos(0, y);
|
||||
|
||||
const auto children_duration = setTree(item, tree.children, h, y, 0);
|
||||
const auto children_duration = setTree(item, tree, h, y, 0);
|
||||
|
||||
item->setBoundingRect(0, 0, children_duration + x, h);
|
||||
m_items.push_back(item);
|
||||
@ -1406,10 +1507,11 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
|
||||
|
||||
y += h + THREADS_ROW_SPACING;
|
||||
|
||||
if (longestTree == &tree)
|
||||
{
|
||||
if (longestTree == threadTree.first)
|
||||
longestItem = item;
|
||||
}
|
||||
|
||||
if (mainThreadItem == nullptr && !strcmp(threadTree.second.thread_name, "Main"))
|
||||
mainThreadItem = item;
|
||||
}
|
||||
|
||||
// Calculating scene rect
|
||||
@ -1422,11 +1524,14 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
|
||||
updateVisibleSceneRect();
|
||||
setScrollbar(m_pScrollbar);
|
||||
|
||||
if (mainThreadItem != nullptr)
|
||||
longestItem = mainThreadItem;
|
||||
|
||||
if (longestItem != nullptr)
|
||||
{
|
||||
m_pScrollbar->setMinimapFrom(longestItem->threadId(), longestItem->items(0));
|
||||
::profiler_gui::EASY_GLOBALS.selected_thread = longestItem->threadId();
|
||||
emit::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(longestItem->threadId());
|
||||
EASY_GLOBALS.selected_thread = longestItem->threadId();
|
||||
emit EASY_GLOBALS.events.selectedThreadChanged(longestItem->threadId());
|
||||
}
|
||||
|
||||
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()).
|
||||
@ -1460,22 +1565,25 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto level = static_cast<unsigned char>(_level);
|
||||
const auto level = static_cast<uint8_t>(_level);
|
||||
_item->reserve(level, static_cast<unsigned int>(_children.size()));
|
||||
|
||||
const short next_level = _level + 1;
|
||||
bool warned = false;
|
||||
qreal total_duration = 0, prev_end = 0, maxh = 0;
|
||||
qreal start_time = -1;
|
||||
for (const auto& child : _children)
|
||||
for (auto child_index : _children)
|
||||
{
|
||||
auto xbegin = time2position(child.node->block()->getBegin());
|
||||
auto& gui_block = easyBlock(child_index);
|
||||
const auto& child = gui_block.tree;
|
||||
|
||||
auto xbegin = time2position(child.node->begin());
|
||||
if (start_time < 0)
|
||||
{
|
||||
start_time = xbegin;
|
||||
}
|
||||
|
||||
auto duration = time2position(child.node->block()->getEnd()) - xbegin;
|
||||
auto duration = time2position(child.node->end()) - xbegin;
|
||||
|
||||
//const auto dt = xbegin - prev_end;
|
||||
//if (dt < 0)
|
||||
@ -1492,14 +1600,13 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block
|
||||
auto i = _item->addItem(level);
|
||||
auto& b = _item->getItem(level, i);
|
||||
|
||||
auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[child.block_index];
|
||||
gui_block.graphics_item = _item->index();
|
||||
gui_block.graphics_item_level = level;
|
||||
gui_block.graphics_item_index = i;
|
||||
|
||||
if (next_level < 256 && next_level < _item->levels() && !child.children.empty())
|
||||
{
|
||||
b.children_begin = static_cast<unsigned int>(_item->items(static_cast<unsigned char>(next_level)).size());
|
||||
b.children_begin = static_cast<unsigned int>(_item->items(static_cast<uint8_t>(next_level)).size());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1529,9 +1636,8 @@ qreal EasyGraphicsView::setTree(EasyGraphicsItem* _item, const ::profiler::Block
|
||||
maxh = h;
|
||||
}
|
||||
|
||||
const auto color = child.node->block()->getColor();
|
||||
b.block = &child;
|
||||
b.color = ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
|
||||
b.block = child_index;// &child;
|
||||
b.color = EASY_GLOBALS.descriptors[child.node->id()]->color();// ::profiler_gui::fromProfilerRgb(::profiler::colors::get_red(color), ::profiler::colors::get_green(color), ::profiler::colors::get_blue(color));
|
||||
b.setPos(xbegin, duration);
|
||||
b.totalHeight = GRAPHICS_ROW_SIZE + h;
|
||||
b.state = BLOCK_ITEM_UNCHANGED;
|
||||
@ -1571,8 +1677,8 @@ void EasyGraphicsView::setScrollbar(EasyGraphicsScrollbar* _scrollbar)
|
||||
connect(m_pScrollbar, &EasyGraphicsScrollbar::wheeled, this, &This::onGraphicsScrollbarWheel);
|
||||
}
|
||||
|
||||
::profiler_gui::EASY_GLOBALS.selected_thread = 0;
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(0);
|
||||
EASY_GLOBALS.selected_thread = 0;
|
||||
emit EASY_GLOBALS.events.selectedThreadChanged(0);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -1647,7 +1753,7 @@ void EasyGraphicsView::onGraphicsScrollbarWheel(qreal _mouseX, int _wheelDelta)
|
||||
{
|
||||
for (auto item : m_items)
|
||||
{
|
||||
if (item->threadId() == ::profiler_gui::EASY_GLOBALS.selected_thread)
|
||||
if (item->threadId() == EASY_GLOBALS.selected_thread)
|
||||
{
|
||||
m_bUpdatingRect = true;
|
||||
auto vbar = verticalScrollBar();
|
||||
@ -1780,8 +1886,8 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
|
||||
}
|
||||
}
|
||||
|
||||
const ::profiler_gui::ProfBlockItem* selectedBlock = nullptr;
|
||||
const auto previouslySelectedBlock = ::profiler_gui::EASY_GLOBALS.selected_block;
|
||||
const ::profiler_gui::EasyBlockItem* selectedBlock = nullptr;
|
||||
const auto previouslySelectedBlock = EASY_GLOBALS.selected_block;
|
||||
if (m_mouseButtons & Qt::LeftButton)
|
||||
{
|
||||
bool clicked = false;
|
||||
@ -1814,15 +1920,15 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
|
||||
{
|
||||
changedSelectedItem = true;
|
||||
selectedBlock = block;
|
||||
::profiler_gui::EASY_GLOBALS.selected_block = block->block->block_index;
|
||||
EASY_GLOBALS.selected_block = block->block;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!changedSelectedItem && ::profiler_gui::EASY_GLOBALS.selected_block != ::profiler_gui::numeric_max(::profiler_gui::EASY_GLOBALS.selected_block))
|
||||
if (!changedSelectedItem && EASY_GLOBALS.selected_block != ::profiler_gui::numeric_max(EASY_GLOBALS.selected_block))
|
||||
{
|
||||
changedSelectedItem = true;
|
||||
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
|
||||
::profiler_gui::set_max(EASY_GLOBALS.selected_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1842,12 +1948,12 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
|
||||
if (changedSelectedItem)
|
||||
{
|
||||
m_bUpdatingRect = true;
|
||||
if (selectedBlock != nullptr && previouslySelectedBlock == ::profiler_gui::EASY_GLOBALS.selected_block && !selectedBlock->block->children.empty())
|
||||
if (selectedBlock != nullptr && previouslySelectedBlock == EASY_GLOBALS.selected_block && !blocksTree(selectedBlock->block).children.empty())
|
||||
{
|
||||
::profiler_gui::EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !::profiler_gui::EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded;
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded;
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(::profiler_gui::EASY_GLOBALS.selected_block);
|
||||
emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block);
|
||||
m_bUpdatingRect = false;
|
||||
|
||||
updateScene();
|
||||
@ -1999,7 +2105,7 @@ void EasyGraphicsView::initMode()
|
||||
connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &This::onScrollbarValueChange);
|
||||
connect(&m_flickerTimer, &QTimer::timeout, this, &This::onFlickerTimeout);
|
||||
|
||||
auto globalSignals = &::profiler_gui::EASY_GLOBALS.events;
|
||||
auto globalSignals = &EASY_GLOBALS.events;
|
||||
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
|
||||
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
|
||||
connect(globalSignals, &::profiler_gui::EasyGlobalSignals::itemsExpandStateChanged, this, &This::onItemsEspandStateChange);
|
||||
@ -2102,11 +2208,11 @@ void EasyGraphicsView::onSelectedBlockChange(unsigned int _block_index)
|
||||
{
|
||||
if (!m_bUpdatingRect)
|
||||
{
|
||||
if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size())
|
||||
if (_block_index < EASY_GLOBALS.gui_blocks.size())
|
||||
{
|
||||
// Scroll to item
|
||||
|
||||
const auto& guiblock = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index];
|
||||
const auto& guiblock = EASY_GLOBALS.gui_blocks[_block_index];
|
||||
const auto thread_item = m_items[guiblock.graphics_item];
|
||||
const auto& item = thread_item->items(guiblock.graphics_item_level)[guiblock.graphics_item_index];
|
||||
|
||||
@ -2181,7 +2287,7 @@ EasyThreadViewWidget::EasyThreadViewWidget(QWidget *parent, EasyGraphicsView* vi
|
||||
//m_layout->addWidget(m_label);
|
||||
//setLayout(m_layout);
|
||||
//show();
|
||||
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
|
||||
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
|
||||
}
|
||||
|
||||
EasyThreadViewWidget::~EasyThreadViewWidget()
|
||||
@ -2192,14 +2298,14 @@ EasyThreadViewWidget::~EasyThreadViewWidget()
|
||||
void EasyThreadViewWidget::onSelectedThreadChange(::profiler::thread_id_t _id)
|
||||
{
|
||||
/*
|
||||
auto threadName = ::profiler_gui::EASY_GLOBALS.profiler_blocks[::profiler_gui::EASY_GLOBALS.selected_thread].thread_name;
|
||||
auto threadName = EASY_GLOBALS.profiler_blocks[EASY_GLOBALS.selected_thread].thread_name;
|
||||
if(threadName[0]!=0)
|
||||
{
|
||||
m_label->setText(threadName);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_label->setText(QString("Thread %1").arg(::profiler_gui::EASY_GLOBALS.selected_thread));
|
||||
m_label->setText(QString("Thread %1").arg(EASY_GLOBALS.selected_thread));
|
||||
}
|
||||
*/
|
||||
QLayoutItem *ditem;
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : blocks_graphics_view.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/06/26
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -18,7 +17,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY__GRAPHICS_VIEW__H_
|
||||
@ -58,7 +71,7 @@ inline qreal microseconds2units(qreal _value)
|
||||
|
||||
class EasyGraphicsItem : public QGraphicsItem
|
||||
{
|
||||
typedef ::profiler_gui::ProfItems Children;
|
||||
typedef ::profiler_gui::EasyItems Children;
|
||||
typedef ::std::vector<unsigned int> DrawIndexes;
|
||||
typedef ::std::vector<Children> Sublevels;
|
||||
|
||||
@ -67,11 +80,11 @@ class EasyGraphicsItem : public QGraphicsItem
|
||||
|
||||
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
|
||||
const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy.
|
||||
unsigned char m_index; ///< This item's index in the list of items of EasyGraphicsView
|
||||
uint8_t m_index; ///< This item's index in the list of items of EasyGraphicsView
|
||||
|
||||
public:
|
||||
|
||||
EasyGraphicsItem(unsigned char _index, const::profiler::BlocksTreeRoot* _root);
|
||||
EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot* _root);
|
||||
virtual ~EasyGraphicsItem();
|
||||
|
||||
// Public virtual methods
|
||||
@ -92,46 +105,46 @@ public:
|
||||
::profiler::thread_id_t threadId() const;
|
||||
|
||||
///< Returns number of levels
|
||||
unsigned char levels() const;
|
||||
uint8_t levels() const;
|
||||
|
||||
float levelY(unsigned char _level) const;
|
||||
float levelY(uint8_t _level) const;
|
||||
|
||||
/** \brief Sets number of levels.
|
||||
|
||||
\note Must be set before doing anything else.
|
||||
|
||||
\param _levels Desired number of levels */
|
||||
void setLevels(unsigned char _levels);
|
||||
void setLevels(uint8_t _levels);
|
||||
|
||||
/** \brief Reserves memory for desired number of items on specified level.
|
||||
|
||||
\param _level Index of the level
|
||||
\param _items Desired number of items on this level */
|
||||
void reserve(unsigned char _level, unsigned int _items);
|
||||
void reserve(uint8_t _level, unsigned int _items);
|
||||
|
||||
/**\brief Returns reference to the array of items of specified level.
|
||||
|
||||
\param _level Index of the level */
|
||||
const Children& items(unsigned char _level) const;
|
||||
const Children& items(uint8_t _level) const;
|
||||
|
||||
/**\brief Returns reference to the item with required index on specified level.
|
||||
|
||||
\param _level Index of the level
|
||||
\param _index Index of required item */
|
||||
const ::profiler_gui::ProfBlockItem& getItem(unsigned char _level, unsigned int _index) const;
|
||||
const ::profiler_gui::EasyBlockItem& getItem(uint8_t _level, unsigned int _index) const;
|
||||
|
||||
/**\brief Returns reference to the item with required index on specified level.
|
||||
|
||||
\param _level Index of the level
|
||||
\param _index Index of required item */
|
||||
::profiler_gui::ProfBlockItem& getItem(unsigned char _level, unsigned int _index);
|
||||
::profiler_gui::EasyBlockItem& getItem(uint8_t _level, unsigned int _index);
|
||||
|
||||
/** \brief Adds new item to required level.
|
||||
|
||||
\param _level Index of the level
|
||||
|
||||
\retval Index of the new created item */
|
||||
unsigned int addItem(unsigned char _level);
|
||||
unsigned int addItem(uint8_t _level);
|
||||
|
||||
/** \brief Finds top-level blocks which are intersects with required selection zone.
|
||||
|
||||
@ -142,7 +155,7 @@ public:
|
||||
\param _blocks Reference to the array of selected blocks */
|
||||
void getBlocks(qreal _left, qreal _right, ::profiler_gui::TreeBlocks& _blocks) const;
|
||||
|
||||
const ::profiler_gui::ProfBlockItem* intersect(const QPointF& _pos) const;
|
||||
const ::profiler_gui::EasyBlockItem* intersect(const QPointF& _pos) const;
|
||||
|
||||
private:
|
||||
|
||||
@ -154,7 +167,7 @@ public:
|
||||
// Public inline methods
|
||||
|
||||
///< Returns this item's index in the list of graphics items of EasyGraphicsView
|
||||
inline unsigned char index() const
|
||||
inline uint8_t index() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
@ -198,7 +211,7 @@ public:
|
||||
|
||||
void setHover(bool _hover);
|
||||
|
||||
bool contains(const QPointF& _pos) const;
|
||||
bool contains(const QPointF& _pos) const override;
|
||||
|
||||
inline bool hoverIndicator() const
|
||||
{
|
||||
@ -363,7 +376,7 @@ public:
|
||||
return m_timelineStep;
|
||||
}
|
||||
|
||||
private:
|
||||
//private:
|
||||
|
||||
// Private inline methods
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : blocks_tree_widget.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/06/26
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -21,7 +20,21 @@
|
||||
* :
|
||||
* : * 2016/08/18 Victor Zarubkin: Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#include <QMenu>
|
||||
@ -31,6 +44,7 @@
|
||||
#include <QProgressDialog>
|
||||
#include <QResizeEvent>
|
||||
#include <QMoveEvent>
|
||||
#include <QDebug>
|
||||
#include "blocks_tree_widget.h"
|
||||
#include "tree_widget_item.h"
|
||||
#include "globals.h"
|
||||
@ -103,8 +117,8 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
|
||||
|
||||
setHeaderItem(header);
|
||||
|
||||
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
|
||||
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
|
||||
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChange);
|
||||
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
|
||||
connect(&m_fillTimer, &QTimer::timeout, this, &This::onFillTimerTimeout);
|
||||
|
||||
loadSettings();
|
||||
@ -115,12 +129,12 @@ EasyTreeWidget::EasyTreeWidget(QWidget* _parent)
|
||||
m_progress->setValue(100);
|
||||
//m_progress->hide();
|
||||
|
||||
QTimer::singleShot(40, this, &This::alignProgressBar);
|
||||
QTimer::singleShot(1500, this, &This::alignProgressBar);
|
||||
}
|
||||
|
||||
EasyTreeWidget::~EasyTreeWidget()
|
||||
{
|
||||
saveSettings();
|
||||
saveSettings();
|
||||
delete m_progress;
|
||||
}
|
||||
|
||||
@ -162,8 +176,8 @@ void EasyTreeWidget::onFillTimerTimeout()
|
||||
connect(this, &Parent::itemExpanded, this, &This::onItemExpand);
|
||||
connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse);
|
||||
connect(this, &Parent::currentItemChanged, this, &This::onCurrentItemChange);
|
||||
onSelectedThreadChange(::profiler_gui::EASY_GLOBALS.selected_thread);
|
||||
onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block);
|
||||
onSelectedThreadChange(EASY_GLOBALS.selected_thread);
|
||||
onSelectedBlockChange(EASY_GLOBALS.selected_block);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -193,7 +207,7 @@ void EasyTreeWidget::setTree(const unsigned int _blocksNumber, const ::profiler:
|
||||
// {
|
||||
// addTopLevelItem(item.second);
|
||||
// m_roots[item.first] = item.second;
|
||||
// if (item.first == ::profiler_gui::EASY_GLOBALS.selected_thread)
|
||||
// if (item.first == EASY_GLOBALS.selected_thread)
|
||||
// item.second->colorize(true);
|
||||
// }
|
||||
//}
|
||||
@ -226,7 +240,7 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::
|
||||
// {
|
||||
// addTopLevelItem(item.second);
|
||||
// m_roots[item.first] = item.second;
|
||||
// if (item.first == ::profiler_gui::EASY_GLOBALS.selected_thread)
|
||||
// if (item.first == EASY_GLOBALS.selected_thread)
|
||||
// item.second->colorize(true);
|
||||
// }
|
||||
//}
|
||||
@ -237,13 +251,15 @@ void EasyTreeWidget::setTreeBlocks(const ::profiler_gui::TreeBlocks& _blocks, ::
|
||||
|
||||
//connect(this, &Parent::itemExpanded, this, &This::onItemExpand);
|
||||
//connect(this, &Parent::itemCollapsed, this, &This::onItemCollapse);
|
||||
//onSelectedBlockChange(::profiler_gui::EASY_GLOBALS.selected_block);
|
||||
//onSelectedBlockChange(EASY_GLOBALS.selected_block);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EasyTreeWidget::clearSilent(bool _global)
|
||||
{
|
||||
const QSignalBlocker b(this);
|
||||
|
||||
m_hierarchyBuilder.interrupt();
|
||||
|
||||
if (m_progress)
|
||||
@ -262,25 +278,36 @@ void EasyTreeWidget::clearSilent(bool _global)
|
||||
|
||||
if (!_global)
|
||||
{
|
||||
if (::profiler_gui::EASY_GLOBALS.collapse_items_on_tree_close) for (auto item : m_items)
|
||||
if (EASY_GLOBALS.collapse_items_on_tree_close) for (auto item : m_items)
|
||||
{
|
||||
auto& gui_block = ::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index];
|
||||
auto& gui_block = item->guiBlock();
|
||||
::profiler_gui::set_max(gui_block.tree_item);
|
||||
gui_block.expanded = false;
|
||||
}
|
||||
else for (auto item : m_items)
|
||||
{
|
||||
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].tree_item);
|
||||
::profiler_gui::set_max(item->guiBlock().tree_item);
|
||||
}
|
||||
}
|
||||
|
||||
m_items.clear();
|
||||
m_roots.clear();
|
||||
|
||||
{ const QSignalBlocker b(this); clear(); } // clear without emitting any signals
|
||||
::std::vector<QTreeWidgetItem*> topLevelItems;
|
||||
topLevelItems.reserve(topLevelItemCount());
|
||||
for (int i = topLevelItemCount() - 1; i >= 0; --i)
|
||||
topLevelItems.push_back(takeTopLevelItem(i));
|
||||
|
||||
auto deleter_thread = ::std::thread([](decltype(topLevelItems) _items) {
|
||||
for (auto item : _items)
|
||||
delete item;
|
||||
}, ::std::move(topLevelItems));
|
||||
deleter_thread.detach();
|
||||
|
||||
//clear();
|
||||
|
||||
if (!_global)
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -325,7 +352,7 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
||||
action->setChecked(m_bColorRows);
|
||||
connect(action, &QAction::triggered, this, &This::onColorizeRowsTriggered);
|
||||
|
||||
if (item != nullptr)
|
||||
if (item != nullptr && item->parent() != nullptr)
|
||||
{
|
||||
//auto itemAction = new EasyItemAction("Show this item on scene", item->block()->block_index);
|
||||
//itemAction->setToolTip("Scroll graphics scene to current item in the tree");
|
||||
@ -343,24 +370,25 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
||||
case COL_MAX_PER_PARENT:
|
||||
case COL_MAX_PER_FRAME:
|
||||
{
|
||||
auto block = item->block();
|
||||
auto i = ::profiler_gui::numeric_max<unsigned int>();
|
||||
auto& block = item->block();
|
||||
auto i = ::profiler_gui::numeric_max<uint32_t>();
|
||||
switch (col)
|
||||
{
|
||||
case COL_MIN_PER_THREAD: i = block->per_thread_stats->min_duration_block; break;
|
||||
case COL_MIN_PER_PARENT: i = block->per_parent_stats->min_duration_block; break;
|
||||
case COL_MIN_PER_FRAME: i = block->per_frame_stats->min_duration_block; break;
|
||||
case COL_MAX_PER_THREAD: i = block->per_thread_stats->max_duration_block; break;
|
||||
case COL_MAX_PER_PARENT: i = block->per_parent_stats->max_duration_block; break;
|
||||
case COL_MAX_PER_FRAME: i = block->per_frame_stats->max_duration_block; break;
|
||||
case COL_MIN_PER_THREAD: i = block.per_thread_stats->min_duration_block; break;
|
||||
case COL_MIN_PER_PARENT: i = block.per_parent_stats->min_duration_block; break;
|
||||
case COL_MIN_PER_FRAME: i = block.per_frame_stats->min_duration_block; break;
|
||||
case COL_MAX_PER_THREAD: i = block.per_thread_stats->max_duration_block; break;
|
||||
case COL_MAX_PER_PARENT: i = block.per_parent_stats->max_duration_block; break;
|
||||
case COL_MAX_PER_FRAME: i = block.per_frame_stats->max_duration_block; break;
|
||||
}
|
||||
|
||||
if (i != ::profiler_gui::numeric_max(i))
|
||||
{
|
||||
menu.addSeparator();
|
||||
auto itemAction = new EasyItemAction("Jump to such item", i);
|
||||
auto itemAction = new QAction("Jump to such item", nullptr);
|
||||
itemAction->setData(i);
|
||||
itemAction->setToolTip("Jump to item with min/max duration (depending on clicked column)");
|
||||
connect(itemAction, &EasyItemAction::clicked, this, &This::onJumpToItemClicked);
|
||||
connect(itemAction, &QAction::triggered, this, &This::onJumpToItemClicked);
|
||||
menu.addAction(itemAction);
|
||||
}
|
||||
|
||||
@ -375,12 +403,13 @@ void EasyTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
||||
auto hidemenu = menu.addMenu("Select columns");
|
||||
auto hdr = headerItem();
|
||||
|
||||
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
|
||||
for (int i = 0; i < COL_COLUMNS_NUMBER; ++i)
|
||||
{
|
||||
auto columnAction = new EasyHideShowColumnAction(hdr->text(i), i);
|
||||
auto columnAction = new QAction(hdr->text(i), nullptr);
|
||||
columnAction->setData(i);
|
||||
columnAction->setCheckable(true);
|
||||
columnAction->setChecked(!isColumnHidden(i));
|
||||
connect(columnAction, &EasyHideShowColumnAction::clicked, this, &This::onHideShowColumn);
|
||||
columnAction->setChecked(!isColumnHidden(i));
|
||||
connect(columnAction, &QAction::triggered, this, &This::onHideShowColumn);
|
||||
hidemenu->addAction(columnAction);
|
||||
}
|
||||
|
||||
@ -405,16 +434,21 @@ void EasyTreeWidget::moveEvent(QMoveEvent* _event)
|
||||
|
||||
void EasyTreeWidget::alignProgressBar()
|
||||
{
|
||||
auto pos = mapToGlobal(rect().center());
|
||||
auto pos = mapToGlobal(rect().center());
|
||||
m_progress->move(pos.x() - (m_progress->width() >> 1), pos.y() - (m_progress->height() >> 1));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EasyTreeWidget::onJumpToItemClicked(unsigned int _block_index)
|
||||
void EasyTreeWidget::onJumpToItemClicked(bool)
|
||||
{
|
||||
::profiler_gui::EASY_GLOBALS.selected_block = _block_index;
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(_block_index);
|
||||
auto action = qobject_cast<QAction*>(sender());
|
||||
if (action == nullptr)
|
||||
return;
|
||||
|
||||
auto block_index = action->data().toUInt();
|
||||
EASY_GLOBALS.selected_block = block_index;
|
||||
emit EASY_GLOBALS.events.selectedBlockChanged(block_index);
|
||||
}
|
||||
|
||||
void EasyTreeWidget::onCollapseAllClicked(bool)
|
||||
@ -425,11 +459,11 @@ void EasyTreeWidget::onCollapseAllClicked(bool)
|
||||
collapseAll();
|
||||
m_bSilentExpandCollapse = false;
|
||||
|
||||
if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
if (EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
{
|
||||
for (auto item : m_items)
|
||||
::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = false;
|
||||
emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
item->guiBlock().expanded = false;
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,11 +476,15 @@ void EasyTreeWidget::onExpandAllClicked(bool)
|
||||
resizeColumnsToContents();
|
||||
m_bSilentExpandCollapse = false;
|
||||
|
||||
if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
if (EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
{
|
||||
for (auto item : m_items)
|
||||
::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded = !item->block()->children.empty();
|
||||
emit::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
{
|
||||
auto& b = item->guiBlock();
|
||||
b.expanded = !b.tree.children.empty();
|
||||
}
|
||||
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,7 +499,7 @@ void EasyTreeWidget::onCollapseAllChildrenClicked(bool)
|
||||
current->collapseAll();
|
||||
m_bSilentExpandCollapse = false;
|
||||
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,7 +515,7 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool)
|
||||
resizeColumnsToContents();
|
||||
m_bSilentExpandCollapse = false;
|
||||
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,30 +523,30 @@ void EasyTreeWidget::onExpandAllChildrenClicked(bool)
|
||||
|
||||
void EasyTreeWidget::onItemExpand(QTreeWidgetItem* _item)
|
||||
{
|
||||
if (!::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
if (!EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
{
|
||||
resizeColumnsToContents();
|
||||
return;
|
||||
}
|
||||
|
||||
::profiler_gui::EASY_GLOBALS.gui_blocks[static_cast<EasyTreeWidgetItem*>(_item)->block()->block_index].expanded = true;
|
||||
static_cast<EasyTreeWidgetItem*>(_item)->guiBlock().expanded = true;
|
||||
|
||||
if (!m_bSilentExpandCollapse)
|
||||
{
|
||||
resizeColumnsToContents();
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item)
|
||||
{
|
||||
if (!::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
if (!EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
return;
|
||||
|
||||
::profiler_gui::EASY_GLOBALS.gui_blocks[static_cast<EasyTreeWidgetItem*>(_item)->block()->block_index].expanded = false;
|
||||
static_cast<EasyTreeWidgetItem*>(_item)->guiBlock().expanded = false;
|
||||
|
||||
if (!m_bSilentExpandCollapse)
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -516,13 +554,13 @@ void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item)
|
||||
void EasyTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem*)
|
||||
{
|
||||
if (_item == nullptr)
|
||||
::profiler_gui::set_max(::profiler_gui::EASY_GLOBALS.selected_block);
|
||||
::profiler_gui::set_max(EASY_GLOBALS.selected_block);
|
||||
else
|
||||
::profiler_gui::EASY_GLOBALS.selected_block = static_cast<EasyTreeWidgetItem*>(_item)->block()->block_index;
|
||||
EASY_GLOBALS.selected_block = static_cast<EasyTreeWidgetItem*>(_item)->block_index();
|
||||
|
||||
disconnect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.selectedBlockChanged(::profiler_gui::EASY_GLOBALS.selected_block);
|
||||
connect(&::profiler_gui::EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
|
||||
disconnect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
|
||||
emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block);
|
||||
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChange);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -567,9 +605,9 @@ void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index)
|
||||
|
||||
EasyTreeWidgetItem* item = nullptr;
|
||||
|
||||
if (_block_index < ::profiler_gui::EASY_GLOBALS.gui_blocks.size())
|
||||
if (_block_index < EASY_GLOBALS.gui_blocks.size())
|
||||
{
|
||||
const auto i = ::profiler_gui::EASY_GLOBALS.gui_blocks[_block_index].tree_item;
|
||||
const auto i = easyBlock(_block_index).tree_item;
|
||||
if (i < m_items.size())
|
||||
item = m_items[i];
|
||||
}
|
||||
@ -578,19 +616,19 @@ void EasyTreeWidget::onSelectedBlockChange(unsigned int _block_index)
|
||||
{
|
||||
//const QSignalBlocker b(this);
|
||||
|
||||
if (::profiler_gui::EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
if (EASY_GLOBALS.bind_scene_and_tree_expand_status)
|
||||
{
|
||||
m_bSilentExpandCollapse = true;
|
||||
setCurrentItem(item);
|
||||
scrollToItem(item, QAbstractItemView::PositionAtCenter);
|
||||
if (::profiler_gui::EASY_GLOBALS.gui_blocks[item->block()->block_index].expanded)
|
||||
if (item->guiBlock().expanded)
|
||||
expandItem(item);
|
||||
else
|
||||
collapseItem(item);
|
||||
resizeColumnsToContents();
|
||||
m_bSilentExpandCollapse = false;
|
||||
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
emit EASY_GLOBALS.events.itemsExpandStateChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -621,16 +659,17 @@ void EasyTreeWidget::resizeColumnsToContents()
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EasyTreeWidget::onHideShowColumn(int _column)
|
||||
void EasyTreeWidget::onHideShowColumn(bool)
|
||||
{
|
||||
if (isColumnHidden(_column))
|
||||
{
|
||||
showColumn(_column);
|
||||
}
|
||||
auto action = qobject_cast<QAction*>(sender());
|
||||
if (action == nullptr)
|
||||
return;
|
||||
|
||||
auto col = action->data().toInt();
|
||||
if (isColumnHidden(col))
|
||||
showColumn(col);
|
||||
else
|
||||
{
|
||||
hideColumn(_column);
|
||||
}
|
||||
hideColumn(col);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -655,17 +694,17 @@ void EasyTreeWidget::loadSettings()
|
||||
|
||||
void EasyTreeWidget::saveSettings()
|
||||
{
|
||||
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
|
||||
settings.beginGroup("tree_widget");
|
||||
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
|
||||
settings.beginGroup("tree_widget");
|
||||
|
||||
settings.setValue("color_rows", m_bColorRows);
|
||||
settings.setValue("color_rows", m_bColorRows);
|
||||
|
||||
for (int i = 0; i < columnCount(); i++)
|
||||
{
|
||||
settings.setValue(QString("Column") + QString::number(i) , isColumnHidden(i));
|
||||
}
|
||||
for (int i = 0; i < columnCount(); i++)
|
||||
{
|
||||
settings.setValue(QString("Column") + QString::number(i) , isColumnHidden(i));
|
||||
}
|
||||
|
||||
settings.endGroup();
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : blocks_tree_widget.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/06/26
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -20,7 +19,21 @@
|
||||
* : * 2016/08/18 Victor Zarubkin: Added loading blocks hierarchy in separate thread;
|
||||
* : Moved sources of TreeWidgetItem into tree_widget_item.h/.cpp
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY__TREE_WIDGET__H_
|
||||
@ -34,27 +47,6 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define DECLARE_QACTION(ClassName, DataType) \
|
||||
class ClassName : public QAction { \
|
||||
Q_OBJECT \
|
||||
private: \
|
||||
DataType m_item; \
|
||||
public: \
|
||||
ClassName(const char* _label, DataType _item) : QAction(_label, nullptr), m_item(_item) { \
|
||||
connect(this, &QAction::triggered, this, &ClassName::onToggle); } \
|
||||
ClassName(const QString& _label, DataType _item) : QAction(_label, nullptr), m_item(_item) { \
|
||||
connect(this, &QAction::triggered, this, &ClassName::onToggle); } \
|
||||
virtual ~ClassName() {} \
|
||||
private: \
|
||||
void onToggle(bool) { emit clicked(m_item); }
|
||||
|
||||
DECLARE_QACTION(EasyItemAction, unsigned int) signals: void clicked(unsigned int _item); };
|
||||
DECLARE_QACTION(EasyHideShowColumnAction, int) signals: void clicked(int _item); };
|
||||
|
||||
#undef DECLARE_QACTION
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EasyTreeWidget : public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -96,7 +88,7 @@ protected:
|
||||
|
||||
private slots:
|
||||
|
||||
void onJumpToItemClicked(unsigned int _block_index);
|
||||
void onJumpToItemClicked(bool);
|
||||
|
||||
void onCollapseAllClicked(bool);
|
||||
|
||||
@ -118,14 +110,14 @@ private slots:
|
||||
|
||||
void resizeColumnsToContents();
|
||||
|
||||
void onHideShowColumn(int _column);
|
||||
void onHideShowColumn(bool);
|
||||
|
||||
void onFillTimerTimeout();
|
||||
|
||||
protected:
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
void saveSettings();
|
||||
void alignProgressBar();
|
||||
|
||||
}; // END of class EasyTreeWidget.
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : common_types.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/07/31
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -13,7 +12,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY_PROFILER__GUI_COMMON_TYPES_H
|
||||
@ -88,7 +101,7 @@ struct do_no_hash {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const QRgb DEFAULT_COLOR = 0x00d4b494;//0x00f0e094;
|
||||
const QRgb DEFAULT_COLOR = profiler::DefaultBlockColor;// 0x00d4b494;
|
||||
|
||||
inline QRgb toRgb(unsigned int _red, unsigned int _green, unsigned int _blue)
|
||||
{
|
||||
@ -102,17 +115,24 @@ inline QRgb fromProfilerRgb(unsigned int _red, unsigned int _green, unsigned int
|
||||
return toRgb(_red, _green, _blue) | 0x00141414;
|
||||
}
|
||||
|
||||
inline QRgb textColorForRgb(QRgb _color)
|
||||
{
|
||||
const QRgb sum = 0xff - ((_color & 0xff000000) >> 24) + ((_color & 0x00ff0000) >> 16) + ((_color & 0x0000ff00) >> 8) + (_color & 0x000000ff);
|
||||
return sum > 0x215 ? ::profiler::colors::Black : ::profiler::colors::White;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ProfBlockItem final
|
||||
struct EasyBlockItem final
|
||||
{
|
||||
const ::profiler::BlocksTree* block; ///< Pointer to profiler block
|
||||
//const ::profiler::BlocksTree* block; ///< Pointer to profiler block
|
||||
qreal x; ///< x coordinate of the item (this is made qreal=double to avoid mistakes on very wide scene)
|
||||
float w; ///< Width of the item
|
||||
QRgb color; ///< Background color of the item
|
||||
unsigned int children_begin; ///< Index of first child item on the next sublevel
|
||||
unsigned short totalHeight; ///< Total height of the item including heights of all it's children
|
||||
::profiler::block_index_t block; ///< Index of profiler block
|
||||
uint32_t children_begin; ///< Index of first child item on the next sublevel
|
||||
uint16_t totalHeight; ///< Total height of the item including heights of all it's children
|
||||
char state; ///< 0 = no change, 1 = paint, -1 = do not paint
|
||||
|
||||
// Possible optimizations:
|
||||
@ -125,31 +145,58 @@ struct ProfBlockItem final
|
||||
inline qreal right() const { return x + w; }
|
||||
inline float width() const { return w; }
|
||||
|
||||
}; // END of struct ProfBlockItem.
|
||||
#pragma pack(pop)
|
||||
}; // END of struct EasyBlockItem.
|
||||
|
||||
typedef ::std::vector<ProfBlockItem> ProfItems;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct ProfSelectedBlock final
|
||||
struct EasyBlock final
|
||||
{
|
||||
const ::profiler::BlocksTreeRoot* root;
|
||||
const ::profiler::BlocksTree* tree;
|
||||
::profiler::BlocksTree tree;
|
||||
uint32_t tree_item;
|
||||
uint32_t graphics_item_index;
|
||||
uint8_t graphics_item_level;
|
||||
uint8_t graphics_item;
|
||||
bool expanded;
|
||||
|
||||
ProfSelectedBlock() : root(nullptr), tree(nullptr)
|
||||
EasyBlock() = default;
|
||||
|
||||
EasyBlock(EasyBlock&& that)
|
||||
: tree(::std::move(that.tree))
|
||||
, tree_item(that.tree_item)
|
||||
, graphics_item_index(that.graphics_item_index)
|
||||
, graphics_item_level(that.graphics_item_level)
|
||||
, graphics_item(that.graphics_item)
|
||||
, expanded(that.expanded)
|
||||
{
|
||||
}
|
||||
|
||||
ProfSelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::BlocksTree* _tree)
|
||||
private:
|
||||
|
||||
EasyBlock(const EasyBlock&) = delete;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef ::std::vector<EasyBlockItem> EasyItems;
|
||||
typedef ::std::vector<EasyBlock> EasyBlocks;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct EasySelectedBlock final
|
||||
{
|
||||
const ::profiler::BlocksTreeRoot* root;
|
||||
::profiler::block_index_t tree;
|
||||
|
||||
EasySelectedBlock() : root(nullptr), tree(0xffffffff)
|
||||
{
|
||||
}
|
||||
|
||||
EasySelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::block_index_t _tree)
|
||||
: root(_root)
|
||||
, tree(_tree)
|
||||
{
|
||||
}
|
||||
|
||||
}; // END of struct ProfSelectedBlock.
|
||||
}; // END of struct EasySelectedBlock.
|
||||
|
||||
typedef ::std::vector<ProfSelectedBlock> TreeBlocks;
|
||||
typedef ::std::vector<EasySelectedBlock> TreeBlocks;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : globals.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/08/03
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -12,7 +11,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#define IGNORE_GLOBALS_DECLARATION
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : globals.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/08/03
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -12,7 +11,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY_PROFILER__GUI_GLOBALS_H
|
||||
@ -30,8 +43,8 @@
|
||||
|
||||
namespace profiler_gui {
|
||||
|
||||
const QString ORGANAZATION_NAME = "EasyProfiler";
|
||||
const QString APPLICATION_NAME = "Easy profiler gui application";
|
||||
const QString ORGANAZATION_NAME = "EasyProfiler";
|
||||
const QString APPLICATION_NAME = "Easy profiler gui application";
|
||||
|
||||
const QColor CHRONOMETER_COLOR = QColor::fromRgba(0x402020c0);
|
||||
const QRgb SELECTED_THREAD_BACKGROUND = 0x00e0e060;
|
||||
@ -42,19 +55,6 @@ namespace profiler_gui {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct EasyBlock final
|
||||
{
|
||||
unsigned int tree_item;
|
||||
unsigned int graphics_item_index;
|
||||
unsigned char graphics_item_level;
|
||||
unsigned char graphics_item;
|
||||
bool expanded;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef ::std::vector<EasyBlock> EasyBlocks;
|
||||
|
||||
template <class T>
|
||||
inline auto toUnicode(const T& _inputString) -> decltype(QTextCodec::codecForLocale()->toUnicode(_inputString))
|
||||
{
|
||||
@ -79,6 +79,7 @@ namespace profiler_gui {
|
||||
|
||||
EasyGlobalSignals events; ///< Global signals
|
||||
::profiler::thread_blocks_tree_t profiler_blocks; ///< Profiler blocks tree loaded from file
|
||||
::profiler::descriptors_list_t descriptors; ///< Profiler block descriptors list
|
||||
EasyBlocks gui_blocks; ///< Profiler graphics blocks builded by GUI
|
||||
::profiler::thread_id_t selected_thread; ///< Current selected thread id
|
||||
unsigned int selected_block; ///< Current selected profiler block index
|
||||
@ -96,13 +97,26 @@ namespace profiler_gui {
|
||||
|
||||
}; // END of struct EasyGlobals.
|
||||
|
||||
#ifndef IGNORE_GLOBALS_DECLARATION
|
||||
static EasyGlobals& EASY_GLOBALS = EasyGlobals::instance();
|
||||
#endif
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // END of namespace profiler_gui.
|
||||
|
||||
#ifndef IGNORE_GLOBALS_DECLARATION
|
||||
static ::profiler_gui::EasyGlobals& EASY_GLOBALS = ::profiler_gui::EasyGlobals::instance();
|
||||
|
||||
inline ::profiler_gui::EasyBlock& easyBlock(::profiler::block_index_t i) {
|
||||
return EASY_GLOBALS.gui_blocks[i];
|
||||
}
|
||||
|
||||
inline ::profiler::SerializedBlockDescriptor& easyDescriptor(::profiler::block_id_t i) {
|
||||
return *EASY_GLOBALS.descriptors[i];
|
||||
}
|
||||
|
||||
inline ::profiler::BlocksTree& blocksTree(::profiler::block_index_t i) {
|
||||
return easyBlock(i).tree;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -2,9 +2,8 @@
|
||||
* file name : globals_qobjects.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/08/08
|
||||
* copyright : (c) 2016 Victor Zarubkin, Sergey Yagovtsev
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* authors : Victor Zarubkin, Sergey Yagovtsev
|
||||
* email : v.s.zarubkin@gmail.com, yse.sey@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of EasyGlobalSignals QObject class.
|
||||
* ----------------- :
|
||||
@ -12,7 +11,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#include "globals_qobjects.h"
|
||||
|
@ -1,5 +1,35 @@
|
||||
#ifndef GLOBALS_QOBJECTS_H
|
||||
#define GLOBALS_QOBJECTS_H
|
||||
/************************************************************************
|
||||
* file name : globals_qobjects.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/08/08
|
||||
* authors : Victor Zarubkin, Sergey Yagovtsev
|
||||
* email : v.s.zarubkin@gmail.com, yse.sey@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains declaration of EasyGlobalSignals QObject class.
|
||||
* ----------------- :
|
||||
* change log : * 2016/08/08 Sergey Yagovtsev: moved sources from globals.h
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY__GLOBALS_QOBJECTS_H___
|
||||
#define EASY__GLOBALS_QOBJECTS_H___
|
||||
|
||||
#include <QObject>
|
||||
#include "profiler/profiler.h"
|
||||
@ -27,4 +57,4 @@ namespace profiler_gui {
|
||||
|
||||
} // END of namespace profiler_gui.
|
||||
|
||||
#endif // GLOBALS_QOBJECTS_H
|
||||
#endif // EASY__GLOBALS_QOBJECTS_H___
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : graphics_scrollbar.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/07/04
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -12,7 +11,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
@ -28,7 +41,7 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const qreal SCALING_COEFFICIENT = 1.25;
|
||||
const qreal SCALING_COEFFICIENT_INV = 1.0 / SCALING_COEFFICIENT;
|
||||
//const qreal SCALING_COEFFICIENT_INV = 1.0 / SCALING_COEFFICIENT;
|
||||
const int DEFAULT_TOP = -40;
|
||||
const int DEFAULT_HEIGHT = 80;
|
||||
const int INDICATOR_SIZE = 8;
|
||||
@ -238,7 +251,7 @@ void EasyMinimapItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h)
|
||||
m_boundingRect.setRect(x, y, w, h);
|
||||
}
|
||||
|
||||
void EasyMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items)
|
||||
void EasyMinimapItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items)
|
||||
{
|
||||
m_pSource = _items;
|
||||
m_threadId = _thread_id;
|
||||
@ -428,7 +441,7 @@ void EasyGraphicsScrollbar::hideChrono()
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EasyGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items)
|
||||
void EasyGraphicsScrollbar::setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items)
|
||||
{
|
||||
m_minimap->setSource(_thread_id, _items);
|
||||
m_slider->setVisible(m_minimap->isVisible());
|
||||
@ -477,7 +490,6 @@ void EasyGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event)
|
||||
|
||||
void EasyGraphicsScrollbar::wheelEvent(QWheelEvent* _event)
|
||||
{
|
||||
qreal deltaSign = _event->delta() < 0 ? -1 : 1;
|
||||
auto w = m_slider->halfwidth() * (_event->delta() < 0 ? ::profiler_gui::SCALING_COEFFICIENT : ::profiler_gui::SCALING_COEFFICIENT_INV);
|
||||
setValue(mapToScene(_event->pos()).x() - m_minimumValue - w);
|
||||
emit wheeled(w * m_windowScale, _event->delta());
|
||||
@ -493,14 +505,14 @@ void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event)
|
||||
|
||||
void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
|
||||
{
|
||||
if (::profiler_gui::EASY_GLOBALS.profiler_blocks.empty())
|
||||
if (EASY_GLOBALS.profiler_blocks.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu menu;
|
||||
|
||||
for (const auto& it : ::profiler_gui::EASY_GLOBALS.profiler_blocks)
|
||||
for (const auto& it : EASY_GLOBALS.profiler_blocks)
|
||||
{
|
||||
QString label;
|
||||
if (it.second.thread_name && it.second.thread_name[0] != 0)
|
||||
@ -512,10 +524,11 @@ void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
|
||||
label = ::std::move(QString("Thread %1").arg(it.first));
|
||||
}
|
||||
|
||||
auto action = new EasyIdAction(label, it.first);
|
||||
auto action = new QAction(label, nullptr);
|
||||
action->setData(it.first);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(it.first == ::profiler_gui::EASY_GLOBALS.selected_thread);
|
||||
connect(action, &EasyIdAction::clicked, this, &This::onThreadActionClicked);
|
||||
action->setChecked(it.first == EASY_GLOBALS.selected_thread);
|
||||
connect(action, &QAction::triggered, this, &This::onThreadActionClicked);
|
||||
|
||||
menu.addAction(action);
|
||||
}
|
||||
@ -526,12 +539,17 @@ void EasyGraphicsScrollbar::contextMenuEvent(QContextMenuEvent* _event)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EasyGraphicsScrollbar::onThreadActionClicked(::profiler::thread_id_t _id)
|
||||
void EasyGraphicsScrollbar::onThreadActionClicked(bool)
|
||||
{
|
||||
if (_id != m_minimap->threadId())
|
||||
auto action = qobject_cast<QAction*>(sender());
|
||||
if (action == nullptr)
|
||||
return;
|
||||
|
||||
const auto thread_id = action->data().toUInt();
|
||||
if (thread_id != m_minimap->threadId())
|
||||
{
|
||||
::profiler_gui::EASY_GLOBALS.selected_thread = _id;
|
||||
emit ::profiler_gui::EASY_GLOBALS.events.selectedThreadChanged(_id);
|
||||
EASY_GLOBALS.selected_thread = thread_id;
|
||||
emit EASY_GLOBALS.events.selectedThreadChanged(thread_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,17 +2,30 @@
|
||||
* file name : graphics_scrollbar.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/07/04
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : .
|
||||
* description : This file contains declaration of
|
||||
* ----------------- :
|
||||
* change log : * 2016/07/04 Victor Zarubkin: Initial commit.
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY__GRAPHICS_SCROLLBAR__H
|
||||
@ -66,7 +79,7 @@ class EasyMinimapItem : public QGraphicsItem
|
||||
QRectF m_boundingRect;
|
||||
qreal m_maxDuration;
|
||||
qreal m_minDuration;
|
||||
const ::profiler_gui::ProfItems* m_pSource;
|
||||
const ::profiler_gui::EasyItems* m_pSource;
|
||||
::profiler::thread_id_t m_threadId;
|
||||
|
||||
public:
|
||||
@ -88,53 +101,12 @@ public:
|
||||
void setBoundingRect(const QRectF& _rect);
|
||||
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
|
||||
|
||||
void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems* _items);
|
||||
void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items);
|
||||
|
||||
}; // END of class EasyMinimapItem.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EasyIdAction : public QAction
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
|
||||
typedef QAction Parent;
|
||||
typedef EasyIdAction This;
|
||||
|
||||
::profiler::thread_id_t m_id;
|
||||
|
||||
public:
|
||||
|
||||
EasyIdAction(const QString& _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id)
|
||||
{
|
||||
connect(this, &Parent::triggered, this, &This::onToggle);
|
||||
}
|
||||
|
||||
EasyIdAction(const char* _label, ::profiler::thread_id_t _id) : Parent(_label, nullptr), m_id(_id)
|
||||
{
|
||||
connect(this, &Parent::triggered, this, &This::onToggle);
|
||||
}
|
||||
|
||||
virtual ~EasyIdAction()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void onToggle(bool)
|
||||
{
|
||||
emit clicked(m_id);
|
||||
}
|
||||
|
||||
signals:
|
||||
|
||||
void clicked(::profiler::thread_id_t _id);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EasyGraphicsScrollbar : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -190,9 +162,9 @@ public:
|
||||
void showChrono();
|
||||
void hideChrono();
|
||||
|
||||
void setMinimapFrom(::profiler::thread_id_t _thread_id, const::profiler_gui::ProfItems* _items);
|
||||
void setMinimapFrom(::profiler::thread_id_t _thread_id, const::profiler_gui::EasyItems* _items);
|
||||
|
||||
inline void setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::ProfItems& _items)
|
||||
inline void setMinimapFrom(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems& _items)
|
||||
{
|
||||
setMinimapFrom(_thread_id, &_items);
|
||||
}
|
||||
@ -205,7 +177,7 @@ signals:
|
||||
|
||||
private slots:
|
||||
|
||||
void onThreadActionClicked(::profiler::thread_id_t _id);
|
||||
void onThreadActionClicked(bool);
|
||||
void onWindowWidthChange(qreal _width);
|
||||
|
||||
}; // END of class EasyGraphicsScrollbar.
|
||||
|
@ -1,38 +1,65 @@
|
||||
#include <QApplication>
|
||||
#include <QTreeView>
|
||||
#include <QFileSystemModel>
|
||||
/************************************************************************
|
||||
* file name : main.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/04/29
|
||||
* authors : Sergey Yagovtsev, Victor Zarubkin
|
||||
* email : yse.sey@gmail.com, v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : Main file for EasyProfiler GUI.
|
||||
* ----------------- :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#include <chrono>
|
||||
#include <QApplication>
|
||||
//#include <QTreeView>
|
||||
//#include <QFileSystemModel>
|
||||
//#include "treemodel.h"
|
||||
#include "main_window.h"
|
||||
#include "profiler/reader.h"
|
||||
|
||||
//#ifdef WIN32
|
||||
|
||||
//#ifdef _WIN32
|
||||
//#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
|
||||
//#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QApplication app(argc, argv);
|
||||
|
||||
//QFileSystemModel *model = new QFileSystemModel;
|
||||
//model->setRootPath(QDir::currentPath());
|
||||
// const char* filename = 0;
|
||||
//QFileSystemModel *model = new QFileSystemModel;
|
||||
//model->setRootPath(QDir::currentPath());
|
||||
// const char* filename = 0;
|
||||
// if(argc > 1 && argv[1]){
|
||||
// filename = argv[1];
|
||||
// filename = argv[1];
|
||||
// }else{
|
||||
// return 255;
|
||||
// }
|
||||
// return 255;
|
||||
// }
|
||||
|
||||
// QFile file(filename);
|
||||
// file.open(QIODevice::ReadOnly);
|
||||
// file.open(QIODevice::ReadOnly);
|
||||
// TreeModel model(file.readAll());
|
||||
// file.close();
|
||||
// file.close();
|
||||
|
||||
|
||||
// QTreeView *tree = new QTreeView();
|
||||
// tree->setModel(&model);
|
||||
// QTreeView *tree = new QTreeView();
|
||||
// tree->setModel(&model);
|
||||
//
|
||||
// tree->show();
|
||||
// tree->show();
|
||||
|
||||
auto now = ::std::chrono::duration_cast<std::chrono::seconds>(::std::chrono::system_clock::now().time_since_epoch()).count() >> 1;
|
||||
srand((unsigned int)now);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,6 @@
|
||||
* file name : main_window.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/06/26
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -11,7 +10,21 @@
|
||||
* change log : * 2016/06/26 Victor Zarubkin: initial commit.
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY_PROFILER_GUI__MAIN_WINDOW__H
|
||||
@ -32,13 +45,16 @@ class QDockWidget;
|
||||
|
||||
class EasyFileReader final
|
||||
{
|
||||
::profiler::SerializedData m_serializedData; ///<
|
||||
::profiler::thread_blocks_tree_t m_blocksTree; ///<
|
||||
QString m_filename; ///<
|
||||
::std::thread m_thread; ///<
|
||||
::std::atomic_bool m_bDone; ///<
|
||||
::std::atomic<int> m_progress; ///<
|
||||
::std::atomic<unsigned int> m_size; ///<
|
||||
::profiler::SerializedData m_serializedBlocks; ///<
|
||||
::profiler::SerializedData m_serializedDescriptors; ///<
|
||||
::profiler::descriptors_list_t m_descriptors; ///<
|
||||
::profiler::blocks_t m_blocks; ///<
|
||||
::profiler::thread_blocks_tree_t m_blocksTree; ///<
|
||||
QString m_filename; ///<
|
||||
::std::thread m_thread; ///<
|
||||
::std::atomic_bool m_bDone; ///<
|
||||
::std::atomic<int> m_progress; ///<
|
||||
::std::atomic<unsigned int> m_size; ///<
|
||||
|
||||
public:
|
||||
|
||||
@ -52,7 +68,9 @@ public:
|
||||
|
||||
void load(const QString& _filename);
|
||||
void interrupt();
|
||||
void get(::profiler::SerializedData& _data, ::profiler::thread_blocks_tree_t& _tree, QString& _filename);
|
||||
void get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors,
|
||||
::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree,
|
||||
QString& _filename);
|
||||
|
||||
}; // END of class EasyFileReader.
|
||||
|
||||
@ -67,13 +85,14 @@ protected:
|
||||
typedef EasyMainWindow This;
|
||||
typedef QMainWindow Parent;
|
||||
|
||||
QString m_lastFile;
|
||||
QDockWidget* m_treeWidget;
|
||||
QDockWidget* m_graphicsView;
|
||||
class QProgressDialog* m_progress;
|
||||
QTimer m_readerTimer;
|
||||
::profiler::SerializedData m_serializedData;
|
||||
EasyFileReader m_reader;
|
||||
QString m_lastFile;
|
||||
QDockWidget* m_treeWidget;
|
||||
QDockWidget* m_graphicsView;
|
||||
class QProgressDialog* m_progress;
|
||||
QTimer m_readerTimer;
|
||||
::profiler::SerializedData m_serializedBlocks;
|
||||
::profiler::SerializedData m_serializedDescriptors;
|
||||
EasyFileReader m_reader;
|
||||
|
||||
public:
|
||||
|
||||
@ -108,7 +127,7 @@ private:
|
||||
|
||||
void loadSettings();
|
||||
void loadGeometry();
|
||||
void saveSettingsAndGeometry();
|
||||
void saveSettingsAndGeometry();
|
||||
|
||||
}; // END of class EasyMainWindow.
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : tree_widget_item.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/08/18
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -13,7 +12,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#include "tree_widget_item.h"
|
||||
@ -21,7 +34,7 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent)
|
||||
EasyTreeWidgetItem::EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock, Parent* _parent)
|
||||
: Parent(_parent)
|
||||
, m_block(_treeBlock)
|
||||
, m_customBGColor(0)
|
||||
@ -75,15 +88,25 @@ bool EasyTreeWidgetItem::operator < (const Parent& _other) const
|
||||
return false;
|
||||
}
|
||||
|
||||
const ::profiler::BlocksTree* EasyTreeWidgetItem::block() const
|
||||
::profiler::block_index_t EasyTreeWidgetItem::block_index() const
|
||||
{
|
||||
return m_block;
|
||||
}
|
||||
|
||||
::profiler_gui::EasyBlock& EasyTreeWidgetItem::guiBlock()
|
||||
{
|
||||
return easyBlock(m_block);
|
||||
}
|
||||
|
||||
const ::profiler::BlocksTree& EasyTreeWidgetItem::block() const
|
||||
{
|
||||
return blocksTree(m_block);
|
||||
}
|
||||
|
||||
::profiler::timestamp_t EasyTreeWidgetItem::duration() const
|
||||
{
|
||||
if (m_block->node)
|
||||
return m_block->node->block()->duration();
|
||||
if (parent() != nullptr)
|
||||
return block().node->duration();
|
||||
return data(COL_DURATION, Qt::UserRole).toULongLong();
|
||||
}
|
||||
|
||||
@ -173,7 +196,8 @@ void EasyTreeWidgetItem::collapseAll()
|
||||
}
|
||||
|
||||
setExpanded(false);
|
||||
::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = false;
|
||||
if (parent() != nullptr)
|
||||
guiBlock().expanded = false;
|
||||
}
|
||||
|
||||
void EasyTreeWidgetItem::expandAll()
|
||||
@ -184,7 +208,8 @@ void EasyTreeWidgetItem::expandAll()
|
||||
}
|
||||
|
||||
setExpanded(true);
|
||||
::profiler_gui::EASY_GLOBALS.gui_blocks[m_block->block_index].expanded = true;
|
||||
if (parent() != nullptr)
|
||||
guiBlock().expanded = true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2,7 +2,6 @@
|
||||
* file name : tree_widget_item.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/08/18
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -14,7 +13,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY__TREE_WIDGET_ITEM__H_
|
||||
@ -75,7 +88,7 @@ class EasyTreeWidgetItem : public QTreeWidgetItem
|
||||
typedef QTreeWidgetItem Parent;
|
||||
typedef EasyTreeWidgetItem This;
|
||||
|
||||
const ::profiler::BlocksTree* m_block;
|
||||
const ::profiler::block_index_t m_block;
|
||||
QRgb m_customBGColor;
|
||||
QRgb m_customTextColor;
|
||||
|
||||
@ -84,14 +97,16 @@ public:
|
||||
using Parent::setBackgroundColor;
|
||||
using Parent::setTextColor;
|
||||
|
||||
EasyTreeWidgetItem(const ::profiler::BlocksTree* _treeBlock, Parent* _parent = nullptr);
|
||||
EasyTreeWidgetItem(const ::profiler::block_index_t _treeBlock = ::profiler_gui::numeric_max<decltype(m_block)>(), Parent* _parent = nullptr);
|
||||
virtual ~EasyTreeWidgetItem();
|
||||
|
||||
bool operator < (const Parent& _other) const override;
|
||||
|
||||
public:
|
||||
|
||||
const ::profiler::BlocksTree* block() const;
|
||||
::profiler::block_index_t block_index() const;
|
||||
::profiler_gui::EasyBlock& guiBlock();
|
||||
const ::profiler::BlocksTree& block() const;
|
||||
|
||||
::profiler::timestamp_t duration() const;
|
||||
::profiler::timestamp_t selfDuration() const;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,6 @@
|
||||
* file name : tree_widget_loader.h
|
||||
* ----------------- :
|
||||
* creation time : 2016/08/18
|
||||
* copyright : (c) 2016 Victor Zarubkin
|
||||
* author : Victor Zarubkin
|
||||
* email : v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
@ -14,7 +13,21 @@
|
||||
* :
|
||||
* : *
|
||||
* ----------------- :
|
||||
* license : TODO: add license text
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
|
||||
#ifndef EASY__TREE_WIDGET_LOADER__H_
|
||||
|
@ -1,17 +1,17 @@
|
||||
project(profiler_reader)
|
||||
|
||||
set(CPP_FILES
|
||||
main.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
${CPP_FILES}
|
||||
${CPP_FILES}
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
|
||||
if(UNIX)
|
||||
set(SPEC_LIB pthread)
|
||||
set(SPEC_LIB pthread)
|
||||
endif(UNIX)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} easy_profiler ${SPEC_LIB})
|
||||
|
@ -16,57 +16,57 @@
|
||||
|
||||
class TreePrinter
|
||||
{
|
||||
struct Info{
|
||||
std::string name;
|
||||
std::string info;
|
||||
};
|
||||
std::vector<Info> m_rows;
|
||||
struct Info{
|
||||
std::string name;
|
||||
std::string info;
|
||||
};
|
||||
std::vector<Info> m_rows;
|
||||
|
||||
public:
|
||||
TreePrinter(){
|
||||
TreePrinter(){
|
||||
|
||||
}
|
||||
void addNewRow(int level)
|
||||
{
|
||||
}
|
||||
void addNewRow(int level)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void printTree()
|
||||
{
|
||||
for (auto& row : m_rows){
|
||||
std::cout << row.name << " " << row.info << std::endl;
|
||||
}
|
||||
}
|
||||
void printTree()
|
||||
{
|
||||
for (auto& row : m_rows){
|
||||
std::cout << row.name << " " << row.info << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void printTree(TreePrinter& printer, const ::profiler::BlocksTree& tree, int level = 0, profiler::timestamp_t parent_dur = 0, profiler::timestamp_t root_dur = 0)
|
||||
{
|
||||
|
||||
if (tree.node){
|
||||
auto duration = tree.node->block()->duration();
|
||||
float duration_ms = duration / 1e6f;
|
||||
float percent = parent_dur ? float(duration) / float(parent_dur)*100.0f : 100.0f;
|
||||
float rpercent = root_dur ? float(duration) / float(root_dur)*100.0f : 100.0f;
|
||||
std::cout << std::string(level, '\t') << tree.node->getName()
|
||||
<< std::string(5 - level, '\t')
|
||||
/*<< std::string(level, ' ')*/ << percent << "%| "
|
||||
<< rpercent << "%| "
|
||||
<< duration_ms << " ms"
|
||||
<< std::endl;
|
||||
if (root_dur == 0){
|
||||
root_dur = tree.node->block()->duration();
|
||||
}
|
||||
}
|
||||
else{
|
||||
root_dur = 0;
|
||||
}
|
||||
|
||||
//
|
||||
//if (tree.node){
|
||||
// auto duration = tree.node->block()->duration();
|
||||
// float duration_ms = duration / 1e6f;
|
||||
// float percent = parent_dur ? float(duration) / float(parent_dur)*100.0f : 100.0f;
|
||||
// float rpercent = root_dur ? float(duration) / float(root_dur)*100.0f : 100.0f;
|
||||
// std::cout << std::string(level, '\t') << tree.node->getName()
|
||||
// << std::string(5 - level, '\t')
|
||||
// /*<< std::string(level, ' ')*/ << percent << "%| "
|
||||
// << rpercent << "%| "
|
||||
// << duration_ms << " ms"
|
||||
// << std::endl;
|
||||
// if (root_dur == 0){
|
||||
// root_dur = tree.node->block()->duration();
|
||||
// }
|
||||
//}
|
||||
//else{
|
||||
// root_dur = 0;
|
||||
//}
|
||||
//
|
||||
|
||||
for (const auto& i : tree.children){
|
||||
//for (const auto& i : tree.children){
|
||||
|
||||
printTree(printer, i, level + 1, tree.node ? tree.node->block()->duration() : 0, root_dur);
|
||||
}
|
||||
// printTree(printer, i, level + 1, tree.node ? tree.node->block()->duration() : 0, root_dur);
|
||||
//}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@ -99,7 +99,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
if (dump_filename.size() > 2)
|
||||
{
|
||||
PROFILER_ENABLE
|
||||
EASY_PROFILER_ENABLE;
|
||||
std::cout << "Will dump reader prof file to " << dump_filename << std::endl;
|
||||
}
|
||||
else
|
||||
@ -110,17 +110,19 @@ int main(int argc, char* argv[])
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
::profiler::SerializedData data;
|
||||
auto blocks_counter = fillTreesFromFile(filename.c_str(), data, threaded_trees, true);
|
||||
::profiler::SerializedData serialized_blocks, serialized_descriptors;
|
||||
::profiler::descriptors_list_t descriptors;
|
||||
::profiler::blocks_t blocks;
|
||||
auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, true);
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
|
||||
std::cout << "Blocks count: " << blocks_counter << std::endl;
|
||||
std::cout << "dT = " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << " usec" << std::endl;
|
||||
//for (const auto & i : threaded_trees){
|
||||
// TreePrinter p;
|
||||
// std::cout << std::string(20, '=') << " thread "<< i.first << " "<< std::string(20, '=') << std::endl;
|
||||
// printTree(p, i.second.tree,-1);
|
||||
// TreePrinter p;
|
||||
// std::cout << std::string(20, '=') << " thread "<< i.first << " "<< std::string(20, '=') << std::endl;
|
||||
// printTree(p, i.second.tree,-1);
|
||||
//}
|
||||
|
||||
if (!dump_filename.empty())
|
||||
|
@ -1,22 +1,22 @@
|
||||
project(profiler_sample)
|
||||
|
||||
set(CPP_FILES
|
||||
main.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
${CPP_FILES}
|
||||
${CPP_FILES}
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
|
||||
set(DISABLED_PROFILER_NAME
|
||||
"${PROJECT_NAME}_disabled_profiler"
|
||||
"${PROJECT_NAME}_disabled_profiler"
|
||||
)
|
||||
add_executable(${DISABLED_PROFILER_NAME} ${SOURCES})
|
||||
|
||||
if(UNIX)
|
||||
set(SPEC_LIB pthread)
|
||||
set(SPEC_LIB pthread)
|
||||
endif(UNIX)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} easy_profiler ${SPEC_LIB})
|
||||
|
237
sample/main.cpp
237
sample/main.cpp
@ -26,22 +26,22 @@ void localSleep(int magic=200000)
|
||||
}
|
||||
|
||||
void loadingResources(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkcyan);
|
||||
EASY_FUNCTION(profiler::colors::DarkCyan);
|
||||
localSleep();
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
void prepareMath(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
|
||||
EASY_FUNCTION(profiler::colors::Blue);
|
||||
int* intarray = new int[OBJECTS];
|
||||
for (int i = 0; i < OBJECTS; ++i)
|
||||
intarray[i] = i * i;
|
||||
delete[] intarray;
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
|
||||
}
|
||||
|
||||
void calcIntersect(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
|
||||
EASY_FUNCTION(profiler::colors::Blue);
|
||||
//int* intarray = new int[OBJECTS * OBJECTS];
|
||||
int* intarray = new int[OBJECTS];
|
||||
for (int i = 0; i < OBJECTS; ++i)
|
||||
@ -51,17 +51,17 @@ void calcIntersect(){
|
||||
intarray[j] = i * j - i / 2 + (OBJECTS - j) * 5;
|
||||
}
|
||||
delete[] intarray;
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(4));
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(4));
|
||||
}
|
||||
|
||||
double multModel(double i)
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
|
||||
EASY_FUNCTION(profiler::colors::Blue);
|
||||
return i * sin(i) * cos(i);
|
||||
}
|
||||
|
||||
void calcPhys(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
|
||||
EASY_FUNCTION(profiler::colors::Blue);
|
||||
double* intarray = new double[OBJECTS];
|
||||
for (int i = 0; i < OBJECTS; ++i)
|
||||
intarray[i] = multModel(double(i)) + double(i / 3) - double((OBJECTS - i) / 2);
|
||||
@ -71,213 +71,218 @@ void calcPhys(){
|
||||
|
||||
double calcSubbrain(int i)
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
|
||||
EASY_FUNCTION(profiler::colors::Blue);
|
||||
return i * i * i - i / 10 + (OBJECTS - i) * 7 ;
|
||||
}
|
||||
|
||||
void calcBrain(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
|
||||
EASY_FUNCTION(profiler::colors::Blue);
|
||||
double* intarray = new double[OBJECTS];
|
||||
for (int i = 0; i < OBJECTS; ++i)
|
||||
intarray[i] = calcSubbrain(i) + double(i * 180 / 3);
|
||||
delete[] intarray;
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(3));
|
||||
}
|
||||
|
||||
void calculateBehavior(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkblue);
|
||||
EASY_FUNCTION(profiler::colors::DarkBlue);
|
||||
calcPhys();
|
||||
calcBrain();
|
||||
}
|
||||
|
||||
void modellingStep(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Navy);
|
||||
prepareMath();
|
||||
calculateBehavior();
|
||||
EASY_FUNCTION(profiler::colors::Navy);
|
||||
prepareMath();
|
||||
calculateBehavior();
|
||||
}
|
||||
|
||||
void prepareRender(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Darkred);
|
||||
EASY_FUNCTION(profiler::colors::DarkRed);
|
||||
localSleep();
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
|
||||
|
||||
}
|
||||
|
||||
int multPhys(int i)
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
return i * i * i * i / 100;
|
||||
}
|
||||
|
||||
int calcPhysicForObject(int i)
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
return multPhys(i) + i / 3 - (OBJECTS - i) * 15;
|
||||
}
|
||||
|
||||
void calculatePhysics(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
unsigned int* intarray = new unsigned int[OBJECTS];
|
||||
for (int i = 0; i < OBJECTS; ++i)
|
||||
intarray[i] = calcPhysicForObject(i);
|
||||
delete[] intarray;
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(8));
|
||||
}
|
||||
|
||||
void frame(){
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Magenta);
|
||||
prepareRender();
|
||||
calculatePhysics();
|
||||
EASY_FUNCTION(profiler::colors::Magenta);
|
||||
prepareRender();
|
||||
calculatePhysics();
|
||||
}
|
||||
|
||||
void loadingResourcesThread(){
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
PROFILER_SET_THREAD_NAME("Resource loading")
|
||||
for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){
|
||||
loadingResources();
|
||||
PROFILER_ADD_EVENT_GROUPED("Resources Loading!",profiler::colors::Cyan);
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
EASY_THREAD("Resource loading");
|
||||
for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){
|
||||
loadingResources();
|
||||
EASY_EVENT("Resources Loading!", profiler::colors::Cyan);
|
||||
localSleep(1200000);
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void modellingThread(){
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
PROFILER_SET_THREAD_NAME("Modelling")
|
||||
for (int i = 0; i < RENDER_SPEPS; i++){
|
||||
modellingStep();
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
EASY_THREAD("Modelling");
|
||||
for (int i = 0; i < RENDER_SPEPS; i++){
|
||||
modellingStep();
|
||||
localSleep(1200000);
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderThread(){
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
PROFILER_SET_THREAD_NAME("Render")
|
||||
for (int i = 0; i < MODELLING_STEPS; i++){
|
||||
frame();
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
EASY_THREAD("Render");
|
||||
for (int i = 0; i < MODELLING_STEPS; i++){
|
||||
frame();
|
||||
localSleep(1200000);
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void four()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(37));
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(37));
|
||||
}
|
||||
|
||||
void five()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
void six()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(42));
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(42));
|
||||
}
|
||||
|
||||
void three()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
four();
|
||||
five();
|
||||
six();
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
four();
|
||||
five();
|
||||
six();
|
||||
}
|
||||
|
||||
void seven()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(147));
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(147));
|
||||
}
|
||||
|
||||
void two()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(26));
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(26));
|
||||
}
|
||||
|
||||
void one()
|
||||
{
|
||||
PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Red);
|
||||
two();
|
||||
three();
|
||||
seven();
|
||||
EASY_FUNCTION(profiler::colors::Red);
|
||||
two();
|
||||
three();
|
||||
seven();
|
||||
}
|
||||
|
||||
/*
|
||||
one
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
*/
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc > 1 && argv[1]){
|
||||
OBJECTS = std::atoi(argv[1]);
|
||||
}
|
||||
if (argc > 2 && argv[2]){
|
||||
RENDER_SPEPS = std::atoi(argv[2]);
|
||||
}
|
||||
if (argc > 3 && argv[3]){
|
||||
MODELLING_STEPS = std::atoi(argv[3]);
|
||||
}
|
||||
if (argc > 4 && argv[4]){
|
||||
RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
|
||||
}
|
||||
if (argc > 1 && argv[1]){
|
||||
OBJECTS = std::atoi(argv[1]);
|
||||
}
|
||||
if (argc > 2 && argv[2]){
|
||||
RENDER_SPEPS = std::atoi(argv[2]);
|
||||
}
|
||||
if (argc > 3 && argv[3]){
|
||||
MODELLING_STEPS = std::atoi(argv[3]);
|
||||
}
|
||||
if (argc > 4 && argv[4]){
|
||||
RESOURCE_LOADING_COUNT = std::atoi(argv[4]);
|
||||
}
|
||||
|
||||
std::cout << "Objects count: " << OBJECTS << std::endl;
|
||||
std::cout << "Render steps: " << RENDER_SPEPS << std::endl;
|
||||
std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl;
|
||||
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
|
||||
std::cout << "Objects count: " << OBJECTS << std::endl;
|
||||
std::cout << "Render steps: " << RENDER_SPEPS << std::endl;
|
||||
std::cout << "Modelling steps: " << MODELLING_STEPS << std::endl;
|
||||
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
PROFILER_ENABLE;
|
||||
PROFILER_SET_MAIN_THREAD;
|
||||
//one();
|
||||
//one();
|
||||
/**/
|
||||
std::vector<std::thread> threads;
|
||||
auto start = std::chrono::system_clock::now();
|
||||
EASY_PROFILER_ENABLE;
|
||||
EASY_MAIN_THREAD;
|
||||
//one();
|
||||
//one();
|
||||
/**/
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
std::thread render = std::thread(renderThread);
|
||||
std::thread modelling = std::thread(modellingThread);
|
||||
std::thread render = std::thread(renderThread);
|
||||
std::thread modelling = std::thread(modellingThread);
|
||||
|
||||
|
||||
for(int i=0; i < 3; i++){
|
||||
threads.emplace_back(std::thread(loadingResourcesThread));
|
||||
threads.emplace_back(std::thread(renderThread));
|
||||
threads.emplace_back(std::thread(modellingThread));
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
g_i = 1;
|
||||
}
|
||||
cv.notify_all();
|
||||
|
||||
for(int i=0; i < 3; i++){
|
||||
threads.emplace_back(std::thread(loadingResourcesThread));
|
||||
threads.emplace_back(std::thread(renderThread));
|
||||
threads.emplace_back(std::thread(modellingThread));
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(cv_m);
|
||||
g_i = 1;
|
||||
}
|
||||
cv.notify_all();
|
||||
|
||||
render.join();
|
||||
modelling.join();
|
||||
for(auto& t : threads){
|
||||
t.join();
|
||||
}
|
||||
/**/
|
||||
for (int i = 0; i < RENDER_SPEPS; ++i) {
|
||||
modellingStep();
|
||||
localSleep(1200000);
|
||||
}
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
auto elapsed =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
render.join();
|
||||
modelling.join();
|
||||
for(auto& t : threads){
|
||||
t.join();
|
||||
}
|
||||
/**/
|
||||
|
||||
std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl;
|
||||
auto end = std::chrono::system_clock::now();
|
||||
auto elapsed =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
|
||||
auto blocks_count = profiler::dumpBlocksToFile("test.prof");
|
||||
std::cout << "Elapsed time: " << elapsed.count() << " usec" << std::endl;
|
||||
|
||||
std::cout << "Blocks count: " << blocks_count << std::endl;
|
||||
auto blocks_count = profiler::dumpBlocksToFile("test.prof");
|
||||
|
||||
return 0;
|
||||
std::cout << "Blocks count: " << blocks_count << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
36
scripts/context_switch_logger.stp
Normal file
36
scripts/context_switch_logger.stp
Normal 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
|
||||
%)
|
||||
}
|
@ -1,24 +1,27 @@
|
||||
project(easy_profiler)
|
||||
|
||||
set(CPP_FILES
|
||||
block.cpp
|
||||
profile_manager.cpp
|
||||
reader.cpp
|
||||
block.cpp
|
||||
profile_manager.cpp
|
||||
reader.cpp
|
||||
event_trace_win.cpp
|
||||
)
|
||||
|
||||
set(H_FILES
|
||||
${ROOT}/include/profiler/profiler.h
|
||||
${ROOT}/include/profiler/reader.h
|
||||
profile_manager.h
|
||||
spin_lock.h
|
||||
${ROOT}/include/profiler/profiler.h
|
||||
${ROOT}/include/profiler/reader.h
|
||||
${ROOT}/include/profiler/event_trace_status.h
|
||||
profile_manager.h
|
||||
spin_lock.h
|
||||
event_trace_win.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
${CPP_FILES}
|
||||
${H_FILES}
|
||||
${CPP_FILES}
|
||||
${H_FILES}
|
||||
)
|
||||
add_definitions(
|
||||
-D_BUILD_PROFILER
|
||||
-D_BUILD_PROFILER
|
||||
)
|
||||
add_library(${PROJECT_NAME} SHARED ${SOURCES})
|
||||
|
||||
|
133
src/block.cpp
133
src/block.cpp
@ -1,3 +1,28 @@
|
||||
/************************************************************************
|
||||
* file name : block.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/02/16
|
||||
* authors : Sergey Yagovtsev, Victor Zarubkin
|
||||
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of profiling blocks
|
||||
* :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
#include "profiler/profiler.h"
|
||||
#include "profile_manager.h"
|
||||
#include <ctime>
|
||||
@ -6,73 +31,69 @@
|
||||
|
||||
using namespace profiler;
|
||||
|
||||
#ifdef WIN32
|
||||
struct ProfPerformanceFrequency {
|
||||
LARGE_INTEGER frequency;
|
||||
ProfPerformanceFrequency() { QueryPerformanceFrequency(&frequency); }
|
||||
} const WINDOWS_CPU_INFO;
|
||||
#ifdef _WIN32
|
||||
decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY = ([](){ LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); return freq.QuadPart; })();
|
||||
#endif
|
||||
|
||||
BaseBlockData::BaseBlockData(source_id_t _source_id, color_t _color, block_type_t _type, thread_id_t _thread_id)
|
||||
: begin(0)
|
||||
, end(0)
|
||||
, thread_id(_thread_id)
|
||||
#ifndef EASY_USE_OLD_FILE_FORMAT
|
||||
, source_id(_source_id)
|
||||
#endif
|
||||
, type(_type)
|
||||
, color(_color)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Block::Block(const char* _name, color_t _color, block_type_t _type, source_id_t _source_id)
|
||||
: Block(_name, getCurrentThreadId(), _color, _type, _source_id)
|
||||
{
|
||||
}
|
||||
|
||||
Block::Block(const char* _name, thread_id_t _thread_id, color_t _color, block_type_t _type, source_id_t _source_id)
|
||||
: BaseBlockData(_source_id, _color, _type, _thread_id)
|
||||
, m_name(_name)
|
||||
{
|
||||
tick(begin);
|
||||
if (BLOCK_TYPE_BLOCK != this->type)
|
||||
{
|
||||
end = begin;
|
||||
}
|
||||
}
|
||||
|
||||
inline timestamp_t getCurrentTime()
|
||||
{
|
||||
#ifdef WIN32
|
||||
//see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx
|
||||
LARGE_INTEGER elapsedMicroseconds;
|
||||
if (!QueryPerformanceCounter(&elapsedMicroseconds))
|
||||
return 0;
|
||||
elapsedMicroseconds.QuadPart *= 1000000000LL;
|
||||
elapsedMicroseconds.QuadPart /= WINDOWS_CPU_INFO.frequency.QuadPart;
|
||||
return (timestamp_t)elapsedMicroseconds.QuadPart;
|
||||
#ifdef _WIN32
|
||||
//see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx
|
||||
LARGE_INTEGER elapsedMicroseconds;
|
||||
if (!QueryPerformanceCounter(&elapsedMicroseconds))
|
||||
return 0;
|
||||
//elapsedMicroseconds.QuadPart *= 1000000000LL;
|
||||
//elapsedMicroseconds.QuadPart /= CPU_FREQUENCY;
|
||||
return (timestamp_t)elapsedMicroseconds.QuadPart;
|
||||
#else
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time_point;
|
||||
time_point = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now());
|
||||
return time_point.time_since_epoch().count();
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time_point;
|
||||
time_point = std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now());
|
||||
return time_point.time_since_epoch().count();
|
||||
#endif
|
||||
}
|
||||
|
||||
void BaseBlockData::tick(timestamp_t& stamp)
|
||||
BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id)
|
||||
: m_begin(_begin_time)
|
||||
, m_end(0)
|
||||
, m_id(_descriptor_id)
|
||||
{
|
||||
stamp = getCurrentTime();
|
||||
|
||||
}
|
||||
|
||||
Block::Block(Block&& that)
|
||||
: BaseBlockData(that.m_begin, that.m_id)
|
||||
, m_name(that.m_name)
|
||||
{
|
||||
m_end = that.m_end;
|
||||
}
|
||||
|
||||
Block::Block(block_type_t _block_type, block_id_t _descriptor_id, const char* _name)
|
||||
: Block(getCurrentTime(), _block_type, _descriptor_id, _name)
|
||||
{
|
||||
}
|
||||
|
||||
Block::Block(timestamp_t _begin_time, block_type_t _block_type, block_id_t _descriptor_id, const char* _name)
|
||||
: BaseBlockData(_begin_time, _descriptor_id)
|
||||
, m_name(_name)
|
||||
{
|
||||
if (static_cast<uint8_t>(_block_type) < BLOCK_TYPE_BLOCK)
|
||||
{
|
||||
m_end = m_begin;
|
||||
}
|
||||
}
|
||||
|
||||
void Block::finish()
|
||||
{
|
||||
m_end = getCurrentTime();
|
||||
}
|
||||
|
||||
void Block::finish(timestamp_t _end_time)
|
||||
{
|
||||
m_end = _end_time;
|
||||
}
|
||||
|
||||
Block::~Block()
|
||||
{
|
||||
if (this->type == BLOCK_TYPE_BLOCK)
|
||||
{
|
||||
if (this->isCleared())//this block was cleared by END_BLOCK macros
|
||||
return;
|
||||
if (!this->isFinished())
|
||||
this->finish();
|
||||
|
||||
endBlock();
|
||||
}
|
||||
if (!isFinished())
|
||||
::profiler::endBlock();
|
||||
}
|
||||
|
177
src/event_trace_win.cpp
Normal file
177
src/event_trace_win.cpp
Normal 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
66
src/event_trace_win.h
Normal 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_
|
@ -1,190 +1,420 @@
|
||||
#include "profile_manager.h"
|
||||
|
||||
#include <thread>
|
||||
#include <string.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using namespace profiler;
|
||||
|
||||
auto& MANAGER = ProfileManager::instance();
|
||||
|
||||
extern "C"{
|
||||
|
||||
void PROFILER_API endBlock()
|
||||
{
|
||||
MANAGER.endBlock();
|
||||
}
|
||||
|
||||
void PROFILER_API setEnabled(bool isEnable)
|
||||
{
|
||||
MANAGER.setEnabled(isEnable);
|
||||
}
|
||||
void PROFILER_API beginBlock(Block& _block)
|
||||
{
|
||||
MANAGER.beginBlock(_block);
|
||||
}
|
||||
|
||||
unsigned int PROFILER_API dumpBlocksToFile(const char* filename)
|
||||
{
|
||||
return MANAGER.dumpBlocksToFile(filename);
|
||||
}
|
||||
|
||||
void PROFILER_API setThreadName(const char* name)
|
||||
{
|
||||
return MANAGER.setThreadName(name);
|
||||
}
|
||||
}
|
||||
|
||||
SerializedBlock* SerializedBlock::create(const Block& block, uint64_t& memory_size)
|
||||
{
|
||||
auto name_length = static_cast<uint16_t>(strlen(block.getName()));
|
||||
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
|
||||
auto data = ::new char[size];
|
||||
::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
|
||||
memory_size += size;
|
||||
return reinterpret_cast<SerializedBlock*>(data);
|
||||
}
|
||||
|
||||
void SerializedBlock::destroy(SerializedBlock* that)
|
||||
{
|
||||
::delete[] reinterpret_cast<char*>(that);
|
||||
}
|
||||
|
||||
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
|
||||
: BaseBlockData(block)
|
||||
{
|
||||
auto name = const_cast<char*>(getName());
|
||||
strncpy(name, block.getName(), name_length);
|
||||
name[name_length] = 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BlockSourceInfo::BlockSourceInfo(const char* _filename, int _linenumber) : m_id(MANAGER.addSource(_filename, _linenumber))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SourceBlock::SourceBlock(const char* _filename, int _line) : m_filename(_filename), m_line(_line)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ProfileManager::ProfileManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ProfileManager::~ProfileManager()
|
||||
{
|
||||
//dumpBlocksToFile("test.prof");
|
||||
}
|
||||
|
||||
ProfileManager& ProfileManager::instance()
|
||||
{
|
||||
///C++11 makes possible to create Singleton without any warry about thread-safeness
|
||||
///http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
||||
static ProfileManager m_profileManager;
|
||||
return m_profileManager;
|
||||
}
|
||||
|
||||
void ProfileManager::beginBlock(Block& _block)
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
|
||||
if (BLOCK_TYPE_BLOCK == _block.getType()){
|
||||
guard_lock_t lock(m_spin);
|
||||
m_openedBracketsMap[_block.getThreadId()].emplace(_block);
|
||||
}
|
||||
else{
|
||||
_internalInsertBlock(_block);
|
||||
}
|
||||
|
||||
}
|
||||
void ProfileManager::endBlock()
|
||||
{
|
||||
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
|
||||
uint32_t threadId = getCurrentThreadId();
|
||||
|
||||
guard_lock_t lock(m_spin);
|
||||
auto& stackOfOpenedBlocks = m_openedBracketsMap[threadId];
|
||||
|
||||
if (stackOfOpenedBlocks.empty())
|
||||
return;
|
||||
|
||||
Block& lastBlock = stackOfOpenedBlocks.top();
|
||||
if(!lastBlock.isFinished())
|
||||
lastBlock.finish();
|
||||
_internalInsertBlock(lastBlock);
|
||||
|
||||
stackOfOpenedBlocks.pop();
|
||||
}
|
||||
|
||||
void ProfileManager::setEnabled(bool isEnable)
|
||||
{
|
||||
m_isEnabled = isEnable;
|
||||
}
|
||||
|
||||
void ProfileManager::_internalInsertBlock(const profiler::Block& _block)
|
||||
{
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
m_blocks.emplace_back(SerializedBlock::create(_block, m_blocksMemorySize));
|
||||
}
|
||||
|
||||
unsigned int ProfileManager::dumpBlocksToFile(const char* filename)
|
||||
{
|
||||
::std::ofstream of(filename, std::fstream::binary);
|
||||
|
||||
auto blocks_number = static_cast<uint32_t>(m_blocks.size());
|
||||
//of.write((const char*)&blocks_number, sizeof(uint32_t));
|
||||
of.write((const char*)&m_blocksMemorySize, sizeof(uint64_t));
|
||||
|
||||
for (auto b : m_blocks)
|
||||
{
|
||||
auto sz = static_cast<uint16_t>(sizeof(BaseBlockData) + strlen(b->getName()) + 1);
|
||||
|
||||
of.write((const char*)&sz, sizeof(uint16_t));
|
||||
of.write(b->data(), sz);
|
||||
|
||||
SerializedBlock::destroy(b);
|
||||
}
|
||||
|
||||
m_blocksMemorySize = 0;
|
||||
m_blocks.clear();
|
||||
|
||||
return blocks_number;
|
||||
}
|
||||
|
||||
void ProfileManager::setThreadName(const char* name)
|
||||
{
|
||||
auto current_thread_id = getCurrentThreadId();
|
||||
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
auto find_it = m_namedThreades.find(current_thread_id);
|
||||
if (find_it != m_namedThreades.end())
|
||||
return;
|
||||
|
||||
profiler::Block block(name, current_thread_id, 0, profiler::BLOCK_TYPE_THREAD_SIGN);
|
||||
m_blocks.emplace_back(SerializedBlock::create(block, m_blocksMemorySize));
|
||||
m_namedThreades.insert(current_thread_id);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int ProfileManager::addSource(const char* _filename, int _line)
|
||||
{
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
const auto id = static_cast<unsigned int>(m_sources.size());
|
||||
m_sources.emplace_back(_filename, _line);
|
||||
return id;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/************************************************************************
|
||||
* file name : profile_manager.cpp
|
||||
* ----------------- :
|
||||
* creation time : 2016/02/16
|
||||
* authors : Sergey Yagovtsev, Victor Zarubkin
|
||||
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
|
||||
* ----------------- :
|
||||
* description : The file contains implementation of Profile manager and implement access c-function
|
||||
* :
|
||||
* license : Lightweight profiler library for c++
|
||||
* : Copyright(C) 2016 Sergey Yagovtsev, Victor Zarubkin
|
||||
* :
|
||||
* : This program is free software : you can redistribute it and / or modify
|
||||
* : it under the terms of the GNU General Public License as published by
|
||||
* : the Free Software Foundation, either version 3 of the License, or
|
||||
* : (at your option) any later version.
|
||||
* :
|
||||
* : This program is distributed in the hope that it will be useful,
|
||||
* : but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* : GNU General Public License for more details.
|
||||
* :
|
||||
* : You should have received a copy of the GNU General Public License
|
||||
* : along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
************************************************************************/
|
||||
#include "profile_manager.h"
|
||||
#include "profiler/serialized_block.h"
|
||||
#include "event_trace_win.h"
|
||||
|
||||
#include <thread>
|
||||
#include <string.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using namespace profiler;
|
||||
|
||||
#ifdef _WIN32
|
||||
extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY;
|
||||
#endif
|
||||
|
||||
//auto& MANAGER = ProfileManager::instance();
|
||||
#define MANAGER ProfileManager::instance()
|
||||
|
||||
extern "C" {
|
||||
|
||||
PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
|
||||
{
|
||||
return MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color);
|
||||
}
|
||||
|
||||
PROFILER_API void endBlock()
|
||||
{
|
||||
MANAGER.endBlock();
|
||||
}
|
||||
|
||||
PROFILER_API void setEnabled(bool isEnable)
|
||||
{
|
||||
MANAGER.setEnabled(isEnable);
|
||||
#ifdef _WIN32
|
||||
if (isEnable)
|
||||
EasyEventTracer::instance().enable(true);
|
||||
else
|
||||
EasyEventTracer::instance().disable();
|
||||
#endif
|
||||
}
|
||||
|
||||
PROFILER_API void beginBlock(Block& _block)
|
||||
{
|
||||
MANAGER.beginBlock(_block);
|
||||
}
|
||||
|
||||
PROFILER_API uint32_t dumpBlocksToFile(const char* filename)
|
||||
{
|
||||
return MANAGER.dumpBlocksToFile(filename);
|
||||
}
|
||||
|
||||
PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line)
|
||||
{
|
||||
return MANAGER.setThreadName(name, filename, _funcname, line);
|
||||
}
|
||||
|
||||
PROFILER_API void setContextSwitchLogFilename(const char* name)
|
||||
{
|
||||
return MANAGER.setContextSwitchLogFilename(name);
|
||||
}
|
||||
|
||||
PROFILER_API const char* getContextSwitchLogFilename()
|
||||
{
|
||||
return MANAGER.getContextSwitchLogFilename();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
|
||||
: BaseBlockData(block)
|
||||
{
|
||||
auto pName = const_cast<char*>(name());
|
||||
if (name_length) strncpy(pName, block.name(), name_length);
|
||||
pName[name_length] = 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color)
|
||||
: m_line(_line)
|
||||
, m_type(_block_type)
|
||||
, m_color(_color)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BlockDescriptor::BlockDescriptor(uint64_t& _used_mem, const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color)
|
||||
: BaseBlockDescriptor(_line, _block_type, _color)
|
||||
, m_name(_name)
|
||||
, m_filename(_filename)
|
||||
{
|
||||
_used_mem += sizeof(profiler::SerializedBlockDescriptor) + strlen(_name) + strlen(_filename) + 2;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||
{
|
||||
auto name_length = static_cast<uint16_t>(strlen(block.name()));
|
||||
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
|
||||
auto data = blocks.alloc.allocate(size);
|
||||
::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
|
||||
blocks.usedMemorySize += size;
|
||||
blocks.closedList.emplace_back(reinterpret_cast<SerializedBlock*>(data));
|
||||
}
|
||||
|
||||
void ThreadStorage::storeCSwitch(const profiler::Block& block)
|
||||
{
|
||||
auto name_length = static_cast<uint16_t>(strlen(block.name()));
|
||||
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 1);
|
||||
auto data = sync.alloc.allocate(size);
|
||||
::new (static_cast<void*>(data)) SerializedBlock(block, name_length);
|
||||
sync.usedMemorySize += size;
|
||||
sync.closedList.emplace_back(reinterpret_cast<SerializedBlock*>(data));
|
||||
}
|
||||
|
||||
void ThreadStorage::clearClosed()
|
||||
{
|
||||
blocks.clearClosed();
|
||||
sync.clearClosed();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr;
|
||||
|
||||
// #ifdef _WIN32
|
||||
// LPTOP_LEVEL_EXCEPTION_FILTER PREVIOUS_FILTER = NULL;
|
||||
// LONG WINAPI easyTopLevelExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
|
||||
// {
|
||||
// std::ofstream testexp("TEST_EXP.txt", std::fstream::binary);
|
||||
// testexp.write("APPLICATION CRASHED!", strlen("APPLICATION CRASHED!"));
|
||||
//
|
||||
// EasyEventTracer::instance().disable();
|
||||
// if (PREVIOUS_FILTER)
|
||||
// return PREVIOUS_FILTER(ExceptionInfo);
|
||||
// return EXCEPTION_CONTINUE_SEARCH;
|
||||
// }
|
||||
// #endif
|
||||
|
||||
ProfileManager::ProfileManager()
|
||||
{
|
||||
// #ifdef _WIN32
|
||||
// PREVIOUS_FILTER = SetUnhandledExceptionFilter(easyTopLevelExceptionFilter);
|
||||
// #endif
|
||||
}
|
||||
|
||||
ProfileManager::~ProfileManager()
|
||||
{
|
||||
//dumpBlocksToFile("test.prof");
|
||||
}
|
||||
|
||||
ProfileManager& ProfileManager::instance()
|
||||
{
|
||||
///C++11 makes possible to create Singleton without any warry about thread-safeness
|
||||
///http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
||||
static ProfileManager m_profileManager;
|
||||
return m_profileManager;
|
||||
}
|
||||
|
||||
void ProfileManager::beginBlock(Block& _block)
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
|
||||
if (THREAD_STORAGE == nullptr)
|
||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||
|
||||
if (!_block.isFinished())
|
||||
THREAD_STORAGE->blocks.openedList.emplace(_block);
|
||||
else
|
||||
THREAD_STORAGE->storeBlock(_block);
|
||||
}
|
||||
|
||||
void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id)
|
||||
{
|
||||
auto ts = findThreadStorage(_thread_id);
|
||||
if (ts != nullptr)
|
||||
ts->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, "");
|
||||
}
|
||||
|
||||
void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id)
|
||||
{
|
||||
auto ts = findThreadStorage(_thread_id);
|
||||
if (ts != nullptr)
|
||||
{
|
||||
profiler::Block lastBlock(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, "");
|
||||
lastBlock.finish(_time);
|
||||
ts->storeCSwitch(lastBlock);
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileManager::endBlock()
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
|
||||
if (THREAD_STORAGE->blocks.openedList.empty())
|
||||
return;
|
||||
|
||||
Block& lastBlock = THREAD_STORAGE->blocks.openedList.top();
|
||||
if (!lastBlock.isFinished())
|
||||
lastBlock.finish();
|
||||
|
||||
THREAD_STORAGE->storeBlock(lastBlock);
|
||||
THREAD_STORAGE->blocks.openedList.pop();
|
||||
}
|
||||
|
||||
void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime)
|
||||
{
|
||||
auto ts = findThreadStorage(_thread_id);
|
||||
if (ts == nullptr || ts->sync.openedList.empty())
|
||||
return;
|
||||
|
||||
Block& lastBlock = ts->sync.openedList.top();
|
||||
lastBlock.finish(_endtime);
|
||||
|
||||
ts->storeCSwitch(lastBlock);
|
||||
ts->sync.openedList.pop();
|
||||
}
|
||||
|
||||
void ProfileManager::setEnabled(bool isEnable)
|
||||
{
|
||||
m_isEnabled = isEnable;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FileWriter final
|
||||
{
|
||||
std::ofstream m_file;
|
||||
|
||||
public:
|
||||
|
||||
FileWriter(const char* _filename) : m_file(_filename, std::fstream::binary) { }
|
||||
|
||||
template <typename T> void write(const char* _data, T _size) {
|
||||
m_file.write(_data, _size);
|
||||
}
|
||||
|
||||
template <class T> void write(const T& _data) {
|
||||
m_file.write((const char*)&_data, sizeof(T));
|
||||
}
|
||||
|
||||
void writeBlock(const profiler::SerializedBlock* _block)
|
||||
{
|
||||
auto sz = static_cast<uint16_t>(sizeof(BaseBlockData) + strlen(_block->name()) + 1);
|
||||
write(sz);
|
||||
write(_block->data(), sz);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define STORE_CSWITCHES_SEPARATELY
|
||||
|
||||
uint32_t ProfileManager::dumpBlocksToFile(const char* filename)
|
||||
{
|
||||
const bool wasEnabled = m_isEnabled;
|
||||
if (wasEnabled)
|
||||
::profiler::setEnabled(false);
|
||||
|
||||
#ifndef _WIN32
|
||||
uint64_t timestamp;
|
||||
uint32_t thread_from, thread_to;
|
||||
|
||||
std::ifstream infile(m_csInfoFilename.c_str());
|
||||
|
||||
if(infile.is_open())
|
||||
{
|
||||
static const auto desc = addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White);
|
||||
while (infile >> timestamp >> thread_from >> thread_to)
|
||||
{
|
||||
beginContextSwitch(thread_from, timestamp, desc);
|
||||
endContextSwitch(thread_to, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
FileWriter of(filename);
|
||||
|
||||
uint64_t usedMemorySize = 0;
|
||||
uint32_t blocks_number = 0;
|
||||
for (const auto& thread_storage : m_threads)
|
||||
{
|
||||
const auto& t = thread_storage.second;
|
||||
usedMemorySize += t.blocks.usedMemorySize + t.sync.usedMemorySize;
|
||||
blocks_number += static_cast<uint32_t>(t.blocks.closedList.size()) + static_cast<uint32_t>(t.sync.closedList.size());
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
of.write(CPU_FREQUENCY);
|
||||
#else
|
||||
of.write(0LL);
|
||||
#endif
|
||||
|
||||
of.write(blocks_number);
|
||||
of.write(usedMemorySize);
|
||||
of.write(static_cast<uint32_t>(m_descriptors.size()));
|
||||
of.write(m_usedMemorySize);
|
||||
|
||||
for (const auto& descriptor : m_descriptors)
|
||||
{
|
||||
const auto name_size = static_cast<uint16_t>(strlen(descriptor.name()) + 1);
|
||||
const auto filename_size = static_cast<uint16_t>(strlen(descriptor.file()) + 1);
|
||||
const auto size = static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor) + name_size + filename_size);
|
||||
|
||||
of.write(size);
|
||||
of.write<profiler::BaseBlockDescriptor>(descriptor);
|
||||
of.write(name_size);
|
||||
of.write(descriptor.name(), name_size);
|
||||
of.write(descriptor.file(), filename_size);
|
||||
}
|
||||
|
||||
for (auto& thread_storage : m_threads)
|
||||
{
|
||||
auto& t = thread_storage.second;
|
||||
|
||||
of.write(thread_storage.first);
|
||||
#ifdef STORE_CSWITCHES_SEPARATELY
|
||||
of.write(static_cast<uint32_t>(t.blocks.closedList.size()));
|
||||
#else
|
||||
of.write(static_cast<uint32_t>(t.blocks.closedList.size()) + static_cast<uint32_t>(t.sync.closedList.size()));
|
||||
uint32_t i = 0;
|
||||
#endif
|
||||
|
||||
for (auto b : t.blocks.closedList)
|
||||
{
|
||||
#ifndef STORE_CSWITCHES_SEPARATELY
|
||||
if (i < t.sync.closedList.size())
|
||||
{
|
||||
auto s = t.sync.closedList[i];
|
||||
if (s->end() <= b->end())// || s->begin() >= b->begin())
|
||||
//if (((s->end() <= b->end() && s->end() >= b->begin()) || (s->begin() >= b->begin() && s->begin() <= b->end())))
|
||||
{
|
||||
if (s->m_begin < b->m_begin)
|
||||
s->m_begin = b->m_begin;
|
||||
if (s->m_end > b->m_end)
|
||||
s->m_end = b->m_end;
|
||||
of.writeBlock(s);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
of.writeBlock(b);
|
||||
}
|
||||
|
||||
#ifdef STORE_CSWITCHES_SEPARATELY
|
||||
of.write(static_cast<uint32_t>(t.sync.closedList.size()));
|
||||
for (auto b : t.sync.closedList)
|
||||
{
|
||||
#else
|
||||
for (; i < t.sync.closedList.size(); ++i)
|
||||
{
|
||||
auto b = t.sync.closedList[i];
|
||||
#endif
|
||||
|
||||
of.writeBlock(b);
|
||||
}
|
||||
|
||||
t.clearClosed();
|
||||
}
|
||||
|
||||
// if (wasEnabled)
|
||||
// ::profiler::setEnabled(true);
|
||||
|
||||
return blocks_number;
|
||||
}
|
||||
|
||||
const char* ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line)
|
||||
{
|
||||
if (THREAD_STORAGE == nullptr)
|
||||
{
|
||||
THREAD_STORAGE = &threadStorage(getCurrentThreadId());
|
||||
}
|
||||
|
||||
if (!THREAD_STORAGE->named)
|
||||
{
|
||||
const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Black);
|
||||
THREAD_STORAGE->storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name));
|
||||
THREAD_STORAGE->name = name;
|
||||
THREAD_STORAGE->named = true;
|
||||
}
|
||||
|
||||
return THREAD_STORAGE->name.c_str();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -26,68 +26,212 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#ifdef WIN32
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <thread>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
inline uint32_t getCurrentThreadId()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return (uint32_t)::GetCurrentThreadId();
|
||||
#ifdef _WIN32
|
||||
return (uint32_t)::GetCurrentThreadId();
|
||||
#else
|
||||
thread_local static uint32_t _id = (uint32_t)std::hash<std::thread::id>()(std::this_thread::get_id());
|
||||
return _id;
|
||||
EASY_THREAD_LOCAL static const pid_t x = syscall(__NR_gettid);
|
||||
EASY_THREAD_LOCAL static const uint32_t _id = (uint32_t)x;//std::hash<std::thread::id>()(std::this_thread::get_id());
|
||||
return _id;
|
||||
#endif
|
||||
}
|
||||
|
||||
class ProfileManager
|
||||
namespace profiler { class SerializedBlock; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T, const uint16_t N>
|
||||
class chunk_allocator final
|
||||
{
|
||||
ProfileManager();
|
||||
ProfileManager(const ProfileManager& p) = delete;
|
||||
ProfileManager& operator=(const ProfileManager&) = delete;
|
||||
static ProfileManager m_profileManager;
|
||||
struct chunk { T data[N]; };
|
||||
|
||||
bool m_isEnabled = false;
|
||||
std::list<chunk> m_chunks;
|
||||
uint16_t m_size;
|
||||
|
||||
typedef std::stack<::std::reference_wrapper<profiler::Block> > stack_of_blocks_t;
|
||||
typedef std::map<size_t, stack_of_blocks_t> map_of_threads_stacks;
|
||||
typedef std::set<size_t> set_of_thread_id;
|
||||
typedef std::vector<profiler::SourceBlock> sources;
|
||||
public:
|
||||
|
||||
map_of_threads_stacks m_openedBracketsMap;
|
||||
chunk_allocator() : m_size(0)
|
||||
{
|
||||
m_chunks.emplace_back();
|
||||
}
|
||||
|
||||
profiler::spin_lock m_spin;
|
||||
profiler::spin_lock m_storedSpin;
|
||||
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
|
||||
T* allocate(uint16_t n)
|
||||
{
|
||||
if (m_size + n <= N)
|
||||
{
|
||||
T* data = m_chunks.back().data + m_size;
|
||||
m_size += n;
|
||||
return data;
|
||||
}
|
||||
|
||||
void _internalInsertBlock(const profiler::Block &_block);
|
||||
m_size = n;
|
||||
m_chunks.emplace_back();
|
||||
return m_chunks.back().data;
|
||||
}
|
||||
|
||||
sources m_sources;
|
||||
void clear()
|
||||
{
|
||||
m_size = 0;
|
||||
m_chunks.clear();
|
||||
m_chunks.emplace_back();
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::list<profiler::SerializedBlock*> serialized_list_t;
|
||||
serialized_list_t m_blocks;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
set_of_thread_id m_namedThreades;
|
||||
const uint16_t SIZEOF_CSWITCH = sizeof(profiler::BaseBlockData) + 1;
|
||||
|
||||
uint64_t m_blocksMemorySize = 0;
|
||||
typedef std::vector<profiler::SerializedBlock*> serialized_list_t;
|
||||
|
||||
template <class T, const uint16_t N>
|
||||
struct BlocksList final
|
||||
{
|
||||
BlocksList() = default;
|
||||
|
||||
class Stack final {
|
||||
//std::stack<T> m_stack;
|
||||
std::vector<T> m_stack;
|
||||
|
||||
public:
|
||||
|
||||
inline void clear() { m_stack.clear(); }
|
||||
inline bool empty() const { return m_stack.empty(); }
|
||||
|
||||
inline void emplace(profiler::Block& _block) {
|
||||
//m_stack.emplace(_block);
|
||||
m_stack.emplace_back(_block);
|
||||
}
|
||||
|
||||
template <class ... TArgs> inline void emplace(TArgs ... _args) {
|
||||
//m_stack.emplace(_args);
|
||||
m_stack.emplace_back(_args...);
|
||||
}
|
||||
|
||||
inline T& top() {
|
||||
//return m_stack.top();
|
||||
return m_stack.back();
|
||||
}
|
||||
|
||||
inline void pop() {
|
||||
//m_stack.pop();
|
||||
m_stack.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
chunk_allocator<char, N> alloc;
|
||||
Stack openedList;
|
||||
serialized_list_t closedList;
|
||||
uint64_t usedMemorySize = 0;
|
||||
|
||||
void clearClosed() {
|
||||
serialized_list_t().swap(closedList);
|
||||
alloc.clear();
|
||||
usedMemorySize = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ThreadStorage final
|
||||
{
|
||||
public:
|
||||
|
||||
BlocksList<std::reference_wrapper<profiler::Block>, SIZEOF_CSWITCH * (uint16_t)1024U> blocks;
|
||||
BlocksList<profiler::Block, SIZEOF_CSWITCH * (uint16_t)128U> sync;
|
||||
std::string name;
|
||||
bool named = false;
|
||||
|
||||
void storeBlock(const profiler::Block& _block);
|
||||
void storeCSwitch(const profiler::Block& _block);
|
||||
void clearClosed();
|
||||
|
||||
ThreadStorage() = default;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ProfileManager final
|
||||
{
|
||||
ProfileManager();
|
||||
ProfileManager(const ProfileManager& p) = delete;
|
||||
ProfileManager& operator=(const ProfileManager&) = delete;
|
||||
|
||||
typedef profiler::guard_lock<profiler::spin_lock> guard_lock_t;
|
||||
typedef std::map<profiler::thread_id_t, ThreadStorage> map_of_threads_stacks;
|
||||
typedef std::vector<profiler::BlockDescriptor> block_descriptors_t;
|
||||
|
||||
map_of_threads_stacks m_threads;
|
||||
block_descriptors_t m_descriptors;
|
||||
uint64_t m_usedMemorySize = 0;
|
||||
profiler::spin_lock m_spin;
|
||||
profiler::spin_lock m_storedSpin;
|
||||
bool m_isEnabled = false;
|
||||
|
||||
std::string m_csInfoFilename = "/tmp/cs_profiling_info.log";
|
||||
|
||||
public:
|
||||
|
||||
static ProfileManager& instance();
|
||||
~ProfileManager();
|
||||
~ProfileManager();
|
||||
|
||||
template <class ... TArgs>
|
||||
uint32_t addBlockDescriptor(TArgs ... _args)
|
||||
{
|
||||
guard_lock_t lock(m_storedSpin);
|
||||
const auto id = static_cast<uint32_t>(m_descriptors.size());
|
||||
m_descriptors.emplace_back(m_usedMemorySize, _args...);
|
||||
return id;
|
||||
}
|
||||
|
||||
void beginBlock(profiler::Block& _block);
|
||||
void endBlock();
|
||||
void setEnabled(bool isEnable);
|
||||
unsigned int dumpBlocksToFile(const char* filename);
|
||||
void setThreadName(const char* name);
|
||||
unsigned int addSource(const char* _filename, int _line);
|
||||
void endBlock();
|
||||
void setEnabled(bool isEnable);
|
||||
uint32_t dumpBlocksToFile(const char* filename);
|
||||
const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line);
|
||||
|
||||
void setContextSwitchLogFilename(const char* name)
|
||||
{
|
||||
m_csInfoFilename = name;
|
||||
}
|
||||
|
||||
const char* getContextSwitchLogFilename() const
|
||||
{
|
||||
return m_csInfoFilename.c_str();
|
||||
}
|
||||
|
||||
void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id);
|
||||
void storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id);
|
||||
void endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime);
|
||||
|
||||
private:
|
||||
|
||||
ThreadStorage& threadStorage(profiler::thread_id_t _thread_id)
|
||||
{
|
||||
guard_lock_t lock(m_spin);
|
||||
return m_threads[_thread_id];
|
||||
}
|
||||
|
||||
ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id)
|
||||
{
|
||||
guard_lock_t lock(m_spin);
|
||||
auto it = m_threads.find(_thread_id);
|
||||
return it != m_threads.end() ? &it->second : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
1053
src/reader.cpp
1053
src/reader.cpp
File diff suppressed because it is too large
Load Diff
128
src/spin_lock.h
128
src/spin_lock.h
@ -16,53 +16,87 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program.If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef ________SPIN_LOCK__________H______
|
||||
#define ________SPIN_LOCK__________H______
|
||||
#ifndef EASY_PROFILER__SPIN_LOCK__________H______
|
||||
#define EASY_PROFILER__SPIN_LOCK__________H______
|
||||
|
||||
#define EASY_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag
|
||||
|
||||
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <atomic>
|
||||
|
||||
namespace profiler{
|
||||
|
||||
class spin_lock
|
||||
{
|
||||
std::atomic_flag m_lock;
|
||||
public:
|
||||
void lock()
|
||||
{
|
||||
while (m_lock.test_and_set(std::memory_order_acquire)){}
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
m_lock.clear(std::memory_order_release);
|
||||
}
|
||||
|
||||
spin_lock(){
|
||||
m_lock.clear();
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class guard_lock
|
||||
{
|
||||
T& m_mutex;
|
||||
bool m_isLocked = false;
|
||||
public:
|
||||
explicit guard_lock(T& m) :m_mutex(m){
|
||||
m_mutex.lock();
|
||||
m_isLocked = true;
|
||||
}
|
||||
~guard_lock(){
|
||||
this->release();
|
||||
}
|
||||
inline void release(){
|
||||
if (m_isLocked){
|
||||
m_mutex.unlock();
|
||||
m_isLocked = false;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace profiler {
|
||||
|
||||
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
|
||||
// std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag...
|
||||
// By the way, Windows critical sections are slower than std::atomic_flag on Unix.
|
||||
class spin_lock final { CRITICAL_SECTION m_lock; public:
|
||||
|
||||
void lock() {
|
||||
EnterCriticalSection(&m_lock);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
LeaveCriticalSection(&m_lock);
|
||||
}
|
||||
|
||||
spin_lock() {
|
||||
InitializeCriticalSection(&m_lock);
|
||||
}
|
||||
|
||||
~spin_lock() {
|
||||
DeleteCriticalSection(&m_lock);
|
||||
}
|
||||
};
|
||||
#else
|
||||
// std::atomic_flag on Unix works fine and very fast (almost instant!)
|
||||
class spin_lock final { ::std::atomic_flag m_lock; public:
|
||||
|
||||
void lock() {
|
||||
while (m_lock.test_and_set(::std::memory_order_acquire));
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
m_lock.clear(::std::memory_order_release);
|
||||
}
|
||||
|
||||
spin_lock() {
|
||||
m_lock.clear();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
class guard_lock final
|
||||
{
|
||||
T& m_lock;
|
||||
bool m_isLocked = false;
|
||||
|
||||
public:
|
||||
|
||||
explicit guard_lock(T& m) : m_lock(m) {
|
||||
m_lock.lock();
|
||||
m_isLocked = true;
|
||||
}
|
||||
|
||||
~guard_lock() {
|
||||
unlock();
|
||||
}
|
||||
|
||||
inline void unlock() {
|
||||
if (m_isLocked) {
|
||||
m_lock.unlock();
|
||||
m_isLocked = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
#ifdef EASY_USE_CRITICAL_SECTION
|
||||
# undef EASY_USE_CRITICAL_SECTION
|
||||
#endif
|
||||
|
||||
#endif // EASY_PROFILER__SPIN_LOCK__________H______
|
||||
|
Loading…
x
Reference in New Issue
Block a user