diff --git a/include/profiler/reader.h b/include/profiler/reader.h index cf61ade..2245994 100644 --- a/include/profiler/reader.h +++ b/include/profiler/reader.h @@ -57,6 +57,8 @@ namespace profiler { { } + //BlockStatistics() = default; + inline ::profiler::timestamp_t average_duration() const { return total_duration / calls_number; @@ -65,7 +67,7 @@ namespace profiler { }; // END of struct BlockStatistics. #pragma pack(pop) - extern "C" void PROFILER_API release_stats(BlockStatistics*& _stats); + extern "C" PROFILER_API void release_stats(BlockStatistics*& _stats); ////////////////////////////////////////////////////////////////////////// @@ -208,13 +210,11 @@ namespace profiler { inline bool got_name() const { - //return thread_name && *thread_name != 0; return thread_name.front() != 0; } inline const char* name() const { - //return thread_name; return thread_name.c_str(); } @@ -237,17 +237,19 @@ namespace profiler { class PROFILER_API SerializedData final { - char* m_data; + char* m_data; + size_t m_size; public: - SerializedData() : m_data(nullptr) + SerializedData() : m_data(nullptr), m_size(0) { } - SerializedData(SerializedData&& that) : m_data(that.m_data) + SerializedData(SerializedData&& that) : m_data(that.m_data), m_size(that.m_size) { that.m_data = nullptr; + that.m_size = 0; } ~SerializedData() @@ -255,34 +257,58 @@ namespace profiler { clear(); } - void set(char* _data); + void set(size_t _size); + void extend(size_t _size); SerializedData& operator = (SerializedData&& that) { - set(that.m_data); + set(that.m_data, that.m_size); that.m_data = nullptr; + that.m_size = 0; return *this; } - char* operator[](uint64_t i) + char* operator [] (uint64_t i) { return m_data + i; } + size_t size() const + { + return m_size; + } + + char* data() + { + return m_data; + } + + const char* data() const + { + return m_data; + } + void clear() { - set(nullptr); + set(nullptr, 0); } void swap(SerializedData& other) { - auto temp = other.m_data; + char* d = other.m_data; + size_t sz = other.m_size; + other.m_data = m_data; - m_data = temp; + other.m_size = m_size; + + m_data = d; + m_size = sz; } private: + void set(char* _data, size_t _size); + SerializedData(const SerializedData&) = delete; SerializedData& operator = (const SerializedData&) = delete; @@ -294,18 +320,18 @@ namespace profiler { } // END of namespace profiler. -extern "C" ::profiler::block_index_t PROFILER_API fillTreesFromFile(::std::atomic& progress, const char* filename, +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 = false); + bool gather_statistics); inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& threaded_trees, - bool gather_statistics = false) + bool gather_statistics) { ::std::atomic progress = ATOMIC_VAR_INIT(0); return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, gather_statistics); diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index fb681fc..5c453af 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -307,7 +307,7 @@ EasyChronometerItem* EasyGraphicsView::createChronometer(bool _main) ////////////////////////////////////////////////////////////////////////// -void EasyGraphicsView::clearSilent() +void EasyGraphicsView::clear() { const QSignalBlocker blocker(this), sceneBlocker(scene()); // block all scene signals (otherwise clear() would be extremely slow!) @@ -341,7 +341,6 @@ void EasyGraphicsView::clearSilent() m_idleTime = 0; // Reset necessary flags - //m_bTest = false; m_bEmpty = true; // notify ProfTreeWidget that selection was reset @@ -351,7 +350,7 @@ void EasyGraphicsView::clearSilent() void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTree) { // clear scene - clearSilent(); + clear(); if (_blocksTree.empty()) { @@ -450,7 +449,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr // Calculating scene rect const qreal endX = time2position(finish) + 1500.0; - scene()->setSceneRect(0, 0, endX, y + TIMELINE_ROW_SIZE); + setSceneRect(0, 0, endX, y + TIMELINE_ROW_SIZE); // Center view on the beginning of the scene updateVisibleSceneRect(); @@ -602,11 +601,9 @@ void EasyGraphicsView::setScrollbar(EasyGraphicsScrollbar* _scrollbar) } m_pScrollbar = _scrollbar; - m_pScrollbar->setMinimapFrom(0, nullptr); - m_pScrollbar->hideChrono(); + m_pScrollbar->clear(); m_pScrollbar->setRange(0, scene()->width()); m_pScrollbar->setSliderWidth(m_visibleSceneRect.width()); - m_pScrollbar->setValue(0); if (makeConnect) { @@ -1444,6 +1441,14 @@ EasyGraphicsView* EasyGraphicsViewWidget::view() return m_view; } +void EasyGraphicsViewWidget::clear() +{ + m_scrollbar->clear(); + m_threadNamesWidget->clear(); + m_view->clear(); + m_view->setSceneRect(0, 0, 10, 10); +} + ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -1506,6 +1511,17 @@ void EasyThreadNameItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte _painter->drawText(rect, Qt::AlignRight | Qt::AlignVCenter, item->threadName()); } + const auto rect_bottom = rect.bottom(); + if (rect_bottom < h) + { + ++i; + rect.translate(5, rect.height()); + rect.setHeight(h - rect_bottom); + _painter->setBrush(brushes[i & 1]); + _painter->setPen(Qt::NoPen); + _painter->drawRect(rect); + } + // Draw separator between thread names area and information area _painter->setPen(Qt::darkGray); _painter->drawLine(QLineF(0, h, w, h)); @@ -1567,6 +1583,13 @@ EasyThreadNamesWidget::~EasyThreadNamesWidget() } +void EasyThreadNamesWidget::clear() +{ + const QSignalBlocker b(this); + scene()->clear(); + setFixedWidth(100); +} + void EasyThreadNamesWidget::setVerticalScrollbarRange(int _minValue, int _maxValue) { verticalScrollBar()->setRange(_minValue, _maxValue + m_additionalHeight); diff --git a/profiler_gui/blocks_graphics_view.h b/profiler_gui/blocks_graphics_view.h index 383d6ae..128bfb8 100644 --- a/profiler_gui/blocks_graphics_view.h +++ b/profiler_gui/blocks_graphics_view.h @@ -141,7 +141,7 @@ public: qreal chronoTimeAux() const; void setScrollbar(EasyGraphicsScrollbar* _scrollbar); - void clearSilent(); + void clear(); void setTree(const ::profiler::thread_blocks_tree_t& _blocksTree); @@ -246,6 +246,8 @@ public: void keyPressEvent(QKeyEvent* _event) override; void keyReleaseEvent(QKeyEvent* _event) override; + void clear(); + const EasyGraphicsView* view() const { return m_view; @@ -278,6 +280,7 @@ public: virtual ~EasyGraphicsViewWidget(); EasyGraphicsView* view(); + void clear(); private: diff --git a/profiler_gui/descriptors_tree_widget.cpp b/profiler_gui/descriptors_tree_widget.cpp index a123118..e2b8ebf 100644 --- a/profiler_gui/descriptors_tree_widget.cpp +++ b/profiler_gui/descriptors_tree_widget.cpp @@ -733,6 +733,11 @@ void EasyDescWidget::build() m_tree->build(); } +void EasyDescWidget::clear() +{ + m_tree->clearSilent(true); +} + void EasyDescWidget::onSeachBoxReturnPressed() { auto matches = m_tree->findNext(m_searchBox->text()); diff --git a/profiler_gui/descriptors_tree_widget.h b/profiler_gui/descriptors_tree_widget.h index 671d8e3..d2512dd 100644 --- a/profiler_gui/descriptors_tree_widget.h +++ b/profiler_gui/descriptors_tree_widget.h @@ -152,6 +152,7 @@ public: // Public non-virtual methods void build(); + void clear(); private slots: diff --git a/profiler_gui/easy_graphics_scrollbar.cpp b/profiler_gui/easy_graphics_scrollbar.cpp index 98d6912..2945e38 100644 --- a/profiler_gui/easy_graphics_scrollbar.cpp +++ b/profiler_gui/easy_graphics_scrollbar.cpp @@ -349,6 +349,17 @@ EasyGraphicsScrollbar::~EasyGraphicsScrollbar() ////////////////////////////////////////////////////////////////////////// +void EasyGraphicsScrollbar::clear() +{ + setMinimapFrom(0, nullptr); + hideChrono(); + setRange(0, 100); + setSliderWidth(2); + setValue(0); +} + +////////////////////////////////////////////////////////////////////////// + qreal EasyGraphicsScrollbar::getWindowScale() const { return m_windowScale; diff --git a/profiler_gui/easy_graphics_scrollbar.h b/profiler_gui/easy_graphics_scrollbar.h index 1d6cb4c..e0726ce 100644 --- a/profiler_gui/easy_graphics_scrollbar.h +++ b/profiler_gui/easy_graphics_scrollbar.h @@ -145,6 +145,8 @@ public: // Public non-virtual methods + void clear(); + qreal getWindowScale() const; ::profiler::thread_id_t minimapThread() const; diff --git a/profiler_gui/icons/attribution.txt b/profiler_gui/icons/attribution.txt index 258f4ec..37a75b0 100644 --- a/profiler_gui/icons/attribution.txt +++ b/profiler_gui/icons/attribution.txt @@ -13,4 +13,5 @@ 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 \ No newline at end of file +play.svg - Icon made by Google from www.flaticon.com +delete.svg - Icon made by Freepik from www.flaticon.com \ No newline at end of file diff --git a/profiler_gui/icons/delete.svg b/profiler_gui/icons/delete.svg new file mode 100644 index 0000000..4090c77 --- /dev/null +++ b/profiler_gui/icons/delete.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index a98d6ec..8553317 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -120,6 +120,7 @@ EasyMainWindow::EasyMainWindow() : Parent() auto toolbar = addToolBar("MainToolBar"); toolbar->setObjectName("ProfilerGUI_MainToolBar"); + toolbar->addAction(QIcon(":/Delete"), tr("Clear all"), this, SLOT(onDeleteClicked(bool))); m_captureAction = toolbar->addAction(QIcon(":/Start"), tr("Capture"), this, SLOT(onCaptureClicked(bool))); m_captureAction->setEnabled(false); @@ -259,6 +260,8 @@ EasyMainWindow::EasyMainWindow() : Parent() menu = menuBar()->addMenu("&Edit"); m_editBlocksAction = menu->addAction(tr("Edit blocks"), this, SLOT(onEditBlocksClicked(bool))); m_editBlocksAction->setEnabled(false); + action = menu->addAction(tr("Clear all"), this, SLOT(onDeleteClicked(bool))); + SET_ICON(action, ":/Delete"); @@ -469,7 +472,7 @@ void EasyMainWindow::listen() loaded += toWrite; seek = toWrite; - m_downloadedBytes.store((loaded / (neededSize+1)) * 100); + m_downloadedBytes.store((100 * loaded / (neededSize + 1)), ::std::memory_order_release); } break; @@ -530,6 +533,30 @@ void EasyMainWindow::onReloadFileClicked(bool) ////////////////////////////////////////////////////////////////////////// +void EasyMainWindow::onDeleteClicked(bool) +{ + static_cast(m_treeWidget->widget())->clearSilent(true); + static_cast(m_graphicsView->widget())->clear(); + +#if EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW != 0 + static_cast(m_descTreeWidget->widget())->clear(); +#endif + if (m_dialogDescTree != nullptr) + m_dialogDescTree->clear(); + m_editBlocksAction->setEnabled(false); + + EASY_GLOBALS.selected_thread = 0; + ::profiler_gui::set_max(EASY_GLOBALS.selected_block); + EASY_GLOBALS.profiler_blocks.clear(); + EASY_GLOBALS.descriptors.clear(); + EASY_GLOBALS.gui_blocks.clear(); + + m_serializedBlocks.clear(); + m_serializedDescriptors.clear(); +} + +////////////////////////////////////////////////////////////////////////// + void EasyMainWindow::onExitClicked(bool) { close(); @@ -768,7 +795,7 @@ void EasyMainWindow::onDownloadTimeout() m_downloadedTimer.stop(); } else{ - m_downloadingProgress->setValue(m_downloadedBytes.load()); + m_downloadingProgress->setValue(m_downloadedBytes.load(::std::memory_order_acquire)); } } @@ -865,17 +892,17 @@ EasyFileReader::~EasyFileReader() bool EasyFileReader::done() const { - return m_bDone.load(); + return m_bDone.load(::std::memory_order_acquire); } int EasyFileReader::progress() const { - return m_progress.load(); + return m_progress.load(::std::memory_order_acquire); } unsigned int EasyFileReader::size() const { - return m_size.load(); + return m_size.load(::std::memory_order_acquire); } const QString& EasyFileReader::filename() const @@ -889,21 +916,21 @@ void EasyFileReader::load(const QString& _filename) 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_progress.store(100); - m_bDone.store(true); + m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, _enableStatistics), ::std::memory_order_release); + m_progress.store(100, ::std::memory_order_release); + m_bDone.store(true, ::std::memory_order_release); }, EASY_GLOBALS.enable_statistics)); } void EasyFileReader::interrupt() { - m_progress.store(-100); + m_progress.store(-100, ::std::memory_order_release); if (m_thread.joinable()) m_thread.join(); - m_bDone.store(false); - m_progress.store(0); - m_size.store(0); + 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_descriptors.clear(); diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 5271b76..bf75d5d 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -153,6 +153,7 @@ protected slots: void onOpenFileClicked(bool); void onReloadFileClicked(bool); + void onDeleteClicked(bool); void onExitClicked(bool); void onEncodingChanged(bool); void onChronoTextPosChanged(bool); diff --git a/profiler_gui/resources.qrc b/profiler_gui/resources.qrc index 5a93934..bf37828 100644 --- a/profiler_gui/resources.qrc +++ b/profiler_gui/resources.qrc @@ -18,5 +18,6 @@ icons/lan.svg icons/lan_on.svg icons/play.svg + icons/delete.svg diff --git a/src/reader.cpp b/src/reader.cpp index c061017..e0e5391 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -54,24 +54,42 @@ namespace profiler { - void SerializedData::set(char* _data) + void SerializedData::set(char* _data, size_t _size) { - if (m_data != nullptr) - delete[] m_data; + delete [] m_data; m_data = _data; + m_size = _size; } - extern "C" void release_stats(BlockStatistics*& _stats) + void SerializedData::set(size_t _size) { - if (!_stats) - { - return; + if (_size != 0) + set(new char[_size], _size); + else + set(nullptr, 0); + } + + void SerializedData::extend(size_t _size) + { + auto olddata = m_data; + auto oldsize = m_size; + + m_size = oldsize + _size; + m_data = new char[m_size]; + + if (olddata != nullptr) { + memcpy(m_data, olddata, oldsize); + delete [] olddata; } + } + + extern "C" PROFILER_API void release_stats(BlockStatistics*& _stats) + { + if (_stats == nullptr) + return; if (--_stats->calls_number == 0) - { delete _stats; - } _stats = nullptr; } @@ -159,14 +177,53 @@ void update_statistics_recursive(StatsMap& _stats_map, ::profiler::BlocksTree& _ { _current.per_frame_stats = update_statistics(_stats_map, _current, _current_index, _parent_index); for (auto i : _current.children) - { update_statistics_recursive(_stats_map, _blocks[i], i, _parent_index, _blocks); - } } ////////////////////////////////////////////////////////////////////////// -extern "C" ::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) +/*void validate_pointers(::std::atomic& _progress, const char* _oldbase, ::profiler::SerializedData& _serialized_blocks, ::profiler::blocks_t& _blocks, size_t _size) +{ + if (_oldbase == nullptr) + { + _progress.store(25, ::std::memory_order_release); + return; + } + + for (size_t i = 0; i < _size; ++i) + { + auto& tree = _blocks[i]; + auto dist = ::std::distance(_oldbase, reinterpret_cast(tree.node)); + tree.node = reinterpret_cast<::profiler::SerializedBlock*>(_serialized_blocks.data() + dist); + _progress.store(20 + static_cast(5 * i / _size), ::std::memory_order_release); + } +} + +void validate_pointers(::std::atomic& _progress, const char* _oldbase, ::profiler::SerializedData& _serialized_descriptors, ::profiler::descriptors_list_t& _descriptors, size_t _size) +{ + if (_oldbase == nullptr) + { + _progress.store(5, ::std::memory_order_release); + return; + } + + for (size_t i = 0; i < _size; ++i) + { + auto dist = ::std::distance(_oldbase, reinterpret_cast(_descriptors[i])); + _descriptors[i] = reinterpret_cast<::profiler::SerializedBlockDescriptor*>(_serialized_descriptors.data() + dist); + _progress.store(static_cast(5 * i / _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) { EASY_FUNCTION(::profiler::colors::Cyan); @@ -189,10 +246,6 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr if (memory_size == 0) return 0; - serialized_blocks.set(new char[memory_size]); - //memset(serialized_blocks[0], 0, memory_size); - - uint32_t total_descriptors_number = 0; inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number))); if (total_descriptors_number == 0) @@ -204,7 +257,9 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr return 0; descriptors.reserve(total_descriptors_number); - serialized_descriptors.set(new char[descriptors_memory_size]); + //const char* olddata = append_regime ? serialized_descriptors.data() : nullptr; + serialized_descriptors.set(descriptors_memory_size); + //validate_pointers(progress, olddata, serialized_descriptors, descriptors, descriptors.size()); uint64_t i = 0; while (!inFile.eof() && descriptors.size() < total_descriptors_number) @@ -228,19 +283,25 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr descriptors.push_back(descriptor); i += sz; - progress.store(static_cast(10 * i / descriptors_memory_size)); + progress.store(static_cast(15 * i / descriptors_memory_size), ::std::memory_order_release); } + if (progress.load(::std::memory_order_acquire) < 0) + return 0; // Loading interrupted + typedef ::std::unordered_map<::profiler::thread_id_t, StatsMap, ::profiler::passthrough_hash> PerThreadStats; PerThreadStats thread_statistics, parent_statistics, frame_statistics; IdMap identification_table; - ::std::vector name; + 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; - blocks.reserve(total_blocks_number); + ::std::vector name; while (!inFile.eof() && read_number < total_blocks_number) { EASY_BLOCK("Read thread data", ::profiler::colors::DarkGreen); @@ -297,14 +358,14 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr root.sync.emplace_back(block_index); - if (progress.load() < 0) - break; + if (progress.load(::std::memory_order_acquire) < 0) + break; // Loading interrupted - progress.store(10 + static_cast(80 * i / memory_size)); + progress.store(20 + static_cast(70 * i / memory_size), ::std::memory_order_release); } - if (progress.load() < 0 || inFile.eof()) - break; + if (progress.load(::std::memory_order_acquire) < 0 || inFile.eof()) + break; // Loading interrupted blocks_number_in_thread = 0; inFile.read((char*)&blocks_number_in_thread, sizeof(decltype(blocks_number_in_thread))); @@ -434,19 +495,15 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr tree.per_thread_stats = update_statistics(per_thread_statistics, tree, block_index, thread_id); } - if (progress.load() < 0) - break; - progress.store(10 + static_cast(80 * i / memory_size)); + if (progress.load(::std::memory_order_acquire) < 0) + break; // Loading interrupted + + progress.store(20 + static_cast(70 * i / memory_size), ::std::memory_order_release); } } - if (progress.load() < 0) - { - serialized_blocks.clear(); - threaded_trees.clear(); - blocks.clear(); - return 0; - } + if (progress.load(::std::memory_order_acquire) < 0) + return 0; // Loading interrupted EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple); if (gather_statistics) @@ -493,7 +550,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr for (auto& t : statistics_threads) { t.join(); - progress.store(90 + (10 * ++j) / n); + progress.store(90 + (10 * ++j) / n, ::std::memory_order_release); } } else @@ -520,7 +577,7 @@ extern "C" ::profiler::block_index_t fillTreesFromFile(::std::atomic& progr ++root.depth; - progress.store(90 + (10 * ++j) / n); + progress.store(90 + (10 * ++j) / n, ::std::memory_order_release); } } // No need to delete BlockStatistics instances - they will be deleted inside BlocksTree destructors