From 3b7266fb372f47dee7213c2f9cf703fbb894465a Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Thu, 29 Sep 2016 22:40:19 +0300 Subject: [PATCH 01/12] Prepare for saving profiled data (does not work yet); * Remastered tool-bars and menus; * Added new painting regime (Settings->View->Hide narrow children) --- include/profiler/reader.h | 140 ++++++-- profiler_gui/descriptors_tree_widget.cpp | 25 +- profiler_gui/easy_graphics_item.cpp | 73 +++-- profiler_gui/globals.cpp | 1 + profiler_gui/globals.h | 1 + profiler_gui/icons/attribution.txt | 3 +- profiler_gui/icons/save.svg | 28 +- profiler_gui/icons/settings.svg | 70 ++++ profiler_gui/main_window.cpp | 364 ++++++++++++++------- profiler_gui/main_window.h | 15 +- profiler_gui/resources.qrc | 1 + reader/main.cpp | 4 +- src/reader.cpp | 386 +++++++++++++++++++---- 13 files changed, 849 insertions(+), 262 deletions(-) create mode 100644 profiler_gui/icons/settings.svg diff --git a/include/profiler/reader.h b/include/profiler/reader.h index ce65e2f..8c4c643 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -78,6 +78,7 @@ namespace profiler { public: typedef ::std::vector blocks_t; + typedef ::std::vector pblocks_t; typedef ::std::vector<::profiler::block_index_t> children_t; children_t children; ///< List of children blocks. May be empty. @@ -234,6 +235,7 @@ namespace profiler { }; // END of class BlocksTreeRoot. typedef ::profiler::BlocksTree::blocks_t blocks_t; + typedef ::profiler::BlocksTree::pblocks_t pblocks_t; typedef ::std::unordered_map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot, ::profiler::passthrough_hash> thread_blocks_tree_t; ////////////////////////////////////////////////////////////////////////// @@ -260,8 +262,8 @@ namespace profiler { clear(); } - void set(size_t _size); - void extend(size_t _size); + void set(uint64_t _size); + void extend(uint64_t _size); SerializedData& operator = (SerializedData&& that) { @@ -276,7 +278,17 @@ namespace profiler { return m_data + i; } - size_t size() const + const char* operator [] (uint64_t i) const + { + return m_data + i; + } + + bool empty() const + { + return m_size == 0; + } + + uint64_t size() const { return m_size; } @@ -299,7 +311,7 @@ namespace profiler { void swap(SerializedData& other) { char* d = other.m_data; - size_t sz = other.m_size; + uint64_t sz = other.m_size; other.m_data = m_data; other.m_size = m_size; @@ -310,7 +322,7 @@ namespace profiler { private: - void set(char* _data, size_t _size); + void set(char* _data, uint64_t _size); SerializedData(const SerializedData&) = delete; SerializedData& operator = (const SerializedData&) = delete; @@ -319,6 +331,51 @@ namespace profiler { ////////////////////////////////////////////////////////////////////////// + struct FileData + { + ::profiler::SerializedData serialized_blocks; + ::profiler::SerializedData serialized_descriptors; + ::std::vector<::profiler::thread_id_t> threads_order; + ::profiler::timestamp_t begin_time = 0ULL; + ::profiler::timestamp_t end_time = 0ULL; + int64_t cpu_frequency = 0LL; + uint32_t total_blocks_number = 0; + uint32_t total_descriptors_number = 0; + + FileData() = default; + FileData(FileData&& _other) + : serialized_blocks(::std::move(_other.serialized_blocks)) + , serialized_descriptors(::std::move(_other.serialized_descriptors)) + , threads_order(::std::move(_other.threads_order)) + , begin_time(_other.begin_time) + , end_time(_other.end_time) + , cpu_frequency(_other.cpu_frequency) + , total_blocks_number(_other.total_blocks_number) + , total_descriptors_number(_other.total_descriptors_number) + { + } + + FileData& operator = (FileData&& _other) + { + serialized_blocks = ::std::move(_other.serialized_blocks); + serialized_descriptors = ::std::move(_other.serialized_descriptors); + threads_order = ::std::move(_other.threads_order); + begin_time = _other.begin_time; + end_time = _other.end_time; + cpu_frequency = _other.cpu_frequency; + total_blocks_number = _other.total_blocks_number; + total_descriptors_number = _other.total_descriptors_number; + return *this; + } + + private: + + FileData(const FileData&) = delete; + FileData& operator = (const FileData&) = delete; + }; + + ////////////////////////////////////////////////////////////////////////// + typedef ::std::vector descriptors_list_t; } // END of namespace profiler. @@ -326,37 +383,50 @@ namespace profiler { extern "C" { PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic& 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, - ::std::stringstream& _log); + ::profiler::FileData& filedata, + ::profiler::descriptors_list_t& descriptors, + ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, + bool gather_statistics, + ::std::stringstream& _log); PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic& 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, - ::std::stringstream& _log); + ::profiler::FileData& filedata, + ::profiler::descriptors_list_t& descriptors, + ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, + bool gather_statistics, + ::std::stringstream& _log); PROFILER_API bool readDescriptionsFromStream(::std::atomic& progress, ::std::stringstream& str, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::std::stringstream& _log); + + PROFILER_API bool writeTreesToStream(::std::atomic& progress, + ::std::stringstream& str, + const ::profiler::FileData& filedata, + const ::profiler::thread_blocks_tree_t& threaded_trees, + const ::profiler::descriptors_list_t& _descriptors, + const ::profiler::pblocks_t& _blocks, + ::std::stringstream& _log); + + PROFILER_API bool writeTreesToFile(::std::atomic& progress, + const char* filename, + const ::profiler::FileData& filedata, + const ::profiler::thread_blocks_tree_t& threaded_trees, + const ::profiler::descriptors_list_t& _descriptors, + const ::profiler::pblocks_t& _blocks, + ::std::stringstream& _log); } -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, +inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::FileData& filedata, + ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, bool gather_statistics, ::std::stringstream& _log) { ::std::atomic progress = ATOMIC_VAR_INIT(0); - return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, gather_statistics, _log); + return fillTreesFromFile(progress, filename, filedata, descriptors, _blocks, threaded_trees, gather_statistics, _log); } inline bool readDescriptionsFromStream(::std::stringstream& str, @@ -368,6 +438,28 @@ inline bool readDescriptionsFromStream(::std::stringstream& str, return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log); } +inline bool writeTreesToStream(::std::stringstream& str, + const ::profiler::FileData& filedata, + const ::profiler::thread_blocks_tree_t& threaded_trees, + const ::profiler::descriptors_list_t& _descriptors, + const ::profiler::pblocks_t& _blocks, + ::std::stringstream& _log) +{ + ::std::atomic progress = ATOMIC_VAR_INIT(0); + return writeTreesToStream(progress, str, filedata, threaded_trees, _descriptors, _blocks, _log); +} + +inline bool writeTreesToFile(const char* filename, + const ::profiler::FileData& filedata, + const ::profiler::thread_blocks_tree_t& threaded_trees, + const ::profiler::descriptors_list_t& _descriptors, + const ::profiler::pblocks_t& _blocks, + ::std::stringstream& _log) +{ + ::std::atomic progress = ATOMIC_VAR_INIT(0); + return writeTreesToFile(progress, filename, filedata, threaded_trees, _descriptors, _blocks, _log); +} + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif // PROFILER_READER____H diff --git a/profiler_gui/descriptors_tree_widget.cpp b/profiler_gui/descriptors_tree_widget.cpp index 7759f1a..feebc9f 100644 --- a/profiler_gui/descriptors_tree_widget.cpp +++ b/profiler_gui/descriptors_tree_widget.cpp @@ -696,6 +696,7 @@ EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent) , m_searchButton(nullptr) { m_searchBox->setFixedWidth(200); + m_searchBox->setContentsMargins(5, 0, 0, 0); auto tb = new QToolBar(); auto refreshButton = tb->addAction(QIcon(":/Reload"), tr("Refresh blocks list")); @@ -703,26 +704,32 @@ EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent) 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)); + QMenu* menu = new QMenu(this); + m_searchButton = menu->menuAction(); + m_searchButton->setText("Find next"); + m_searchButton->setIcon(QIcon(":/Search-next")); + m_searchButton->setData(true); + connect(m_searchButton, &QAction::triggered, this, &This::findNext); + auto actionGroup = new QActionGroup(this); - actionGroup->setExclusive(true); - + 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); + 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); + menu->addAction(a); + + tb->addSeparator(); + tb->addAction(m_searchButton); + tb->addWidget(m_searchBox); auto searchbox = new QHBoxLayout(); searchbox->setContentsMargins(0, 0, 0, 0); diff --git a/profiler_gui/easy_graphics_item.cpp b/profiler_gui/easy_graphics_item.cpp index d8111fb..366fdbc 100644 --- a/profiler_gui/easy_graphics_item.cpp +++ b/profiler_gui/easy_graphics_item.cpp @@ -47,6 +47,9 @@ enum BlockItemState ////////////////////////////////////////////////////////////////////////// +const int MIN_ITEM_WIDTH = 2; +const int MIN_ITEMS_SPACING = 2; +const int NARROW_ITEM_WIDTH = 20; const QRgb BORDERS_COLOR = ::profiler::colors::Grey700 & 0x00ffffff;// 0x00686868; inline QRgb selectedItemBorderColor(::profiler::color_t _color) { @@ -181,6 +184,21 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* m_levels[next_level][children_begin].state = BLOCK_ITEM_DO_NOT_PAINT; }; + auto const dont_skip_children = [this, &levelsNumber](short next_level, decltype(::profiler_gui::EasyBlockItem::children_begin) children_begin) + { + if (next_level < levelsNumber && children_begin != MAX_CHILD_INDEX) + { + if (m_levelsIndexes[next_level] == MAX_CHILD_INDEX) + { + // Mark first potentially visible child item on next sublevel + m_levelsIndexes[next_level] = children_begin; + } + + // Mark children items that we want to draw them + m_levels[next_level][children_begin].state = BLOCK_ITEM_DO_PAINT; + } + }; + bool selectedItemsWasPainted = false; for (uint8_t l = 0; l < levelsNumber; ++l) { @@ -209,21 +227,29 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* continue; } - const auto x = item.left() * currentScale - dx; + auto x = item.left() * currentScale - dx; auto w = item.width() * currentScale; if (x + w <= prevRight) { // This item is not visible - if (w < 20) + if (EASY_GLOBALS.hide_narrow_children && w < NARROW_ITEM_WIDTH) skip_children(next_level, item.children_begin); + else + dont_skip_children(next_level, item.children_begin); continue; } + if (x < prevRight) + { + w -= prevRight - x; + x = prevRight; + } + const auto& itemBlock = easyBlock(item.block); const auto& itemDesc = easyDescriptor(itemBlock.tree.node->id()); int h = 0, flags = 0; - if (w < 20 || !itemBlock.expanded) + if ((EASY_GLOBALS.hide_narrow_children && w < NARROW_ITEM_WIDTH) || !itemBlock.expanded) { // Items which width is less than 20 will be painted as big rectangles which are hiding it's children @@ -254,15 +280,16 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _painter->setPen(BORDERS_COLOR & inverseColor);// BORDERS_COLOR); } - if (w < 2) w = 2; + if (w < MIN_ITEM_WIDTH) + w = MIN_ITEM_WIDTH; // Draw rectangle rect.setRect(x, top, w, h); _painter->drawRect(rect); - prevRight = rect.right(); + prevRight = rect.right() + MIN_ITEMS_SPACING; skip_children(next_level, item.children_begin); - if (w < 20) + if (w < NARROW_ITEM_WIDTH) continue; if (item.totalHeight > ::profiler_gui::GRAPHICS_ROW_SIZE) @@ -272,18 +299,6 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* } else { - if (next_level < levelsNumber && item.children_begin != MAX_CHILD_INDEX) - { - if (m_levelsIndexes[next_level] == MAX_CHILD_INDEX) - { - // Mark first potentially visible child item on next sublevel - m_levelsIndexes[next_level] = item.children_begin; - } - - // Mark children items that we want to draw them - m_levels[next_level][item.children_begin].state = BLOCK_ITEM_DO_PAINT; - } - if (item.block == EASY_GLOBALS.selected_block) selectedItemsWasPainted = true; @@ -312,13 +327,19 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* if (dh > 0) h -= dh; + if (w < MIN_ITEM_WIDTH) + w = MIN_ITEM_WIDTH; + rect.setRect(x, top, w, h); _painter->drawRect(rect); + prevRight = rect.right() + MIN_ITEMS_SPACING; + dont_skip_children(next_level, item.children_begin); + if (w < NARROW_ITEM_WIDTH) + continue; + if (!(item.width() < 1)) flags = Qt::AlignHCenter; - - prevRight = rect.right(); } // Draw text----------------------------------- @@ -375,7 +396,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* const auto& itemBlock = easyBlock(item.block); auto top = levelY(guiblock.graphics_item_level); auto w = ::std::max(item.width() * currentScale, 1.0); - decltype(top) h = (selectedItemsWasPainted && itemBlock.expanded && w > 20) ? ::profiler_gui::GRAPHICS_ROW_SIZE : item.totalHeight; + decltype(top) h = (!itemBlock.expanded || (w < NARROW_ITEM_WIDTH && EASY_GLOBALS.hide_narrow_children)) ? item.totalHeight : ::profiler_gui::GRAPHICS_ROW_SIZE; auto dh = top + h - visibleBottom; if (dh < h) @@ -405,7 +426,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* rect.setRect(x, top, w, h); _painter->drawRect(rect); - if (!selectedItemsWasPainted && w > 20) + if (!selectedItemsWasPainted && w > NARROW_ITEM_WIDTH) { // Draw text----------------------------------- // calculating text coordinates @@ -492,8 +513,8 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* left = prevRight; } - if (width < 2) - width = 2; + if (width < MIN_ITEM_WIDTH) + width = MIN_ITEM_WIDTH; const bool self_thread = item.node->id() != 0 && EASY_GLOBALS.profiler_blocks.find(item.node->id()) != EASY_GLOBALS.profiler_blocks.end(); ::profiler::color_t color = 0; @@ -516,7 +537,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* rect.setRect(left, top, width, h); _painter->drawRect(rect); - prevRight = left + width; + prevRight = left + width + MIN_ITEMS_SPACING; } } } @@ -725,7 +746,7 @@ const ::profiler_gui::EasyBlockItem* EasyGraphicsItem::intersect(const QPointF& } const auto w = item.width() * currentScale; - if (i == levelIndex || w < 20 || !easyBlock(item.block).expanded) + if (i == levelIndex || (w < NARROW_ITEM_WIDTH && EASY_GLOBALS.hide_narrow_children) || !easyBlock(item.block).expanded) { return &item; } diff --git a/profiler_gui/globals.cpp b/profiler_gui/globals.cpp index 572acbb..635cf13 100644 --- a/profiler_gui/globals.cpp +++ b/profiler_gui/globals.cpp @@ -51,6 +51,7 @@ namespace profiler_gui { , enable_event_indicators(true) , enable_statistics(true) , draw_graphics_items_borders(true) + , hide_narrow_children(false) , display_only_relevant_stats(true) , collapse_items_on_tree_close(false) , all_items_expanded_by_default(true) diff --git a/profiler_gui/globals.h b/profiler_gui/globals.h index 292fdab..744aaeb 100644 --- a/profiler_gui/globals.h +++ b/profiler_gui/globals.h @@ -101,6 +101,7 @@ namespace profiler_gui { 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 + bool hide_narrow_children; ///< Hide children for narrow graphics blocks bool display_only_relevant_stats; ///< Display only relevant information in ProfTreeWidget (excludes min, max, average times if there are only 1 calls number) bool collapse_items_on_tree_close; ///< Collapse all items which were displayed in the hierarchy tree after tree close/reset bool all_items_expanded_by_default; ///< Expand all items after file is opened diff --git a/profiler_gui/icons/attribution.txt b/profiler_gui/icons/attribution.txt index 25e902b..304043f 100644 --- a/profiler_gui/icons/attribution.txt +++ b/profiler_gui/icons/attribution.txt @@ -17,4 +17,5 @@ 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 \ No newline at end of file +search-next.svg - Icon made by Freepik from www.flaticon.com +settings.svg - Icon made by Freepik from www.flaticon.com \ No newline at end of file diff --git a/profiler_gui/icons/save.svg b/profiler_gui/icons/save.svg index c3b92ad..d618cd5 100644 --- a/profiler_gui/icons/save.svg +++ b/profiler_gui/icons/save.svg @@ -1,14 +1,24 @@ - - - + + - + + + + + + + diff --git a/profiler_gui/icons/settings.svg b/profiler_gui/icons/settings.svg new file mode 100644 index 0000000..07714c0 --- /dev/null +++ b/profiler_gui/icons/settings.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index c57bd31..521b909 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -53,6 +53,8 @@ #include #include #include +#include +#include #include #include #include @@ -80,7 +82,7 @@ const int LOADER_TIMER_INTERVAL = 40; ////////////////////////////////////////////////////////////////////////// -EasyMainWindow::EasyMainWindow() : Parent() +EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("127.0.0.1"), m_lastPort(::profiler::DEFAULT_PORT) { { QIcon icon(":/logo"); if (!icon.isNull()) QApplication::setWindowIcon(icon); } @@ -118,9 +120,27 @@ EasyMainWindow::EasyMainWindow() : Parent() addDockWidget(Qt::BottomDockWidgetArea, m_descTreeWidget); #endif - auto toolbar = addToolBar("MainToolBar"); - toolbar->setObjectName("ProfilerGUI_MainToolBar"); - toolbar->addAction(QIcon(":/Delete"), tr("Clear all"), this, SLOT(onDeleteClicked(bool))); + + loadSettings(); + + + auto toolbar = addToolBar("FileToolbar"); + toolbar->setObjectName("ProfilerGUI_FileToolbar"); + toolbar->setContentsMargins(1, 0, 1, 0); + + toolbar->addAction(QIcon(":/Open"), tr("Open"), this, SLOT(onOpenFileClicked(bool))); + toolbar->addAction(QIcon(":/Reload"), tr("Reload"), this, SLOT(onReloadFileClicked(bool))); + m_saveAction = toolbar->addAction(QIcon(":/Save"), tr("Save"), this, SLOT(onSaveFileClicked(bool))); + m_deleteAction = toolbar->addAction(QIcon(":/Delete"), tr("Clear all"), this, SLOT(onDeleteClicked(bool))); + + m_saveAction->setEnabled(false); + m_deleteAction->setEnabled(false); + + + + toolbar = addToolBar("ProfileToolbar"); + toolbar->setObjectName("ProfilerGUI_ProfileToolbar"); + toolbar->setContentsMargins(1, 0, 1, 0); toolbar->addAction(QIcon(":/List"), tr("Blocks"), this, SLOT(onEditBlocksClicked(bool))); m_captureAction = toolbar->addAction(QIcon(":/Start"), tr("Capture"), this, SLOT(onCaptureClicked(bool))); @@ -129,18 +149,22 @@ EasyMainWindow::EasyMainWindow() : Parent() toolbar->addSeparator(); m_connectAction = toolbar->addAction(QIcon(":/Connection"), tr("Connect"), this, SLOT(onConnectClicked(bool))); - toolbar->addWidget(new QLabel(" IP:")); + auto lbl = new QLabel("IP:", toolbar); + lbl->setContentsMargins(5, 0, 1, 0); + toolbar->addWidget(lbl); m_ipEdit = new QLineEdit(); QRegExp rx("^0*(2(5[0-5]|[0-4]\\d)|1?\\d{1,2})(\\.0*(2(5[0-5]|[0-4]\\d)|1?\\d{1,2})){3}$"); m_ipEdit->setValidator(new QRegExpValidator(rx, m_ipEdit)); - m_ipEdit->setText("127.0.0.1"); + m_ipEdit->setText(m_lastAddress); m_ipEdit->setFixedWidth(m_ipEdit->fontMetrics().width(QString("255.255.255.255")) + 20); toolbar->addWidget(m_ipEdit); - toolbar->addWidget(new QLabel(" Port:")); + lbl = new QLabel("Port:", toolbar); + lbl->setContentsMargins(5, 0, 1, 0); + toolbar->addWidget(lbl); m_portEdit = new QLineEdit(); m_portEdit->setValidator(new QIntValidator(1, 65535, m_portEdit)); - m_portEdit->setText(QString::number(::profiler::DEFAULT_PORT)); + m_portEdit->setText(QString::number(m_lastPort)); m_portEdit->setFixedWidth(m_portEdit->fontMetrics().width(QString("000000")) + 10); toolbar->addWidget(m_portEdit); @@ -148,86 +172,23 @@ EasyMainWindow::EasyMainWindow() : Parent() connect(m_portEdit, &QLineEdit::returnPressed, [this](){ onConnectClicked(true); }); - loadSettings(); - if (!m_lastAddress.isEmpty()) - m_ipEdit->setText(m_lastAddress); - if (m_lastPort != 0) - m_portEdit->setText(QString::number(m_lastPort)); + toolbar = addToolBar("SetupToolbar"); + toolbar->setObjectName("ProfilerGUI_SetupToolbar"); + toolbar->setContentsMargins(1, 0, 1, 0); - auto menu = menuBar()->addMenu("&File"); - menu->addAction(QIcon(":/Open"), "&Open", this, SLOT(onOpenFileClicked(bool))); - menu->addAction(QIcon(":/Reload"), "&Reload", this, SLOT(onReloadFileClicked(bool))); - menu->addSeparator(); - menu->addAction(QIcon(":/Exit"), "&Exit", this, SLOT(onExitClicked(bool))); + toolbar->addAction(QIcon(":/Expand"), "Expand all", this, SLOT(onExpandAllClicked(bool))); + toolbar->addAction(QIcon(":/Collapse"), "Collapse all", this, SLOT(onCollapseAllClicked(bool))); + toolbar->addSeparator(); + auto menu = new QMenu("Settings", this); + QToolButton* toolButton = new QToolButton(toolbar); + toolButton->setIcon(QIcon(":/Settings")); + toolButton->setMenu(menu); + toolButton->setPopupMode(QToolButton::InstantPopup); + toolbar->addWidget(toolButton); - - menu = menuBar()->addMenu("&View"); - - menu->addAction(QIcon(":/Expand"), "Expand all", this, SLOT(onExpandAllClicked(bool))); - menu->addAction(QIcon(":/Collapse"), "Collapse all", this,SLOT(onCollapseAllClicked(bool))); - - menu->addSeparator(); - - auto action = menu->addAction("Draw items' borders"); - action->setCheckable(true); - action->setChecked(EASY_GLOBALS.draw_graphics_items_borders); - connect(action, &QAction::triggered, this, &This::onDrawBordersChanged); - - action = menu->addAction("Collapse items on tree reset"); - action->setCheckable(true); - action->setChecked(EASY_GLOBALS.collapse_items_on_tree_close); - connect(action, &QAction::triggered, this, &This::onCollapseItemsAfterCloseChanged); - - action = menu->addAction("Expand all on file open"); - action->setCheckable(true); - action->setChecked(EASY_GLOBALS.all_items_expanded_by_default); - connect(action, &QAction::triggered, this, &This::onAllItemsExpandedByDefaultChange); - - action = menu->addAction("Bind scene and tree expand"); - action->setCheckable(true); - action->setChecked(EASY_GLOBALS.bind_scene_and_tree_expand_status); - connect(action, &QAction::triggered, this, &This::onBindExpandStatusChange); - - action = menu->addAction("Draw event indicators"); - action->setCheckable(true); - action->setChecked(EASY_GLOBALS.enable_event_indicators); - connect(action, &QAction::triggered, this, &This::onEventIndicatorsChange); - - menu->addSeparator(); - auto submenu = menu->addMenu("Chronometer text"); - auto actionGroup = new QActionGroup(this); - actionGroup->setExclusive(true); - - action = new QAction("At top", actionGroup); - action->setCheckable(true); - action->setData(static_cast(::profiler_gui::ChronoTextPosition_Top)); - if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Top) - action->setChecked(true); - submenu->addAction(action); - connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); - - action = new QAction("At center", actionGroup); - action->setCheckable(true); - action->setData(static_cast(::profiler_gui::ChronoTextPosition_Center)); - if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Center) - action->setChecked(true); - submenu->addAction(action); - connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); - - action = new QAction("At bottom", actionGroup); - action->setCheckable(true); - action->setData(static_cast(::profiler_gui::ChronoTextPosition_Bottom)); - if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Bottom) - action->setChecked(true); - submenu->addAction(action); - connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); - - - - menu = menuBar()->addMenu("&Settings"); - action = menu->addAction("Statistics enabled"); + auto action = menu->addAction("Statistics enabled"); action->setCheckable(true); action->setChecked(EASY_GLOBALS.enable_statistics); connect(action, &QAction::triggered, this, &This::onEnableDisableStatistics); @@ -244,8 +205,69 @@ EasyMainWindow::EasyMainWindow() : Parent() SET_ICON(action, ":/Stats-off"); } + menu->addSeparator(); - submenu = menu->addMenu("&Remote"); + auto submenu = menu->addMenu("View"); + action = submenu->addAction("Draw items' borders"); + action->setCheckable(true); + action->setChecked(EASY_GLOBALS.draw_graphics_items_borders); + connect(action, &QAction::triggered, this, &This::onDrawBordersChanged); + + action = submenu->addAction("Hide narrow children"); + action->setCheckable(true); + action->setChecked(EASY_GLOBALS.hide_narrow_children); + connect(action, &QAction::triggered, this, &This::onHideNarrowChildrenChanged); + + action = submenu->addAction("Collapse items on tree reset"); + action->setCheckable(true); + action->setChecked(EASY_GLOBALS.collapse_items_on_tree_close); + connect(action, &QAction::triggered, this, &This::onCollapseItemsAfterCloseChanged); + + action = submenu->addAction("Expand all on file open"); + action->setCheckable(true); + action->setChecked(EASY_GLOBALS.all_items_expanded_by_default); + connect(action, &QAction::triggered, this, &This::onAllItemsExpandedByDefaultChange); + + action = submenu->addAction("Bind scene and tree expand"); + action->setCheckable(true); + action->setChecked(EASY_GLOBALS.bind_scene_and_tree_expand_status); + connect(action, &QAction::triggered, this, &This::onBindExpandStatusChange); + + action = submenu->addAction("Draw event indicators"); + action->setCheckable(true); + action->setChecked(EASY_GLOBALS.enable_event_indicators); + connect(action, &QAction::triggered, this, &This::onEventIndicatorsChange); + + submenu->addSeparator(); + auto actionGroup = new QActionGroup(this); + actionGroup->setExclusive(true); + + action = new QAction("Chrono text at top", actionGroup); + action->setCheckable(true); + action->setData(static_cast(::profiler_gui::ChronoTextPosition_Top)); + if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Top) + action->setChecked(true); + submenu->addAction(action); + connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); + + action = new QAction("Chrono text at center", actionGroup); + action->setCheckable(true); + action->setData(static_cast(::profiler_gui::ChronoTextPosition_Center)); + if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Center) + action->setChecked(true); + submenu->addAction(action); + connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); + + action = new QAction("Chrono text at bottom", actionGroup); + action->setCheckable(true); + action->setData(static_cast(::profiler_gui::ChronoTextPosition_Bottom)); + if (EASY_GLOBALS.chrono_text_position == ::profiler_gui::ChronoTextPosition_Bottom) + action->setChecked(true); + submenu->addAction(action); + connect(action, &QAction::triggered, this, &This::onChronoTextPosChanged); + + + submenu = menu->addMenu("Remote"); m_eventTracingEnableAction = submenu->addAction("Event tracing enabled"); m_eventTracingEnableAction->setCheckable(true); m_eventTracingEnableAction->setEnabled(false); @@ -257,13 +279,13 @@ EasyMainWindow::EasyMainWindow() : Parent() m_eventTracingPriorityAction->setEnabled(false); connect(m_eventTracingPriorityAction, &QAction::triggered, this, &This::onEventTracingPriorityChange); - menu->addSeparator(); - submenu = menu->addMenu("&Encoding"); + + submenu = menu->addMenu("Encoding"); actionGroup = new QActionGroup(this); actionGroup->setExclusive(true); auto default_codec_mib = QTextCodec::codecForLocale()->mibEnum(); - foreach (int mib, QTextCodec::availableMibs()) + foreach(int mib, QTextCodec::availableMibs()) { auto codec = QTextCodec::codecForMib(mib)->name(); @@ -352,6 +374,41 @@ void EasyMainWindow::onReloadFileClicked(bool) ////////////////////////////////////////////////////////////////////////// +void EasyMainWindow::onSaveFileClicked(bool) +{ + if (m_filedata.serialized_blocks.empty()) + return; + + const auto i = m_lastFile.lastIndexOf(QChar('/')); + const auto j = m_lastFile.lastIndexOf(QChar('\\')); + auto k = ::std::max(i, j); + + QString dir; + if (k > 0) + dir = m_lastFile.mid(0, ++k); + + auto filename = QFileDialog::getSaveFileName(this, "Save profiler log", dir, "Profiler Log File (*.prof);;All Files (*.*)"); + if (!filename.isEmpty()) + { + QMessageBox::warning(this, "Warning", "Saving is not working yet :)", QMessageBox::Close); + + /* + ::std::stringstream errorMessage; + + ::profiler::pblocks_t blocks(EASY_GLOBALS.gui_blocks.size()); + for (size_t i = 0, size = EASY_GLOBALS.gui_blocks.size(); i < size; ++i) + blocks[i] = &EASY_GLOBALS.gui_blocks[i].tree; + + if (writeTreesToFile(filename.toStdString().c_str(), m_filedata, EASY_GLOBALS.profiler_blocks, EASY_GLOBALS.descriptors, blocks, errorMessage)) + m_lastFile = filename; + else + QMessageBox::warning(this, "Warning", QString("Can not save blocks to file.\n\nReason:\n%1").arg(errorMessage.str().c_str()), QMessageBox::Close); + */ + } +} + +////////////////////////////////////////////////////////////////////////// + void EasyMainWindow::onDeleteClicked(bool) { static_cast(m_treeWidget->widget())->clearSilent(true); @@ -369,8 +426,11 @@ void EasyMainWindow::onDeleteClicked(bool) EASY_GLOBALS.descriptors.clear(); EASY_GLOBALS.gui_blocks.clear(); - m_serializedBlocks.clear(); - m_serializedDescriptors.clear(); + m_filedata.serialized_blocks.clear(); + m_filedata.serialized_descriptors.clear(); + + m_saveAction->setEnabled(false); + m_deleteAction->setEnabled(false); } ////////////////////////////////////////////////////////////////////////// @@ -433,6 +493,12 @@ void EasyMainWindow::onDrawBordersChanged(bool _checked) static_cast(m_graphicsView->widget())->view()->scene()->update(); } +void EasyMainWindow::onHideNarrowChildrenChanged(bool _checked) +{ + EASY_GLOBALS.hide_narrow_children = _checked; + static_cast(m_graphicsView->widget())->view()->scene()->update(); +} + void EasyMainWindow::onCollapseItemsAfterCloseChanged(bool _checked) { EASY_GLOBALS.collapse_items_on_tree_close = _checked; @@ -551,6 +617,10 @@ void EasyMainWindow::loadSettings() if (!flag.isNull()) EASY_GLOBALS.draw_graphics_items_borders = flag.toBool(); + flag = settings.value("hide_narrow_children"); + if (!flag.isNull()) + EASY_GLOBALS.hide_narrow_children = flag.toBool(); + flag = settings.value("collapse_items_on_tree_close"); if (!flag.isNull()) EASY_GLOBALS.collapse_items_on_tree_close = flag.toBool(); @@ -607,6 +677,7 @@ void EasyMainWindow::saveSettingsAndGeometry() settings.setValue("port", (quint32)m_lastPort); settings.setValue("chrono_text_position", static_cast(EASY_GLOBALS.chrono_text_position)); settings.setValue("draw_graphics_items_borders", EASY_GLOBALS.draw_graphics_items_borders); + settings.setValue("hide_narrow_children", EASY_GLOBALS.hide_narrow_children); settings.setValue("collapse_items_on_tree_close", EASY_GLOBALS.collapse_items_on_tree_close); settings.setValue("all_items_expanded_by_default", EASY_GLOBALS.all_items_expanded_by_default); settings.setValue("bind_scene_and_tree_expand_status", EASY_GLOBALS.bind_scene_and_tree_expand_status); @@ -687,12 +758,12 @@ void EasyMainWindow::onFileReaderTimeout() { static_cast(m_treeWidget->widget())->clearSilent(true); - ::profiler::SerializedData serialized_blocks, serialized_descriptors; + ::profiler::FileData fd; ::profiler::descriptors_list_t descriptors; ::profiler::blocks_t blocks; ::profiler::thread_blocks_tree_t threads_map; QString filename; - m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map, filename); + m_reader.get(fd, descriptors, blocks, threads_map, filename); if (threads_map.size() > 0xff) { @@ -705,8 +776,7 @@ void EasyMainWindow::onFileReaderTimeout() if (m_reader.isFile()) m_lastFile = ::std::move(filename); - m_serializedBlocks = ::std::move(serialized_blocks); - m_serializedDescriptors = ::std::move(serialized_descriptors); + m_filedata = ::std::move(fd); EASY_GLOBALS.selected_thread = 0; ::profiler_gui::set_max(EASY_GLOBALS.selected_block); EASY_GLOBALS.profiler_blocks.swap(threads_map); @@ -728,6 +798,9 @@ void EasyMainWindow::onFileReaderTimeout() #endif if (m_dialogDescTree != nullptr) m_dialogDescTree->build(); + + m_saveAction->setEnabled(true); + m_deleteAction->setEnabled(true); } else { @@ -803,7 +876,7 @@ void EasyFileReader::load(const QString& _filename) m_isFile = true; m_filename = _filename; m_thread = ::std::move(::std::thread([this](bool _enableStatistics) { - m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, _enableStatistics, m_errorMessage), ::std::memory_order_release); + m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_filedata, m_descriptors, m_blocks, m_blocksTree, _enableStatistics, m_errorMessage), ::std::memory_order_release); m_progress.store(100, ::std::memory_order_release); m_bDone.store(true, ::std::memory_order_release); }, EASY_GLOBALS.enable_statistics)); @@ -817,7 +890,7 @@ void EasyFileReader::load(::std::stringstream& _stream) m_filename.clear(); m_stream.swap(_stream); m_thread = ::std::move(::std::thread([this](bool _enableStatistics) { - m_size.store(fillTreesFromStream(m_progress, m_stream, m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, _enableStatistics, m_errorMessage), ::std::memory_order_release); + m_size.store(fillTreesFromStream(m_progress, m_stream, m_filedata, m_descriptors, m_blocks, m_blocksTree, _enableStatistics, m_errorMessage), ::std::memory_order_release); m_progress.store(100, ::std::memory_order_release); m_bDone.store(true, ::std::memory_order_release); }, EASY_GLOBALS.enable_statistics)); @@ -832,8 +905,8 @@ void EasyFileReader::interrupt() m_bDone.store(false, ::std::memory_order_release); m_progress.store(0, ::std::memory_order_release); m_size.store(0, ::std::memory_order_release); - m_serializedBlocks.clear(); - m_serializedDescriptors.clear(); + m_filedata.serialized_blocks.clear(); + m_filedata.serialized_descriptors.clear(); m_descriptors.clear(); m_blocks.clear(); m_blocksTree.clear(); @@ -842,18 +915,23 @@ void EasyFileReader::interrupt() { decltype(m_errorMessage) dummy; dummy.swap(m_errorMessage); } } -void EasyFileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors, - ::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree, - QString& _filename) +void EasyFileReader::get(::profiler::FileData& _filedata, ::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& _tree, QString& _filename) { if (done()) { - m_serializedBlocks.swap(_serializedBlocks); - m_serializedDescriptors.swap(_serializedDescriptors); + m_filedata.serialized_blocks.swap(_filedata.serialized_blocks); + m_filedata.serialized_descriptors.swap(_filedata.serialized_descriptors); + m_filedata.threads_order.swap(_filedata.threads_order); ::profiler::descriptors_list_t(::std::move(m_descriptors)).swap(_descriptors); m_blocks.swap(_blocks); m_blocksTree.swap(_tree); m_filename.swap(_filename); + _filedata.cpu_frequency = m_filedata.cpu_frequency; + _filedata.begin_time = m_filedata.begin_time; + _filedata.end_time = m_filedata.end_time; + _filedata.total_blocks_number = m_filedata.total_blocks_number; + _filedata.total_descriptors_number = m_filedata.total_descriptors_number; } } @@ -993,27 +1071,77 @@ void EasyMainWindow::onGetBlockDescriptionsClicked(bool) { // Read descriptions from stream decltype(EASY_GLOBALS.descriptors) descriptors; - decltype(m_serializedDescriptors) serializedDescriptors; + decltype(m_filedata.serialized_descriptors) serializedDescriptors; ::std::stringstream errorMessage; if (readDescriptionsFromStream(m_listener.data(), serializedDescriptors, descriptors, errorMessage)) { - if (EASY_GLOBALS.descriptors.size() > descriptors.size()) - onDeleteClicked(true); // Clear all contents because new descriptors list conflicts with old one - - EASY_GLOBALS.descriptors.swap(descriptors); - m_serializedDescriptors.swap(serializedDescriptors); - - if (m_descTreeDialog != nullptr) + bool cancel = false; + const bool doFlush = m_filedata.total_descriptors_number != descriptors.size(); + if (doFlush && !m_filedata.serialized_blocks.empty()) { -#if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0 - static_cast(m_descTreeWidget->widget())->build(); -#endif - m_dialogDescTree->build(); - m_descTreeDialog->raise(); + auto button = QMessageBox::question(this, "Information", + QString("New blocks description number = %1\ndiffers from the old one = %2.\nTo avoid possible conflicts\nall profiled data will be deleted.\nPress \"Yes\" to continue or \"No\" to cancel.") + .arg(descriptors.size()) + .arg(m_filedata.total_descriptors_number), + QMessageBox::Yes, QMessageBox::No); + + if (button == QMessageBox::Yes) + onDeleteClicked(true); // Clear all contents because new descriptors list conflicts with old one + else + cancel = true; } - else + + if (!cancel) { - onEditBlocksClicked(true); + auto oldnumber = m_filedata.total_descriptors_number; + m_filedata.total_descriptors_number = static_cast(descriptors.size()); + EASY_GLOBALS.descriptors.swap(descriptors); + m_filedata.serialized_descriptors.swap(serializedDescriptors); + + if (!doFlush && !m_filedata.serialized_blocks.empty() && descriptors.size() > oldnumber) + { + // There are dynamically added descriptors, add them to the new list too + + auto diff = descriptors.size() - oldnumber; + EASY_GLOBALS.descriptors.reserve(EASY_GLOBALS.descriptors.size() + diff); + for (decltype(diff) i = 0; i < diff; ++i) + { + auto desc = descriptors[oldnumber + i]; + for (decltype(oldnumber) j = 0; j < oldnumber; ++j) + { + if (descriptors[j] == desc) + { + EASY_GLOBALS.descriptors.push_back(EASY_GLOBALS.descriptors[j]); + desc = nullptr; + break; + } + } + + if (desc != nullptr) + { + QMessageBox::warning(this, "Warning", "Conflict with dynamically added block descriptions.\nAll profiled data will be cleared.", QMessageBox::Close); + onDeleteClicked(true); + cancel = true; + break; + } + } + } + + if (!cancel) + { + if (m_descTreeDialog != nullptr) + { +#if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0 + static_cast(m_descTreeWidget->widget())->build(); +#endif + m_dialogDescTree->build(); + m_descTreeDialog->raise(); + } + else + { + onEditBlocksClicked(true); + } + } } } else diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index a38dd10..aa4c99e 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -61,8 +61,7 @@ namespace profiler { namespace net { struct EasyProfilerStatus; } } class EasyFileReader Q_DECL_FINAL { - ::profiler::SerializedData m_serializedBlocks; ///< - ::profiler::SerializedData m_serializedDescriptors; ///< + ::profiler::FileData m_filedata; ///< ::profiler::descriptors_list_t m_descriptors; ///< ::profiler::blocks_t m_blocks; ///< ::profiler::thread_blocks_tree_t m_blocksTree; ///< @@ -89,8 +88,8 @@ public: 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, + void get(::profiler::FileData& _filedata, ::profiler::descriptors_list_t& _descriptors, + ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree, QString& _filename); QString getError(); @@ -172,14 +171,16 @@ protected: class QMessageBox* m_listenerDialog = nullptr; QTimer m_readerTimer; QTimer m_listenerTimer; - ::profiler::SerializedData m_serializedBlocks; - ::profiler::SerializedData m_serializedDescriptors; + ::profiler::FileData m_filedata; EasyFileReader m_reader; EasySocketListener m_listener; class QLineEdit* m_ipEdit = nullptr; class QLineEdit* m_portEdit = nullptr; + class QAction* m_saveAction = nullptr; + class QAction* m_deleteAction = nullptr; + class QAction* m_captureAction = nullptr; class QAction* m_connectAction = nullptr; class QAction* m_eventTracingEnableAction = nullptr; @@ -200,6 +201,7 @@ protected slots: void onOpenFileClicked(bool); void onReloadFileClicked(bool); + void onSaveFileClicked(bool); void onDeleteClicked(bool); void onExitClicked(bool); void onEncodingChanged(bool); @@ -207,6 +209,7 @@ protected slots: void onEventIndicatorsChange(bool); void onEnableDisableStatistics(bool); void onDrawBordersChanged(bool); + void onHideNarrowChildrenChanged(bool); void onCollapseItemsAfterCloseChanged(bool); void onAllItemsExpandedByDefaultChange(bool); void onBindExpandStatusChange(bool); diff --git a/profiler_gui/resources.qrc b/profiler_gui/resources.qrc index 3396613..185a294 100644 --- a/profiler_gui/resources.qrc +++ b/profiler_gui/resources.qrc @@ -22,5 +22,6 @@ icons/list.svg icons/search-next.svg icons/search-prev.svg + icons/settings.svg diff --git a/reader/main.cpp b/reader/main.cpp index df490ee..f894cb0 100644 --- a/reader/main.cpp +++ b/reader/main.cpp @@ -110,11 +110,11 @@ int main(int argc, char* argv[]) auto start = std::chrono::system_clock::now(); - ::profiler::SerializedData serialized_blocks, serialized_descriptors; + ::profiler::FileData fd; ::profiler::descriptors_list_t descriptors; ::profiler::blocks_t blocks; ::std::stringstream errorMessage; - auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, true, errorMessage); + auto blocks_counter = fillTreesFromFile(filename.c_str(), fd, descriptors, blocks, threaded_trees, true, errorMessage); if (blocks_counter == 0) std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str(); diff --git a/src/reader.cpp b/src/reader.cpp index ebae752..ea3d725 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -60,6 +60,13 @@ const uint32_t COMPATIBLE_VERSIONS[] = { }; const uint16_t COMPATIBLE_VERSIONS_NUM = sizeof(COMPATIBLE_VERSIONS) / sizeof(uint32_t); +#undef EASY_FULL_VER + +const int64_t TIME_FACTOR = 1000000000LL; +const uint32_t PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8) | 'y'; + +////////////////////////////////////////////////////////////////////////// + bool isCompatibleVersion(uint32_t _version) { if (_version == ::profiler::EASY_FULL_VERSION) @@ -67,18 +74,29 @@ bool isCompatibleVersion(uint32_t _version) return COMPATIBLE_VERSIONS_NUM > 1 && ::std::binary_search(COMPATIBLE_VERSIONS + 1, COMPATIBLE_VERSIONS + COMPATIBLE_VERSIONS_NUM, _version); } -#undef EASY_FULL_VER +inline void write(::std::stringstream& _stream, const char* _value, size_t _size) +{ + _stream.write(_value, _size); +} + +template +inline void write(::std::stringstream& _stream, const T& _value) +{ + _stream.write((const char*)&_value, sizeof(T)); +} + +////////////////////////////////////////////////////////////////////////// namespace profiler { - void SerializedData::set(char* _data, size_t _size) + void SerializedData::set(char* _data, uint64_t _size) { delete [] m_data; m_data = _data; m_size = _size; } - void SerializedData::set(size_t _size) + void SerializedData::set(uint64_t _size) { if (_size != 0) set(new char[_size], _size); @@ -86,7 +104,7 @@ namespace profiler { set(nullptr, 0); } - void SerializedData::extend(size_t _size) + void SerializedData::extend(uint64_t _size) { auto olddata = m_data; auto oldsize = m_size; @@ -234,23 +252,93 @@ void validate_pointers(::std::atomic& _progress, const char* _oldbase, ::pr ////////////////////////////////////////////////////////////////////////// -const int64_t TIME_FACTOR = 1000000000LL; -const uint32_t PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8) | 'y'; +uint64_t write_block_recursive(float& _progress, float _prog_per_block, ::std::vector& _buf, ::std::stringstream& _stream, const ::profiler::FileData& _filedata, const ::profiler::BlocksTree& _tree, const ::profiler::pblocks_t& _blocks, const ::profiler::descriptors_list_t& _descriptors) +{ + uint64_t total_size = 0; + for (const auto chld : _tree.children) + total_size += write_block_recursive(_progress, _prog_per_block, _buf, _stream, _filedata, *_blocks[chld], _blocks, _descriptors); + + auto sz = static_cast(sizeof(::profiler::SerializedBlock) + strlen(_tree.node->name()) + 1); + + _buf.resize(sz); + memcpy(_buf.data(), _tree.node->data(), sz); + + auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(_buf.data()); + auto t_end = t_begin + 1; + + *t_begin *= _filedata.cpu_frequency; + *t_begin /= TIME_FACTOR; + *t_end *= _filedata.cpu_frequency; + *t_end /= TIME_FACTOR; + + if (_tree.node->id() >= _filedata.total_descriptors_number) + { + auto desc = _descriptors[_tree.node->id()]; + for (uint32_t i = 0; i < _filedata.total_descriptors_number; ++i) + { + if (_descriptors[i] == desc) + { + reinterpret_cast<::profiler::SerializedBlock*>(_buf.data())->setId(i); + break; + } + } + } + + write(_stream, sz); + write(_stream, _buf.data(), sz); + total_size += sz; + + _progress += _prog_per_block; + + return total_size; +} + +uint64_t write_block_recursive(float& _progress, float _prog_per_block, ::std::vector& _buf, ::std::stringstream& _stream, const ::profiler::FileData& _filedata, const ::profiler::BlocksTree& _tree, const ::profiler::pblocks_t& _blocks) +{ + uint64_t total_size = 0; + for (const auto chld : _tree.children) + total_size += write_block_recursive(_progress, _prog_per_block, _buf, _stream, _filedata, *_blocks[chld], _blocks); + + auto sz = static_cast(sizeof(::profiler::SerializedBlock) + strlen(_tree.node->name()) + 1); + + _buf.resize(sz); + memcpy(_buf.data(), _tree.node->data(), sz); + + auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(_buf.data()); + auto t_end = t_begin + 1; + + *t_begin *= _filedata.cpu_frequency; + *t_begin /= TIME_FACTOR; + *t_end *= _filedata.cpu_frequency; + *t_end /= TIME_FACTOR; + + write(_stream, sz); + write(_stream, _buf.data(), sz); + total_size += sz; + + _progress += _prog_per_block; + + return total_size; +} ////////////////////////////////////////////////////////////////////////// extern "C" { PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic& 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, - ::std::stringstream& _log) + ::profiler::FileData& filedata, + ::profiler::descriptors_list_t& descriptors, + ::profiler::blocks_t& blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, + bool gather_statistics, + ::std::stringstream& _log) { - progress.store(0); + auto oldprogress = progress.exchange(0, ::std::memory_order_release); + if (oldprogress < 0) + { + _log << "Reading was interrupted"; + return 0; + } ::std::ifstream inFile(filename, ::std::fstream::binary); if (!inFile.is_open()) @@ -265,7 +353,7 @@ extern "C" { stringstream_parent& s = str; auto oldbuf = s.rdbuf(inFile.rdbuf()); - auto result = fillTreesFromStream(progress, str, serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, gather_statistics, _log); + auto result = fillTreesFromStream(progress, str, filedata, descriptors, blocks, threaded_trees, gather_statistics, _log); s.rdbuf(oldbuf); return result; @@ -274,17 +362,21 @@ extern "C" { ////////////////////////////////////////////////////////////////////////// PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic& 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, - ::std::stringstream& _log) + ::profiler::FileData& filedata, + ::profiler::descriptors_list_t& descriptors, + ::profiler::blocks_t& blocks, + ::profiler::thread_blocks_tree_t& threaded_trees, + bool gather_statistics, + ::std::stringstream& _log) { EASY_FUNCTION(::profiler::colors::Cyan); - progress.store(0); + auto oldprogress = progress.exchange(0, ::std::memory_order_release); + if (oldprogress < 0) + { + _log << "Reading was interrupted"; + return 0; + } uint32_t signature = 0; inFile.read((char*)&signature, sizeof(uint32_t)); @@ -302,23 +394,24 @@ extern "C" { return 0; } - int64_t cpu_frequency = 0LL; - inFile.read((char*)&cpu_frequency, sizeof(int64_t)); + filedata.cpu_frequency = 0LL; + inFile.read((char*)&filedata.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) + filedata.begin_time = 0; + filedata.end_time = 0; + inFile.read((char*)&filedata.begin_time, sizeof(::profiler::timestamp_t)); + inFile.read((char*)&filedata.end_time, sizeof(::profiler::timestamp_t)); + if (filedata.cpu_frequency != 0) { - begin_time *= TIME_FACTOR; - begin_time /= cpu_frequency; - end_time *= TIME_FACTOR; - end_time /= cpu_frequency; + filedata.begin_time *= TIME_FACTOR; + filedata.begin_time /= filedata.cpu_frequency; + filedata.end_time *= TIME_FACTOR; + filedata.end_time /= filedata.cpu_frequency; } - uint32_t total_blocks_number = 0; - inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number))); - if (total_blocks_number == 0) + filedata.total_blocks_number = 0; + inFile.read((char*)&filedata.total_blocks_number, sizeof(decltype(filedata.total_blocks_number))); + if (filedata.total_blocks_number == 0) { _log << "Profiled blocks number == 0"; return 0; @@ -328,13 +421,13 @@ extern "C" { inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); if (memory_size == 0) { - _log << "Wrong memory size == 0 for " << total_blocks_number << " blocks"; + _log << "Wrong memory size == 0 for " << filedata.total_blocks_number << " blocks"; return 0; } - uint32_t total_descriptors_number = 0; - inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number))); - if (total_descriptors_number == 0) + filedata.total_descriptors_number = 0; + inFile.read((char*)&filedata.total_descriptors_number, sizeof(decltype(filedata.total_descriptors_number))); + if (filedata.total_descriptors_number == 0) { _log << "Blocks description number == 0"; return 0; @@ -344,17 +437,17 @@ extern "C" { inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); if (descriptors_memory_size == 0) { - _log << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions"; + _log << "Wrong memory size == 0 for " << filedata.total_descriptors_number << " blocks descriptions"; 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()); + descriptors.reserve(filedata.total_descriptors_number); + //const char* olddata = append_regime ? filedata.serialized_descriptors.data() : nullptr; + filedata.serialized_descriptors.set(descriptors_memory_size); + //validate_pointers(progress, olddata, filedata.serialized_descriptors, descriptors, descriptors.size()); uint64_t i = 0; - while (!inFile.eof() && descriptors.size() < total_descriptors_number) + while (!inFile.eof() && descriptors.size() < filedata.total_descriptors_number) { uint16_t sz = 0; inFile.read((char*)&sz, sizeof(sz)); @@ -369,7 +462,7 @@ extern "C" { // return 0; //} - char* data = serialized_descriptors[i]; + char* data = filedata.serialized_descriptors[i]; inFile.read(data, sz); auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data); descriptors.push_back(descriptor); @@ -387,16 +480,16 @@ extern "C" { PerThreadStats thread_statistics, parent_statistics, frame_statistics; IdMap identification_table; - 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()); + blocks.reserve(filedata.total_blocks_number); + //olddata = append_regime ? filedata.serialized_blocks.data() : nullptr; + filedata.serialized_blocks.set(memory_size); + //validate_pointers(progress, olddata, filedata.serialized_blocks, blocks, blocks.size()); i = 0; uint32_t read_number = 0; ::profiler::block_index_t blocks_counter = 0; ::std::vector name; - while (!inFile.eof() && read_number < total_blocks_number) + while (!inFile.eof() && read_number < filedata.total_blocks_number) { EASY_BLOCK("Read thread data", ::profiler::colors::DarkGreen); @@ -404,6 +497,7 @@ extern "C" { inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); auto& root = threaded_trees[thread_id]; + filedata.threads_order.push_back(thread_id); uint16_t name_size = 0; inFile.read((char*)&name_size, sizeof(uint16_t)); @@ -431,25 +525,25 @@ extern "C" { return 0; } - char* data = serialized_blocks[i]; + char* data = filedata.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 (filedata.cpu_frequency != 0) { *t_begin *= TIME_FACTOR; - *t_begin /= cpu_frequency; + *t_begin /= filedata.cpu_frequency; *t_end *= TIME_FACTOR; - *t_end /= cpu_frequency; + *t_end /= filedata.cpu_frequency; } - if (*t_end > begin_time) + if (*t_end > filedata.begin_time) { - if (*t_begin < begin_time) - *t_begin = begin_time; + if (*t_begin < filedata.begin_time) + *t_begin = filedata.begin_time; blocks.emplace_back(); ::profiler::BlocksTree& tree = blocks.back(); @@ -487,11 +581,11 @@ extern "C" { return 0; } - char* data = serialized_blocks[i]; + char* data = filedata.serialized_blocks[i]; inFile.read(data, sz); i += sz; auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); - if (baseData->id() >= total_descriptors_number) + if (baseData->id() >= filedata.total_descriptors_number) { _log << "Bad block id == " << baseData->id(); return 0; @@ -507,18 +601,18 @@ extern "C" { auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data); auto t_end = t_begin + 1; - if (cpu_frequency != 0) + if (filedata.cpu_frequency != 0) { *t_begin *= TIME_FACTOR; - *t_begin /= cpu_frequency; + *t_begin /= filedata.cpu_frequency; *t_end *= TIME_FACTOR; - *t_end /= cpu_frequency; + *t_end /= filedata.cpu_frequency; } - if (*t_end >= begin_time) + if (*t_end >= filedata.begin_time) { - if (*t_begin < begin_time) - *t_begin = begin_time; + if (*t_begin < filedata.begin_time) + *t_begin = filedata.begin_time; blocks.emplace_back(); ::profiler::BlocksTree& tree = blocks.back(); @@ -795,4 +889,162 @@ extern "C" { ////////////////////////////////////////////////////////////////////////// + PROFILER_API bool writeTreesToFile(::std::atomic& progress, + const char* filename, + const ::profiler::FileData& filedata, + const ::profiler::thread_blocks_tree_t& threaded_trees, + const ::profiler::descriptors_list_t& _descriptors, + const ::profiler::pblocks_t& _blocks, + ::std::stringstream& _log) + { + ::std::ofstream of(filename, std::fstream::binary); + if (!of.is_open()) + { + _log << "Can not open file " << filename << " for writing"; + return false; + } + + ::std::stringstream str; + //typedef ::std::basic_iostream<::std::stringstream::char_type, ::std::stringstream::traits_type> stringstream_parent; + //stringstream_parent& s = str; + //auto oldbuf = s.rdbuf(of.rdbuf()); + + auto result = writeTreesToStream(progress, str, filedata, threaded_trees, _descriptors, _blocks, _log); + + of << str.str(); + //of.close(); + //s.rdbuf(oldbuf); + return result; + } + + PROFILER_API bool writeTreesToStream(::std::atomic& progress, + ::std::stringstream& str, + const ::profiler::FileData& filedata, + const ::profiler::thread_blocks_tree_t& threaded_trees, + const ::profiler::descriptors_list_t& _descriptors, + const ::profiler::pblocks_t& _blocks, + ::std::stringstream& _log) + { + auto oldprogress = progress.exchange(0, ::std::memory_order_release); + if (oldprogress < 0) + { + _log << "Writing was interrupted"; + return false; // Loading interrupted + } + + write(str, PROFILER_SIGNATURE); + write(str, ::profiler::EASY_FULL_VERSION); + write(str, filedata.cpu_frequency); + + decltype(filedata.begin_time) begin_time = filedata.begin_time; + begin_time *= filedata.cpu_frequency; + begin_time /= TIME_FACTOR; + write(str, begin_time); + + decltype(filedata.end_time) end_time = filedata.end_time; + end_time *= filedata.cpu_frequency; + end_time /= TIME_FACTOR; + write(str, end_time); + + write(str, filedata.total_blocks_number); + write(str, filedata.serialized_blocks.size()); + write(str, filedata.total_descriptors_number); + write(str, filedata.serialized_descriptors.size()); + + decltype(filedata.total_descriptors_number) n = 0; + uint64_t i = 0, size = filedata.serialized_descriptors.size(); + while (i < size) + { + const char* data = filedata.serialized_descriptors[i]; + auto descriptor = reinterpret_cast(data); + auto sz = static_cast(sizeof(::profiler::SerializedBlockDescriptor) + strlen(descriptor->name()) + strlen(descriptor->file()) + 2); + + write(str, sz); + write(str, data, sz); + ++n; + + i += sz; + + auto oldprogress = progress.exchange(static_cast(20 * i / filedata.serialized_descriptors.size()), ::std::memory_order_release); + if (oldprogress < 0) + { + _log << "Writing was interrupted"; + return false; // Loading interrupted + } + } + + if (n != filedata.total_descriptors_number || i != size) + printf("ERROR writing descriptors\n"); + + float prog = (float)progress.load(::std::memory_order_acquire); + if (prog < 0) + { + _log << "Writing was interrupted"; + return false; // Loading interrupted + } + + const float prog_per_thread = 80.f / (float)threaded_trees.size(); + + i = 0; + ::std::vector buffer; + for (auto tid : filedata.threads_order) + { + auto it = threaded_trees.find(tid); + if (it == threaded_trees.end()) + { + printf("Bad thread id = %u\n", tid); + continue; + } + + const auto& root = it->second; + + auto total = root.children.size() + root.sync.size(); + const float prog_per_block = total > 0 ? prog_per_thread / total : 0.f; + + write(str, root.thread_id); + + auto name_size = static_cast(strlen(root.name()) + 1); + const char* name = name_size > 1 ? root.name() : ""; + write(str, name_size); + write(str, name, name_size); + + auto blocks_number_in_thread = static_cast(root.sync.size()); + write(str, blocks_number_in_thread); + for (auto b : root.sync) + { + i += write_block_recursive(prog, prog_per_block, buffer, str, filedata, *_blocks[b], _blocks); + + auto oldprogress = progress.exchange(static_cast(prog), ::std::memory_order_release); + if (oldprogress < 0) + { + _log << "Writing was interrupted"; + return false; // Loading interrupted + } + } + + blocks_number_in_thread = static_cast(root.children.size()); + write(str, blocks_number_in_thread); + for (auto b : root.children) + { + i += write_block_recursive(prog, prog_per_block, buffer, str, filedata, *_blocks[b], _blocks, _descriptors); + + auto oldprogress = progress.exchange(static_cast(prog), ::std::memory_order_release); + if (oldprogress < 0) + { + _log << "Writing was interrupted"; + return false; // Loading interrupted + } + } + } + + if (i != filedata.serialized_blocks.size()) + printf("ERROR writing blocks\n"); + + printf("Finished writing to file\n"); + progress.store(100, ::std::memory_order_release); + return true; + } + + ////////////////////////////////////////////////////////////////////////// + } From c4e553c4bb67f2d19869208b9630b7bbf7e2ce45 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Thu, 29 Sep 2016 22:54:54 +0300 Subject: [PATCH 02/12] Same interface for win and linux --- include/profiler/profiler.h | 6 ------ src/profile_manager.h | 4 ---- 2 files changed, 10 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index f6aa7c3..11522c8 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -212,7 +212,6 @@ breakdown, but if you care about that then you change set event tracing priority */ # define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority) ::profiler::setLowPriorityEventTracing(isLowPriority); -# ifndef _WIN32 /** Macro for setting temporary log-file path for Unix event tracing system. \note Default value is "/tmp/cs_profiling_info.log". @@ -226,9 +225,6 @@ breakdown, but if you care about that then you change set event tracing priority \ingroup profiler */ # define EASY_EVENT_TRACING_LOG ::profiler::getContextSwitchLogFilename(); -# endif - - // EasyProfiler settings: @@ -515,7 +511,6 @@ namespace profiler { */ PROFILER_API void setLowPriorityEventTracing(bool _isLowPriority); -#ifndef _WIN32 /** Set temporary log-file path for Unix event tracing system. \note Default value is "/tmp/cs_profiling_info.log". @@ -529,7 +524,6 @@ namespace profiler { \ingroup profiler */ PROFILER_API const char* getContextSwitchLogFilename(); -#endif PROFILER_API void startListenSignalToCapture(); PROFILER_API void stopListenSignalToCapture(); diff --git a/src/profile_manager.h b/src/profile_manager.h index 6fb4837..a7ba132 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -345,9 +345,7 @@ class ProfileManager std::atomic_bool m_isEnabled; std::atomic_bool m_isEventTracingEnabled; -#ifndef _WIN32 std::string m_csInfoFilename = "/tmp/cs_profiling_info.log"; -#endif uint32_t dumpBlocksToStream(profiler::OStream& _outputStream); void setBlockStatus(profiler::block_id_t _id, profiler::EasyBlockStatus _status); @@ -381,7 +379,6 @@ public: uint32_t dumpBlocksToFile(const char* filename); const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard); -#ifndef _WIN32 void setContextSwitchLogFilename(const char* name) { m_csInfoFilename = name; @@ -391,7 +388,6 @@ public: { return m_csInfoFilename.c_str(); } -#endif void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, const char* _target_process, bool _lockSpin = true); void storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, bool _lockSpin = true); From 5b6c9210c7f86d48ada6f96b2df038821270d5ac Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Thu, 29 Sep 2016 22:57:14 +0300 Subject: [PATCH 03/12] For previous commit --- src/profile_manager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 1bbe56d..1be4ba0 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -117,7 +117,6 @@ extern "C" { PROFILER_API void setLowPriorityEventTracing(bool) { } #endif -#ifndef _WIN32 PROFILER_API void setContextSwitchLogFilename(const char* name) { return MANAGER.setContextSwitchLogFilename(name); @@ -127,7 +126,6 @@ extern "C" { { return MANAGER.getContextSwitchLogFilename(); } -#endif PROFILER_API void startListenSignalToCapture() { From 477e6430409997957a1b64254b070bc7053d9db0 Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Thu, 29 Sep 2016 23:08:20 +0300 Subject: [PATCH 04/12] Disable EasyProfiler by default. For building with profiler define macro BUILD_WITH_EASY_PROFILER --- include/profiler/profiler.h | 6 +++--- include/profiler/profiler_aux.h | 14 +++++++------- sample/CMakeLists.txt | 2 +- src/CMakeLists.txt | 1 + 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 11522c8..554da6e 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -33,7 +33,7 @@ namespace profiler { const uint32_t EASY_FULL_VERSION = ((uint32_t)EASY_VERSION_MAJOR << 24) | ((uint32_t)EASY_VERSION_MINOR << 16) | (uint32_t)EASY_VERSION_REV; } -#ifndef FULL_DISABLE_PROFILER +#ifdef BUILD_WITH_EASY_PROFILER /** \defgroup profiler EasyProfiler @@ -275,7 +275,7 @@ Otherwise, no log messages will be printed. # define EASY_LOG_ENABLED 1 -#else // #ifndef FULL_DISABLE_PROFILER +#else // #ifdef BUILD_WITH_EASY_PROFILER # define EASY_BLOCK(...) # define EASY_FUNCTION(...) @@ -299,7 +299,7 @@ Otherwise, no log messages will be printed. # define EASY_LOW_PRIORITY_EVENT_TRACING true # define EASY_LOG_ENABLED 0 -#endif // #ifndef FULL_DISABLE_PROFILER +#endif // #ifndef BUILD_WITH_EASY_PROFILER ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// diff --git a/include/profiler/profiler_aux.h b/include/profiler/profiler_aux.h index 376251a..117959d 100644 --- a/include/profiler/profiler_aux.h +++ b/include/profiler/profiler_aux.h @@ -48,18 +48,16 @@ namespace profiler { FORCE_ON_WITHOUT_CHILDREN = FORCE_ON | OFF_RECURSIVE, ///< The block is ALWAYS ON but all of it's children are OFF. }; - struct passthrough_hash EASY_FINAL { - template inline size_t operator () (T _value) const { - return static_cast(_value); - } + struct passthrough_hash EASY_FINAL { + template inline size_t operator () (T _value) const { + return static_cast(_value); + } }; } ////////////////////////////////////////////////////////////////////////// -#ifndef FULL_DISABLE_PROFILER - #include # define EASY_STRINGIFY(a) #a @@ -69,6 +67,8 @@ namespace profiler { # 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) +#ifdef BUILD_WITH_EASY_PROFILER + namespace profiler { template struct NameSwitch EASY_FINAL { @@ -138,7 +138,7 @@ namespace profiler { # define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::compiletime_name(name, EASY_UNIQUE_LINE_ID) # define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference::value>::runtime_name(name) -#endif // FULL_DISABLE_PROFILER +#endif // BUILD_WITH_EASY_PROFILER ////////////////////////////////////////////////////////////////////////// diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index 7106410..1686389 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -22,4 +22,4 @@ endif(UNIX) target_link_libraries(${PROJECT_NAME} easy_profiler ${SPEC_LIB}) target_link_libraries(${DISABLED_PROFILER_NAME} easy_profiler ${SPEC_LIB}) -target_compile_definitions(${DISABLED_PROFILER_NAME} PRIVATE FULL_DISABLE_PROFILER) +target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_WITH_EASY_PROFILER) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 87be249..90cc2e1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ set(SOURCES ) add_definitions( -D_BUILD_PROFILER + -DBUILD_WITH_EASY_PROFILER ) if(WIN32) From b3be5c85a532160f0aafb42594bab3be4246901a Mon Sep 17 00:00:00 2001 From: Sergey Yagovtsev Date: Fri, 30 Sep 2016 00:12:36 +0400 Subject: [PATCH 05/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5144dae..d32a5f9 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ You can see the results of measuring in simple GUI application which provides fu # Usage -First of all you can specify path to include directory which contains `include/profiler` directory. +First of all you can specify path to include directory which contains `include/profiler` directory and define macro `BUILD_WITH_EASY_PROFILER`. For linking with easy_profiler you can specify path to library. Example of usage. From dc01c490203f770fea468338b52a740f8eb83d71 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 2 Oct 2016 12:13:12 +0300 Subject: [PATCH 06/12] Saving network data using temporary cache file + Question box when clicked on "Clear all" --- include/profiler/reader.h | 57 ++---- profiler_gui/main_window.cpp | 112 +++++++----- profiler_gui/main_window.h | 17 +- reader/main.cpp | 6 +- src/reader.cpp | 331 ++++++----------------------------- 5 files changed, 149 insertions(+), 374 deletions(-) diff --git a/include/profiler/reader.h b/include/profiler/reader.h index 8c4c643..1134ff6 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -78,7 +78,6 @@ namespace profiler { public: typedef ::std::vector blocks_t; - typedef ::std::vector pblocks_t; typedef ::std::vector<::profiler::block_index_t> children_t; children_t children; ///< List of children blocks. May be empty. @@ -235,7 +234,6 @@ namespace profiler { }; // END of class BlocksTreeRoot. typedef ::profiler::BlocksTree::blocks_t blocks_t; - typedef ::profiler::BlocksTree::pblocks_t pblocks_t; typedef ::std::unordered_map<::profiler::thread_id_t, ::profiler::BlocksTreeRoot, ::profiler::passthrough_hash> thread_blocks_tree_t; ////////////////////////////////////////////////////////////////////////// @@ -383,18 +381,22 @@ namespace profiler { extern "C" { PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic& progress, const char* filename, - ::profiler::FileData& filedata, + ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& threaded_trees, + uint32_t& total_descriptors_number, bool gather_statistics, ::std::stringstream& _log); PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic& progress, ::std::stringstream& str, - ::profiler::FileData& filedata, + ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& threaded_trees, + uint32_t& total_descriptors_number, bool gather_statistics, ::std::stringstream& _log); @@ -402,31 +404,18 @@ extern "C" { ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::std::stringstream& _log); - - PROFILER_API bool writeTreesToStream(::std::atomic& progress, - ::std::stringstream& str, - const ::profiler::FileData& filedata, - const ::profiler::thread_blocks_tree_t& threaded_trees, - const ::profiler::descriptors_list_t& _descriptors, - const ::profiler::pblocks_t& _blocks, - ::std::stringstream& _log); - - PROFILER_API bool writeTreesToFile(::std::atomic& progress, - const char* filename, - const ::profiler::FileData& filedata, - const ::profiler::thread_blocks_tree_t& threaded_trees, - const ::profiler::descriptors_list_t& _descriptors, - const ::profiler::pblocks_t& _blocks, - ::std::stringstream& _log); } -inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::FileData& filedata, +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, + ::profiler::thread_blocks_tree_t& threaded_trees, + uint32_t& total_descriptors_number, + bool gather_statistics, ::std::stringstream& _log) { ::std::atomic progress = ATOMIC_VAR_INIT(0); - return fillTreesFromFile(progress, filename, filedata, descriptors, _blocks, threaded_trees, gather_statistics, _log); + return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, total_descriptors_number, gather_statistics, _log); } inline bool readDescriptionsFromStream(::std::stringstream& str, @@ -438,28 +427,6 @@ inline bool readDescriptionsFromStream(::std::stringstream& str, return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log); } -inline bool writeTreesToStream(::std::stringstream& str, - const ::profiler::FileData& filedata, - const ::profiler::thread_blocks_tree_t& threaded_trees, - const ::profiler::descriptors_list_t& _descriptors, - const ::profiler::pblocks_t& _blocks, - ::std::stringstream& _log) -{ - ::std::atomic progress = ATOMIC_VAR_INIT(0); - return writeTreesToStream(progress, str, filedata, threaded_trees, _descriptors, _blocks, _log); -} - -inline bool writeTreesToFile(const char* filename, - const ::profiler::FileData& filedata, - const ::profiler::thread_blocks_tree_t& threaded_trees, - const ::profiler::descriptors_list_t& _descriptors, - const ::profiler::pblocks_t& _blocks, - ::std::stringstream& _log) -{ - ::std::atomic progress = ATOMIC_VAR_INIT(0); - return writeTreesToFile(progress, filename, filedata, threaded_trees, _descriptors, _blocks, _log); -} - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif // PROFILER_READER____H diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 521b909..d621c21 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include "main_window.h" #include "blocks_tree_widget.h" @@ -79,6 +80,7 @@ ////////////////////////////////////////////////////////////////////////// const int LOADER_TIMER_INTERVAL = 40; +const auto NETWORK_CACHE_FILE = "easy_profiler_stream.cache"; ////////////////////////////////////////////////////////////////////////// @@ -376,7 +378,7 @@ void EasyMainWindow::onReloadFileClicked(bool) void EasyMainWindow::onSaveFileClicked(bool) { - if (m_filedata.serialized_blocks.empty()) + if (m_serializedBlocks.empty()) return; const auto i = m_lastFile.lastIndexOf(QChar('/')); @@ -390,26 +392,30 @@ void EasyMainWindow::onSaveFileClicked(bool) auto filename = QFileDialog::getSaveFileName(this, "Save profiler log", dir, "Profiler Log File (*.prof);;All Files (*.*)"); if (!filename.isEmpty()) { - QMessageBox::warning(this, "Warning", "Saving is not working yet :)", QMessageBox::Close); - - /* - ::std::stringstream errorMessage; - - ::profiler::pblocks_t blocks(EASY_GLOBALS.gui_blocks.size()); - for (size_t i = 0, size = EASY_GLOBALS.gui_blocks.size(); i < size; ++i) - blocks[i] = &EASY_GLOBALS.gui_blocks[i].tree; - - if (writeTreesToFile(filename.toStdString().c_str(), m_filedata, EASY_GLOBALS.profiler_blocks, EASY_GLOBALS.descriptors, blocks, errorMessage)) + auto result = QFile::copy(m_bNetworkFileRegime ? QString(NETWORK_CACHE_FILE) : m_lastFile, filename); + if (result) + { m_lastFile = filename; + if (m_bNetworkFileRegime) + { + m_bNetworkFileRegime = false; + QFile::remove(NETWORK_CACHE_FILE); + } + } + else if (m_bNetworkFileRegime) + { + QMessageBox::warning(this, "Warning", "Can not save network cahce to file.\nSaving incomplete.", QMessageBox::Close); + } else - QMessageBox::warning(this, "Warning", QString("Can not save blocks to file.\n\nReason:\n%1").arg(errorMessage.str().c_str()), QMessageBox::Close); - */ + { + QMessageBox::warning(this, "Warning", "Can not copy last file.\nSaving incomplete.", QMessageBox::Close); + } } } ////////////////////////////////////////////////////////////////////////// -void EasyMainWindow::onDeleteClicked(bool) +void EasyMainWindow::clear() { static_cast(m_treeWidget->widget())->clearSilent(true); static_cast(m_graphicsView->widget())->clear(); @@ -426,11 +432,20 @@ void EasyMainWindow::onDeleteClicked(bool) EASY_GLOBALS.descriptors.clear(); EASY_GLOBALS.gui_blocks.clear(); - m_filedata.serialized_blocks.clear(); - m_filedata.serialized_descriptors.clear(); + m_serializedBlocks.clear(); + m_serializedDescriptors.clear(); m_saveAction->setEnabled(false); m_deleteAction->setEnabled(false); + + m_bNetworkFileRegime = false; +} + +void EasyMainWindow::onDeleteClicked(bool) +{ + auto button = QMessageBox::question(this, "Clear all profiled data", "All profiled data is going to be deleted!\nContinue?", QMessageBox::Yes, QMessageBox::No); + if (button == QMessageBox::Yes) + clear(); } ////////////////////////////////////////////////////////////////////////// @@ -758,12 +773,14 @@ void EasyMainWindow::onFileReaderTimeout() { static_cast(m_treeWidget->widget())->clearSilent(true); - ::profiler::FileData fd; + ::profiler::SerializedData serialized_blocks; + ::profiler::SerializedData serialized_descriptors; ::profiler::descriptors_list_t descriptors; ::profiler::blocks_t blocks; ::profiler::thread_blocks_tree_t threads_map; QString filename; - m_reader.get(fd, descriptors, blocks, threads_map, filename); + uint32_t descriptorsNumberInFile = 0; + m_reader.get(serialized_blocks, serialized_descriptors, descriptors, blocks, threads_map, descriptorsNumberInFile, filename); if (threads_map.size() > 0xff) { @@ -774,9 +791,12 @@ void EasyMainWindow::onFileReaderTimeout() qWarning() << "Warning: Currently, maximum number of displayed threads is 255! Some threads will not be displayed."; } - if (m_reader.isFile()) + m_bNetworkFileRegime = !m_reader.isFile(); + if (!m_bNetworkFileRegime) m_lastFile = ::std::move(filename); - m_filedata = ::std::move(fd); + m_serializedBlocks = ::std::move(serialized_blocks); + m_serializedDescriptors = ::std::move(serialized_descriptors); + m_descriptorsNumberInFile = descriptorsNumberInFile; EASY_GLOBALS.selected_thread = 0; ::profiler_gui::set_max(EASY_GLOBALS.selected_block); EASY_GLOBALS.profiler_blocks.swap(threads_map); @@ -876,7 +896,8 @@ void EasyFileReader::load(const QString& _filename) m_isFile = true; m_filename = _filename; m_thread = ::std::move(::std::thread([this](bool _enableStatistics) { - m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_filedata, m_descriptors, m_blocks, m_blocksTree, _enableStatistics, m_errorMessage), ::std::memory_order_release); + m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, + m_descriptors, m_blocks, m_blocksTree, m_descriptorsNumberInFile, _enableStatistics, m_errorMessage), ::std::memory_order_release); m_progress.store(100, ::std::memory_order_release); m_bDone.store(true, ::std::memory_order_release); }, EASY_GLOBALS.enable_statistics)); @@ -890,7 +911,13 @@ void EasyFileReader::load(::std::stringstream& _stream) m_filename.clear(); m_stream.swap(_stream); m_thread = ::std::move(::std::thread([this](bool _enableStatistics) { - m_size.store(fillTreesFromStream(m_progress, m_stream, m_filedata, m_descriptors, m_blocks, m_blocksTree, _enableStatistics, m_errorMessage), ::std::memory_order_release); + ::std::ofstream cache_file(NETWORK_CACHE_FILE, ::std::fstream::binary); + if (cache_file.is_open()) { + cache_file << m_stream.str(); + cache_file.close(); + } + m_size.store(fillTreesFromStream(m_progress, m_stream, m_serializedBlocks, m_serializedDescriptors, m_descriptors, + m_blocks, m_blocksTree, m_descriptorsNumberInFile, _enableStatistics, m_errorMessage), ::std::memory_order_release); m_progress.store(100, ::std::memory_order_release); m_bDone.store(true, ::std::memory_order_release); }, EASY_GLOBALS.enable_statistics)); @@ -905,33 +932,30 @@ void EasyFileReader::interrupt() m_bDone.store(false, ::std::memory_order_release); m_progress.store(0, ::std::memory_order_release); m_size.store(0, ::std::memory_order_release); - m_filedata.serialized_blocks.clear(); - m_filedata.serialized_descriptors.clear(); + m_serializedBlocks.clear(); + m_serializedDescriptors.clear(); m_descriptors.clear(); m_blocks.clear(); m_blocksTree.clear(); + m_descriptorsNumberInFile = 0; { decltype(m_stream) dummy; dummy.swap(m_stream); } { decltype(m_errorMessage) dummy; dummy.swap(m_errorMessage); } } -void EasyFileReader::get(::profiler::FileData& _filedata, ::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, - ::profiler::thread_blocks_tree_t& _tree, QString& _filename) +void EasyFileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors, + ::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, + ::profiler::thread_blocks_tree_t& _tree, uint32_t& _descriptorsNumberInFile, QString& _filename) { if (done()) { - m_filedata.serialized_blocks.swap(_filedata.serialized_blocks); - m_filedata.serialized_descriptors.swap(_filedata.serialized_descriptors); - m_filedata.threads_order.swap(_filedata.threads_order); + m_serializedBlocks.swap(_serializedBlocks); + m_serializedDescriptors.swap(_serializedDescriptors); ::profiler::descriptors_list_t(::std::move(m_descriptors)).swap(_descriptors); m_blocks.swap(_blocks); m_blocksTree.swap(_tree); m_filename.swap(_filename); - _filedata.cpu_frequency = m_filedata.cpu_frequency; - _filedata.begin_time = m_filedata.begin_time; - _filedata.end_time = m_filedata.end_time; - _filedata.total_blocks_number = m_filedata.total_blocks_number; - _filedata.total_descriptors_number = m_filedata.total_descriptors_number; + _descriptorsNumberInFile = m_descriptorsNumberInFile; } } @@ -1071,34 +1095,34 @@ void EasyMainWindow::onGetBlockDescriptionsClicked(bool) { // Read descriptions from stream decltype(EASY_GLOBALS.descriptors) descriptors; - decltype(m_filedata.serialized_descriptors) serializedDescriptors; + decltype(m_serializedDescriptors) serializedDescriptors; ::std::stringstream errorMessage; if (readDescriptionsFromStream(m_listener.data(), serializedDescriptors, descriptors, errorMessage)) { bool cancel = false; - const bool doFlush = m_filedata.total_descriptors_number != descriptors.size(); - if (doFlush && !m_filedata.serialized_blocks.empty()) + const bool doFlush = m_descriptorsNumberInFile != descriptors.size(); + if (doFlush && !m_serializedBlocks.empty()) { auto button = QMessageBox::question(this, "Information", QString("New blocks description number = %1\ndiffers from the old one = %2.\nTo avoid possible conflicts\nall profiled data will be deleted.\nPress \"Yes\" to continue or \"No\" to cancel.") .arg(descriptors.size()) - .arg(m_filedata.total_descriptors_number), + .arg(m_descriptorsNumberInFile), QMessageBox::Yes, QMessageBox::No); if (button == QMessageBox::Yes) - onDeleteClicked(true); // Clear all contents because new descriptors list conflicts with old one + clear(); // Clear all contents because new descriptors list conflicts with old one else cancel = true; } if (!cancel) { - auto oldnumber = m_filedata.total_descriptors_number; - m_filedata.total_descriptors_number = static_cast(descriptors.size()); + auto oldnumber = m_descriptorsNumberInFile; + m_descriptorsNumberInFile = static_cast(descriptors.size()); EASY_GLOBALS.descriptors.swap(descriptors); - m_filedata.serialized_descriptors.swap(serializedDescriptors); + m_serializedDescriptors.swap(serializedDescriptors); - if (!doFlush && !m_filedata.serialized_blocks.empty() && descriptors.size() > oldnumber) + if (!doFlush && !m_serializedBlocks.empty() && descriptors.size() > oldnumber) { // There are dynamically added descriptors, add them to the new list too @@ -1120,7 +1144,7 @@ void EasyMainWindow::onGetBlockDescriptionsClicked(bool) if (desc != nullptr) { QMessageBox::warning(this, "Warning", "Conflict with dynamically added block descriptions.\nAll profiled data will be cleared.", QMessageBox::Close); - onDeleteClicked(true); + clear(); cancel = true; break; } diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index aa4c99e..ceab11b 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -61,13 +61,15 @@ namespace profiler { namespace net { struct EasyProfilerStatus; } } class EasyFileReader Q_DECL_FINAL { - ::profiler::FileData m_filedata; ///< + ::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; ///< ::std::stringstream m_stream; ///< ::std::stringstream m_errorMessage; ///< QString m_filename; ///< + uint32_t m_descriptorsNumberInFile = 0; ///< ::std::thread m_thread; ///< ::std::atomic_bool m_bDone; ///< ::std::atomic m_progress; ///< @@ -88,9 +90,9 @@ public: void load(const QString& _filename); void load(::std::stringstream& _stream); void interrupt(); - void get(::profiler::FileData& _filedata, ::profiler::descriptors_list_t& _descriptors, - ::profiler::blocks_t& _blocks, ::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, + uint32_t& _descriptorsNumberInFile, QString& _filename); QString getError(); @@ -171,7 +173,8 @@ protected: class QMessageBox* m_listenerDialog = nullptr; QTimer m_readerTimer; QTimer m_listenerTimer; - ::profiler::FileData m_filedata; + ::profiler::SerializedData m_serializedBlocks; + ::profiler::SerializedData m_serializedDescriptors; EasyFileReader m_reader; EasySocketListener m_listener; @@ -186,7 +189,9 @@ protected: class QAction* m_eventTracingEnableAction = nullptr; class QAction* m_eventTracingPriorityAction = nullptr; + uint32_t m_descriptorsNumberInFile = 0; uint16_t m_lastPort = 0; + bool m_bNetworkFileRegime = false; public: @@ -233,6 +238,8 @@ private: // Private non-virtual methods + void clear(); + void loadFile(const QString& filename); void readStream(::std::stringstream& data); diff --git a/reader/main.cpp b/reader/main.cpp index f894cb0..d2b4dc3 100644 --- a/reader/main.cpp +++ b/reader/main.cpp @@ -110,11 +110,13 @@ int main(int argc, char* argv[]) auto start = std::chrono::system_clock::now(); - ::profiler::FileData fd; + ::profiler::SerializedData serialized_blocks, serialized_descriptors; ::profiler::descriptors_list_t descriptors; ::profiler::blocks_t blocks; ::std::stringstream errorMessage; - auto blocks_counter = fillTreesFromFile(filename.c_str(), fd, descriptors, blocks, threaded_trees, true, errorMessage); + uint32_t descriptorsNumberInFile = 0; + auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks, + threaded_trees, descriptorsNumberInFile, true, errorMessage); if (blocks_counter == 0) std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str(); diff --git a/src/reader.cpp b/src/reader.cpp index ea3d725..d22a153 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -252,84 +252,15 @@ void validate_pointers(::std::atomic& _progress, const char* _oldbase, ::pr ////////////////////////////////////////////////////////////////////////// -uint64_t write_block_recursive(float& _progress, float _prog_per_block, ::std::vector& _buf, ::std::stringstream& _stream, const ::profiler::FileData& _filedata, const ::profiler::BlocksTree& _tree, const ::profiler::pblocks_t& _blocks, const ::profiler::descriptors_list_t& _descriptors) -{ - uint64_t total_size = 0; - for (const auto chld : _tree.children) - total_size += write_block_recursive(_progress, _prog_per_block, _buf, _stream, _filedata, *_blocks[chld], _blocks, _descriptors); - - auto sz = static_cast(sizeof(::profiler::SerializedBlock) + strlen(_tree.node->name()) + 1); - - _buf.resize(sz); - memcpy(_buf.data(), _tree.node->data(), sz); - - auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(_buf.data()); - auto t_end = t_begin + 1; - - *t_begin *= _filedata.cpu_frequency; - *t_begin /= TIME_FACTOR; - *t_end *= _filedata.cpu_frequency; - *t_end /= TIME_FACTOR; - - if (_tree.node->id() >= _filedata.total_descriptors_number) - { - auto desc = _descriptors[_tree.node->id()]; - for (uint32_t i = 0; i < _filedata.total_descriptors_number; ++i) - { - if (_descriptors[i] == desc) - { - reinterpret_cast<::profiler::SerializedBlock*>(_buf.data())->setId(i); - break; - } - } - } - - write(_stream, sz); - write(_stream, _buf.data(), sz); - total_size += sz; - - _progress += _prog_per_block; - - return total_size; -} - -uint64_t write_block_recursive(float& _progress, float _prog_per_block, ::std::vector& _buf, ::std::stringstream& _stream, const ::profiler::FileData& _filedata, const ::profiler::BlocksTree& _tree, const ::profiler::pblocks_t& _blocks) -{ - uint64_t total_size = 0; - for (const auto chld : _tree.children) - total_size += write_block_recursive(_progress, _prog_per_block, _buf, _stream, _filedata, *_blocks[chld], _blocks); - - auto sz = static_cast(sizeof(::profiler::SerializedBlock) + strlen(_tree.node->name()) + 1); - - _buf.resize(sz); - memcpy(_buf.data(), _tree.node->data(), sz); - - auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(_buf.data()); - auto t_end = t_begin + 1; - - *t_begin *= _filedata.cpu_frequency; - *t_begin /= TIME_FACTOR; - *t_end *= _filedata.cpu_frequency; - *t_end /= TIME_FACTOR; - - write(_stream, sz); - write(_stream, _buf.data(), sz); - total_size += sz; - - _progress += _prog_per_block; - - return total_size; -} - -////////////////////////////////////////////////////////////////////////// - extern "C" { PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic& progress, const char* filename, - ::profiler::FileData& filedata, + ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& blocks, ::profiler::thread_blocks_tree_t& threaded_trees, + uint32_t& total_descriptors_number, bool gather_statistics, ::std::stringstream& _log) { @@ -353,7 +284,8 @@ extern "C" { stringstream_parent& s = str; auto oldbuf = s.rdbuf(inFile.rdbuf()); - auto result = fillTreesFromStream(progress, str, filedata, descriptors, blocks, threaded_trees, gather_statistics, _log); + auto result = fillTreesFromStream(progress, str, serialized_blocks, serialized_descriptors, descriptors, blocks, + threaded_trees, total_descriptors_number, gather_statistics, _log); s.rdbuf(oldbuf); return result; @@ -362,10 +294,12 @@ extern "C" { ////////////////////////////////////////////////////////////////////////// PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic& progress, ::std::stringstream& inFile, - ::profiler::FileData& filedata, + ::profiler::SerializedData& serialized_blocks, + ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& blocks, ::profiler::thread_blocks_tree_t& threaded_trees, + uint32_t& total_descriptors_number, bool gather_statistics, ::std::stringstream& _log) { @@ -394,24 +328,24 @@ extern "C" { return 0; } - filedata.cpu_frequency = 0LL; - inFile.read((char*)&filedata.cpu_frequency, sizeof(int64_t)); + int64_t cpu_frequency = 0LL; + inFile.read((char*)&cpu_frequency, sizeof(int64_t)); - filedata.begin_time = 0; - filedata.end_time = 0; - inFile.read((char*)&filedata.begin_time, sizeof(::profiler::timestamp_t)); - inFile.read((char*)&filedata.end_time, sizeof(::profiler::timestamp_t)); - if (filedata.cpu_frequency != 0) + ::profiler::timestamp_t begin_time = 0ULL; + ::profiler::timestamp_t end_time = 0ULL; + inFile.read((char*)&begin_time, sizeof(::profiler::timestamp_t)); + inFile.read((char*)&end_time, sizeof(::profiler::timestamp_t)); + if (cpu_frequency != 0) { - filedata.begin_time *= TIME_FACTOR; - filedata.begin_time /= filedata.cpu_frequency; - filedata.end_time *= TIME_FACTOR; - filedata.end_time /= filedata.cpu_frequency; + begin_time *= TIME_FACTOR; + begin_time /= cpu_frequency; + end_time *= TIME_FACTOR; + end_time /= cpu_frequency; } - filedata.total_blocks_number = 0; - inFile.read((char*)&filedata.total_blocks_number, sizeof(decltype(filedata.total_blocks_number))); - if (filedata.total_blocks_number == 0) + uint32_t total_blocks_number = 0; + inFile.read((char*)&total_blocks_number, sizeof(uint32_t)); + if (total_blocks_number == 0) { _log << "Profiled blocks number == 0"; return 0; @@ -421,13 +355,13 @@ extern "C" { inFile.read((char*)&memory_size, sizeof(decltype(memory_size))); if (memory_size == 0) { - _log << "Wrong memory size == 0 for " << filedata.total_blocks_number << " blocks"; + _log << "Wrong memory size == 0 for " << total_blocks_number << " blocks"; return 0; } - filedata.total_descriptors_number = 0; - inFile.read((char*)&filedata.total_descriptors_number, sizeof(decltype(filedata.total_descriptors_number))); - if (filedata.total_descriptors_number == 0) + total_descriptors_number = 0; + inFile.read((char*)&total_descriptors_number, sizeof(uint32_t)); + if (total_descriptors_number == 0) { _log << "Blocks description number == 0"; return 0; @@ -437,17 +371,17 @@ extern "C" { inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size))); if (descriptors_memory_size == 0) { - _log << "Wrong memory size == 0 for " << filedata.total_descriptors_number << " blocks descriptions"; + _log << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions"; return 0; } - descriptors.reserve(filedata.total_descriptors_number); - //const char* olddata = append_regime ? filedata.serialized_descriptors.data() : nullptr; - filedata.serialized_descriptors.set(descriptors_memory_size); - //validate_pointers(progress, olddata, filedata.serialized_descriptors, descriptors, descriptors.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()); uint64_t i = 0; - while (!inFile.eof() && descriptors.size() < filedata.total_descriptors_number) + while (!inFile.eof() && descriptors.size() < total_descriptors_number) { uint16_t sz = 0; inFile.read((char*)&sz, sizeof(sz)); @@ -462,7 +396,7 @@ extern "C" { // return 0; //} - char* data = filedata.serialized_descriptors[i]; + char* data = serialized_descriptors[i]; inFile.read(data, sz); auto descriptor = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(data); descriptors.push_back(descriptor); @@ -480,16 +414,16 @@ extern "C" { PerThreadStats thread_statistics, parent_statistics, frame_statistics; IdMap identification_table; - blocks.reserve(filedata.total_blocks_number); - //olddata = append_regime ? filedata.serialized_blocks.data() : nullptr; - filedata.serialized_blocks.set(memory_size); - //validate_pointers(progress, olddata, filedata.serialized_blocks, blocks, blocks.size()); + 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 name; - while (!inFile.eof() && read_number < filedata.total_blocks_number) + while (!inFile.eof() && read_number < total_blocks_number) { EASY_BLOCK("Read thread data", ::profiler::colors::DarkGreen); @@ -497,7 +431,6 @@ extern "C" { inFile.read((char*)&thread_id, sizeof(decltype(thread_id))); auto& root = threaded_trees[thread_id]; - filedata.threads_order.push_back(thread_id); uint16_t name_size = 0; inFile.read((char*)&name_size, sizeof(uint16_t)); @@ -525,25 +458,25 @@ extern "C" { return 0; } - char* data = filedata.serialized_blocks[i]; + 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 (filedata.cpu_frequency != 0) + if (cpu_frequency != 0) { *t_begin *= TIME_FACTOR; - *t_begin /= filedata.cpu_frequency; + *t_begin /= cpu_frequency; *t_end *= TIME_FACTOR; - *t_end /= filedata.cpu_frequency; + *t_end /= cpu_frequency; } - if (*t_end > filedata.begin_time) + if (*t_end > begin_time) { - if (*t_begin < filedata.begin_time) - *t_begin = filedata.begin_time; + if (*t_begin < begin_time) + *t_begin = begin_time; blocks.emplace_back(); ::profiler::BlocksTree& tree = blocks.back(); @@ -581,11 +514,11 @@ extern "C" { return 0; } - char* data = filedata.serialized_blocks[i]; + char* data = serialized_blocks[i]; inFile.read(data, sz); i += sz; auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data); - if (baseData->id() >= filedata.total_descriptors_number) + if (baseData->id() >= total_descriptors_number) { _log << "Bad block id == " << baseData->id(); return 0; @@ -601,18 +534,18 @@ extern "C" { auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data); auto t_end = t_begin + 1; - if (filedata.cpu_frequency != 0) + if (cpu_frequency != 0) { *t_begin *= TIME_FACTOR; - *t_begin /= filedata.cpu_frequency; + *t_begin /= cpu_frequency; *t_end *= TIME_FACTOR; - *t_end /= filedata.cpu_frequency; + *t_end /= cpu_frequency; } - if (*t_end >= filedata.begin_time) + if (*t_end >= begin_time) { - if (*t_begin < filedata.begin_time) - *t_begin = filedata.begin_time; + if (*t_begin < begin_time) + *t_begin = begin_time; blocks.emplace_back(); ::profiler::BlocksTree& tree = blocks.back(); @@ -889,162 +822,4 @@ extern "C" { ////////////////////////////////////////////////////////////////////////// - PROFILER_API bool writeTreesToFile(::std::atomic& progress, - const char* filename, - const ::profiler::FileData& filedata, - const ::profiler::thread_blocks_tree_t& threaded_trees, - const ::profiler::descriptors_list_t& _descriptors, - const ::profiler::pblocks_t& _blocks, - ::std::stringstream& _log) - { - ::std::ofstream of(filename, std::fstream::binary); - if (!of.is_open()) - { - _log << "Can not open file " << filename << " for writing"; - return false; - } - - ::std::stringstream str; - //typedef ::std::basic_iostream<::std::stringstream::char_type, ::std::stringstream::traits_type> stringstream_parent; - //stringstream_parent& s = str; - //auto oldbuf = s.rdbuf(of.rdbuf()); - - auto result = writeTreesToStream(progress, str, filedata, threaded_trees, _descriptors, _blocks, _log); - - of << str.str(); - //of.close(); - //s.rdbuf(oldbuf); - return result; - } - - PROFILER_API bool writeTreesToStream(::std::atomic& progress, - ::std::stringstream& str, - const ::profiler::FileData& filedata, - const ::profiler::thread_blocks_tree_t& threaded_trees, - const ::profiler::descriptors_list_t& _descriptors, - const ::profiler::pblocks_t& _blocks, - ::std::stringstream& _log) - { - auto oldprogress = progress.exchange(0, ::std::memory_order_release); - if (oldprogress < 0) - { - _log << "Writing was interrupted"; - return false; // Loading interrupted - } - - write(str, PROFILER_SIGNATURE); - write(str, ::profiler::EASY_FULL_VERSION); - write(str, filedata.cpu_frequency); - - decltype(filedata.begin_time) begin_time = filedata.begin_time; - begin_time *= filedata.cpu_frequency; - begin_time /= TIME_FACTOR; - write(str, begin_time); - - decltype(filedata.end_time) end_time = filedata.end_time; - end_time *= filedata.cpu_frequency; - end_time /= TIME_FACTOR; - write(str, end_time); - - write(str, filedata.total_blocks_number); - write(str, filedata.serialized_blocks.size()); - write(str, filedata.total_descriptors_number); - write(str, filedata.serialized_descriptors.size()); - - decltype(filedata.total_descriptors_number) n = 0; - uint64_t i = 0, size = filedata.serialized_descriptors.size(); - while (i < size) - { - const char* data = filedata.serialized_descriptors[i]; - auto descriptor = reinterpret_cast(data); - auto sz = static_cast(sizeof(::profiler::SerializedBlockDescriptor) + strlen(descriptor->name()) + strlen(descriptor->file()) + 2); - - write(str, sz); - write(str, data, sz); - ++n; - - i += sz; - - auto oldprogress = progress.exchange(static_cast(20 * i / filedata.serialized_descriptors.size()), ::std::memory_order_release); - if (oldprogress < 0) - { - _log << "Writing was interrupted"; - return false; // Loading interrupted - } - } - - if (n != filedata.total_descriptors_number || i != size) - printf("ERROR writing descriptors\n"); - - float prog = (float)progress.load(::std::memory_order_acquire); - if (prog < 0) - { - _log << "Writing was interrupted"; - return false; // Loading interrupted - } - - const float prog_per_thread = 80.f / (float)threaded_trees.size(); - - i = 0; - ::std::vector buffer; - for (auto tid : filedata.threads_order) - { - auto it = threaded_trees.find(tid); - if (it == threaded_trees.end()) - { - printf("Bad thread id = %u\n", tid); - continue; - } - - const auto& root = it->second; - - auto total = root.children.size() + root.sync.size(); - const float prog_per_block = total > 0 ? prog_per_thread / total : 0.f; - - write(str, root.thread_id); - - auto name_size = static_cast(strlen(root.name()) + 1); - const char* name = name_size > 1 ? root.name() : ""; - write(str, name_size); - write(str, name, name_size); - - auto blocks_number_in_thread = static_cast(root.sync.size()); - write(str, blocks_number_in_thread); - for (auto b : root.sync) - { - i += write_block_recursive(prog, prog_per_block, buffer, str, filedata, *_blocks[b], _blocks); - - auto oldprogress = progress.exchange(static_cast(prog), ::std::memory_order_release); - if (oldprogress < 0) - { - _log << "Writing was interrupted"; - return false; // Loading interrupted - } - } - - blocks_number_in_thread = static_cast(root.children.size()); - write(str, blocks_number_in_thread); - for (auto b : root.children) - { - i += write_block_recursive(prog, prog_per_block, buffer, str, filedata, *_blocks[b], _blocks, _descriptors); - - auto oldprogress = progress.exchange(static_cast(prog), ::std::memory_order_release); - if (oldprogress < 0) - { - _log << "Writing was interrupted"; - return false; // Loading interrupted - } - } - } - - if (i != filedata.serialized_blocks.size()) - printf("ERROR writing blocks\n"); - - printf("Finished writing to file\n"); - progress.store(100, ::std::memory_order_release); - return true; - } - - ////////////////////////////////////////////////////////////////////////// - } From 4eef4daf30943e0f9e9964631ac4935709eb27e3 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 2 Oct 2016 12:33:08 +0300 Subject: [PATCH 07/12] Minor refactoring --- profiler_gui/common_types.h | 5 ++--- profiler_gui/easy_graphics_item.cpp | 9 +++++---- profiler_gui/globals.cpp | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/profiler_gui/common_types.h b/profiler_gui/common_types.h index 80ce6a2..a08b777 100644 --- a/profiler_gui/common_types.h +++ b/profiler_gui/common_types.h @@ -150,18 +150,17 @@ inline ::profiler::color_t textColorForRgb(::profiler::color_t _color) #pragma pack(push, 1) struct EasyBlockItem Q_DECL_FINAL { - //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 ::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 + int8_t state; ///< 0 = no change, 1 = paint, -1 = do not paint // Possible optimizations: // 1) We can save 1 more byte per block if we will use char instead of short + real time calculations for "totalHeight" var; // 2) We can save 12 bytes per block if "x" and "w" vars will be removed (all this information exist inside BlocksTree), - // but this will make impossible to run graphics test without loading any .prof file. + // but this requires runtime x-coodinate calculation because BlocksTree has x value in nanoseconds. inline void setPos(qreal _x, float _w) { x = _x; w = _w; } inline qreal left() const { return x; } diff --git a/profiler_gui/easy_graphics_item.cpp b/profiler_gui/easy_graphics_item.cpp index 366fdbc..71128a1 100644 --- a/profiler_gui/easy_graphics_item.cpp +++ b/profiler_gui/easy_graphics_item.cpp @@ -38,7 +38,7 @@ ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -enum BlockItemState +enum BlockItemState : int8_t { BLOCK_ITEM_DO_NOT_PAINT = -1, BLOCK_ITEM_UNCHANGED, @@ -47,8 +47,9 @@ enum BlockItemState ////////////////////////////////////////////////////////////////////////// -const int MIN_ITEM_WIDTH = 2; -const int MIN_ITEMS_SPACING = 2; +const int MIN_ITEM_WIDTH = 3; +const int MIN_ITEMS_SPACING = 3; +const int MIN_SYNC_SPACING = 1; const int NARROW_ITEM_WIDTH = 20; const QRgb BORDERS_COLOR = ::profiler::colors::Grey700 & 0x00ffffff;// 0x00686868; @@ -537,7 +538,7 @@ void EasyGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* rect.setRect(left, top, width, h); _painter->drawRect(rect); - prevRight = left + width + MIN_ITEMS_SPACING; + prevRight = left + width + MIN_SYNC_SPACING; } } } diff --git a/profiler_gui/globals.cpp b/profiler_gui/globals.cpp index 635cf13..a660d27 100644 --- a/profiler_gui/globals.cpp +++ b/profiler_gui/globals.cpp @@ -51,7 +51,7 @@ namespace profiler_gui { , enable_event_indicators(true) , enable_statistics(true) , draw_graphics_items_borders(true) - , hide_narrow_children(false) + , hide_narrow_children(true) , display_only_relevant_stats(true) , collapse_items_on_tree_close(false) , all_items_expanded_by_default(true) From 5de9fcf82403a4353a07dff3698d848db2042de5 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 2 Oct 2016 16:17:22 +0300 Subject: [PATCH 08/12] Moved working with files from QFile to std::fstream because QFile has no overwrite mode (old file should be removed first); Added merging algorithm for block descriptions when refreshing descriptions list. --- profiler_gui/main_window.cpp | 122 +++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 35 deletions(-) diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index d621c21..874bab7 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -392,23 +392,54 @@ void EasyMainWindow::onSaveFileClicked(bool) auto filename = QFileDialog::getSaveFileName(this, "Save profiler log", dir, "Profiler Log File (*.prof);;All Files (*.*)"); if (!filename.isEmpty()) { - auto result = QFile::copy(m_bNetworkFileRegime ? QString(NETWORK_CACHE_FILE) : m_lastFile, filename); - if (result) + bool inOk = false, outOk = false; + int8_t retry1 = -1; + while (++retry1 < 4) { - m_lastFile = filename; - if (m_bNetworkFileRegime) + ::std::ifstream inFile(m_bNetworkFileRegime ? NETWORK_CACHE_FILE : m_lastFile.toStdString().c_str(), ::std::fstream::binary); + if (!inFile.is_open()) { - m_bNetworkFileRegime = false; - QFile::remove(NETWORK_CACHE_FILE); + ::std::this_thread::sleep_for(::std::chrono::milliseconds(500)); + continue; } + + inOk = true; + + int8_t retry2 = -1; + while (++retry2 < 4) + { + ::std::ofstream outFile(filename.toStdString(), ::std::fstream::binary); + if (!outFile.is_open()) + { + ::std::this_thread::sleep_for(::std::chrono::milliseconds(500)); + continue; + } + + outFile << inFile.rdbuf(); + outOk = true; + break; + } + + break; } - else if (m_bNetworkFileRegime) + + if (outOk) { - QMessageBox::warning(this, "Warning", "Can not save network cahce to file.\nSaving incomplete.", QMessageBox::Close); + if (m_bNetworkFileRegime) + QFile::remove(QString(NETWORK_CACHE_FILE)); + m_lastFile = filename; + m_bNetworkFileRegime = false; + } + else if (inOk) + { + QMessageBox::warning(this, "Warning", "Can not open destination file.\nSaving incomplete.", QMessageBox::Close); } else { - QMessageBox::warning(this, "Warning", "Can not copy last file.\nSaving incomplete.", QMessageBox::Close); + if (m_bNetworkFileRegime) + QMessageBox::warning(this, "Warning", "Can not open network cache file.\nSaving incomplete.", QMessageBox::Close); + else + QMessageBox::warning(this, "Warning", "Can not open source file.\nSaving incomplete.", QMessageBox::Close); } } } @@ -1094,17 +1125,20 @@ void EasyMainWindow::onGetBlockDescriptionsClicked(bool) if (m_listener.size() != 0) { // Read descriptions from stream + decltype(EASY_GLOBALS.descriptors) descriptors; decltype(m_serializedDescriptors) serializedDescriptors; ::std::stringstream errorMessage; if (readDescriptionsFromStream(m_listener.data(), serializedDescriptors, descriptors, errorMessage)) { + // Merge old and new descriptions + bool cancel = false; - const bool doFlush = m_descriptorsNumberInFile != descriptors.size(); + const bool doFlush = m_descriptorsNumberInFile > descriptors.size(); if (doFlush && !m_serializedBlocks.empty()) { auto button = QMessageBox::question(this, "Information", - QString("New blocks description number = %1\ndiffers from the old one = %2.\nTo avoid possible conflicts\nall profiled data will be deleted.\nPress \"Yes\" to continue or \"No\" to cancel.") + QString("New blocks description number = %1\nis less than the old one = %2.\nTo avoid possible conflicts\nall profiled data will be deleted.\nContinue?") .arg(descriptors.size()) .arg(m_descriptorsNumberInFile), QMessageBox::Yes, QMessageBox::No); @@ -1117,42 +1151,60 @@ void EasyMainWindow::onGetBlockDescriptionsClicked(bool) if (!cancel) { - auto oldnumber = m_descriptorsNumberInFile; - m_descriptorsNumberInFile = static_cast(descriptors.size()); - EASY_GLOBALS.descriptors.swap(descriptors); - m_serializedDescriptors.swap(serializedDescriptors); - - if (!doFlush && !m_serializedBlocks.empty() && descriptors.size() > oldnumber) + if (!doFlush && m_descriptorsNumberInFile < EASY_GLOBALS.descriptors.size()) { // There are dynamically added descriptors, add them to the new list too - auto diff = descriptors.size() - oldnumber; - EASY_GLOBALS.descriptors.reserve(EASY_GLOBALS.descriptors.size() + diff); - for (decltype(diff) i = 0; i < diff; ++i) + auto newnumber = static_cast(descriptors.size()); + auto size = static_cast(EASY_GLOBALS.descriptors.size()); + auto diff = newnumber - size; + decltype(newnumber) failnumber = 0; + + descriptors.reserve(descriptors.size() + EASY_GLOBALS.descriptors.size() - m_descriptorsNumberInFile); + for (auto i = m_descriptorsNumberInFile; i < size; ++i) { - auto desc = descriptors[oldnumber + i]; - for (decltype(oldnumber) j = 0; j < oldnumber; ++j) + auto id = EASY_GLOBALS.descriptors[i]->id(); + if (id < newnumber) + descriptors.push_back(descriptors[id]); + else + ++failnumber; + } + + if (failnumber != 0) + { + // There are some errors... + + // revert changes + descriptors.resize(newnumber); + + // clear all profiled data to avoid conflicts + auto button = QMessageBox::question(this, "Information", + "There are errors while merging block descriptions lists.\nTo avoid possible conflicts\nall profiled data will be deleted.\nContinue?", + QMessageBox::Yes, QMessageBox::No); + + if (button == QMessageBox::Yes) + clear(); // Clear all contents because new descriptors list conflicts with old one + else + cancel = true; + } + + if (!cancel && diff != 0) + { + for (auto& b : EASY_GLOBALS.gui_blocks) { - if (descriptors[j] == desc) - { - EASY_GLOBALS.descriptors.push_back(EASY_GLOBALS.descriptors[j]); - desc = nullptr; - break; - } + if (b.tree.node->id() >= m_descriptorsNumberInFile) + b.tree.node->setId(b.tree.node->id() + diff); } - if (desc != nullptr) - { - QMessageBox::warning(this, "Warning", "Conflict with dynamically added block descriptions.\nAll profiled data will be cleared.", QMessageBox::Close); - clear(); - cancel = true; - break; - } + m_descriptorsNumberInFile = newnumber; } } if (!cancel) { + EASY_GLOBALS.descriptors.swap(descriptors); + m_serializedDescriptors.swap(serializedDescriptors); + if (m_descTreeDialog != nullptr) { #if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0 From 19966b40c6975e8ff7a385fd7804d8f0cfc7c790 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 2 Oct 2016 17:45:55 +0300 Subject: [PATCH 09/12] Crash fix --- profiler_gui/blocks_tree_widget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 0a8a34f..81b6f41 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -614,7 +614,7 @@ void EasyTreeWidget::onBlockStatusChangeClicked(bool _checked) void EasyTreeWidget::onItemExpand(QTreeWidgetItem* _item) { - if (!EASY_GLOBALS.bind_scene_and_tree_expand_status) + if (!EASY_GLOBALS.bind_scene_and_tree_expand_status || _item->parent() == nullptr) { resizeColumnsToContents(); return; @@ -631,7 +631,7 @@ void EasyTreeWidget::onItemExpand(QTreeWidgetItem* _item) void EasyTreeWidget::onItemCollapse(QTreeWidgetItem* _item) { - if (!EASY_GLOBALS.bind_scene_and_tree_expand_status) + if (!EASY_GLOBALS.bind_scene_and_tree_expand_status || _item->parent() == nullptr) return; static_cast(_item)->guiBlock().expanded = false; From bc83a837f75517a7db828469a8ab9962f8b37dee Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 2 Oct 2016 17:52:14 +0300 Subject: [PATCH 10/12] New icons --- profiler_gui/icons/attribution.txt | 44 ++++----- profiler_gui/icons/open-folder2.svg | 44 +++++++++ profiler_gui/icons/reload-folder2.svg | 52 +++++++++++ profiler_gui/icons/save.svg | 127 +++++++++++++++----------- profiler_gui/main_window.cpp | 2 +- profiler_gui/resources.qrc | 3 +- 6 files changed, 196 insertions(+), 76 deletions(-) create mode 100644 profiler_gui/icons/open-folder2.svg create mode 100644 profiler_gui/icons/reload-folder2.svg diff --git a/profiler_gui/icons/attribution.txt b/profiler_gui/icons/attribution.txt index 304043f..2acd148 100644 --- a/profiler_gui/icons/attribution.txt +++ b/profiler_gui/icons/attribution.txt @@ -1,21 +1,23 @@ -logo.svg - Icon made by Freepik from www.flaticon.com -off.svg - Icon made by Freepik from www.flaticon.com -open-folder.svg - Icon made by Freepik from www.flaticon.com -reload.svg - Icon made by Freepik from www.flaticon.com -expand.svg - Icon made by Freepik from www.flaticon.com -collapse.svg - Icon made by Freepik from www.flaticon.com -colors.svg - Icon made by Freepik from www.flaticon.com -colors-black.svg - Icon made by Freepik from www.flaticon.com -save.svg - Icon made by Freepik from www.flaticon.com -statistics.svg - Icon made by Freepik from www.flaticon.com -statistics2.svg - Icon made by Freepik from www.flaticon.com -lan.svg - Icon made by Freepik from www.flaticon.com -lan_on.svg - Icon made by Freepik from www.flaticon.com -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 -settings.svg - Icon made by Freepik from www.flaticon.com \ No newline at end of file +logo.svg - Icon made by Freepik from www.flaticon.com +off.svg - Icon made by Freepik from www.flaticon.com +open-folder.svg - Icon made by Freepik from www.flaticon.com +open-folder2.svg - Icon made by Freepik from www.flaticon.com +reload-folder2.svg - Icon made by Freepik from www.flaticon.com +reload.svg - Icon made by Freepik from www.flaticon.com +expand.svg - Icon made by Freepik from www.flaticon.com +collapse.svg - Icon made by Freepik from www.flaticon.com +colors.svg - Icon made by Freepik from www.flaticon.com +colors-black.svg - Icon made by Freepik from www.flaticon.com +save.svg - Icon made by Freepik from www.flaticon.com +statistics.svg - Icon made by Freepik from www.flaticon.com +statistics2.svg - Icon made by Freepik from www.flaticon.com +lan.svg - Icon made by Freepik from www.flaticon.com +lan_on.svg - Icon made by Freepik from www.flaticon.com +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 +settings.svg - Icon made by Freepik from www.flaticon.com \ No newline at end of file diff --git a/profiler_gui/icons/open-folder2.svg b/profiler_gui/icons/open-folder2.svg new file mode 100644 index 0000000..b6454a9 --- /dev/null +++ b/profiler_gui/icons/open-folder2.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/profiler_gui/icons/reload-folder2.svg b/profiler_gui/icons/reload-folder2.svg new file mode 100644 index 0000000..d3f047c --- /dev/null +++ b/profiler_gui/icons/reload-folder2.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/profiler_gui/icons/save.svg b/profiler_gui/icons/save.svg index d618cd5..85a9cb5 100644 --- a/profiler_gui/icons/save.svg +++ b/profiler_gui/icons/save.svg @@ -1,53 +1,74 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + +image/svg+xml \ No newline at end of file diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 874bab7..d2a662c 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -131,7 +131,7 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_lastAddress("127.0.0.1"), m_lastP toolbar->setContentsMargins(1, 0, 1, 0); toolbar->addAction(QIcon(":/Open"), tr("Open"), this, SLOT(onOpenFileClicked(bool))); - toolbar->addAction(QIcon(":/Reload"), tr("Reload"), this, SLOT(onReloadFileClicked(bool))); + toolbar->addAction(QIcon(":/Reopen"), tr("Reload last file"), this, SLOT(onReloadFileClicked(bool))); m_saveAction = toolbar->addAction(QIcon(":/Save"), tr("Save"), this, SLOT(onSaveFileClicked(bool))); m_deleteAction = toolbar->addAction(QIcon(":/Delete"), tr("Clear all"), this, SLOT(onDeleteClicked(bool))); diff --git a/profiler_gui/resources.qrc b/profiler_gui/resources.qrc index 185a294..8bc879d 100644 --- a/profiler_gui/resources.qrc +++ b/profiler_gui/resources.qrc @@ -2,7 +2,8 @@ icons/logo.svg icons/off.svg - icons/open-folder.svg + icons/open-folder2.svg + icons/reload-folder2.svg icons/reload.svg icons/expand.svg icons/collapse.svg From 01b946f396b2df403d7924920bb402df0a6630bb Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Sun, 2 Oct 2016 17:52:42 +0300 Subject: [PATCH 11/12] Thread names change --- profiler_gui/easy_graphics_item.cpp | 14 +++++++++- profiler_gui/tree_widget_loader.cpp | 40 +++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/profiler_gui/easy_graphics_item.cpp b/profiler_gui/easy_graphics_item.cpp index 71128a1..ef6917c 100644 --- a/profiler_gui/easy_graphics_item.cpp +++ b/profiler_gui/easy_graphics_item.cpp @@ -73,10 +73,22 @@ const auto SELECTED_ITEM_FONT = ::profiler_gui::EFont("Helvetica", 10, QFont::Bo EasyGraphicsItem::EasyGraphicsItem(uint8_t _index, const::profiler::BlocksTreeRoot& _root) : QGraphicsItem(nullptr) - , m_threadName(_root.got_name() ? QString("%1 Thread %2").arg(_root.name()).arg(_root.thread_id) : QString("Thread %1").arg(_root.thread_id)) , m_pRoot(&_root) , m_index(_index) { + const auto u_thread = ::profiler_gui::toUnicode("thread"); + if (_root.got_name()) + { + QString rootname(::profiler_gui::toUnicode(_root.name())); + if (rootname.contains(u_thread, Qt::CaseInsensitive)) + m_threadName = ::std::move(QString("%1 %2").arg(rootname).arg(_root.thread_id)); + else + m_threadName = ::std::move(QString("%1 Thread %2").arg(rootname).arg(_root.thread_id)); + } + else + { + m_threadName = ::std::move(QString("Thread %1").arg(_root.thread_id)); + } } EasyGraphicsItem::~EasyGraphicsItem() diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index f258999..39af6c4 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -168,6 +168,7 @@ void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI } //const QSignalBlocker b(this); + const auto u_thread = ::profiler_gui::toUnicode("thread"); int i = 0; const int total = static_cast(_blocksTree.size()); for (const auto& threadTree : _blocksTree) @@ -178,10 +179,21 @@ void FillTreeClass::setTreeInternal1(T& _safelocker, Items& _items, ThreadedI const auto& root = threadTree.second; auto item = new EasyTreeWidgetItem(); - if (root.got_name()) - item->setText(COL_NAME, QString("%1 Thread %2").arg(root.name()).arg(root.thread_id)); - else - item->setText(COL_NAME, QString("Thread %1").arg(root.thread_id)); + QString threadName; + if (root.got_name()) + { + QString rootname(::profiler_gui::toUnicode(root.name())); + if (rootname.contains(u_thread, Qt::CaseInsensitive)) + threadName = ::std::move(QString("%1 %2").arg(rootname).arg(root.thread_id)); + else + threadName = ::std::move(QString("%1 Thread %2").arg(rootname).arg(root.thread_id)); + } + else + { + threadName = ::std::move(QString("Thread %1").arg(root.thread_id)); + } + + item->setText(COL_NAME, threadName); ::profiler::timestamp_t duration = 0; if (!root.children.empty()) @@ -239,6 +251,7 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI RootsMap threadsMap; + const auto u_thread = ::profiler_gui::toUnicode("thread"); int i = 0, total = static_cast(_blocks.size()); //const QSignalBlocker b(this); for (const auto& block : _blocks) @@ -266,10 +279,21 @@ void FillTreeClass::setTreeInternal2(T& _safelocker, Items& _items, ThreadedI { thread_item = new EasyTreeWidgetItem(); - if (block.root->got_name()) - thread_item->setText(COL_NAME, QString("%1 Thread %2").arg(block.root->name()).arg(block.root->thread_id)); - else - thread_item->setText(COL_NAME, QString("Thread %1").arg(block.root->thread_id)); + QString threadName; + if (block.root->got_name()) + { + QString rootname(::profiler_gui::toUnicode(block.root->name())); + if (rootname.contains(u_thread, Qt::CaseInsensitive)) + threadName = ::std::move(QString("%1 %2").arg(rootname).arg(block.root->thread_id)); + else + threadName = ::std::move(QString("%1 Thread %2").arg(rootname).arg(block.root->thread_id)); + } + else + { + threadName = ::std::move(QString("Thread %1").arg(block.root->thread_id)); + } + + thread_item->setText(COL_NAME, threadName); if (!block.root->children.empty()) duration = blocksTree(block.root->children.back()).node->end() - blocksTree(block.root->children.front()).node->begin(); From 8054c3ab6f93c70f8f7178539cf6df2276c331ad Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Wed, 19 Oct 2016 22:21:04 +0300 Subject: [PATCH 12/12] init thread storage on end block --- src/profile_manager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 1be4ba0..e3346ba 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -472,6 +472,9 @@ void ProfileManager::endBlock() if (!m_isEnabled.load(std::memory_order_acquire)) return; + if (THREAD_STORAGE == nullptr) + THREAD_STORAGE = &threadStorage(getCurrentThreadId()); + if (THREAD_STORAGE->blocks.openedList.empty()) return;