mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 00:31:02 +08:00
Many new features:
* Reading blocks from stream without temporary file; * Reading blocks description from stream; * Control blocks statuses over network: connect to the application, refresh blocks list, change block's status, launch profiling.
This commit is contained in:
parent
485cec2b4f
commit
8fd70c5420
@ -14,13 +14,21 @@ const uint32_t EASY_MESSAGE_SIGN = 20160909;
|
||||
enum MessageType : uint8_t
|
||||
{
|
||||
MESSAGE_TYPE_ZERO,
|
||||
|
||||
MESSAGE_TYPE_REQUEST_START_CAPTURE,
|
||||
MESSAGE_TYPE_REPLY_START_CAPTURING,
|
||||
MESSAGE_TYPE_REQUEST_STOP_CAPTURE,
|
||||
MESSAGE_TYPE_REPLY_PREPARE_BLOCKS,
|
||||
MESSAGE_TYPE_REPLY_END_SEND_BLOCKS,
|
||||
|
||||
MESSAGE_TYPE_REPLY_BLOCKS,
|
||||
MESSAGE_TYPE_ACCEPTED_CONNECTION
|
||||
MESSAGE_TYPE_REPLY_BLOCKS_END,
|
||||
|
||||
MESSAGE_TYPE_ACCEPTED_CONNECTION,
|
||||
|
||||
MESSAGE_TYPE_REQUEST_BLOCKS_DESCRIPTION,
|
||||
MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION,
|
||||
MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION_END,
|
||||
|
||||
MESSAGE_TYPE_EDIT_BLOCK_STATUS,
|
||||
};
|
||||
|
||||
struct Message
|
||||
@ -41,14 +49,36 @@ struct DataMessage : public Message
|
||||
{
|
||||
uint32_t size = 0;//bytes
|
||||
|
||||
DataMessage():
|
||||
Message(MESSAGE_TYPE_REPLY_BLOCKS)
|
||||
DataMessage(MessageType _t = MESSAGE_TYPE_REPLY_BLOCKS) :
|
||||
Message(_t)
|
||||
{}
|
||||
|
||||
DataMessage(uint32_t _s):
|
||||
Message(MESSAGE_TYPE_REPLY_BLOCKS)
|
||||
DataMessage(uint32_t _s, MessageType _t = MESSAGE_TYPE_REPLY_BLOCKS) :
|
||||
Message(_t)
|
||||
, size(_s)
|
||||
{}
|
||||
|
||||
const char* data() const
|
||||
{
|
||||
return reinterpret_cast<const char*>(this) + sizeof(DataMessage);
|
||||
}
|
||||
};
|
||||
|
||||
struct BlockStatusMessage : public Message
|
||||
{
|
||||
uint32_t id;
|
||||
uint8_t status;
|
||||
|
||||
BlockStatusMessage(uint32_t _id, uint8_t _status)
|
||||
: Message(MESSAGE_TYPE_EDIT_BLOCK_STATUS)
|
||||
, id(_id)
|
||||
, status(_status)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BlockStatusMessage() = delete;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
@ -323,13 +323,28 @@ namespace profiler {
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
||||
extern "C" PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
|
||||
::profiler::SerializedData& serialized_blocks,
|
||||
::profiler::SerializedData& serialized_descriptors,
|
||||
::profiler::descriptors_list_t& descriptors,
|
||||
::profiler::blocks_t& _blocks,
|
||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
||||
bool gather_statistics);
|
||||
extern "C" {
|
||||
|
||||
PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
|
||||
::profiler::SerializedData& serialized_blocks,
|
||||
::profiler::SerializedData& serialized_descriptors,
|
||||
::profiler::descriptors_list_t& descriptors,
|
||||
::profiler::blocks_t& _blocks,
|
||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
||||
bool gather_statistics);
|
||||
|
||||
PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
|
||||
::profiler::SerializedData& serialized_blocks,
|
||||
::profiler::SerializedData& serialized_descriptors,
|
||||
::profiler::descriptors_list_t& descriptors,
|
||||
::profiler::blocks_t& _blocks,
|
||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
||||
bool gather_statistics);
|
||||
|
||||
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
|
||||
::profiler::SerializedData& serialized_descriptors,
|
||||
::profiler::descriptors_list_t& descriptors);
|
||||
}
|
||||
|
||||
inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks,
|
||||
::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors,
|
||||
@ -340,6 +355,12 @@ inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profi
|
||||
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, gather_statistics);
|
||||
}
|
||||
|
||||
inline bool readDescriptionsFromStream(::std::stringstream& str, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors)
|
||||
{
|
||||
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
|
||||
return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // PROFILER_READER____H
|
||||
|
@ -40,7 +40,7 @@
|
||||
#include <QSettings>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QToolBar>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <thread>
|
||||
@ -222,6 +222,7 @@ void EasyDescTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
||||
_event->accept();
|
||||
|
||||
QMenu menu;
|
||||
menu.setToolTipsVisible(true);
|
||||
auto action = menu.addAction("Expand all");
|
||||
SET_ICON(action, ":/Expand");
|
||||
connect(action, &QAction::triggered, this, &This::expandAll);
|
||||
@ -253,22 +254,27 @@ void EasyDescTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
|
||||
|
||||
menu.addSeparator();
|
||||
auto submenu = menu.addMenu("Change status");
|
||||
submenu->setToolTipsVisible(true);
|
||||
|
||||
#define ADD_STATUS_ACTION(NameValue, StatusValue)\
|
||||
#define ADD_STATUS_ACTION(NameValue, StatusValue, ToolTipValue)\
|
||||
action = submenu->addAction(NameValue);\
|
||||
action->setCheckable(true);\
|
||||
action->setChecked(desc.status() == StatusValue);\
|
||||
action->setData(static_cast<quint32>(StatusValue));\
|
||||
action->setToolTip(ToolTipValue);\
|
||||
connect(action, &QAction::triggered, this, &This::onBlockStatusChangeClicked)
|
||||
|
||||
ADD_STATUS_ACTION("Off", ::profiler::OFF);
|
||||
ADD_STATUS_ACTION("On", ::profiler::ON);
|
||||
ADD_STATUS_ACTION("Force-On", ::profiler::FORCE_ON);
|
||||
ADD_STATUS_ACTION("Off-recursive", ::profiler::OFF_RECURSIVE);
|
||||
ADD_STATUS_ACTION("On-without-children", ::profiler::ON_WITHOUT_CHILDREN);
|
||||
ADD_STATUS_ACTION("Force-On-without-children", ::profiler::FORCE_ON_WITHOUT_CHILDREN);
|
||||
|
||||
ADD_STATUS_ACTION("Off", ::profiler::OFF, "Do not profile this block.");
|
||||
ADD_STATUS_ACTION("On", ::profiler::ON, "Profile this block\nif parent enabled children.");
|
||||
ADD_STATUS_ACTION("Force-On", ::profiler::FORCE_ON, "Always profile this block even\nif it's parent disabled children.");
|
||||
ADD_STATUS_ACTION("Off-recursive", ::profiler::OFF_RECURSIVE, "Do not profile neither this block\nnor it's children.");
|
||||
ADD_STATUS_ACTION("On-without-children", ::profiler::ON_WITHOUT_CHILDREN, "Profile this block, but\ndo not profile it's children.");
|
||||
ADD_STATUS_ACTION("Force-On-without-children", ::profiler::FORCE_ON_WITHOUT_CHILDREN, "Always profile this block, but\ndo not profile it's children.");
|
||||
#undef ADD_STATUS_ACTION
|
||||
|
||||
submenu->setEnabled(EASY_GLOBALS.connected);
|
||||
if (!EASY_GLOBALS.connected)
|
||||
submenu->setTitle(QString("%1 (connection needed)").arg(submenu->title()));
|
||||
}
|
||||
|
||||
menu.exec(QCursor::pos());
|
||||
@ -340,8 +346,6 @@ struct FileItems
|
||||
|
||||
void EasyDescTreeWidget::build()
|
||||
{
|
||||
clearSilent(false);
|
||||
|
||||
auto f = font();
|
||||
f.setBold(true);
|
||||
|
||||
@ -421,6 +425,9 @@ void EasyDescTreeWidget::onItemExpand(QTreeWidgetItem*)
|
||||
|
||||
void EasyDescTreeWidget::onDoubleClick(QTreeWidgetItem* _item, int _column)
|
||||
{
|
||||
if (!EASY_GLOBALS.connected)
|
||||
return;
|
||||
|
||||
if (_column >= DESC_COL_TYPE && _item->parent() != nullptr)
|
||||
{
|
||||
auto item = static_cast<EasyDescWidgetItem*>(_item);
|
||||
@ -460,7 +467,7 @@ void EasyDescTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidget
|
||||
|
||||
void EasyDescTreeWidget::onBlockStatusChangeClicked(bool _checked)
|
||||
{
|
||||
if (!_checked)
|
||||
if (!_checked || !EASY_GLOBALS.connected)
|
||||
return;
|
||||
|
||||
auto item = currentItem();
|
||||
@ -686,14 +693,41 @@ EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent)
|
||||
, m_tree(new EasyDescTreeWidget())
|
||||
, m_searchBox(new QLineEdit())
|
||||
, m_foundNumber(new QLabel("Found 0 matches"))
|
||||
, m_searchButton(nullptr)
|
||||
{
|
||||
m_searchBox->setMinimumWidth(64);
|
||||
m_searchBox->setFixedWidth(200);
|
||||
|
||||
auto tb = new QToolBar();
|
||||
auto refreshButton = tb->addAction(QIcon(":/Reload"), tr("Refresh blocks list"));
|
||||
refreshButton->setEnabled(EASY_GLOBALS.connected);
|
||||
refreshButton->setToolTip(tr("Refresh blocks list.\nConnection needed."));
|
||||
connect(refreshButton, &QAction::triggered, &EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::blocksRefreshRequired);
|
||||
|
||||
tb->addSeparator();
|
||||
m_searchButton = tb->addAction(QIcon(":/Search-next"), tr("Find next"), this, SLOT(findNext(bool)));
|
||||
tb->addWidget(m_searchBox);
|
||||
|
||||
m_searchButton->setData(true);
|
||||
m_searchButton->setMenu(new QMenu(this));
|
||||
|
||||
auto actionGroup = new QActionGroup(this);
|
||||
actionGroup->setExclusive(true);
|
||||
|
||||
auto a = new QAction(tr("Find next"), actionGroup);
|
||||
a->setCheckable(true);
|
||||
a->setChecked(true);
|
||||
connect(a, &QAction::triggered, this, &This::findNextFromMenu);
|
||||
m_searchButton->menu()->addAction(a);
|
||||
|
||||
a = new QAction(tr("Find previous"), actionGroup);
|
||||
a->setCheckable(true);
|
||||
connect(a, &QAction::triggered, this, &This::findPrevFromMenu);
|
||||
m_searchButton->menu()->addAction(a);
|
||||
|
||||
auto searchbox = new QHBoxLayout();
|
||||
searchbox->setContentsMargins(0, 0, 0, 0);
|
||||
searchbox->addWidget(new QLabel("Search:"));
|
||||
searchbox->addWidget(m_searchBox);
|
||||
searchbox->addStretch(50);
|
||||
searchbox->addWidget(tb);
|
||||
searchbox->addStretch(100);
|
||||
searchbox->addWidget(m_foundNumber, Qt::AlignRight);
|
||||
|
||||
auto lay = new QVBoxLayout(this);
|
||||
@ -702,6 +736,7 @@ EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent)
|
||||
lay->addWidget(m_tree);
|
||||
|
||||
connect(m_searchBox, &QLineEdit::returnPressed, this, &This::onSeachBoxReturnPressed);
|
||||
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::connectionChanged, refreshButton, &QAction::setEnabled);
|
||||
}
|
||||
|
||||
EasyDescWidget::~EasyDescWidget()
|
||||
@ -713,16 +748,10 @@ void EasyDescWidget::keyPressEvent(QKeyEvent* _event)
|
||||
{
|
||||
if (_event->key() == Qt::Key_F3)
|
||||
{
|
||||
int matches = 0;
|
||||
if (_event->modifiers() & Qt::ShiftModifier)
|
||||
matches = m_tree->findPrev(m_searchBox->text());
|
||||
findPrev(true);
|
||||
else
|
||||
matches = m_tree->findNext(m_searchBox->text());
|
||||
|
||||
if (matches == 1)
|
||||
m_foundNumber->setText(QString("Found 1 match"));
|
||||
else
|
||||
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
|
||||
findNext(true);
|
||||
}
|
||||
|
||||
_event->accept();
|
||||
@ -730,12 +759,14 @@ void EasyDescWidget::keyPressEvent(QKeyEvent* _event)
|
||||
|
||||
void EasyDescWidget::build()
|
||||
{
|
||||
clear();
|
||||
m_tree->build();
|
||||
}
|
||||
|
||||
void EasyDescWidget::clear()
|
||||
{
|
||||
m_tree->clearSilent(true);
|
||||
m_foundNumber->setText(QString("Found 0 matches"));
|
||||
}
|
||||
|
||||
void EasyDescWidget::onSeachBoxReturnPressed()
|
||||
@ -748,4 +779,58 @@ void EasyDescWidget::onSeachBoxReturnPressed()
|
||||
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
|
||||
}
|
||||
|
||||
void EasyDescWidget::findNext(bool)
|
||||
{
|
||||
auto matches = m_tree->findNext(m_searchBox->text());
|
||||
|
||||
if (matches == 1)
|
||||
m_foundNumber->setText(QString("Found 1 match"));
|
||||
else
|
||||
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
|
||||
}
|
||||
|
||||
void EasyDescWidget::findPrev(bool)
|
||||
{
|
||||
auto matches = m_tree->findPrev(m_searchBox->text());
|
||||
|
||||
if (matches == 1)
|
||||
m_foundNumber->setText(QString("Found 1 match"));
|
||||
else
|
||||
m_foundNumber->setText(QString("Found %1 matches").arg(matches));
|
||||
}
|
||||
|
||||
void EasyDescWidget::findNextFromMenu(bool _checked)
|
||||
{
|
||||
if (!_checked)
|
||||
return;
|
||||
|
||||
if (m_searchButton->data().toBool() == false)
|
||||
{
|
||||
m_searchButton->setData(true);
|
||||
m_searchButton->setText(tr("Find next"));
|
||||
m_searchButton->setIcon(QIcon(":/Search-next"));
|
||||
disconnect(m_searchButton, &QAction::triggered, this, &This::findPrev);
|
||||
connect(m_searchButton, &QAction::triggered, this, &This::findNext);
|
||||
}
|
||||
|
||||
findNext(true);
|
||||
}
|
||||
|
||||
void EasyDescWidget::findPrevFromMenu(bool _checked)
|
||||
{
|
||||
if (!_checked)
|
||||
return;
|
||||
|
||||
if (m_searchButton->data().toBool() == true)
|
||||
{
|
||||
m_searchButton->setData(false);
|
||||
m_searchButton->setText(tr("Find prev"));
|
||||
m_searchButton->setIcon(QIcon(":/Search-prev"));
|
||||
disconnect(m_searchButton, &QAction::triggered, this, &This::findNext);
|
||||
connect(m_searchButton, &QAction::triggered, this, &This::findPrev);
|
||||
}
|
||||
|
||||
findPrev(true);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -135,9 +135,10 @@ class EasyDescWidget : public QWidget
|
||||
|
||||
private:
|
||||
|
||||
EasyDescTreeWidget* m_tree;
|
||||
class QLineEdit* m_searchBox;
|
||||
class QLabel* m_foundNumber;
|
||||
EasyDescTreeWidget* m_tree;
|
||||
class QLineEdit* m_searchBox;
|
||||
class QLabel* m_foundNumber;
|
||||
class QAction* m_searchButton;
|
||||
|
||||
public:
|
||||
|
||||
@ -157,6 +158,10 @@ public:
|
||||
private slots:
|
||||
|
||||
void onSeachBoxReturnPressed();
|
||||
void findNext(bool);
|
||||
void findPrev(bool);
|
||||
void findNextFromMenu(bool);
|
||||
void findPrevFromMenu(bool);
|
||||
|
||||
}; // END of class EasyDescWidget.
|
||||
|
||||
|
@ -47,6 +47,7 @@ namespace profiler_gui {
|
||||
: selected_thread(0U)
|
||||
, selected_block(::profiler_gui::numeric_max<decltype(selected_block)>())
|
||||
, chrono_text_position(ChronoTextPosition_Center)
|
||||
, connected(false)
|
||||
, enable_event_indicators(true)
|
||||
, enable_statistics(true)
|
||||
, draw_graphics_items_borders(true)
|
||||
|
@ -97,6 +97,7 @@ namespace profiler_gui {
|
||||
::profiler::thread_id_t selected_thread; ///< Current selected thread id
|
||||
::profiler::block_index_t selected_block; ///< Current selected profiler block index
|
||||
ChronometerTextPosition chrono_text_position; ///< Selected interval text position
|
||||
bool connected; ///< Is connected to source (to be able to capture profiling information)
|
||||
bool enable_event_indicators; ///< Enable event indicators painting (These are narrow rectangles at the bottom of each thread)
|
||||
bool enable_statistics; ///< Enable gathering and using statistics (Disable if you want to consume less memory)
|
||||
bool draw_graphics_items_borders; ///< Draw borders for graphics blocks or not
|
||||
|
@ -51,6 +51,8 @@ namespace profiler_gui {
|
||||
void selectedBlockChanged(uint32_t _block_index);
|
||||
void itemsExpandStateChanged();
|
||||
void blockStatusChanged(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status);
|
||||
void connectionChanged(bool _connected);
|
||||
void blocksRefreshRequired(bool);
|
||||
|
||||
}; // END of class EasyGlobalSignals.
|
||||
|
||||
|
@ -15,3 +15,6 @@ wifi.svg - Icon made by Freepik from www.flaticon.com
|
||||
wifi_on.svg - Icon made by Freepik from www.flaticon.com
|
||||
play.svg - Icon made by Google from www.flaticon.com
|
||||
delete.svg - Icon made by Freepik from www.flaticon.com
|
||||
list.svg - Icon made by Freepik from www.flaticon.com
|
||||
search-prev.svg - Icon made by Freepik from www.flaticon.com
|
||||
search-next.svg - Icon made by Freepik from www.flaticon.com
|
63
profiler_gui/icons/list.svg
Normal file
63
profiler_gui/icons/list.svg
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="485.69px" height="485.69px" viewBox="0 0 485.69 485.69" style="enable-background:new 0 0 485.69 485.69;"
|
||||
xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path style="fill:#212121;" d="M410.428,34.738h-76.405l5.155,23.852c0.634,2.961,0.603,5.934,0.271,8.859h54.621V452.98H91.588V67.449h54.637
|
||||
c-0.332-2.941-0.348-5.914,0.285-8.891l5.156-23.82H75.248c-9.031,0-16.34,7.324-16.34,16.354v418.243
|
||||
c0,9.016,7.309,16.354,16.34,16.354h335.18c9.031,0,16.354-7.341,16.354-16.354V51.093
|
||||
C426.783,42.062,419.459,34.738,410.428,34.738z"/>
|
||||
<path style="fill:#212121;" d="M355.568,152.949h-111.71c-9.047,0-16.355,7.324-16.355,16.34c0,9.035,7.309,16.355,16.355,16.355h111.71
|
||||
c9.047,0,16.354-7.32,16.354-16.355C371.924,160.273,364.615,152.949,355.568,152.949z"/>
|
||||
<path style="fill:#212121;" d="M355.568,253.254h-111.71c-9.047,0-16.355,7.323-16.355,16.354c0,9.021,7.309,16.357,16.355,16.357h111.71
|
||||
c9.047,0,16.354-7.34,16.354-16.357C371.924,260.577,364.615,253.254,355.568,253.254z"/>
|
||||
<path style="fill:#f44336;" d="M119.556,156.792c-6.898,5.82-7.786,16.137-1.965,23.047l23.855,28.27c3.117,3.699,7.688,5.805,12.496,5.805
|
||||
c0.398,0,0.792-0.016,1.203-0.047c5.219-0.379,9.949-3.258,12.703-7.719l42.914-69.477c4.746-7.688,2.375-17.75-5.312-22.492
|
||||
c-7.688-4.777-17.75-2.375-22.497,5.313l-31.066,50.273l-9.301-11.012C136.763,151.843,126.467,150.956,119.556,156.792z"/>
|
||||
<path style="fill:#212121;" d="M158.72,245.094c-13.554,0-24.535,10.978-24.535,24.517c0,13.543,10.98,24.52,24.535,24.52
|
||||
c13.543,0,24.52-10.977,24.52-24.52C183.24,256.07,172.263,245.094,158.72,245.094z"/>
|
||||
<path style="fill:#212121;" d="M355.568,351.359h-111.71c-9.047,0-16.355,7.309-16.355,16.358c0,9.017,7.309,16.34,16.355,16.34h111.71
|
||||
c9.047,0,16.354-7.323,16.354-16.34C371.924,358.667,364.615,351.359,355.568,351.359z"/>
|
||||
<path style="fill:#212121;" d="M158.72,343.199c-13.554,0-24.535,10.977-24.535,24.52c0,13.539,10.98,24.521,24.535,24.521
|
||||
c13.543,0,24.52-10.979,24.52-24.521C183.24,354.176,172.263,343.199,158.72,343.199z"/>
|
||||
<path style="fill:#212121;" d="M173.463,75.613h138.73c3.401,0,6.613-1.521,8.746-4.176c2.137-2.629,2.961-6.105,2.229-9.43L311.686,8.859
|
||||
C310.564,3.687,305.994,0,300.708,0H184.963c-5.281,0-9.852,3.688-10.977,8.859l-11.5,53.148
|
||||
c-0.695,3.324,0.125,6.801,2.247,9.43C166.868,74.093,170.08,75.613,173.463,75.613z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
57
profiler_gui/icons/search-next.svg
Normal file
57
profiler_gui/icons/search-next.svg
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="47px" height="47px" viewBox="0 0 47 47" style="enable-background:new 0 0 47 47;" xml:space="preserve">
|
||||
<g>
|
||||
<g id="Layer_1_18_">
|
||||
<g>
|
||||
<path style="fill:#212121;" d="M46.368,43.354l-7.177-7.178c-0.476-0.475-1.117-0.67-1.737-0.604l-1.005-1.006c3.353-3.803,5.204-8.623,5.204-13.736
|
||||
c0-5.563-2.166-10.793-6.1-14.727C31.618,2.167,26.388,0,20.825,0S10.03,2.167,6.097,6.102c-8.122,8.12-8.122,21.335,0,29.457
|
||||
c3.934,3.935,9.164,6.101,14.727,6.101c5.115,0,9.934-1.851,13.738-5.204l1.005,1.005c-0.066,0.62,0.129,1.263,0.604,1.737
|
||||
l7.178,7.177C43.765,46.791,44.312,47,44.857,47s1.094-0.208,1.51-0.626C47.203,45.54,47.203,44.188,46.368,43.354z
|
||||
M20.824,37.386c-4.421,0-8.578-1.722-11.706-4.849c-6.456-6.456-6.456-16.96,0-23.415c3.128-3.127,7.285-4.85,11.707-4.85
|
||||
c4.421,0,8.58,1.723,11.708,4.851c3.127,3.127,4.849,7.285,4.849,11.706c0,4.422-1.723,8.579-4.852,11.706
|
||||
C29.403,35.664,25.245,37.386,20.824,37.386z"/>
|
||||
<path style="fill:#f44336;" d="M33.258,25.352L26.85,20.01c-0.319-0.266-0.764-0.322-1.138-0.147c-0.375,0.176-0.614,0.553-0.614,0.967v2.258h-5.341
|
||||
c-0.59,0-1.068,0.479-1.068,1.068v4.023c0,0.59,0.478,1.068,1.068,1.068h5.341v2.261c0,0.415,0.239,0.792,0.614,0.968
|
||||
c0.146,0.067,0.3,0.102,0.453,0.102c0.245,0,0.488-0.084,0.685-0.248l6.408-5.34c0.243-0.203,0.385-0.504,0.385-0.82
|
||||
S33.501,25.555,33.258,25.352z"/>
|
||||
<path style="fill:#212121;" d="M22.96,17.5v-4.023c0-0.59-0.478-1.068-1.068-1.068h-5.339V10.15c0-0.415-0.24-0.792-0.615-0.968
|
||||
c-0.376-0.175-0.819-0.118-1.137,0.146l-6.411,5.341c-0.244,0.203-0.384,0.503-0.384,0.821c0,0.317,0.141,0.618,0.384,0.821
|
||||
l6.411,5.341c0.195,0.163,0.438,0.248,0.684,0.248c0.154,0,0.309-0.034,0.454-0.101c0.375-0.177,0.615-0.553,0.615-0.968v-2.263
|
||||
h5.339C22.482,18.567,22.96,18.089,22.96,17.5z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
57
profiler_gui/icons/search-prev.svg
Normal file
57
profiler_gui/icons/search-prev.svg
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="47px" height="47px" viewBox="0 0 47 47" style="enable-background:new 0 0 47 47;" xml:space="preserve">
|
||||
<g>
|
||||
<g id="Layer_1_18_">
|
||||
<g>
|
||||
<path style="fill:#212121;" d="M46.368,43.354l-7.177-7.178c-0.476-0.475-1.117-0.67-1.737-0.604l-1.005-1.006c3.353-3.803,5.204-8.623,5.204-13.736
|
||||
c0-5.563-2.166-10.793-6.1-14.727C31.618,2.167,26.388,0,20.825,0S10.03,2.167,6.097,6.102c-8.122,8.12-8.122,21.335,0,29.457
|
||||
c3.934,3.935,9.164,6.101,14.727,6.101c5.115,0,9.934-1.851,13.738-5.204l1.005,1.005c-0.066,0.62,0.129,1.263,0.604,1.737
|
||||
l7.178,7.177C43.765,46.791,44.312,47,44.857,47s1.094-0.208,1.51-0.626C47.203,45.54,47.203,44.188,46.368,43.354z
|
||||
M20.824,37.386c-4.421,0-8.578-1.722-11.706-4.849c-6.456-6.456-6.456-16.96,0-23.415c3.128-3.127,7.285-4.85,11.707-4.85
|
||||
c4.421,0,8.58,1.723,11.708,4.851c3.127,3.127,4.849,7.285,4.849,11.706c0,4.422-1.723,8.579-4.852,11.706
|
||||
C29.403,35.664,25.245,37.386,20.824,37.386z"/>
|
||||
<path style="fill:#212121;" d="M33.258,25.352L26.85,20.01c-0.319-0.266-0.764-0.322-1.138-0.147c-0.375,0.176-0.614,0.553-0.614,0.967v2.258h-5.341
|
||||
c-0.59,0-1.068,0.479-1.068,1.068v4.023c0,0.59,0.478,1.068,1.068,1.068h5.341v2.261c0,0.415,0.239,0.792,0.614,0.968
|
||||
c0.146,0.067,0.3,0.102,0.453,0.102c0.245,0,0.488-0.084,0.685-0.248l6.408-5.34c0.243-0.203,0.385-0.504,0.385-0.82
|
||||
S33.501,25.555,33.258,25.352z"/>
|
||||
<path style="fill:#f44336;" d="M22.96,17.5v-4.023c0-0.59-0.478-1.068-1.068-1.068h-5.339V10.15c0-0.415-0.24-0.792-0.615-0.968
|
||||
c-0.376-0.175-0.819-0.118-1.137,0.146l-6.411,5.341c-0.244,0.203-0.384,0.503-0.384,0.821c0,0.317,0.141,0.618,0.384,0.821
|
||||
l6.411,5.341c0.195,0.163,0.438,0.248,0.684,0.248c0.154,0,0.309-0.034,0.454-0.101c0.375-0.177,0.615-0.553,0.615-0.968v-2.263
|
||||
h5.339C22.482,18.567,22.96,18.089,22.96,17.5z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,6 @@
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QTimer>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include "profiler/easy_socket.h"
|
||||
#include "profiler/reader.h"
|
||||
@ -65,23 +64,27 @@ class EasyFileReader Q_DECL_FINAL
|
||||
::profiler::descriptors_list_t m_descriptors; ///<
|
||||
::profiler::blocks_t m_blocks; ///<
|
||||
::profiler::thread_blocks_tree_t m_blocksTree; ///<
|
||||
::std::stringstream m_stream; ///<
|
||||
QString m_filename; ///<
|
||||
::std::thread m_thread; ///<
|
||||
::std::atomic_bool m_bDone; ///<
|
||||
::std::atomic<int> m_progress; ///<
|
||||
::std::atomic<unsigned int> m_size; ///<
|
||||
bool m_isFile = false; ///<
|
||||
|
||||
public:
|
||||
|
||||
EasyFileReader();
|
||||
~EasyFileReader();
|
||||
|
||||
const bool isFile() const;
|
||||
bool done() const;
|
||||
int progress() const;
|
||||
unsigned int size() const;
|
||||
const QString& filename() const;
|
||||
|
||||
void load(const QString& _filename);
|
||||
void load(::std::stringstream& _stream);
|
||||
void interrupt();
|
||||
void get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors,
|
||||
::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree,
|
||||
@ -91,6 +94,52 @@ public:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum EasyListenerRegime : uint8_t
|
||||
{
|
||||
LISTENER_IDLE = 0,
|
||||
LISTENER_CAPTURE,
|
||||
LISTENER_DESCRIBE
|
||||
};
|
||||
|
||||
class EasySocketListener Q_DECL_FINAL
|
||||
{
|
||||
EasySocket m_easySocket; ///<
|
||||
::std::stringstream m_receivedData; ///<
|
||||
::std::thread m_thread; ///<
|
||||
uint64_t m_receivedSize; ///<
|
||||
::std::atomic_bool m_bInterrupt; ///<
|
||||
::std::atomic_bool m_bConnected; ///<
|
||||
EasyListenerRegime m_regime; ///<
|
||||
|
||||
public:
|
||||
|
||||
EasySocketListener();
|
||||
~EasySocketListener();
|
||||
|
||||
bool connected() const;
|
||||
EasyListenerRegime regime() const;
|
||||
uint64_t size() const;
|
||||
|
||||
::std::stringstream& data();
|
||||
void clearData();
|
||||
|
||||
bool connect(const char* _ipaddress, uint16_t _port);
|
||||
|
||||
void startCapture();
|
||||
void stopCapture();
|
||||
void requestBlocksDescription();
|
||||
|
||||
void sendBlockStatus(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status);
|
||||
|
||||
private:
|
||||
|
||||
void listenCapture();
|
||||
void listenDescription();
|
||||
|
||||
}; // END of class EasySocketListener.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EasyMainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -103,37 +152,24 @@ protected:
|
||||
QString m_lastFile;
|
||||
QDockWidget* m_treeWidget = nullptr;
|
||||
QDockWidget* m_graphicsView = nullptr;
|
||||
class QProgressDialog* m_downloadingProgress = nullptr;
|
||||
|
||||
#if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0
|
||||
QDockWidget* m_descTreeWidget = nullptr;
|
||||
#endif
|
||||
|
||||
class QProgressDialog* m_progress = nullptr;
|
||||
class QAction* m_editBlocksAction = nullptr;
|
||||
class QDialog* m_descTreeDialog = nullptr;
|
||||
class EasyDescWidget* m_dialogDescTree = nullptr;
|
||||
class QMessageBox* m_listenerDialog = nullptr;
|
||||
QTimer m_readerTimer;
|
||||
QTimer m_downloadedTimer;
|
||||
QTimer m_listenerTimer;
|
||||
::profiler::SerializedData m_serializedBlocks;
|
||||
::profiler::SerializedData m_serializedDescriptors;
|
||||
EasyFileReader m_reader;
|
||||
|
||||
QTcpSocket* m_server = nullptr;
|
||||
|
||||
std::stringstream m_receivedProfileData;
|
||||
bool m_recFrames = false;
|
||||
EasySocketListener m_listener;
|
||||
|
||||
class QLineEdit* m_ipEdit = nullptr;
|
||||
class QLineEdit* m_portEdit = nullptr;
|
||||
bool m_isConnected = false;
|
||||
|
||||
std::thread m_thread;
|
||||
|
||||
EasySocket m_easySocket;
|
||||
|
||||
bool m_downloading = false;
|
||||
::std::atomic<int> m_downloadedBytes;
|
||||
|
||||
class QAction* m_captureAction = nullptr;
|
||||
class QAction* m_connectAction = nullptr;
|
||||
@ -147,8 +183,6 @@ public:
|
||||
|
||||
void closeEvent(QCloseEvent* close_event) override;
|
||||
|
||||
void listen();
|
||||
|
||||
protected slots:
|
||||
|
||||
void onOpenFileClicked(bool);
|
||||
@ -166,34 +200,28 @@ protected slots:
|
||||
void onExpandAllClicked(bool);
|
||||
void onCollapseAllClicked(bool);
|
||||
void onFileReaderTimeout();
|
||||
void onDownloadTimeout();
|
||||
void onListenerTimerTimeout();
|
||||
void onFileReaderCancel();
|
||||
void onEditBlocksClicked(bool);
|
||||
void onDescTreeDialogClose(int);
|
||||
void onListenerDialogClose(int);
|
||||
void onCaptureClicked(bool);
|
||||
|
||||
void readTcpData();
|
||||
void onNewConnection();
|
||||
void onDisconnection();
|
||||
void onConnected();
|
||||
void onErrorConnection(QAbstractSocket::SocketError socketError);
|
||||
void onDisconnect();
|
||||
void onGetBlockDescriptionsClicked(bool);
|
||||
void onConnectClicked(bool);
|
||||
|
||||
void handleResults(const QString &s);
|
||||
void onBlockStatusChange(::profiler::block_id_t _id, ::profiler::EasyBlockStatus _status);
|
||||
|
||||
private:
|
||||
|
||||
// Private non-virtual methods
|
||||
|
||||
void loadFile(const QString& filename);
|
||||
void readStream(::std::stringstream& data);
|
||||
|
||||
void loadSettings();
|
||||
void loadGeometry();
|
||||
void saveSettingsAndGeometry();
|
||||
|
||||
bool m_isClientPreparedBlocks = false;
|
||||
bool m_isClientCaptured = false;
|
||||
|
||||
}; // END of class EasyMainWindow.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -19,5 +19,8 @@
|
||||
<file alias="Connection-on">icons/lan_on.svg</file>
|
||||
<file alias="Start">icons/play.svg</file>
|
||||
<file alias="Delete">icons/delete.svg</file>
|
||||
<file alias="List">icons/list.svg</file>
|
||||
<file alias="Search-next">icons/search-next.svg</file>
|
||||
<file alias="Search-prev">icons/search-prev.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -18,6 +18,8 @@ int MODELLING_STEPS = 1500;
|
||||
int RENDER_STEPS = 1500;
|
||||
int RESOURCE_LOADING_COUNT = 50;
|
||||
|
||||
//#define SAMPLE_NETWORK_TEST
|
||||
|
||||
void localSleep(int magic=200000)
|
||||
{
|
||||
//PROFILER_BEGIN_FUNCTION_BLOCK_GROUPED(profiler::colors::Blue);
|
||||
@ -134,7 +136,11 @@ void loadingResourcesThread(){
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
EASY_THREAD("Resource loading");
|
||||
#ifdef SAMPLE_NETWORK_TEST
|
||||
while (true) {
|
||||
#else
|
||||
for(int i = 0; i < RESOURCE_LOADING_COUNT; i++){
|
||||
#endif
|
||||
loadingResources();
|
||||
EASY_EVENT("Resources Loading!", profiler::colors::Cyan);
|
||||
localSleep(1200000);
|
||||
@ -146,7 +152,11 @@ void modellingThread(){
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
EASY_THREAD("Modelling");
|
||||
#ifdef SAMPLE_NETWORK_TEST
|
||||
while (true) {
|
||||
#else
|
||||
for (int i = 0; i < MODELLING_STEPS; i++){
|
||||
#endif
|
||||
modellingStep();
|
||||
localSleep(1200000);
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
@ -157,7 +167,11 @@ void renderThread(){
|
||||
//std::unique_lock<std::mutex> lk(cv_m);
|
||||
//cv.wait(lk, []{return g_i == 1; });
|
||||
EASY_THREAD("Render");
|
||||
#ifdef SAMPLE_NETWORK_TEST
|
||||
while (true) {
|
||||
#else
|
||||
for (int i = 0; i < RENDER_STEPS; i++){
|
||||
#endif
|
||||
frame();
|
||||
localSleep(1200000);
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
@ -187,15 +201,19 @@ int main(int argc, char* argv[])
|
||||
std::cout << "Resource loading count: " << RESOURCE_LOADING_COUNT << std::endl;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
#ifndef SAMPLE_NETWORK_TEST
|
||||
EASY_PROFILER_ENABLE;
|
||||
#endif
|
||||
|
||||
EASY_MAIN_THREAD;
|
||||
profiler::startListenSignalToCapture();
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
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));
|
||||
threads.emplace_back(loadingResourcesThread);
|
||||
threads.emplace_back(renderThread);
|
||||
threads.emplace_back(modellingThread);
|
||||
}
|
||||
|
||||
cv_m.lock();
|
||||
|
@ -52,6 +52,8 @@
|
||||
//extern ProfileManager& MANAGER;
|
||||
#define MANAGER ProfileManager::instance()
|
||||
|
||||
::std::atomic_uint64_t TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
|
||||
|
||||
namespace profiler {
|
||||
|
||||
const decltype(EVENT_DESCRIPTOR::Opcode) SWITCH_CONTEXT_OPCODE = 36;
|
||||
@ -109,6 +111,8 @@ namespace profiler {
|
||||
|
||||
auto _contextSwitchEvent = reinterpret_cast<CSwitch*>(_traceEvent->UserData);
|
||||
const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
|
||||
if (time > TRACING_END_TIME.load(::std::memory_order_acquire))
|
||||
return;
|
||||
|
||||
const char* process_name = "";
|
||||
|
||||
@ -277,8 +281,11 @@ namespace profiler {
|
||||
but if that would not work, return to using shell command "logman stop".
|
||||
*/
|
||||
|
||||
static Properties p; // static is safe because we are guarded by spin-lock m_spin
|
||||
p = m_properties; // Use copy of m_properties to make sure m_properties will not be changed
|
||||
// static is safe because we are guarded by spin-lock m_spin
|
||||
static Properties p = ([]{ Properties prp; strncpy(prp.sessionName, KERNEL_LOGGER_NAME, sizeof(prp.sessionName)); return prp; })();
|
||||
p.base = m_properties.base; // Use copy of m_properties to make sure m_properties will not be changed
|
||||
|
||||
// Stop another session
|
||||
ControlTrace(NULL, KERNEL_LOGGER_NAME, reinterpret_cast<EVENT_TRACE_PROPERTIES*>(&p), EVENT_TRACE_CONTROL_STOP);
|
||||
|
||||
// Console window variant:
|
||||
@ -394,6 +401,8 @@ namespace profiler {
|
||||
if (!m_bEnabled)
|
||||
return;
|
||||
|
||||
TRACING_END_TIME.store(getCurrentTime(), ::std::memory_order_release);
|
||||
|
||||
ControlTrace(m_openedHandle, KERNEL_LOGGER_NAME, props(), EVENT_TRACE_CONTROL_STOP);
|
||||
CloseTrace(m_openedHandle);
|
||||
|
||||
@ -407,6 +416,8 @@ namespace profiler {
|
||||
PROCESS_INFO_TABLE.clear();
|
||||
THREAD_PROCESS_INFO_TABLE.clear();
|
||||
THREAD_PROCESS_INFO_TABLE[0U] = nullptr;
|
||||
|
||||
TRACING_END_TIME.store(~0ULL, ::std::memory_order_release);
|
||||
}
|
||||
|
||||
} // END of namespace profiler.
|
||||
|
@ -670,22 +670,23 @@ void ProfileManager::startListenSignalToCapture()
|
||||
{
|
||||
if (!m_isAlreadyListened)
|
||||
{
|
||||
m_stopListen.store(false);
|
||||
m_listenThread = std::thread(&ProfileManager::startListen, this);
|
||||
m_stopListen.store(false, std::memory_order_release);
|
||||
m_listenThread = std::thread(&ProfileManager::listen, this);
|
||||
m_isAlreadyListened = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileManager::stopListenSignalToCapture()
|
||||
{
|
||||
m_stopListen.store(true);
|
||||
m_stopListen.store(true, std::memory_order_release);
|
||||
m_isAlreadyListened = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ProfileManager::startListen()
|
||||
//#define EASY_DEBUG_NET_PRINT
|
||||
|
||||
void ProfileManager::listen()
|
||||
{
|
||||
EASY_THREAD("EasyProfiler.Listen");
|
||||
|
||||
@ -694,7 +695,7 @@ void ProfileManager::startListen()
|
||||
|
||||
socket.bind(profiler::DEFAULT_PORT);
|
||||
int bytes = 0;
|
||||
while (!m_stopListen.load())
|
||||
while (!m_stopListen.load(std::memory_order_acquire))
|
||||
{
|
||||
bool hasConnect = false;
|
||||
|
||||
@ -703,14 +704,17 @@ void ProfileManager::startListen()
|
||||
|
||||
EASY_EVENT("ClientConnected", profiler::colors::White, profiler::OFF);
|
||||
hasConnect = true;
|
||||
|
||||
#ifdef EASY_DEBUG_NET_PRINT
|
||||
printf("Client Accepted!\n");
|
||||
#endif
|
||||
|
||||
replyMessage.type = profiler::net::MESSAGE_TYPE_ACCEPTED_CONNECTION;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
while (hasConnect && !m_stopListen.load())
|
||||
while (hasConnect && !m_stopListen.load(std::memory_order_acquire))
|
||||
{
|
||||
char buffer[256] = {};
|
||||
|
||||
@ -727,62 +731,129 @@ void ProfileManager::startListen()
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (message->type) {
|
||||
case profiler::net::MESSAGE_TYPE_REQUEST_START_CAPTURE:
|
||||
switch (message->type)
|
||||
{
|
||||
printf("RECEIVED MESSAGE_TYPE_REQUEST_START_CAPTURE\n");
|
||||
ProfileManager::setEnabled(true);
|
||||
EASY_EVENT("StartCapture", profiler::colors::Green, profiler::OFF);
|
||||
case profiler::net::MESSAGE_TYPE_REQUEST_START_CAPTURE:
|
||||
{
|
||||
#ifdef EASY_DEBUG_NET_PRINT
|
||||
printf("RECEIVED MESSAGE_TYPE_REQUEST_START_CAPTURE\n");
|
||||
#endif
|
||||
|
||||
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
hasConnect = bytes > 0;
|
||||
ProfileManager::setEnabled(true);
|
||||
EASY_EVENT("StartCapture", profiler::colors::Green, profiler::OFF);
|
||||
|
||||
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_START_CAPTURING;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case profiler::net::MESSAGE_TYPE_REQUEST_STOP_CAPTURE:
|
||||
{
|
||||
#ifdef EASY_DEBUG_NET_PRINT
|
||||
printf("RECEIVED MESSAGE_TYPE_REQUEST_STOP_CAPTURE\n");
|
||||
#endif
|
||||
|
||||
EASY_EVENT("StopCapture", profiler::colors::Red, profiler::OFF);
|
||||
ProfileManager::setEnabled(false);
|
||||
|
||||
//TODO
|
||||
//if connection aborted - ignore this part
|
||||
|
||||
profiler::net::DataMessage dm;
|
||||
profiler::OStream os;
|
||||
dumpBlocksToStream(os);
|
||||
dm.size = (uint32_t)os.stream().str().length();
|
||||
|
||||
int packet_size = int(sizeof(dm)) + int(dm.size);
|
||||
|
||||
char *sendbuf = new char[packet_size];
|
||||
|
||||
memset(sendbuf, 0, packet_size);
|
||||
memcpy(sendbuf, &dm, sizeof(dm));
|
||||
memcpy(sendbuf + sizeof(dm), os.stream().str().c_str(), dm.size);
|
||||
|
||||
bytes = socket.send(sendbuf, packet_size);
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
/*std::string tempfilename = "test_snd.prof";
|
||||
std::ofstream of(tempfilename, std::fstream::binary);
|
||||
of.write((const char*)os.stream().str().c_str(), dm.size);
|
||||
of.close();*/
|
||||
|
||||
delete[] sendbuf;
|
||||
|
||||
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_BLOCKS_END;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case profiler::net::MESSAGE_TYPE_REQUEST_BLOCKS_DESCRIPTION:
|
||||
{
|
||||
#ifdef EASY_DEBUG_NET_PRINT
|
||||
printf("RECEIVED MESSAGE_TYPE_REQUEST_BLOCKS_DESCRIPTION\n");
|
||||
#endif
|
||||
|
||||
profiler::OStream os;
|
||||
|
||||
// Write block descriptors
|
||||
m_storedSpin.lock();
|
||||
os.write(static_cast<uint32_t>(m_descriptors.size()));
|
||||
os.write(m_usedMemorySize);
|
||||
for (const auto descriptor : m_descriptors)
|
||||
{
|
||||
const auto name_size = descriptor->nameSize();
|
||||
const auto filename_size = descriptor->filenameSize();
|
||||
const auto size = static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor) + name_size + filename_size);
|
||||
|
||||
os.write(size);
|
||||
os.write<profiler::BaseBlockDescriptor>(*descriptor);
|
||||
os.write(name_size);
|
||||
os.write(descriptor->name(), name_size);
|
||||
os.write(descriptor->filename(), filename_size);
|
||||
}
|
||||
m_storedSpin.unlock();
|
||||
// END of Write block descriptors.
|
||||
|
||||
profiler::net::DataMessage dm((uint32_t)os.stream().str().length(), profiler::net::MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION);
|
||||
int packet_size = int(sizeof(dm)) + int(dm.size);
|
||||
|
||||
char *sendbuf = new char[packet_size];
|
||||
|
||||
memset(sendbuf, 0, packet_size);
|
||||
memcpy(sendbuf, &dm, sizeof(dm));
|
||||
memcpy(sendbuf + sizeof(dm), os.stream().str().c_str(), dm.size);
|
||||
|
||||
bytes = socket.send(sendbuf, packet_size);
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
delete[] sendbuf;
|
||||
|
||||
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_BLOCKS_DESCRIPTION_END;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case profiler::net::MESSAGE_TYPE_EDIT_BLOCK_STATUS:
|
||||
{
|
||||
#ifdef EASY_DEBUG_NET_PRINT
|
||||
printf("RECEIVED MESSAGE_TYPE_EDIT_BLOCK_STATUS\n");
|
||||
#endif
|
||||
|
||||
auto data = reinterpret_cast<const profiler::net::BlockStatusMessage*>(message);
|
||||
setBlockStatus(data->id, static_cast<::profiler::EasyBlockStatus>(data->status));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case profiler::net::MESSAGE_TYPE_REQUEST_STOP_CAPTURE:
|
||||
{
|
||||
printf("RECEIVED MESSAGE_TYPE_REQUEST_STOP_CAPTURE\n");
|
||||
EASY_EVENT("StopCapture", profiler::colors::Red, profiler::OFF);
|
||||
ProfileManager::setEnabled(false);
|
||||
|
||||
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_PREPARE_BLOCKS;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
//TODO
|
||||
//if connection aborted - ignore this part
|
||||
|
||||
profiler::net::DataMessage dm;
|
||||
profiler::OStream os;
|
||||
dumpBlocksToStream(os);
|
||||
dm.size = (uint32_t)os.stream().str().length();
|
||||
|
||||
int packet_size = int(sizeof(dm)) + int(dm.size);
|
||||
|
||||
char *sendbuf = new char[packet_size];
|
||||
|
||||
memset(sendbuf, 0, packet_size);
|
||||
memcpy(sendbuf, &dm, sizeof(dm));
|
||||
memcpy(sendbuf + sizeof(dm), os.stream().str().c_str(), dm.size);
|
||||
|
||||
bytes = socket.send(sendbuf, packet_size);
|
||||
hasConnect = bytes > 0;
|
||||
|
||||
/*std::string tempfilename = "test_snd.prof";
|
||||
std::ofstream of(tempfilename, std::fstream::binary);
|
||||
of.write((const char*)os.stream().str().c_str(), dm.size);
|
||||
of.close();*/
|
||||
|
||||
delete[] sendbuf;
|
||||
replyMessage.type = profiler::net::MESSAGE_TYPE_REPLY_END_SEND_BLOCKS;
|
||||
bytes = socket.send(&replyMessage, sizeof(replyMessage));
|
||||
hasConnect = bytes > 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//nn_freemsg (buf);
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ class ProfileManager
|
||||
|
||||
std::thread m_listenThread;
|
||||
bool m_isAlreadyListened = false;
|
||||
void startListen();
|
||||
void listen();
|
||||
|
||||
int m_socket = 0;//TODO crossplatform
|
||||
|
||||
|
681
src/reader.cpp
681
src/reader.cpp
@ -45,6 +45,7 @@
|
||||
#include "profiler/reader.h"
|
||||
#include "hashed_cstr.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
@ -219,389 +220,467 @@ void validate_pointers(::std::atomic<int>& _progress, const char* _oldbase, ::pr
|
||||
|
||||
const int64_t TIME_FACTOR = 1000000000LL;
|
||||
|
||||
extern "C" PROFILER_API::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
|
||||
::profiler::SerializedData& serialized_blocks,
|
||||
::profiler::SerializedData& serialized_descriptors,
|
||||
::profiler::descriptors_list_t& descriptors,
|
||||
::profiler::blocks_t& blocks,
|
||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
||||
bool gather_statistics)
|
||||
{
|
||||
EASY_FUNCTION(::profiler::colors::Cyan);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
::std::ifstream inFile(filename, ::std::fstream::binary);
|
||||
progress.store(0);
|
||||
extern "C" {
|
||||
|
||||
if (!inFile.is_open())
|
||||
return 0;
|
||||
|
||||
int64_t cpu_frequency = 0LL;
|
||||
inFile.read((char*)&cpu_frequency, sizeof(int64_t));
|
||||
|
||||
::profiler::timestamp_t begin_time = 0, end_time = 0;
|
||||
inFile.read((char*)&begin_time, sizeof(::profiler::timestamp_t));
|
||||
inFile.read((char*)&end_time, sizeof(::profiler::timestamp_t));
|
||||
if (cpu_frequency != 0)
|
||||
PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
|
||||
::profiler::SerializedData& serialized_blocks,
|
||||
::profiler::SerializedData& serialized_descriptors,
|
||||
::profiler::descriptors_list_t& descriptors,
|
||||
::profiler::blocks_t& blocks,
|
||||
::profiler::thread_blocks_tree_t& threaded_trees,
|
||||
bool gather_statistics)
|
||||
{
|
||||
begin_time *= TIME_FACTOR;
|
||||
begin_time /= cpu_frequency;
|
||||
end_time *= TIME_FACTOR;
|
||||
end_time /= cpu_frequency;
|
||||
::std::ifstream inFile(filename, ::std::fstream::binary);
|
||||
progress.store(0);
|
||||
if (!inFile.is_open())
|
||||
return 0;
|
||||
::std::stringstream str;
|
||||
str.set_rdbuf(inFile.rdbuf());
|
||||
return fillTreesFromStream(progress, str, serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, gather_statistics);
|
||||
}
|
||||
|
||||
uint32_t total_blocks_number = 0;
|
||||
inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number)));
|
||||
if (total_blocks_number == 0)
|
||||
return 0;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t memory_size = 0;
|
||||
inFile.read((char*)&memory_size, sizeof(decltype(memory_size)));
|
||||
if (memory_size == 0)
|
||||
return 0;
|
||||
|
||||
uint32_t total_descriptors_number = 0;
|
||||
inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number)));
|
||||
if (total_descriptors_number == 0)
|
||||
return 0;
|
||||
|
||||
uint64_t descriptors_memory_size = 0;
|
||||
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size)));
|
||||
if (descriptors_memory_size == 0)
|
||||
return 0;
|
||||
|
||||
descriptors.reserve(total_descriptors_number);
|
||||
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
|
||||
serialized_descriptors.set(descriptors_memory_size);
|
||||
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
|
||||
|
||||
uint64_t i = 0;
|
||||
while (!inFile.eof() && descriptors.size() < total_descriptors_number)
|
||||
PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic<int>& progress, ::std::stringstream& inFile,
|
||||
::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)
|
||||
{
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
if (sz == 0)
|
||||
EASY_FUNCTION(::profiler::colors::Cyan);
|
||||
|
||||
progress.store(0);
|
||||
|
||||
int64_t cpu_frequency = 0LL;
|
||||
inFile.read((char*)&cpu_frequency, sizeof(int64_t));
|
||||
|
||||
::profiler::timestamp_t begin_time = 0, end_time = 0;
|
||||
inFile.read((char*)&begin_time, sizeof(::profiler::timestamp_t));
|
||||
inFile.read((char*)&end_time, sizeof(::profiler::timestamp_t));
|
||||
if (cpu_frequency != 0)
|
||||
{
|
||||
descriptors.push_back(nullptr);
|
||||
continue;
|
||||
begin_time *= TIME_FACTOR;
|
||||
begin_time /= cpu_frequency;
|
||||
end_time *= TIME_FACTOR;
|
||||
end_time /= cpu_frequency;
|
||||
}
|
||||
|
||||
//if (i + sz > descriptors_memory_size) {
|
||||
// printf("FILE CORRUPTED\n");
|
||||
// return 0;
|
||||
//}
|
||||
uint32_t total_blocks_number = 0;
|
||||
inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number)));
|
||||
if (total_blocks_number == 0)
|
||||
return 0;
|
||||
|
||||
char* data = serialized_descriptors[i];
|
||||
inFile.read(data, sz);
|
||||
auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data);
|
||||
descriptors.push_back(descriptor);
|
||||
uint64_t memory_size = 0;
|
||||
inFile.read((char*)&memory_size, sizeof(decltype(memory_size)));
|
||||
if (memory_size == 0)
|
||||
return 0;
|
||||
|
||||
i += sz;
|
||||
auto oldprogress = progress.exchange(static_cast<int>(15 * i / descriptors_memory_size), ::std::memory_order_release);
|
||||
if (oldprogress < 0)
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
uint32_t total_descriptors_number = 0;
|
||||
inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number)));
|
||||
if (total_descriptors_number == 0)
|
||||
return 0;
|
||||
|
||||
typedef ::std::unordered_map<::profiler::thread_id_t, StatsMap, ::profiler::passthrough_hash> PerThreadStats;
|
||||
PerThreadStats thread_statistics, parent_statistics, frame_statistics;
|
||||
IdMap identification_table;
|
||||
uint64_t descriptors_memory_size = 0;
|
||||
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size)));
|
||||
if (descriptors_memory_size == 0)
|
||||
return 0;
|
||||
|
||||
blocks.reserve(total_blocks_number);
|
||||
//olddata = append_regime ? serialized_blocks.data() : nullptr;
|
||||
serialized_blocks.set(memory_size);
|
||||
//validate_pointers(progress, olddata, serialized_blocks, blocks, blocks.size());
|
||||
descriptors.reserve(total_descriptors_number);
|
||||
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
|
||||
serialized_descriptors.set(descriptors_memory_size);
|
||||
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
|
||||
|
||||
i = 0;
|
||||
uint32_t read_number = 0;
|
||||
::profiler::block_index_t blocks_counter = 0;
|
||||
::std::vector<char> name;
|
||||
while (!inFile.eof() && read_number < total_blocks_number)
|
||||
{
|
||||
EASY_BLOCK("Read thread data", ::profiler::colors::DarkGreen);
|
||||
|
||||
::profiler::thread_id_t thread_id = 0;
|
||||
inFile.read((char*)&thread_id, sizeof(decltype(thread_id)));
|
||||
|
||||
auto& root = threaded_trees[thread_id];
|
||||
|
||||
uint16_t name_size = 0;
|
||||
inFile.read((char*)&name_size, sizeof(uint16_t));
|
||||
if (name_size != 0)
|
||||
uint64_t i = 0;
|
||||
while (!inFile.eof() && descriptors.size() < total_descriptors_number)
|
||||
{
|
||||
name.resize(name_size);
|
||||
inFile.read(name.data(), name_size);
|
||||
root.thread_name = name.data();
|
||||
}
|
||||
|
||||
uint32_t blocks_number_in_thread = 0;
|
||||
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread)));
|
||||
auto threshold = read_number + blocks_number_in_thread;
|
||||
while (!inFile.eof() && read_number < threshold)
|
||||
{
|
||||
EASY_BLOCK("Read context switch", ::profiler::colors::Green);
|
||||
|
||||
++read_number;
|
||||
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
if (sz == 0)
|
||||
return 0;
|
||||
{
|
||||
descriptors.push_back(nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
char* data = serialized_blocks[i];
|
||||
//if (i + sz > descriptors_memory_size) {
|
||||
// printf("FILE CORRUPTED\n");
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
char* data = serialized_descriptors[i];
|
||||
inFile.read(data, sz);
|
||||
auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data);
|
||||
descriptors.push_back(descriptor);
|
||||
|
||||
i += sz;
|
||||
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
|
||||
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
|
||||
auto t_end = t_begin + 1;
|
||||
|
||||
if (cpu_frequency != 0)
|
||||
{
|
||||
*t_begin *= TIME_FACTOR;
|
||||
*t_begin /= cpu_frequency;
|
||||
*t_end *= TIME_FACTOR;
|
||||
*t_end /= cpu_frequency;
|
||||
}
|
||||
|
||||
if (*t_end > begin_time)
|
||||
{
|
||||
if (*t_begin < begin_time)
|
||||
*t_begin = begin_time;
|
||||
|
||||
blocks.emplace_back();
|
||||
::profiler::BlocksTree& tree = blocks.back();
|
||||
tree.node = baseData;
|
||||
const auto block_index = blocks_counter++;
|
||||
|
||||
root.sync.emplace_back(block_index);
|
||||
}
|
||||
|
||||
auto oldprogress = progress.exchange(20 + static_cast<int>(70 * i / memory_size), ::std::memory_order_release);
|
||||
auto oldprogress = progress.exchange(static_cast<int>(15 * i / descriptors_memory_size), ::std::memory_order_release);
|
||||
if (oldprogress < 0)
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
|
||||
if (inFile.eof())
|
||||
break;
|
||||
typedef ::std::unordered_map<::profiler::thread_id_t, StatsMap, ::profiler::passthrough_hash> PerThreadStats;
|
||||
PerThreadStats thread_statistics, parent_statistics, frame_statistics;
|
||||
IdMap identification_table;
|
||||
|
||||
blocks_number_in_thread = 0;
|
||||
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread)));
|
||||
threshold = read_number + blocks_number_in_thread;
|
||||
while (!inFile.eof() && read_number < threshold)
|
||||
blocks.reserve(total_blocks_number);
|
||||
//olddata = append_regime ? serialized_blocks.data() : nullptr;
|
||||
serialized_blocks.set(memory_size);
|
||||
//validate_pointers(progress, olddata, serialized_blocks, blocks, blocks.size());
|
||||
|
||||
i = 0;
|
||||
uint32_t read_number = 0;
|
||||
::profiler::block_index_t blocks_counter = 0;
|
||||
::std::vector<char> name;
|
||||
while (!inFile.eof() && read_number < total_blocks_number)
|
||||
{
|
||||
EASY_BLOCK("Read block", ::profiler::colors::Green);
|
||||
EASY_BLOCK("Read thread data", ::profiler::colors::DarkGreen);
|
||||
|
||||
++read_number;
|
||||
::profiler::thread_id_t thread_id = 0;
|
||||
inFile.read((char*)&thread_id, sizeof(decltype(thread_id)));
|
||||
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
if (sz == 0)
|
||||
return 0;
|
||||
auto& root = threaded_trees[thread_id];
|
||||
|
||||
char* data = serialized_blocks[i];
|
||||
inFile.read(data, sz);
|
||||
i += sz;
|
||||
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
|
||||
auto desc = descriptors[baseData->id()];
|
||||
if (desc == nullptr)
|
||||
return 0;
|
||||
|
||||
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
|
||||
auto t_end = t_begin + 1;
|
||||
|
||||
if (cpu_frequency != 0)
|
||||
uint16_t name_size = 0;
|
||||
inFile.read((char*)&name_size, sizeof(uint16_t));
|
||||
if (name_size != 0)
|
||||
{
|
||||
*t_begin *= TIME_FACTOR;
|
||||
*t_begin /= cpu_frequency;
|
||||
*t_end *= TIME_FACTOR;
|
||||
*t_end /= cpu_frequency;
|
||||
name.resize(name_size);
|
||||
inFile.read(name.data(), name_size);
|
||||
root.thread_name = name.data();
|
||||
}
|
||||
|
||||
if (*t_end >= begin_time)
|
||||
uint32_t blocks_number_in_thread = 0;
|
||||
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread)));
|
||||
auto threshold = read_number + blocks_number_in_thread;
|
||||
while (!inFile.eof() && read_number < threshold)
|
||||
{
|
||||
if (*t_begin < begin_time)
|
||||
*t_begin = begin_time;
|
||||
EASY_BLOCK("Read context switch", ::profiler::colors::Green);
|
||||
|
||||
blocks.emplace_back();
|
||||
::profiler::BlocksTree& tree = blocks.back();
|
||||
tree.node = baseData;
|
||||
const auto block_index = blocks_counter++;
|
||||
++read_number;
|
||||
|
||||
auto& per_parent_statistics = parent_statistics[thread_id];
|
||||
auto& per_thread_statistics = thread_statistics[thread_id];
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
if (sz == 0)
|
||||
return 0;
|
||||
|
||||
if (*tree.node->name() != 0)
|
||||
char* data = serialized_blocks[i];
|
||||
inFile.read(data, sz);
|
||||
i += sz;
|
||||
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
|
||||
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
|
||||
auto t_end = t_begin + 1;
|
||||
|
||||
if (cpu_frequency != 0)
|
||||
{
|
||||
// If block has runtime name then generate new id for such block.
|
||||
// Blocks with the same name will have same id.
|
||||
|
||||
IdMap::key_type key(tree.node->name());
|
||||
auto it = identification_table.find(key);
|
||||
if (it != identification_table.end())
|
||||
{
|
||||
// There is already block with such name, use it's id
|
||||
baseData->setId(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
// There were no blocks with such name, generate new id and save it in the table for further usage.
|
||||
auto id = static_cast<::profiler::block_id_t>(descriptors.size());
|
||||
identification_table.emplace(key, id);
|
||||
if (descriptors.capacity() == descriptors.size())
|
||||
descriptors.reserve((descriptors.size() * 3) >> 1);
|
||||
descriptors.push_back(descriptors[baseData->id()]);
|
||||
baseData->setId(id);
|
||||
}
|
||||
*t_begin *= TIME_FACTOR;
|
||||
*t_begin /= cpu_frequency;
|
||||
*t_end *= TIME_FACTOR;
|
||||
*t_end /= cpu_frequency;
|
||||
}
|
||||
|
||||
if (!root.children.empty())
|
||||
if (*t_end > begin_time)
|
||||
{
|
||||
auto& back = blocks[root.children.back()];
|
||||
auto t1 = back.node->end();
|
||||
auto mt0 = tree.node->begin();
|
||||
if (mt0 < t1)//parent - starts earlier than last ends
|
||||
if (*t_begin < begin_time)
|
||||
*t_begin = begin_time;
|
||||
|
||||
blocks.emplace_back();
|
||||
::profiler::BlocksTree& tree = blocks.back();
|
||||
tree.node = baseData;
|
||||
const auto block_index = blocks_counter++;
|
||||
|
||||
root.sync.emplace_back(block_index);
|
||||
}
|
||||
|
||||
auto oldprogress = progress.exchange(20 + static_cast<int>(70 * i / memory_size), ::std::memory_order_release);
|
||||
if (oldprogress < 0)
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
|
||||
if (inFile.eof())
|
||||
break;
|
||||
|
||||
blocks_number_in_thread = 0;
|
||||
inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread)));
|
||||
threshold = read_number + blocks_number_in_thread;
|
||||
while (!inFile.eof() && read_number < threshold)
|
||||
{
|
||||
EASY_BLOCK("Read block", ::profiler::colors::Green);
|
||||
|
||||
++read_number;
|
||||
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
if (sz == 0)
|
||||
return 0;
|
||||
|
||||
char* data = serialized_blocks[i];
|
||||
inFile.read(data, sz);
|
||||
i += sz;
|
||||
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
|
||||
auto desc = descriptors[baseData->id()];
|
||||
if (desc == nullptr)
|
||||
return 0;
|
||||
|
||||
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
|
||||
auto t_end = t_begin + 1;
|
||||
|
||||
if (cpu_frequency != 0)
|
||||
{
|
||||
*t_begin *= TIME_FACTOR;
|
||||
*t_begin /= cpu_frequency;
|
||||
*t_end *= TIME_FACTOR;
|
||||
*t_end /= cpu_frequency;
|
||||
}
|
||||
|
||||
if (*t_end >= begin_time)
|
||||
{
|
||||
if (*t_begin < begin_time)
|
||||
*t_begin = begin_time;
|
||||
|
||||
blocks.emplace_back();
|
||||
::profiler::BlocksTree& tree = blocks.back();
|
||||
tree.node = baseData;
|
||||
const auto block_index = blocks_counter++;
|
||||
|
||||
auto& per_parent_statistics = parent_statistics[thread_id];
|
||||
auto& per_thread_statistics = thread_statistics[thread_id];
|
||||
|
||||
if (*tree.node->name() != 0)
|
||||
{
|
||||
//auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree);
|
||||
/**/
|
||||
EASY_BLOCK("Find children", ::profiler::colors::Blue);
|
||||
auto rlower1 = ++root.children.rbegin();
|
||||
for (; rlower1 != root.children.rend() && !(mt0 > blocks[*rlower1].node->begin()); ++rlower1);
|
||||
auto lower = rlower1.base();
|
||||
::std::move(lower, root.children.end(), ::std::back_inserter(tree.children));
|
||||
// If block has runtime name then generate new id for such block.
|
||||
// Blocks with the same name will have same id.
|
||||
|
||||
root.children.erase(lower, root.children.end());
|
||||
EASY_END_BLOCK;
|
||||
|
||||
::profiler::timestamp_t children_duration = 0;
|
||||
if (gather_statistics)
|
||||
IdMap::key_type key(tree.node->name());
|
||||
auto it = identification_table.find(key);
|
||||
if (it != identification_table.end())
|
||||
{
|
||||
EASY_BLOCK("Gather statistic within parent", ::profiler::colors::Magenta);
|
||||
per_parent_statistics.clear();
|
||||
|
||||
//per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows
|
||||
//per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows
|
||||
// TODO: check this behavior on Linux
|
||||
|
||||
for (auto i : tree.children)
|
||||
{
|
||||
auto& child = blocks[i];
|
||||
child.per_parent_stats = update_statistics(per_parent_statistics, child, i, block_index);
|
||||
|
||||
children_duration += child.node->duration();
|
||||
if (tree.depth < child.depth)
|
||||
tree.depth = child.depth;
|
||||
}
|
||||
// There is already block with such name, use it's id
|
||||
baseData->setId(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i : tree.children)
|
||||
{
|
||||
const auto& child = blocks[i];
|
||||
children_duration += child.node->duration();
|
||||
if (tree.depth < child.depth)
|
||||
tree.depth = child.depth;
|
||||
}
|
||||
// There were no blocks with such name, generate new id and save it in the table for further usage.
|
||||
auto id = static_cast<::profiler::block_id_t>(descriptors.size());
|
||||
identification_table.emplace(key, id);
|
||||
if (descriptors.capacity() == descriptors.size())
|
||||
descriptors.reserve((descriptors.size() * 3) >> 1);
|
||||
descriptors.push_back(descriptors[baseData->id()]);
|
||||
baseData->setId(id);
|
||||
}
|
||||
}
|
||||
|
||||
++tree.depth;
|
||||
if (!root.children.empty())
|
||||
{
|
||||
auto& back = blocks[root.children.back()];
|
||||
auto t1 = back.node->end();
|
||||
auto mt0 = tree.node->begin();
|
||||
if (mt0 < t1)//parent - starts earlier than last ends
|
||||
{
|
||||
//auto lower = ::std::lower_bound(root.children.begin(), root.children.end(), tree);
|
||||
/**/
|
||||
EASY_BLOCK("Find children", ::profiler::colors::Blue);
|
||||
auto rlower1 = ++root.children.rbegin();
|
||||
for (; rlower1 != root.children.rend() && !(mt0 > blocks[*rlower1].node->begin()); ++rlower1);
|
||||
auto lower = rlower1.base();
|
||||
::std::move(lower, root.children.end(), ::std::back_inserter(tree.children));
|
||||
|
||||
root.children.erase(lower, root.children.end());
|
||||
EASY_END_BLOCK;
|
||||
|
||||
::profiler::timestamp_t children_duration = 0;
|
||||
if (gather_statistics)
|
||||
{
|
||||
EASY_BLOCK("Gather statistic within parent", ::profiler::colors::Magenta);
|
||||
per_parent_statistics.clear();
|
||||
|
||||
//per_parent_statistics.reserve(tree.children.size()); // this gives slow-down on Windows
|
||||
//per_parent_statistics.reserve(tree.children.size() * 2); // this gives no speed-up on Windows
|
||||
// TODO: check this behavior on Linux
|
||||
|
||||
for (auto i : tree.children)
|
||||
{
|
||||
auto& child = blocks[i];
|
||||
child.per_parent_stats = update_statistics(per_parent_statistics, child, i, block_index);
|
||||
|
||||
children_duration += child.node->duration();
|
||||
if (tree.depth < child.depth)
|
||||
tree.depth = child.depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i : tree.children)
|
||||
{
|
||||
const auto& child = blocks[i];
|
||||
children_duration += child.node->duration();
|
||||
if (tree.depth < child.depth)
|
||||
tree.depth = child.depth;
|
||||
}
|
||||
}
|
||||
|
||||
++tree.depth;
|
||||
}
|
||||
}
|
||||
|
||||
root.children.emplace_back(block_index);// ::std::move(tree));
|
||||
if (desc->type() == ::profiler::BLOCK_TYPE_EVENT)
|
||||
root.events.emplace_back(block_index);
|
||||
|
||||
|
||||
if (gather_statistics)
|
||||
{
|
||||
EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral);
|
||||
tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, thread_id);
|
||||
}
|
||||
}
|
||||
|
||||
root.children.emplace_back(block_index);// ::std::move(tree));
|
||||
if (desc->type() == ::profiler::BLOCK_TYPE_EVENT)
|
||||
root.events.emplace_back(block_index);
|
||||
auto oldprogress = progress.exchange(20 + static_cast<int>(70 * i / memory_size), ::std::memory_order_release);
|
||||
if (oldprogress < 0)
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
}
|
||||
|
||||
if (progress.load(::std::memory_order_acquire) < 0)
|
||||
return 0; // Loading interrupted
|
||||
|
||||
if (gather_statistics)
|
||||
EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple);
|
||||
if (gather_statistics)
|
||||
{
|
||||
::std::vector<::std::thread> statistics_threads;
|
||||
statistics_threads.reserve(threaded_trees.size());
|
||||
|
||||
for (auto& it : threaded_trees)
|
||||
{
|
||||
auto& root = it.second;
|
||||
root.thread_id = it.first;
|
||||
//root.tree.shrink_to_fit();
|
||||
|
||||
auto& per_frame_statistics = frame_statistics[root.thread_id];
|
||||
auto& per_parent_statistics = parent_statistics[it.first];
|
||||
per_parent_statistics.clear();
|
||||
|
||||
statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &blocks](::profiler::BlocksTreeRoot& root)
|
||||
{
|
||||
EASY_BLOCK("Gather per thread statistics", ::profiler::colors::Coral);
|
||||
tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, thread_id);
|
||||
}
|
||||
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
|
||||
//{
|
||||
// return blocks[left].node->begin() < blocks[right].node->begin();
|
||||
//});
|
||||
|
||||
for (auto i : root.children)
|
||||
{
|
||||
auto& frame = blocks[i];
|
||||
frame.per_parent_stats = update_statistics(per_parent_statistics, frame, i, root.thread_id);
|
||||
|
||||
per_frame_statistics.clear();
|
||||
update_statistics_recursive(per_frame_statistics, frame, i, i, blocks);
|
||||
|
||||
if (root.depth < frame.depth)
|
||||
root.depth = frame.depth;
|
||||
|
||||
root.active_time += frame.node->duration();
|
||||
}
|
||||
|
||||
++root.depth;
|
||||
}, ::std::ref(root)));
|
||||
}
|
||||
|
||||
auto oldprogress = progress.exchange(20 + static_cast<int>(70 * i / memory_size), ::std::memory_order_release);
|
||||
if (oldprogress < 0)
|
||||
return 0; // Loading interrupted
|
||||
}
|
||||
}
|
||||
|
||||
if (progress.load(::std::memory_order_acquire) < 0)
|
||||
return 0; // Loading interrupted
|
||||
|
||||
EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple);
|
||||
if (gather_statistics)
|
||||
{
|
||||
::std::vector<::std::thread> statistics_threads;
|
||||
statistics_threads.reserve(threaded_trees.size());
|
||||
|
||||
for (auto& it : threaded_trees)
|
||||
{
|
||||
auto& root = it.second;
|
||||
root.thread_id = it.first;
|
||||
//root.tree.shrink_to_fit();
|
||||
|
||||
auto& per_frame_statistics = frame_statistics[root.thread_id];
|
||||
auto& per_parent_statistics = parent_statistics[it.first];
|
||||
per_parent_statistics.clear();
|
||||
|
||||
statistics_threads.emplace_back(::std::thread([&per_parent_statistics, &per_frame_statistics, &blocks](::profiler::BlocksTreeRoot& root)
|
||||
int j = 0, n = static_cast<int>(statistics_threads.size());
|
||||
for (auto& t : statistics_threads)
|
||||
{
|
||||
t.join();
|
||||
progress.store(90 + (10 * ++j) / n, ::std::memory_order_release);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int j = 0, n = static_cast<int>(threaded_trees.size());
|
||||
for (auto& it : threaded_trees)
|
||||
{
|
||||
auto& root = it.second;
|
||||
root.thread_id = it.first;
|
||||
|
||||
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
|
||||
//{
|
||||
// return blocks[left].node->begin() < blocks[right].node->begin();
|
||||
//});
|
||||
|
||||
//root.tree.shrink_to_fit();
|
||||
for (auto i : root.children)
|
||||
{
|
||||
auto& frame = blocks[i];
|
||||
frame.per_parent_stats = update_statistics(per_parent_statistics, frame, i, root.thread_id);
|
||||
|
||||
per_frame_statistics.clear();
|
||||
update_statistics_recursive(per_frame_statistics, frame, i, i, blocks);
|
||||
|
||||
if (root.depth < frame.depth)
|
||||
root.depth = frame.depth;
|
||||
|
||||
root.active_time += frame.node->duration();
|
||||
}
|
||||
|
||||
++root.depth;
|
||||
}, ::std::ref(root)));
|
||||
}
|
||||
|
||||
int j = 0, n = static_cast<int>(statistics_threads.size());
|
||||
for (auto& t : statistics_threads)
|
||||
{
|
||||
t.join();
|
||||
progress.store(90 + (10 * ++j) / n, ::std::memory_order_release);
|
||||
progress.store(90 + (10 * ++j) / n, ::std::memory_order_release);
|
||||
}
|
||||
}
|
||||
// No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors
|
||||
|
||||
return blocks_counter;
|
||||
}
|
||||
else
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& inFile,
|
||||
::profiler::SerializedData& serialized_descriptors,
|
||||
::profiler::descriptors_list_t& descriptors)
|
||||
{
|
||||
int j = 0, n = static_cast<int>(threaded_trees.size());
|
||||
for (auto& it : threaded_trees)
|
||||
EASY_FUNCTION(::profiler::colors::Cyan);
|
||||
|
||||
progress.store(0);
|
||||
|
||||
uint32_t total_descriptors_number = 0;
|
||||
inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number)));
|
||||
if (total_descriptors_number == 0)
|
||||
return false;
|
||||
|
||||
uint64_t descriptors_memory_size = 0;
|
||||
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size)));
|
||||
if (descriptors_memory_size == 0)
|
||||
return false;
|
||||
|
||||
descriptors.reserve(total_descriptors_number);
|
||||
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
|
||||
serialized_descriptors.set(descriptors_memory_size);
|
||||
//validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size());
|
||||
|
||||
uint64_t i = 0;
|
||||
while (!inFile.eof() && descriptors.size() < total_descriptors_number)
|
||||
{
|
||||
auto& root = it.second;
|
||||
root.thread_id = it.first;
|
||||
|
||||
//::std::sort(root.sync.begin(), root.sync.end(), [&blocks](::profiler::block_index_t left, ::profiler::block_index_t right)
|
||||
//{
|
||||
// return blocks[left].node->begin() < blocks[right].node->begin();
|
||||
//});
|
||||
|
||||
//root.tree.shrink_to_fit();
|
||||
for (auto i : root.children)
|
||||
uint16_t sz = 0;
|
||||
inFile.read((char*)&sz, sizeof(sz));
|
||||
if (sz == 0)
|
||||
{
|
||||
auto& frame = blocks[i];
|
||||
if (root.depth < frame.depth)
|
||||
root.depth = frame.depth;
|
||||
root.active_time += frame.node->duration();
|
||||
descriptors.push_back(nullptr);
|
||||
continue;
|
||||
}
|
||||
|
||||
++root.depth;
|
||||
//if (i + sz > descriptors_memory_size) {
|
||||
// printf("FILE CORRUPTED\n");
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
progress.store(90 + (10 * ++j) / n, ::std::memory_order_release);
|
||||
char* data = serialized_descriptors[i];
|
||||
inFile.read(data, sz);
|
||||
auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data);
|
||||
descriptors.push_back(descriptor);
|
||||
|
||||
i += sz;
|
||||
auto oldprogress = progress.exchange(static_cast<int>(100 * i / descriptors_memory_size), ::std::memory_order_release);
|
||||
if (oldprogress < 0)
|
||||
return false; // Loading interrupted
|
||||
}
|
||||
}
|
||||
// No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors
|
||||
|
||||
return blocks_counter;
|
||||
return !descriptors.empty();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user