mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 08:41:02 +08:00
update #42 : Slightly better solution with less amount of black magic - different data structures for context switch events. Core API changed!
This commit is contained in:
parent
b14dbef78d
commit
93c3066095
@ -54,17 +54,25 @@
|
||||
using namespace profiler;
|
||||
|
||||
#ifndef EASY_PROFILER_API_DISABLED
|
||||
Event::Event(timestamp_t _begin_time) : m_begin(_begin_time), m_end(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Event::Event(timestamp_t _begin_time, timestamp_t _end_time) : m_begin(_begin_time), m_end(_end_time)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id)
|
||||
: m_begin(_begin_time)
|
||||
, m_end(0)
|
||||
: Event(_begin_time)
|
||||
, m_id(_descriptor_id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseBlockData::BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _descriptor_id)
|
||||
: m_begin(_begin_time)
|
||||
, m_end(_end_time)
|
||||
: Event(_begin_time, _end_time)
|
||||
, m_id(_descriptor_id)
|
||||
{
|
||||
|
||||
@ -133,9 +141,25 @@ Block::~Block()
|
||||
::profiler::endBlock();
|
||||
}
|
||||
#else
|
||||
Event::Event(timestamp_t) : m_begin(0), m_end(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Event::Event(timestamp_t, timestamp_t) : m_begin(0), m_end(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseBlockData::BaseBlockData(timestamp_t, block_id_t)
|
||||
: m_begin(0)
|
||||
, m_end(0)
|
||||
: Event(0, 0)
|
||||
, m_id(~0U)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseBlockData::BaseBlockData(timestamp_t, timestamp_t, block_id_t)
|
||||
: Event(0, 0)
|
||||
, m_id(~0U)
|
||||
{
|
||||
|
||||
@ -199,16 +223,16 @@ Block::~Block()
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CSwitchBlock::CSwitchBlock(timestamp_t _begin_time, thread_id_t _tid, const char* _runtimeName)
|
||||
: Block(_begin_time, _begin_time, 0, _runtimeName)
|
||||
CSwitchEvent::CSwitchEvent(timestamp_t _begin_time, thread_id_t _tid)
|
||||
: Event(_begin_time)
|
||||
, m_thread_id(_tid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSwitchBlock::CSwitchBlock(CSwitchBlock&& _that)
|
||||
: Block(std::forward<Block>(_that))
|
||||
, m_thread_id(_that.m_thread_id)
|
||||
CSwitchBlock::CSwitchBlock(timestamp_t _begin_time, thread_id_t _tid, const char* _runtimeName)
|
||||
: CSwitchEvent(_begin_time, _tid)
|
||||
, m_name(_runtimeName)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -493,7 +493,7 @@ namespace profiler {
|
||||
|
||||
//***********************************************
|
||||
|
||||
class PROFILER_API BaseBlockData
|
||||
class PROFILER_API Event
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
|
||||
@ -501,6 +501,29 @@ namespace profiler {
|
||||
|
||||
timestamp_t m_begin;
|
||||
timestamp_t m_end;
|
||||
|
||||
public:
|
||||
|
||||
Event(const Event&) = default;
|
||||
Event(timestamp_t _begin_time);
|
||||
Event(timestamp_t _begin_time, timestamp_t _end_time);
|
||||
|
||||
inline timestamp_t begin() const { return m_begin; }
|
||||
inline timestamp_t end() const { return m_end; }
|
||||
inline timestamp_t duration() const { return m_end - m_begin; }
|
||||
|
||||
private:
|
||||
|
||||
Event() = delete;
|
||||
|
||||
}; // END class Event.
|
||||
|
||||
class PROFILER_API BaseBlockData : public Event
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
|
||||
protected:
|
||||
|
||||
block_id_t m_id;
|
||||
|
||||
public:
|
||||
@ -509,11 +532,7 @@ namespace profiler {
|
||||
BaseBlockData(timestamp_t _begin_time, block_id_t _id);
|
||||
BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id);
|
||||
|
||||
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:
|
||||
@ -521,6 +540,20 @@ namespace profiler {
|
||||
BaseBlockData() = delete;
|
||||
|
||||
}; // END of class BaseBlockData.
|
||||
|
||||
class PROFILER_API CSwitchEvent : public Event
|
||||
{
|
||||
thread_id_t m_thread_id;
|
||||
|
||||
public:
|
||||
|
||||
CSwitchEvent() = default;
|
||||
CSwitchEvent(const CSwitchEvent&) = default;
|
||||
CSwitchEvent(timestamp_t _begin_time, thread_id_t _tid);
|
||||
|
||||
inline thread_id_t tid() const { return m_thread_id; }
|
||||
|
||||
}; // END of class CSwitchEvent.
|
||||
#pragma pack(pop)
|
||||
|
||||
//***********************************************
|
||||
|
@ -121,7 +121,12 @@ namespace profiler {
|
||||
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.)
|
||||
|
||||
union {
|
||||
::profiler::SerializedBlock* node; ///< Pointer to serilized data for regular block (id, name, begin, end etc.)
|
||||
::profiler::SerializedCSwitch* cs; ///< Pointer to serilized data for context switch (thread_id, 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
|
||||
|
@ -51,7 +51,7 @@ namespace profiler {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PROFILER_API SerializedBlock : public BaseBlockData
|
||||
class PROFILER_API SerializedBlock EASY_FINAL : public BaseBlockData
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
friend ::ThreadStorage;
|
||||
@ -63,68 +63,43 @@ namespace profiler {
|
||||
///< Run-time block name is stored right after main BaseBlockData data
|
||||
inline const char* name() const { return data() + sizeof(BaseBlockData); }
|
||||
|
||||
protected:
|
||||
private:
|
||||
|
||||
SerializedBlock(const ::profiler::Block& block, uint16_t name_length);
|
||||
SerializedBlock(const Block& block, uint16_t name_length);
|
||||
|
||||
SerializedBlock(const SerializedBlock&) = delete;
|
||||
SerializedBlock& operator = (const SerializedBlock&) = delete;
|
||||
|
||||
//TODO yse: reason of deleted
|
||||
//~SerializedBlock() = delete;
|
||||
|
||||
protected:
|
||||
|
||||
SerializedBlock(const ::profiler::Block& block);
|
||||
~SerializedBlock() = delete;
|
||||
|
||||
}; // END of SerializedBlock.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/** This is serious work-around to be able to read/write valid
|
||||
thread ids after changing thread_id_t from 32-bit to 64-bit.
|
||||
|
||||
Before v1.3.0 thread_id_t was uint32_t and has been stored in BaseBlockData::m_id.
|
||||
After v1.3.0 we have to allocate additional 4 bytes per context switch block to
|
||||
be able to store 64-bit value.
|
||||
|
||||
This is bad design decision at first look, but it has backward compatibility,
|
||||
does not require serious changes to Core API (except this particular class)
|
||||
and saves 4 bytes per context switch block.
|
||||
|
||||
TODO: think about better solution.
|
||||
*/
|
||||
class PROFILER_API SerializedCSwitch : public SerializedBlock
|
||||
class PROFILER_API SerializedCSwitch EASY_FINAL : public CSwitchEvent
|
||||
{
|
||||
friend ::ProfileManager;
|
||||
friend ::ThreadStorage;
|
||||
|
||||
uint32_t m_reserve; /** Additional 4 bytes used to store second part of thread_id_t
|
||||
(first part is stored in BaseBlockData::m_id as it was before
|
||||
changing thread_id_t to 64-bit) */
|
||||
|
||||
public:
|
||||
|
||||
///< Thread id is stored in m_id + m_reserve
|
||||
inline thread_id_t tid() const { return *reinterpret_cast<const thread_id_t*>(&m_id); }
|
||||
inline const char* data() const { return reinterpret_cast<const char*>(this); }
|
||||
|
||||
///< Run-time block name is stored right after main BaseBlockData data and reserved 4 bytes block
|
||||
inline const char* name() const { return data() + sizeof(BaseBlockData) + 4; }
|
||||
///< Run-time block name is stored right after main CSwitchEvent data
|
||||
inline const char* name() const { return data() + sizeof(CSwitchEvent); }
|
||||
|
||||
private:
|
||||
|
||||
SerializedCSwitch(const CSwitchBlock& block, uint16_t name_length);
|
||||
|
||||
SerializedCSwitch(const SerializedBlock&) = delete;
|
||||
SerializedCSwitch& operator = (const SerializedBlock&) = delete;
|
||||
SerializedCSwitch(const SerializedCSwitch&) = delete;
|
||||
SerializedCSwitch& operator = (const SerializedCSwitch&) = delete;
|
||||
~SerializedCSwitch() = delete;
|
||||
|
||||
}; // END of SerializedCSwitch.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma pack(push, 1)
|
||||
class PROFILER_API SerializedBlockDescriptor EASY_FINAL : public BaseBlockDescriptor
|
||||
{
|
||||
uint16_t m_nameLength; ///< Length of the name including trailing '\0' sybmol
|
||||
|
@ -519,17 +519,9 @@ SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
|
||||
pName[name_length] = 0;
|
||||
}
|
||||
|
||||
SerializedBlock::SerializedBlock(const Block& block)
|
||||
: BaseBlockData(block)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SerializedCSwitch::SerializedCSwitch(const CSwitchBlock& block, uint16_t name_length)
|
||||
: SerializedBlock(block)
|
||||
: CSwitchEvent(block)
|
||||
{
|
||||
*reinterpret_cast<thread_id_t*>(&m_id) = block.tid();
|
||||
|
||||
auto pName = const_cast<char*>(name());
|
||||
if (name_length) strncpy(pName, block.name(), name_length);
|
||||
pName[name_length] = 0;
|
||||
@ -681,7 +673,7 @@ void ThreadStorage::storeBlock(const profiler::Block& block)
|
||||
void ThreadStorage::storeCSwitch(const CSwitchBlock& block)
|
||||
{
|
||||
auto name_length = static_cast<uint16_t>(strlen(block.name()));
|
||||
auto size = static_cast<uint16_t>(sizeof(BaseBlockData) + name_length + 5);
|
||||
auto size = static_cast<uint16_t>(sizeof(CSwitchEvent) + name_length + 1);
|
||||
auto data = sync.closedList.allocate(size);
|
||||
::new (data) SerializedCSwitch(block, name_length);
|
||||
sync.usedMemorySize += size;
|
||||
|
@ -421,29 +421,20 @@ struct BlocksList
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CSwitchBlock : public ::profiler::Block
|
||||
class CSwitchBlock : public profiler::CSwitchEvent
|
||||
{
|
||||
::profiler::thread_id_t m_thread_id;
|
||||
const char* m_name;
|
||||
|
||||
public:
|
||||
|
||||
CSwitchBlock(::profiler::timestamp_t _begin_time, ::profiler::thread_id_t _tid, const char* _runtimeName);
|
||||
CSwitchBlock(CSwitchBlock&& _that);
|
||||
|
||||
inline ::profiler::thread_id_t tid() const {
|
||||
return m_thread_id;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
CSwitchBlock(const CSwitchBlock&) = delete;
|
||||
CSwitchBlock& operator = (const CSwitchBlock&) = delete;
|
||||
CSwitchBlock(profiler::timestamp_t _begin_time, profiler::thread_id_t _tid, const char* _runtimeName);
|
||||
inline const char* name() const { return m_name; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const uint16_t SIZEOF_BLOCK = sizeof(profiler::BaseBlockData) + 1 + sizeof(uint16_t); // SerializedBlock stores BaseBlockData + at least 1 character for name ('\0') + 2 bytes for size of serialized data
|
||||
const uint16_t SIZEOF_CSWITCH = SIZEOF_BLOCK + 4; // SerializedCSwitch also stores additional 4 bytes to be able to save 64-bit thread_id
|
||||
const uint16_t SIZEOF_CSWITCH = sizeof(profiler::CSwitchEvent) + 1 + sizeof(uint16_t); // SerializedCSwitch also stores additional 4 bytes to be able to save 64-bit thread_id
|
||||
|
||||
struct ThreadStorage
|
||||
{
|
||||
|
@ -609,7 +609,7 @@ extern "C" {
|
||||
char* data = serialized_blocks[i];
|
||||
inFile.read(data, sz);
|
||||
i += sz;
|
||||
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
|
||||
auto baseData = reinterpret_cast<::profiler::SerializedCSwitch*>(data);
|
||||
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
|
||||
auto t_end = t_begin + 1;
|
||||
|
||||
@ -626,7 +626,7 @@ extern "C" {
|
||||
|
||||
blocks.emplace_back();
|
||||
::profiler::BlocksTree& tree = blocks.back();
|
||||
tree.node = baseData;
|
||||
tree.cs = baseData;
|
||||
const auto block_index = blocks_counter++;
|
||||
|
||||
root.wait_time += baseData->duration();
|
||||
|
@ -1711,7 +1711,19 @@ void EasyGraphicsView::onIdleTimeout()
|
||||
|
||||
lay->addWidget(new QLabel("Thread:", widget), row, 0, Qt::AlignRight);
|
||||
|
||||
const ::profiler::thread_id_t tid = EASY_GLOBALS.version < ::profiler_gui::V130 ? cse->tree.node->id() : static_cast<const ::profiler::SerializedCSwitch*>(cse->tree.node)->tid();
|
||||
const char* process_name = "";
|
||||
::profiler::thread_id_t tid = 0;
|
||||
if (EASY_GLOBALS.version < ::profiler_gui::V130)
|
||||
{
|
||||
tid = cse->tree.node->id();
|
||||
process_name = cse->tree.node->name();
|
||||
}
|
||||
else
|
||||
{
|
||||
tid = cse->tree.cs->tid();
|
||||
process_name = cse->tree.cs->name();
|
||||
}
|
||||
|
||||
auto it = EASY_GLOBALS.profiler_blocks.find(tid);
|
||||
|
||||
if (it != EASY_GLOBALS.profiler_blocks.end())
|
||||
@ -1728,7 +1740,7 @@ void EasyGraphicsView::onIdleTimeout()
|
||||
++row;
|
||||
|
||||
lay->addWidget(new QLabel("Process:", widget), row, 0, Qt::AlignRight);
|
||||
lay->addWidget(new QLabel(cse->tree.node->name(), widget), row, 1, 1, 2, Qt::AlignLeft);
|
||||
lay->addWidget(new QLabel(process_name, widget), row, 1, 1, 2, Qt::AlignLeft);
|
||||
++row;
|
||||
|
||||
const auto duration = itemBlock.node->duration();
|
||||
@ -2139,10 +2151,7 @@ void EasyThreadNamesWidget::removePopup(bool _removeFromScene)
|
||||
delete widget;
|
||||
|
||||
if (_removeFromScene)
|
||||
{
|
||||
scene()->removeItem(m_popupWidget);
|
||||
setFixedWidth(m_maxLength);
|
||||
}
|
||||
|
||||
m_popupWidget = nullptr;
|
||||
}
|
||||
@ -2221,22 +2230,38 @@ void EasyThreadNamesWidget::onIdleTimeout()
|
||||
auto scenePos = mapToScene(mapFromGlobal(QCursor::pos()));
|
||||
|
||||
if (scenePos.x() < visibleSceneRect.left() || scenePos.x() > visibleSceneRect.right())
|
||||
{
|
||||
if (m_idleTime > 3000)
|
||||
setFixedWidth(m_maxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
if (scenePos.y() < visibleSceneRect.top() || scenePos.y() > visibleSceneRect.bottom())
|
||||
{
|
||||
if (m_idleTime > 3000)
|
||||
setFixedWidth(m_maxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
auto const parentView = static_cast<EasyThreadNamesWidget*>(scene()->parent());
|
||||
const auto view = parentView->view();
|
||||
|
||||
if (scenePos.y() > view->visibleSceneRect().bottom())
|
||||
{
|
||||
if (m_idleTime > 3000)
|
||||
setFixedWidth(m_maxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
const qreal y = scenePos.y() - visibleSceneRect.top();
|
||||
|
||||
const auto& items = view->getItems();
|
||||
if (items.empty())
|
||||
{
|
||||
if (m_idleTime > 3000)
|
||||
setFixedWidth(m_maxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
EasyGraphicsItem* intersectingItem = nullptr;
|
||||
for (auto item : items)
|
||||
@ -2332,7 +2357,7 @@ void EasyThreadNamesWidget::onIdleTimeout()
|
||||
|
||||
auto br = m_popupWidget->boundingRect();
|
||||
|
||||
if (m_maxLength < br.width())
|
||||
if (maximumWidth() < br.width())
|
||||
{
|
||||
setFixedWidth(static_cast<int>(br.width()));
|
||||
visibleSceneRect.setWidth(br.width());
|
||||
|
@ -1013,7 +1013,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
|
||||
if (width < MIN_SYNC_SIZE)
|
||||
width = MIN_SYNC_SIZE;
|
||||
|
||||
const ::profiler::thread_id_t tid = EASY_GLOBALS.version < ::profiler_gui::V130 ? item.node->id() : static_cast<const ::profiler::SerializedCSwitch*>(item.node)->tid();
|
||||
const ::profiler::thread_id_t tid = EASY_GLOBALS.version < ::profiler_gui::V130 ? item.node->id() : item.cs->tid();
|
||||
const bool self_thread = tid != 0 && EASY_GLOBALS.profiler_blocks.find(tid) != EASY_GLOBALS.profiler_blocks.end();
|
||||
|
||||
::profiler::color_t color = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user