mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 00:21:11 +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:
parent
21bcefcb75
commit
f665478830
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,7 @@ namespace profiler_gui {
|
||||
void hexThreadIdChanged();
|
||||
void refreshRequired();
|
||||
void blocksTreeModeChanged();
|
||||
void rulerVisible(bool);
|
||||
|
||||
void sceneCleared();
|
||||
void sceneSizeChanged(qreal left, qreal right);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user