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

#48 [Core] Rearranged file header members order to minimize padding;

[Core] Changed version to 2.0.0;
This commit is contained in:
Victor Zarubkin 2018-04-02 01:53:29 +03:00
parent f736af9721
commit 3253fe2633
6 changed files with 273 additions and 111 deletions

View File

@ -5,8 +5,8 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
option(EASY_PROFILER_NO_GUI "Build easy_profiler without the GUI application (required Qt)" OFF)
set(EASY_PROGRAM_VERSION_MAJOR 1)
set(EASY_PROGRAM_VERSION_MINOR 3)
set(EASY_PROGRAM_VERSION_MAJOR 2)
set(EASY_PROGRAM_VERSION_MINOR 0)
set(EASY_PROGRAM_VERSION_PATCH 0)
set(EASY_PRODUCT_VERSION_STRING "${EASY_PROGRAM_VERSION_MAJOR}.${EASY_PROGRAM_VERSION_MINOR}.${EASY_PROGRAM_VERSION_PATCH}")

View File

@ -1,4 +1,4 @@
# easy_profiler [![1.3.0](https://img.shields.io/badge/version-1.3.0-009688.svg)](https://github.com/yse/easy_profiler/releases)
# easy_profiler [![2.0.0](https://img.shields.io/badge/version-2.0.0-009688.svg)](https://github.com/yse/easy_profiler/releases)
[![Build Status](https://travis-ci.org/yse/easy_profiler.svg?branch=develop)](https://travis-ci.org/yse/easy_profiler)
[![Build Status](https://ci.appveyor.com/api/projects/status/github/yse/easy_profiler?branch=develop&svg=true)](https://ci.appveyor.com/project/yse/easy-profiler/branch/develop)

View File

@ -20,6 +20,7 @@ extern const uint32_t PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8
const uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///< minimal compatible version (.prof file format was not changed seriously since this version)
const uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file
const uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t
const uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged
# undef EASY_VERSION_INT
const uint64_t TIME_FACTOR = 1000000000ULL;
@ -78,6 +79,117 @@ using CsStatsMap = ::std::unordered_map<::profiler::hashed_stdstring, ::profiler
using namespace profiler::reader;
//////////////////////////////////////////////////////////////////////////
struct EasyFileHeader
{
uint32_t signature = 0;
uint32_t version = 0;
processid_t pid = 0;
int64_t cpu_frequency = 0;
::profiler::timestamp_t begin_time = 0;
::profiler::timestamp_t end_time = 0;
uint64_t memory_size = 0;
uint64_t descriptors_memory_size = 0;
uint32_t total_blocks_number = 0;
uint32_t total_descriptors_number = 0;
};
bool readHeader_v1(EasyFileHeader& _header, ::std::stringstream& inFile, ::std::stringstream& _log)
{
// File header before v2.0.0
if (_header.version > EASY_V_100)
{
if (_header.version < EASY_V_130)
{
uint32_t old_pid = 0;
inFile.read((char*)&old_pid, sizeof(uint32_t));
_header.pid = old_pid;
}
else
{
inFile.read((char*)&_header.pid, sizeof(processid_t));
}
}
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&_header.end_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t));
if (_header.total_blocks_number == 0)
{
_log << "Profiled blocks number == 0";
return false;
}
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size)));
if (_header.memory_size == 0)
{
_log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks";
return false;
}
inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t));
if (_header.total_descriptors_number == 0)
{
_log << "Blocks description number == 0";
return false;
}
inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size)));
if (_header.descriptors_memory_size == 0)
{
_log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions";
return false;
}
return true;
}
bool readHeader_v2(EasyFileHeader& _header, std::stringstream& inFile, std::stringstream& _log)
{
// File header after v2.0.0
inFile.read((char*)&_header.pid, sizeof(processid_t));
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&_header.end_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size)));
if (_header.memory_size == 0)
{
_log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks";
return false;
}
inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size)));
if (_header.descriptors_memory_size == 0)
{
_log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions";
return false;
}
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t));
if (_header.total_blocks_number == 0)
{
_log << "Profiled blocks number == 0";
return false;
}
inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t));
if (_header.total_descriptors_number == 0)
{
_log << "Blocks description number == 0";
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
::profiler::block_index_t FileReader::readFile(const ::std::string &filename)
{
::std::ifstream file(filename, ::std::fstream::binary);
@ -108,68 +220,38 @@ using namespace profiler::reader;
return 0;
}
processid_t pid = 0;
if (m_version > EASY_V_100)
EasyFileHeader header;
header.signature = signature;
header.version = m_version;
if (m_version < EASY_V_200)
{
if (m_version < EASY_V_130)
{
uint32_t old_pid = 0;
inFile.read((char*)&old_pid, sizeof(uint32_t));
pid = old_pid;
}
else
{
inFile.read((char*)&pid, sizeof(processid_t));
}
if (!readHeader_v1(header, inFile, errorMessage))
return 0;
}
else
{
if (!readHeader_v2(header, inFile, errorMessage))
return 0;
}
int64_t file_cpu_frequency = 0LL;
inFile.read((char*)&file_cpu_frequency, sizeof(int64_t));
const uint64_t cpu_frequency = file_cpu_frequency;
const uint64_t cpu_frequency = header.cpu_frequency;
const double conversion_factor = (cpu_frequency != 0 ? static_cast<double>(TIME_FACTOR) / static_cast<double>(cpu_frequency) : 1.);
::profiler::timestamp_t begin_time = 0ULL;
::profiler::timestamp_t end_time = 0ULL;
inFile.read((char*)&begin_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&end_time, sizeof(::profiler::timestamp_t));
auto begin_time = header.begin_time;
auto end_time = header.end_time;
const auto memory_size = header.memory_size;
const auto descriptors_memory_size = header.descriptors_memory_size;
const auto total_blocks_number = header.total_blocks_number;
uint32_t total_descriptors_number = header.total_descriptors_number;
if (cpu_frequency != 0)
{
EASY_CONVERT_TO_NANO(begin_time, cpu_frequency, conversion_factor);
EASY_CONVERT_TO_NANO(end_time, cpu_frequency, conversion_factor);
}
uint32_t total_blocks_number = 0;
inFile.read((char*)&total_blocks_number, sizeof(uint32_t));
if (total_blocks_number == 0)
{
errorMessage << "Profiled blocks number == 0";
return 0;
}
uint64_t memory_size = 0;
inFile.read((char*)&memory_size, sizeof(decltype(memory_size)));
if (memory_size == 0)
{
errorMessage << "Wrong memory size == 0 for " << total_blocks_number << " blocks";
return 0;
}
uint32_t total_descriptors_number = 0;
inFile.read((char*)&total_descriptors_number, sizeof(uint32_t));
if (total_descriptors_number == 0)
{
errorMessage << "Blocks description number == 0";
return 0;
}
uint64_t descriptors_memory_size = 0;
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size)));
if (descriptors_memory_size == 0)
{
errorMessage << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions";
return 0;
}
m_BlockDescriptors.reserve(total_descriptors_number);
serialized_descriptors.set(descriptors_memory_size);

