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

Writing signature and version into file to let reader check if file is valid;

* Added output messages
This commit is contained in:
Victor Zarubkin 2016-09-27 22:28:04 +03:00
parent 6e50f6517d
commit 4a05cafab4
7 changed files with 161 additions and 23 deletions

View File

@ -26,6 +26,13 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
namespace profiler {
const uint8_t EASY_VERSION_MAJOR = 0;
const uint8_t EASY_VERSION_MINOR = 1;
const uint16_t EASY_VERSION_REV = 0;
const uint32_t EASY_FULL_VERSION = ((uint32_t)EASY_VERSION_MAJOR << 24) | ((uint32_t)EASY_VERSION_MINOR << 16) | (uint32_t)EASY_VERSION_REV;
}
#ifndef FULL_DISABLE_PROFILER
/**

View File

@ -331,7 +331,8 @@ extern "C" {
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
bool gather_statistics);
bool gather_statistics,
::std::stringstream& _log);
PROFILER_API ::profiler::block_index_t fillTreesFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
::profiler::SerializedData& serialized_blocks,
@ -339,26 +340,32 @@ extern "C" {
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& _blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
bool gather_statistics);
bool gather_statistics,
::std::stringstream& _log);
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& str,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors);
::profiler::descriptors_list_t& descriptors,
::std::stringstream& _log);
}
inline ::profiler::block_index_t fillTreesFromFile(const char* filename, ::profiler::SerializedData& serialized_blocks,
::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& threaded_trees,
bool gather_statistics)
bool gather_statistics,
::std::stringstream& _log)
{
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, gather_statistics);
return fillTreesFromFile(progress, filename, serialized_blocks, serialized_descriptors, descriptors, _blocks, threaded_trees, gather_statistics, _log);
}
inline bool readDescriptionsFromStream(::std::stringstream& str, ::profiler::SerializedData& serialized_descriptors, ::profiler::descriptors_list_t& descriptors)
inline bool readDescriptionsFromStream(::std::stringstream& str,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors,
::std::stringstream& _log)
{
::std::atomic<int> progress = ATOMIC_VAR_INIT(0);
return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors);
return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -710,13 +710,9 @@ void EasyMainWindow::onFileReaderTimeout()
if (m_dialogDescTree != nullptr)
m_dialogDescTree->build();
}
else if (m_reader.isFile())
{
qWarning() << "Warning: Can not open file " << m_reader.filename() << " or file is corrupted";
}
else
{
qWarning() << "Warning: Can not read from stream: bad data";
QMessageBox::warning(this, "Warning", QString("Can not read profiled blocks.\n\nReason:\n%1").arg(m_reader.getError()), QMessageBox::Close);
}
m_reader.interrupt();
@ -788,7 +784,7 @@ void EasyFileReader::load(const QString& _filename)
m_isFile = true;
m_filename = _filename;
m_thread = ::std::move(::std::thread([this](bool _enableStatistics) {
m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, _enableStatistics), ::std::memory_order_release);
m_size.store(fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, _enableStatistics, m_errorMessage), ::std::memory_order_release);
m_progress.store(100, ::std::memory_order_release);
m_bDone.store(true, ::std::memory_order_release);
}, EASY_GLOBALS.enable_statistics));
@ -802,7 +798,7 @@ void EasyFileReader::load(::std::stringstream& _stream)
m_filename.clear();
m_stream.swap(_stream);
m_thread = ::std::move(::std::thread([this](bool _enableStatistics) {
m_size.store(fillTreesFromStream(m_progress, m_stream, m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, _enableStatistics), ::std::memory_order_release);
m_size.store(fillTreesFromStream(m_progress, m_stream, m_serializedBlocks, m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree, _enableStatistics, m_errorMessage), ::std::memory_order_release);
m_progress.store(100, ::std::memory_order_release);
m_bDone.store(true, ::std::memory_order_release);
}, EASY_GLOBALS.enable_statistics));
@ -823,8 +819,8 @@ void EasyFileReader::interrupt()
m_blocks.clear();
m_blocksTree.clear();
decltype(m_stream) dummy;
dummy.swap(m_stream);
{ decltype(m_stream) dummy; dummy.swap(m_stream); }
{ decltype(m_errorMessage) dummy; dummy.swap(m_errorMessage); }
}
void EasyFileReader::get(::profiler::SerializedData& _serializedBlocks, ::profiler::SerializedData& _serializedDescriptors,
@ -842,6 +838,11 @@ void EasyFileReader::get(::profiler::SerializedData& _serializedBlocks, ::profil
}
}
QString EasyFileReader::getError()
{
return QString(m_errorMessage.str().c_str());
}
//////////////////////////////////////////////////////////////////////////
void EasyMainWindow::onConnectClicked(bool)
@ -922,7 +923,8 @@ void EasyMainWindow::onGetBlockDescriptionsClicked(bool)
// Read descriptions from stream
decltype(EASY_GLOBALS.descriptors) descriptors;
decltype(m_serializedDescriptors) serializedDescriptors;
if (readDescriptionsFromStream(m_listener.data(), serializedDescriptors, descriptors))
::std::stringstream errorMessage;
if (readDescriptionsFromStream(m_listener.data(), serializedDescriptors, descriptors, errorMessage))
{
if (EASY_GLOBALS.descriptors.size() > descriptors.size())
onDeleteClicked(true); // Clear all contents because new descriptors list conflicts with old one
@ -943,6 +945,10 @@ void EasyMainWindow::onGetBlockDescriptionsClicked(bool)
onEditBlocksClicked(true);
}
}
else
{
QMessageBox::warning(this, "Warning", QString("Can not read blocks description from stream.\n\nReason:\n%1").arg(errorMessage.str().c_str()), QMessageBox::Close);
}
m_listener.clearData();
}

View File

@ -65,6 +65,7 @@ class EasyFileReader Q_DECL_FINAL
::profiler::blocks_t m_blocks; ///<
::profiler::thread_blocks_tree_t m_blocksTree; ///<
::std::stringstream m_stream; ///<
::std::stringstream m_errorMessage; ///<
QString m_filename; ///<
::std::thread m_thread; ///<
::std::atomic_bool m_bDone; ///<
@ -90,6 +91,8 @@ public:
::profiler::descriptors_list_t& _descriptors, ::profiler::blocks_t& _blocks, ::profiler::thread_blocks_tree_t& _tree,
QString& _filename);
QString getError();
}; // END of class EasyFileReader.
//////////////////////////////////////////////////////////////////////////

View File

@ -12,7 +12,7 @@
#include <chrono>
#include <iostream>
#include <string>
#include <sstream>
class TreePrinter
{
@ -113,7 +113,10 @@ int main(int argc, char* argv[])
::profiler::SerializedData serialized_blocks, serialized_descriptors;
::profiler::descriptors_list_t descriptors;
::profiler::blocks_t blocks;
auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, true);
::std::stringstream errorMessage;
auto blocks_counter = fillTreesFromFile(filename.c_str(), serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, true, errorMessage);
if (blocks_counter == 0)
std::cout << "Can not read blocks from file " << filename.c_str() << "\nReason: " << errorMessage.str();
auto end = std::chrono::system_clock::now();

View File

@ -38,6 +38,7 @@
using namespace profiler;
const uint32_t PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8) | 'y';
const uint8_t FORCE_ON_FLAG = profiler::FORCE_ON & ~profiler::ON;
//auto& MANAGER = ProfileManager::instance();
@ -553,6 +554,10 @@ uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream)
++it;
}
// Write profiler signature and version
_outputStream.write(PROFILER_SIGNATURE);
_outputStream.write(profiler::EASY_FULL_VERSION);
// Write CPU frequency to let GUI calculate real time value from CPU clocks
#ifdef _WIN32
_outputStream.write(CPU_FREQUENCY);
@ -829,6 +834,10 @@ void ProfileManager::listen()
profiler::OStream os;
// Write profiler signature and version
os.write(PROFILER_SIGNATURE);
os.write(profiler::EASY_FULL_VERSION);
// Write block descriptors
m_storedSpin.lock();
os.write(static_cast<uint32_t>(m_descriptors.size()));

View File

@ -53,6 +53,22 @@
//////////////////////////////////////////////////////////////////////////
#define EASY_FULL_VER(Major, Minor, Rev) (((uint32_t)(Major) << 24) | ((uint32_t)(Minor) << 16) | (uint32_t)(Rev))
const uint32_t COMPATIBLE_VERSIONS[] = {
::profiler::EASY_FULL_VERSION
};
const uint16_t COMPATIBLE_VERSIONS_NUM = sizeof(COMPATIBLE_VERSIONS) / sizeof(uint32_t);
bool isCompatibleVersion(uint32_t _version)
{
if (_version == ::profiler::EASY_FULL_VERSION)
return true;
return COMPATIBLE_VERSIONS_NUM > 1 && ::std::binary_search(COMPATIBLE_VERSIONS + 1, COMPATIBLE_VERSIONS + COMPATIBLE_VERSIONS_NUM, _version);
}
#undef EASY_FULL_VER
namespace profiler {
void SerializedData::set(char* _data, size_t _size)
@ -219,6 +235,7 @@ void validate_pointers(::std::atomic<int>& _progress, const char* _oldbase, ::pr
//////////////////////////////////////////////////////////////////////////
const int64_t TIME_FACTOR = 1000000000LL;
const uint32_t PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8) | 'y';
//////////////////////////////////////////////////////////////////////////
@ -230,13 +247,17 @@ extern "C" {
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
bool gather_statistics)
bool gather_statistics,
::std::stringstream& _log)
{
progress.store(0);
::std::ifstream inFile(filename, ::std::fstream::binary);
if (!inFile.is_open())
{
_log << "Can not open file " << filename;
return 0;
}
::std::stringstream str;
@ -244,7 +265,7 @@ extern "C" {
stringstream_parent& s = str;
auto oldbuf = s.rdbuf(inFile.rdbuf());
auto result = fillTreesFromStream(progress, str, serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, gather_statistics);
auto result = fillTreesFromStream(progress, str, serialized_blocks, serialized_descriptors, descriptors, blocks, threaded_trees, gather_statistics, _log);
s.rdbuf(oldbuf);
return result;
@ -258,12 +279,29 @@ extern "C" {
::profiler::descriptors_list_t& descriptors,
::profiler::blocks_t& blocks,
::profiler::thread_blocks_tree_t& threaded_trees,
bool gather_statistics)
bool gather_statistics,
::std::stringstream& _log)
{
EASY_FUNCTION(::profiler::colors::Cyan);
progress.store(0);
uint32_t signature = 0;
inFile.read((char*)&signature, sizeof(uint32_t));
if (signature != PROFILER_SIGNATURE)
{
_log << "Wrong signature " << signature << "\nThis is not EasyProfiler file/stream.";
return 0;
}
uint32_t version = 0;
inFile.read((char*)&version, sizeof(uint32_t));
if (!isCompatibleVersion(version))
{
_log << "Incompatible version: v" << (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
return 0;
}
int64_t cpu_frequency = 0LL;
inFile.read((char*)&cpu_frequency, sizeof(int64_t));
@ -281,22 +319,34 @@ extern "C" {
uint32_t total_blocks_number = 0;
inFile.read((char*)&total_blocks_number, sizeof(decltype(total_blocks_number)));
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;
}
uint32_t total_descriptors_number = 0;
inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number)));
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;
@ -327,7 +377,10 @@ extern "C" {
i += sz;
auto oldprogress = progress.exchange(static_cast<int>(15 * i / descriptors_memory_size), ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return 0; // Loading interrupted
}
}
typedef ::std::unordered_map<::profiler::thread_id_t, StatsMap, ::profiler::passthrough_hash> PerThreadStats;
@ -373,7 +426,10 @@ extern "C" {
uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz));
if (sz == 0)
{
_log << "Bad CSwitch block size == 0";
return 0;
}
char* data = serialized_blocks[i];
inFile.read(data, sz);
@ -405,7 +461,10 @@ extern "C" {
auto oldprogress = progress.exchange(20 + static_cast<int>(70 * i / memory_size), ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return 0; // Loading interrupted
}
}
if (inFile.eof())
@ -423,15 +482,27 @@ extern "C" {
uint16_t sz = 0;
inFile.read((char*)&sz, sizeof(sz));
if (sz == 0)
{
_log << "Bad block size == 0";
return 0;
}
char* data = serialized_blocks[i];
inFile.read(data, sz);
i += sz;
auto baseData = reinterpret_cast<::profiler::SerializedBlock*>(data);
if (baseData->id() >= total_descriptors_number)
{
_log << "Bad block id == " << baseData->id();
return 0;
}
auto desc = descriptors[baseData->id()];
if (desc == nullptr)
{
_log << "Bad block id == " << baseData->id() << ". Description is null.";
return 0;
}
auto t_begin = reinterpret_cast<::profiler::timestamp_t*>(data);
auto t_end = t_begin + 1;
@ -548,12 +619,18 @@ extern "C" {
auto oldprogress = progress.exchange(20 + static_cast<int>(70 * i / memory_size), ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return 0; // Loading interrupted
}
}
}
if (progress.load(::std::memory_order_acquire) < 0)
{
_log << "Reading was interrupted";
return 0; // Loading interrupted
}
EASY_BLOCK("Gather statistics for roots", ::profiler::colors::Purple);
if (gather_statistics)
@ -639,21 +716,44 @@ extern "C" {
PROFILER_API bool readDescriptionsFromStream(::std::atomic<int>& progress, ::std::stringstream& inFile,
::profiler::SerializedData& serialized_descriptors,
::profiler::descriptors_list_t& descriptors)
::profiler::descriptors_list_t& descriptors,
::std::stringstream& _log)
{
EASY_FUNCTION(::profiler::colors::Cyan);
progress.store(0);
uint32_t signature = 0;
inFile.read((char*)&signature, sizeof(uint32_t));
if (signature != PROFILER_SIGNATURE)
{
_log << "Wrong signature " << signature << "\nThis is not EasyProfiler file/stream.";
return false;
}
uint32_t version = 0;
inFile.read((char*)&version, sizeof(uint32_t));
if (!isCompatibleVersion(version))
{
_log << "Incompatible version: v" << (version >> 24) << "." << ((version & 0x00ff0000) >> 16) << "." << (version & 0x0000ffff);
return false;
}
uint32_t total_descriptors_number = 0;
inFile.read((char*)&total_descriptors_number, sizeof(decltype(total_descriptors_number)));
if (total_descriptors_number == 0)
{
_log << "Blocks description number == 0";
return false;
}
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 false;
}
descriptors.reserve(total_descriptors_number);
//const char* olddata = append_regime ? serialized_descriptors.data() : nullptr;
@ -684,7 +784,10 @@ extern "C" {
i += sz;
auto oldprogress = progress.exchange(static_cast<int>(100 * i / descriptors_memory_size), ::std::memory_order_release);
if (oldprogress < 0)
{
_log << "Reading was interrupted";
return false; // Loading interrupted
}
}
return !descriptors.empty();