diff --git a/easy_profiler_core/include/easy/reader.h b/easy_profiler_core/include/easy/reader.h index 0a1687c..aac2322 100644 --- a/easy_profiler_core/include/easy/reader.h +++ b/easy_profiler_core/include/easy/reader.h @@ -283,86 +283,41 @@ namespace profiler { class PROFILER_API SerializedData EASY_FINAL { - char* m_data; - size_t m_size; + uint64_t m_size; + char* m_data; public: SerializedData(const SerializedData&) = delete; SerializedData& operator = (const SerializedData&) = delete; - SerializedData() : m_data(nullptr), m_size(0) - { - } + SerializedData(); - SerializedData(SerializedData&& that) : m_data(that.m_data), m_size(that.m_size) - { - that.m_data = nullptr; - that.m_size = 0; - } + SerializedData(SerializedData&& that); - ~SerializedData() - { - clear(); - } + ~SerializedData(); void set(uint64_t _size); + void extend(uint64_t _size); - SerializedData& operator = (SerializedData&& that) - { - set(that.m_data, that.m_size); - that.m_data = nullptr; - that.m_size = 0; - return *this; - } + SerializedData& operator = (SerializedData&& that); - char* operator [] (uint64_t i) - { - return m_data + i; - } + char* operator [] (uint64_t i); - const char* operator [] (uint64_t i) const - { - return m_data + i; - } + const char* operator [] (uint64_t i) const; - bool empty() const - { - return m_size == 0; - } + bool empty() const; - uint64_t size() const - { - return m_size; - } + uint64_t size() const; - char* data() - { - return m_data; - } + char* data(); - const char* data() const - { - return m_data; - } + const char* data() const; - void clear() - { - set(nullptr, 0); - } + void clear(); - void swap(SerializedData& other) - { - char* d = other.m_data; - uint64_t sz = other.m_size; - - other.m_data = m_data; - other.m_size = m_size; - - m_data = d; - m_size = (size_t)sz; - } + void swap(SerializedData& other); private: @@ -409,6 +364,7 @@ extern "C" { PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic& progress, const char* filename, const profiler::SerializedData& serialized_descriptors, + const profiler::descriptors_list_t& descriptors, profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& trees, profiler::block_getter_fn block_getter, @@ -419,6 +375,7 @@ extern "C" { PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic& progress, std::ostream& str, const profiler::SerializedData& serialized_descriptors, + const profiler::descriptors_list_t& descriptors, profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& trees, profiler::block_getter_fn block_getter, @@ -445,6 +402,7 @@ inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler: inline profiler::block_index_t writeTreesToFile(const char* filename, const profiler::SerializedData& serialized_descriptors, + const profiler::descriptors_list_t& descriptors, profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& trees, profiler::block_getter_fn block_getter, @@ -454,12 +412,13 @@ inline profiler::block_index_t writeTreesToFile(const char* filename, std::ostream& log) { std::atomic progress = ATOMIC_VAR_INIT(0); - return writeTreesToFile(progress, filename, serialized_descriptors, descriptors_count, trees, std::move(block_getter), - begin_time, end_time, pid, log); + return writeTreesToFile(progress, filename, serialized_descriptors, descriptors, descriptors_count, trees, + std::move(block_getter), begin_time, end_time, pid, log); } inline profiler::block_index_t writeTreesToStream(std::ostream& str, const profiler::SerializedData& serialized_descriptors, + const profiler::descriptors_list_t& descriptors, profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& trees, profiler::block_getter_fn block_getter, @@ -469,8 +428,8 @@ inline profiler::block_index_t writeTreesToStream(std::ostream& str, std::ostream& log) { std::atomic progress = ATOMIC_VAR_INIT(0); - return writeTreesToStream(progress, str, serialized_descriptors, descriptors_count, trees, std::move(block_getter), - begin_time, end_time, pid, log); + return writeTreesToStream(progress, str, serialized_descriptors, descriptors, descriptors_count, trees, + std::move(block_getter), begin_time, end_time, pid, log); } inline bool readDescriptionsFromStream(std::istream& str, diff --git a/easy_profiler_core/reader.cpp b/easy_profiler_core/reader.cpp index 180b276..fb45a90 100644 --- a/easy_profiler_core/reader.cpp +++ b/easy_profiler_core/reader.cpp @@ -129,11 +129,26 @@ inline bool isCompatibleVersion(uint32_t _version) namespace profiler { + SerializedData::SerializedData() : m_size(0), m_data(nullptr) + { + } + + SerializedData::SerializedData(SerializedData&& that) : m_size(that.m_size), m_data(that.m_data) + { + that.m_size = 0; + that.m_data = nullptr; + } + + SerializedData::~SerializedData() + { + clear(); + } + void SerializedData::set(char* _data, uint64_t _size) { delete [] m_data; - m_data = _data; m_size = _size; + m_data = _data; } void SerializedData::set(uint64_t _size) @@ -146,8 +161,8 @@ namespace profiler { void SerializedData::extend(uint64_t _size) { - auto olddata = m_data; auto oldsize = m_size; + auto olddata = m_data; m_size = oldsize + _size; m_data = new char[m_size]; @@ -158,6 +173,61 @@ namespace profiler { } } + SerializedData& SerializedData::operator = (SerializedData&& that) + { + set(that.m_data, that.m_size); + that.m_size = 0; + that.m_data = nullptr; + return *this; + } + + char* SerializedData::operator [] (uint64_t i) + { + return m_data + i; + } + + const char* SerializedData::operator [] (uint64_t i) const + { + return m_data + i; + } + + bool SerializedData::empty() const + { + return m_size == 0; + } + + uint64_t SerializedData::size() const + { + return m_size; + } + + char* SerializedData::data() + { + return m_data; + } + + const char* SerializedData::data() const + { + return m_data; + } + + void SerializedData::clear() + { + set(nullptr, 0); + } + + void SerializedData::swap(SerializedData& other) + { + char* d = other.m_data; + const auto sz = other.m_size; + + other.m_data = m_data; + other.m_size = m_size; + + m_data = d; + m_size = sz; + } + extern "C" PROFILER_API void release_stats(BlockStatistics*& _stats) { if (_stats == nullptr) @@ -653,6 +723,12 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic< return 0; } + if (i + sz > memory_size) + { + _log << "File corrupted.\nActual context switches data size > size pointed in file."; + return 0; + } + char* data = serialized_blocks[i]; inFile.read(data, sz); i += sz; @@ -714,6 +790,12 @@ extern "C" PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic< return 0; } + if (i + sz > memory_size) + { + _log << "File corrupted.\nActual blocks data size > size pointed in file."; + return 0; + } + char* data = serialized_blocks[i]; inFile.read(data, sz); i += sz; @@ -1146,7 +1228,9 @@ BlocksRange findRange(const profiler::BlocksTree::children_t& children, profiler BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children, const BlocksRange& range, - const profiler::block_getter_fn& getter, bool contextSwitches) + const profiler::block_getter_fn& getter, + const profiler::descriptors_list_t& descriptors, + bool contextSwitches) { BlocksMemoryAndCount memoryAndCount; @@ -1157,12 +1241,18 @@ BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTre const auto& child = getter(children[i]); // Calculate self memory consumption - const uint64_t usedMemorySize = sizeof(profiler::SerializedBlock) + strlen(child.node->name()) + 1; + const auto& desc = *descriptors[child.node->id()]; + uint64_t usedMemorySize = 0; + + if (desc.type() == profiler::BlockType::Value) + usedMemorySize = sizeof(profiler::ArbitraryValue) + child.value->data_size(); + else + usedMemorySize = sizeof(profiler::SerializedBlock) + strlen(child.node->name()) + 1; // Calculate children memory consumption const BlocksRange childRange(0, static_cast(child.children.size())); const auto childrenMemoryAndCount = calculateUsedMemoryAndBlocksCount(child.children, childRange, - getter, + getter, descriptors, false); // Accumulate memory and count @@ -1185,37 +1275,53 @@ BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTre return memoryAndCount; } -void serialize(profiler::SerializedData& output, uint64_t& position, const profiler::BlocksTree::children_t& children, - const BlocksRange& range, const profiler::block_getter_fn& getter, bool contextSwitches) +void serializeBlocks(std::ostream& output, std::vector& buffer, const profiler::BlocksTree::children_t& children, + const BlocksRange& range, const profiler::block_getter_fn& getter, + const profiler::descriptors_list_t& descriptors) { - if (!contextSwitches) + for (auto i = range.begin; i < range.end; ++i) { - // Serialize blocks + const auto& child = getter(children[i]); - for (auto i = range.begin; i < range.end; ++i) + // Serialize children + const BlocksRange childRange(0, static_cast(child.children.size())); + serializeBlocks(output, buffer, child.children, childRange, getter, descriptors); + + // Serialize self + const auto& desc = *descriptors[child.node->id()]; + uint16_t usedMemorySize = 0; + + if (desc.type() == profiler::BlockType::Value) { - const auto& child = getter(children[i]); + usedMemorySize = static_cast(sizeof(profiler::ArbitraryValue)) + child.value->data_size(); + buffer.resize(usedMemorySize + sizeof(uint16_t)); + unaligned_store16(buffer.data(), usedMemorySize); + memcpy(buffer.data() + sizeof(uint16_t), child.value, static_cast(usedMemorySize)); + } + else + { + usedMemorySize = static_cast(sizeof(profiler::SerializedBlock) + + strlen(child.node->name()) + 1); - // Serialize children - const BlocksRange childRange(0, static_cast(child.children.size())); - serialize(output, position, child.children, childRange, getter, false); + buffer.resize(usedMemorySize + sizeof(uint16_t)); + unaligned_store16(buffer.data(), usedMemorySize); + memcpy(buffer.data() + sizeof(uint16_t), child.node, static_cast(usedMemorySize)); - // Serialize self - const auto usedMemorySize = static_cast( - sizeof(profiler::SerializedBlock) + strlen(child.node->name()) + 1); - - unaligned_store16(output.data() + position, usedMemorySize); - memcpy(output.data() + position + sizeof(uint16_t), child.node, static_cast(usedMemorySize)); - - // TODO: write valid block id (it can be dynamic) - - position += usedMemorySize + sizeof(uint16_t); + if (child.node->id() != desc.id()) + { + // This block id is dynamic. Restore it's value like it was before in the input .prof file + auto block = reinterpret_cast(buffer.data() + sizeof(uint16_t)); + block->setId(desc.id()); + } } - return; + write(output, buffer.data(), buffer.size()); } +} - // Serialize context switches +void serializeContextSwitches(std::ostream& output, std::vector& buffer, const profiler::BlocksTree::children_t& children, + const BlocksRange& range, const profiler::block_getter_fn& getter) +{ for (auto i = range.begin; i < range.end; ++i) { const auto& child = getter(children[i]); @@ -1223,15 +1329,39 @@ void serialize(profiler::SerializedData& output, uint64_t& position, const profi const auto usedMemorySize = static_cast( sizeof(profiler::SerializedCSwitch) + strlen(child.cs->name()) + 1); - unaligned_store16(output.data() + position, usedMemorySize); - memcpy(output.data() + position + sizeof(uint16_t), child.cs, static_cast(usedMemorySize)); + buffer.resize(usedMemorySize + sizeof(uint16_t)); + unaligned_store16(buffer.data(), usedMemorySize); + memcpy(buffer.data() + sizeof(uint16_t), child.cs, static_cast(usedMemorySize)); - position += usedMemorySize + sizeof(uint16_t); + write(output, buffer.data(), buffer.size()); + } +} + +void serializeDescriptors(std::ostream& output, std::vector& buffer, + const profiler::descriptors_list_t& descriptors, + profiler::block_id_t descriptors_count) +{ + const size_t size = std::min(descriptors.size(), static_cast(descriptors_count)); + for (size_t i = 0; i < size; ++i) + { + const auto& desc = *descriptors[i]; + if (desc.id() != i) + break; + + const auto usedMemorySize = static_cast(sizeof(profiler::SerializedBlockDescriptor) + + strlen(desc.name()) + strlen(desc.file()) + 2); + + buffer.resize(usedMemorySize + sizeof(uint16_t)); + unaligned_store16(buffer.data(), usedMemorySize); + memcpy(buffer.data() + sizeof(uint16_t), &desc, static_cast(usedMemorySize)); + + write(output, buffer.data(), buffer.size()); } } extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic& progress, const char* filename, const profiler::SerializedData& serialized_descriptors, + const profiler::descriptors_list_t& descriptors, profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& trees, profiler::block_getter_fn block_getter, @@ -1251,8 +1381,8 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic& progress, std::ostream& str, const profiler::SerializedData& serialized_descriptors, + const profiler::descriptors_list_t& descriptors, profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& trees, profiler::block_getter_fn block_getter, @@ -1281,6 +1412,7 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomicbegin()); + endTime = std::max(endTime, block_getter(tree.children[range.blocks.end - 1]).node->end()); + } + + range.cswitchesMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.sync, range.cswitches, block_getter, + descriptors, true); total += range.cswitchesMemoryAndCount; + if (range.cswitchesMemoryAndCount.blocksCount != 0) + { + beginTime = std::min(beginTime, block_getter(tree.children[range.cswitches.begin]).cs->begin()); + endTime = std::max(endTime, block_getter(tree.children[range.cswitches.end - 1]).cs->end()); + } + block_ranges[id] = range; if (!update_progress_write(progress, 15 / static_cast(trees.size() - i), log)) @@ -1322,22 +1468,20 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic(str, 0LL); // CPU frequency - write(str, begin_time); - write(str, end_time); + write(str, beginTime); + write(str, endTime); write(str, total.usedMemorySize); write(str, usedMemorySizeDescriptors); write(str, total.blocksCount); write(str, descriptors_count); + std::vector buffer; + // Serialize all descriptors - // TODO + serializeDescriptors(str, buffer, descriptors, descriptors_count); // Serialize all blocks - profiler::SerializedData serializedBlocks; - serializedBlocks.set(total.usedMemorySize + sizeof(uint16_t) * total.blocksCount); - uint64_t position = 0; - i = 0; for (const auto& kv : trees) { @@ -1349,25 +1493,16 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic(trees.size() - i), log)) return 0; diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index 7cd7463..d491bab 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -407,6 +407,8 @@ void BlocksGraphicsView::clear() EASY_GLOBALS.selected_thread = 0; emit EASY_GLOBALS.events.selectedThreadChanged(0); + + emit EASY_GLOBALS.events.rulerVisible(false); } void BlocksGraphicsView::notifySceneSizeChange() @@ -438,7 +440,10 @@ void BlocksGraphicsView::notifyVisibleRegionPosChange() void BlocksGraphicsView::notifyVisibleRegionPosChange(qreal _pos) { - m_offset = estd::clamp(0., _pos, m_sceneWidth - m_visibleRegionWidth); + if (m_sceneWidth < m_visibleRegionWidth) + m_offset = 0; + else + m_offset = estd::clamp(0., _pos, m_sceneWidth - m_visibleRegionWidth); notifyVisibleRegionPosChange(); } @@ -616,25 +621,15 @@ const BlocksGraphicsView::Items &BlocksGraphicsView::getItems() const bool BlocksGraphicsView::getSelectionRegionForSaving(profiler::timestamp_t& _beginTime, profiler::timestamp_t& _endTime) const { - if (m_selectedBlocks.empty()) + if (m_bEmpty) return false; - _beginTime = ~0ULL; - _endTime = 0; + if (!m_selectionItem->isVisible() && !m_rulerItem->isVisible()) + return false; - for (const auto& selection : m_selectedBlocks) - { - const auto& tree = easyBlocksTree(selection.tree); - _beginTime = std::min(_beginTime, tree.node->begin()); - _endTime = std::max(_endTime, tree.node->end()); - } - - if (_beginTime > 10) - _beginTime -= 10; - else - _beginTime = 0; - - _endTime += 10; + decltype(m_selectionItem) ruler = m_selectionItem->isVisible() ? m_selectionItem : m_rulerItem; + _beginTime = m_beginTime + position2time(ruler->left()); + _endTime = m_beginTime + position2time(ruler->right()); return true; } @@ -923,7 +918,10 @@ void BlocksGraphicsView::onWheel(qreal _scenePos, int _wheelDelta) notifyVisibleRegionSizeChange(); // Calculate new offset to simulate QGraphicsView::AnchorUnderMouse scaling behavior - m_offset = clamp(0., initialPosition - _scenePos / m_scale, m_sceneWidth - m_visibleRegionWidth); + if (m_sceneWidth < m_visibleRegionWidth) + m_offset = 0; + else + m_offset = clamp(0., initialPosition - _scenePos / m_scale, m_sceneWidth - m_visibleRegionWidth); // Update slider position profiler_gui::BoolFlagGuard guard(m_bUpdatingRect, true); // To be sure that updateVisibleSceneRect will not be called by scrollbar change @@ -980,6 +978,7 @@ void BlocksGraphicsView::mousePressEvent(QMouseEvent* _event) m_selectionItem->setLeftRight(mouseX, mouseX); m_selectionItem->hide(); m_pScrollbar->hideSelectionIndicator(); + emit EASY_GLOBALS.events.rulerVisible(m_rulerItem->isVisible()); } } @@ -1009,6 +1008,7 @@ void BlocksGraphicsView::mouseDoubleClickEvent(QMouseEvent* _event) m_rulerItem->setLeftRight(mouseX, mouseX); m_rulerItem->hide(); emit sceneUpdated(); + emit EASY_GLOBALS.events.rulerVisible(m_selectionItem->isVisible()); } _event->accept(); @@ -1035,6 +1035,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event) { m_selectionItem->hide(); m_pScrollbar->hideSelectionIndicator(); + emit EASY_GLOBALS.events.rulerVisible(m_rulerItem->isVisible()); } if (!m_selectedBlocks.empty()) @@ -1071,6 +1072,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event) { chronoHidden = true; m_rulerItem->hide(); + emit EASY_GLOBALS.events.rulerVisible(m_selectionItem->isVisible()); } else if (m_selectionItem->isVisible() && m_selectionItem->hoverIndicator()) { @@ -1216,6 +1218,9 @@ void BlocksGraphicsView::addSelectionToHierarchy() void BlocksGraphicsView::onZoomSelection() { + if (m_selectionItem->width() < 1e-6) + return; + auto deltaScale = m_visibleRegionWidth / m_selectionItem->width(); if (fabs(deltaScale - 1) < 1e-6) @@ -1254,6 +1259,9 @@ void BlocksGraphicsView::onInspectCurrentView(bool _strict) m_selectionItem->show(); m_pScrollbar->setSelectionPos(m_selectionItem->left(), m_selectionItem->right()); m_pScrollbar->showSelectionIndicator(); + + emit EASY_GLOBALS.events.rulerVisible(true); + addSelectionToHierarchy(); } else @@ -1306,6 +1314,7 @@ bool BlocksGraphicsView::moveChrono(GraphicsRulerItem* _chronometerItem, qreal _ if (!_chronometerItem->isVisible() && _chronometerItem->width() > 1e-6) { _chronometerItem->show(); + emit EASY_GLOBALS.events.rulerVisible(true); return true; } diff --git a/profiler_gui/globals_qobjects.h b/profiler_gui/globals_qobjects.h index 89dfb70..fbaa97b 100644 --- a/profiler_gui/globals_qobjects.h +++ b/profiler_gui/globals_qobjects.h @@ -93,6 +93,7 @@ namespace profiler_gui { void hexThreadIdChanged(); void refreshRequired(); void blocksTreeModeChanged(); + void rulerVisible(bool); void sceneCleared(); void sceneSizeChanged(qreal left, qreal right); diff --git a/profiler_gui/main_window.cpp b/profiler_gui/main_window.cpp index 2f4dc4f..231936c 100644 --- a/profiler_gui/main_window.cpp +++ b/profiler_gui/main_window.cpp @@ -379,8 +379,10 @@ MainWindow::MainWindow() : Parent(), m_theme("default"), m_lastAddress("localhos }); action = toolbar->addAction(QIcon(imagePath("crop")), "Snapshot"); - action->setToolTip("Save selected area\nas separate .prof file."); + action->setToolTip("Take a snapshot.\nSave selected area to\nseparate .prof file."); + action->setEnabled(false); connect(action, &QAction::triggered, this, &This::onSnapshotClicked); + connect(&EASY_GLOBALS.events, &profiler_gui::GlobalSignals::rulerVisible, action, &QAction::setEnabled); toolbar->addSeparator(); auto menu = new QMenu("Settings", this); @@ -1944,7 +1946,8 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks) } else { - QMessageBox::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1").arg(m_reader.getError()), QMessageBox::Close); + QMessageBox::warning(this, "Warning", QString("Cannot read profiled blocks.\n\nReason:\n%1") + .arg(m_reader.getError()), QMessageBox::Close); if (m_reader.isFile()) { @@ -1964,7 +1967,12 @@ void MainWindow::onLoadingFinish(profiler::block_index_t& _nblocks) void MainWindow::onSavingFinish() { - + const auto errorMessage = m_reader.getError(); + if (!errorMessage.isEmpty()) + { + QMessageBox::warning(this, "Warning", QString("Cannot save profiled blocks.\n\nReason:\n%1") + .arg(errorMessage), QMessageBox::Close); + } } void MainWindow::onFileReaderTimeout() @@ -2114,7 +2122,8 @@ void FileReader::load(std::stringstream& _stream) } void FileReader::save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime, - const profiler::SerializedData& _serializedDescriptors, profiler::block_id_t descriptors_count, + const profiler::SerializedData& _serializedDescriptors, + const profiler::descriptors_list_t& _descriptors, profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& _trees, profiler::block_getter_fn block_getter, profiler::processid_t _pid) { @@ -2125,13 +2134,37 @@ void FileReader::save(const QString& _filename, profiler::timestamp_t _beginTime m_filename = _filename; auto serializedDescriptors = std::ref(_serializedDescriptors); + auto descriptors = std::ref(_descriptors); auto trees = std::ref(_trees); - m_thread = std::thread([=] (profiler::block_getter_fn getter) { - writeTreesToFile(m_progress, m_filename.toStdString().c_str(), serializedDescriptors, descriptors_count, trees, - getter, _beginTime, _endTime, _pid, m_errorMessage); + m_thread = std::thread([=] (profiler::block_getter_fn getter) + { + const QString tmpFile = m_filename + ".tmp"; + + const auto result = writeTreesToFile(m_progress, tmpFile.toStdString().c_str(), serializedDescriptors, + descriptors, descriptors_count, trees, getter, _beginTime, _endTime, + _pid, m_errorMessage); + + if (result == 0 || !m_errorMessage.str().empty()) + { + // Remove temporary file in case of error + QFile::remove(tmpFile); + } + else + { + // Remove old file if exists + { + QFile out(m_filename); + if (out.exists()) + out.remove(); + } + + QFile::rename(tmpFile, m_filename); + } + m_progress.store(100, std::memory_order_release); m_bDone.store(true, std::memory_order_release); + }, std::move(block_getter)); } @@ -2254,8 +2287,9 @@ void MainWindow::onSnapshotClicked(bool) createProgressDialog(tr("Saving selected region...")); m_readerTimer.start(); - m_reader.save(filename, beginTime, endTime, m_serializedDescriptors, m_descriptorsNumberInFile, - EASY_GLOBALS.profiler_blocks, easyBlocksTree, EASY_GLOBALS.pid); + + m_reader.save(filename, beginTime, endTime, m_serializedDescriptors, EASY_GLOBALS.descriptors, + m_descriptorsNumberInFile, EASY_GLOBALS.profiler_blocks, easyBlocksTree, EASY_GLOBALS.pid); } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/main_window.h b/profiler_gui/main_window.h index 7d12d47..7330eca 100644 --- a/profiler_gui/main_window.h +++ b/profiler_gui/main_window.h @@ -130,8 +130,9 @@ public: /** \brief Save data to file. */ void save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime, - const profiler::SerializedData& _serializedDescriptors, profiler::block_id_t descriptors_count, - const profiler::thread_blocks_tree_t& _trees, profiler::block_getter_fn block_getter, profiler::processid_t _pid); + const profiler::SerializedData& _serializedDescriptors, const profiler::descriptors_list_t& _descriptors, + profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& _trees, + profiler::block_getter_fn block_getter, profiler::processid_t _pid); void interrupt(); void get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,