0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-26 08:01:51 +08:00

#91 [Core][UI] functions profiler::writeTreesToFile(), profiler::writeTreesToStream() are now working. Snapshot feature is now working: select an area on Diagram (with right mouse button or double-click) and press Snapshot button to save it to separate file.

This commit is contained in:
Victor Zarubkin 2018-04-25 21:37:18 +03:00
parent 21bcefcb75
commit f665478830
6 changed files with 283 additions and 144 deletions

View File

@ -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<int>& 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<int>& 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<int> 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<int> 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,

View File

@ -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<profiler::block_index_t>(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<char>& 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<profiler::block_index_t>(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<uint16_t>(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<size_t>(usedMemorySize));
}
else
{
usedMemorySize = static_cast<uint16_t>(sizeof(profiler::SerializedBlock)
+ strlen(child.node->name()) + 1);
// Serialize children
const BlocksRange childRange(0, static_cast<profiler::block_index_t>(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<size_t>(usedMemorySize));
// Serialize self
const auto usedMemorySize = static_cast<uint16_t>(
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<size_t>(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<profiler::SerializedBlock*>(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<char>& 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<uint16_t>(
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<size_t>(usedMemorySize));
buffer.resize(usedMemorySize + sizeof(uint16_t));
unaligned_store16(buffer.data(), usedMemorySize);
memcpy(buffer.data() + sizeof(uint16_t), child.cs, static_cast<size_t>(usedMemorySize));
position += usedMemorySize + sizeof(uint16_t);
write(output, buffer.data(), buffer.size());
}
}
void serializeDescriptors(std::ostream& output, std::vector<char>& buffer,
const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count)
{
const size_t size = std::min(descriptors.size(), static_cast<size_t>(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<uint16_t>(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<size_t>(usedMemorySize));
write(output, buffer.data(), buffer.size());
}
}
extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& 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<int
}
// Write data to file
auto result = writeTreesToStream(progress, outFile, serialized_descriptors, descriptors_count, trees, std::move(block_getter),
begin_time, end_time, pid, log);
auto result = writeTreesToStream(progress, outFile, serialized_descriptors, descriptors, descriptors_count, trees,
std::move(block_getter), begin_time, end_time, pid, log);
return result;
}
@ -1261,6 +1391,7 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int
extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<int>& 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::atomic<i
ranges_t block_ranges;
// Calculate block ranges and used memory (for serialization)
profiler::timestamp_t beginTime = begin_time, endTime = end_time;
size_t i = 0;
for (const auto& kv : trees)
{
@ -1292,12 +1424,26 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
range.blocks = findRange(tree.children, begin_time, end_time, block_getter);
range.cswitches = findRange(tree.sync, begin_time, end_time, block_getter);
range.blocksMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.children, range.blocks, block_getter, false);
range.blocksMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.children, range.blocks, block_getter,
descriptors, false);
total += range.blocksMemoryAndCount;
range.cswitchesMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.sync, range.cswitches, block_getter, true);
if (range.blocksMemoryAndCount.blocksCount != 0)
{
beginTime = std::min(beginTime, block_getter(tree.children[range.blocks.begin]).node->begin());
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<int>(trees.size() - i), log))
@ -1322,22 +1468,20 @@ extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<i
// write 0 because we do not need to convert time from ticks to nanoseconds (it's already converted)
write<int64_t>(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<char> 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<i
write(str, id);
write(str, nameSize);
write(str, tree.name(), nameSize);
write(str, range.cswitchesMemoryAndCount.blocksCount);
// Serialize context switches
write(str, range.cswitchesMemoryAndCount.blocksCount);
if (range.cswitchesMemoryAndCount.blocksCount != 0)
{
const auto previousPosition = position;
serialize(serializedBlocks, position, tree.sync, range.cswitches, block_getter, true);
write(str, serializedBlocks.data() + previousPosition, position - previousPosition);
}
serializeContextSwitches(str, buffer, tree.sync, range.cswitches, block_getter);
// Serialize blocks
write(str, range.blocksMemoryAndCount.blocksCount);
if (range.blocksMemoryAndCount.blocksCount != 0)
{
const auto previousPosition = position;
serialize(serializedBlocks, position, tree.children, range.blocks, block_getter, false);
write(str, serializedBlocks.data() + previousPosition, position - previousPosition);
}
serializeBlocks(str, buffer, tree.children, range.blocks, block_getter, descriptors);
if (!update_progress_write(progress, 40 + 60 / static_cast<int>(trees.size() - i), log))
return 0;

View File

@ -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;
}

View File

@ -93,6 +93,7 @@ namespace profiler_gui {
void hexThreadIdChanged();
void refreshRequired();
void blocksTreeModeChanged();
void rulerVisible(bool);
void sceneCleared();
void sceneSizeChanged(qreal left, qreal right);

View File

@ -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);
}
//////////////////////////////////////////////////////////////////////////

View File

@ -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,