View File

@ -654,7 +654,7 @@ ProfileManager::ProfileManager() :
#else
m_processId((processid_t)getpid())
#endif
, m_usedMemorySize(0)
, m_descriptorsMemorySize(0)
, m_beginTime(0)
, m_endTime(0)
{
@ -751,7 +751,7 @@ const BaseBlockDescriptor* ProfileManager::addBlockDescriptor(EasyBlockStatus _d
return m_descriptors[it->second];
const auto nameLen = strlen(_name);
m_usedMemorySize += sizeof(profiler::SerializedBlockDescriptor) + nameLen + strlen(_filename) + 2;
m_descriptorsMemorySize += sizeof(profiler::SerializedBlockDescriptor) + nameLen + strlen(_filename) + 2;
#if EASY_BLOCK_DESC_FULL_COPY == 0
BlockDescriptor* desc = nullptr;
@ -1395,10 +1395,10 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream, bo
_outputStream.write(m_endTime);
// Write blocks number and used memory size
_outputStream.write(blocks_number);
_outputStream.write(usedMemorySize);
_outputStream.write(m_descriptorsMemorySize);
_outputStream.write(blocks_number);
_outputStream.write(static_cast<uint32_t>(m_descriptors.size()));
_outputStream.write(m_usedMemorySize);
// Write block descriptors
for (const auto descriptor : m_descriptors)
@ -1818,7 +1818,7 @@ void ProfileManager::listen(uint16_t _port)
// Write block descriptors
m_storedSpin.lock();
os.write(static_cast<uint32_t>(m_descriptors.size()));
os.write(m_usedMemorySize);
os.write(m_descriptorsMemorySize);
for (const auto descriptor : m_descriptors)
{
const auto name_size = descriptor->nameSize();

View File

@ -94,7 +94,7 @@ class ProfileManager
map_of_threads_stacks m_threads;
block_descriptors_t m_descriptors;
descriptors_map_t m_descriptorsMap;
uint64_t m_usedMemorySize;
uint64_t m_descriptorsMemorySize;
profiler::timestamp_t m_beginTime;
profiler::timestamp_t m_endTime;
std::atomic<profiler::timestamp_t> m_frameMax;

View File

@ -90,6 +90,7 @@ extern const uint32_t EASY_CURRENT_VERSION;
const uint32_t MIN_COMPATIBLE_VERSION = EASY_VERSION_INT(0, 1, 0); ///< minimal compatible version (.prof file format was not changed seriously since this version)
const uint32_t EASY_V_100 = EASY_VERSION_INT(1, 0, 0); ///< in v1.0.0 some additional data were added into .prof file
const uint32_t EASY_V_130 = EASY_VERSION_INT(1, 3, 0); ///< in v1.3.0 changed sizeof(thread_id_t) uint32_t -> uint64_t
const uint32_t EASY_V_200 = EASY_VERSION_INT(2, 0, 0); ///< in v2.0.0 file header was slightly rearranged
# undef EASY_VERSION_INT
const uint64_t TIME_FACTOR = 1000000000ULL;
@ -390,6 +391,115 @@ static bool update_progress(::std::atomic<int>& progress, int new_value, ::std::
//////////////////////////////////////////////////////////////////////////
struct EasyFileHeader
{
uint32_t signature = 0;
uint32_t version = 0;
processid_t pid = 0;
int64_t cpu_frequency = 0;
profiler::timestamp_t begin_time = 0;
profiler::timestamp_t end_time = 0;
uint64_t memory_size = 0;
uint64_t descriptors_memory_size = 0;
uint32_t total_blocks_number = 0;
uint32_t total_descriptors_number = 0;
};
bool readHeader_v1(EasyFileHeader& _header, ::std::stringstream& inFile, std::stringstream& _log)
{
// File header before v2.0.0
if (_header.version > EASY_V_100)
{
if (_header.version < EASY_V_130)
{
uint32_t old_pid = 0;
inFile.read((char*)&old_pid, sizeof(uint32_t));
_header.pid = old_pid;
}
else
{
inFile.read((char*)&_header.pid, sizeof(processid_t));
}
}
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&_header.end_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t));
if (_header.total_blocks_number == 0)
{
_log << "Profiled blocks number == 0";
return false;
}
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size)));
if (_header.memory_size == 0)
{
_log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks";
return false;
}
inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t));
if (_header.total_descriptors_number == 0)
{
_log << "Blocks description number == 0";
return false;
}
inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size)));
if (_header.descriptors_memory_size == 0)
{
_log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions";
return false;
}
return true;
}
bool readHeader_v2(EasyFileHeader& _header, ::std::stringstream& inFile, std::stringstream& _log)
{
// File header after v2.0.0
inFile.read((char*)&_header.pid, sizeof(processid_t));
inFile.read((char*)&_header.cpu_frequency, sizeof(int64_t));
inFile.read((char*)&_header.begin_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&_header.end_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&_header.memory_size, sizeof(decltype(_header.memory_size)));
if (_header.memory_size == 0)
{
_log << "Wrong memory size == 0 for " << _header.total_blocks_number << " blocks";
return false;
}
inFile.read((char*)&_header.descriptors_memory_size, sizeof(decltype(_header.descriptors_memory_size)));
if (_header.descriptors_memory_size == 0)
{
_log << "Wrong memory size == 0 for " << _header.total_descriptors_number << " blocks descriptions";
return false;
}
inFile.read((char*)&_header.total_blocks_number, sizeof(uint32_t));
if (_header.total_blocks_number == 0)
{
_log << "Profiled blocks number == 0";
return false;
}
inFile.read((char*)&_header.total_descriptors_number, sizeof(uint32_t));
if (_header.total_descriptors_number == 0)
{
_log << "Blocks description number == 0";
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
extern "C" {
PROFILER_API ::profiler::block_index_t fillTreesFromFile(::std::atomic<int>& progress, const char* filename,
@ -468,68 +578,38 @@ extern "C" {
return 0;
}
processid_t pid = 0;
if (version > EASY_V_100)
EasyFileHeader header;
header.signature = signature;
header.version = version;
if (version < EASY_V_200)
{
if (version < EASY_V_130)
{
uint32_t old_pid = 0;
inFile.read((char*)&old_pid, sizeof(uint32_t));
pid = old_pid;
}
else
{
inFile.read((char*)&pid, sizeof(processid_t));
}
if (!readHeader_v1(header, inFile, _log))
return 0;
}
else
{
if (!readHeader_v2(header, inFile, _log))
return 0;
}
int64_t file_cpu_frequency = 0LL;
inFile.read((char*)&file_cpu_frequency, sizeof(int64_t));
const uint64_t cpu_frequency = file_cpu_frequency;
const uint64_t cpu_frequency = header.cpu_frequency;
const double conversion_factor = (cpu_frequency != 0 ? static_cast<double>(TIME_FACTOR) / static_cast<double>(cpu_frequency) : 1.);
::profiler::timestamp_t begin_time = 0ULL;
::profiler::timestamp_t end_time = 0ULL;
inFile.read((char*)&begin_time, sizeof(::profiler::timestamp_t));
inFile.read((char*)&end_time, sizeof(::profiler::timestamp_t));
auto begin_time = header.begin_time;
auto end_time = header.end_time;
const auto memory_size = header.memory_size;
const auto descriptors_memory_size = header.descriptors_memory_size;
const auto total_blocks_number = header.total_blocks_number;
total_descriptors_number = header.total_descriptors_number;
if (cpu_frequency != 0)
{
EASY_CONVERT_TO_NANO(begin_time, cpu_frequency, conversion_factor);
EASY_CONVERT_TO_NANO(end_time, cpu_frequency, conversion_factor);
}
uint32_t total_blocks_number = 0;
inFile.read((char*)&total_blocks_number, sizeof(uint32_t));
if (total_blocks_number == 0)
{
_log << "Profiled blocks number == 0";
return 0;
}
uint64_t memory_size = 0;
inFile.read((char*)&memory_size, sizeof(decltype(memory_size)));
if (memory_size == 0)
{
_log << "Wrong memory size == 0 for " << total_blocks_number << " blocks";
return 0;
}
total_descriptors_number = 0;
inFile.read((char*)&total_descriptors_number, sizeof(uint32_t));
if (total_descriptors_number == 0)
{
_log << "Blocks description number == 0";
return 0;
}
uint64_t descriptors_memory_size = 0;
inFile.read((char*)&descriptors_memory_size, sizeof(decltype(descriptors_memory_size)));
if (descriptors_memory_size == 0)
{
_log << "Wrong memory size == 0 for " << total_descriptors_number << " blocks descriptions";
return 0;
}
descriptors.reserve(total_descriptors_number);
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
serialized_descriptors.set(descriptors_memory_size);