mirror of
https://github.com/yse/easy_profiler.git
synced 2024-12-27 00:31:02 +08:00
[ui] fixed SocketListener listen methods; moved SocketListener and FileReader into separate source files.
This commit is contained in:
parent
00ee2d0e18
commit
6ae08c3a70
@ -30,6 +30,8 @@ if (Qt5Widgets_FOUND)
|
|||||||
descriptors_tree_widget.cpp
|
descriptors_tree_widget.cpp
|
||||||
dialog.h
|
dialog.h
|
||||||
dialog.cpp
|
dialog.cpp
|
||||||
|
file_reader.h
|
||||||
|
file_reader.cpp
|
||||||
fps_widget.h
|
fps_widget.h
|
||||||
fps_widget.cpp
|
fps_widget.cpp
|
||||||
globals.h
|
globals.h
|
||||||
@ -49,6 +51,8 @@ if (Qt5Widgets_FOUND)
|
|||||||
main_window.cpp
|
main_window.cpp
|
||||||
round_progress_widget.h
|
round_progress_widget.h
|
||||||
round_progress_widget.cpp
|
round_progress_widget.cpp
|
||||||
|
socket_listener.h
|
||||||
|
socket_listener.cpp
|
||||||
text_highlighter.h
|
text_highlighter.h
|
||||||
text_highlighter.cpp
|
text_highlighter.cpp
|
||||||
timer.h
|
timer.h
|
||||||
|
@ -600,4 +600,17 @@ namespace profiler_gui {
|
|||||||
return median;
|
return median;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void clear_stream(std::stringstream& _stream)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__) && __GNUC__ < 5
|
||||||
|
// gcc 4 has a known bug which has been solved in gcc 5:
|
||||||
|
// std::stringstream has no swap() method :(
|
||||||
|
_stream.str(std::string());
|
||||||
|
#else
|
||||||
|
std::stringstream().swap(_stream);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace profiler_gui.
|
} // end of namespace profiler_gui.
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
#ifndef EASY_PROFILER_GUI_COMMON_FUNCTIONS_H
|
#ifndef EASY_PROFILER_GUI_COMMON_FUNCTIONS_H
|
||||||
#define EASY_PROFILER_GUI_COMMON_FUNCTIONS_H
|
#define EASY_PROFILER_GUI_COMMON_FUNCTIONS_H
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -254,6 +255,10 @@ void deleteTreeItem(QTreeWidgetItem* item);
|
|||||||
|
|
||||||
profiler::timestamp_t calculateMedian(const DurationsCountMap& durations);
|
profiler::timestamp_t calculateMedian(const DurationsCountMap& durations);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void clear_stream(std::stringstream& _stream);
|
||||||
|
|
||||||
} // END of namespace profiler_gui.
|
} // END of namespace profiler_gui.
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
241
profiler_gui/file_reader.cpp
Normal file
241
profiler_gui/file_reader.cpp
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
//
|
||||||
|
// Created by vzarubkin on 29.10.19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#include <easy/writer.h>
|
||||||
|
|
||||||
|
#include "common_functions.h"
|
||||||
|
#include "globals.h"
|
||||||
|
#include "file_reader.h"
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FileReader::FileReader()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FileReader::~FileReader()
|
||||||
|
{
|
||||||
|
interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool FileReader::isFile() const
|
||||||
|
{
|
||||||
|
return m_isFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool FileReader::isSaving() const
|
||||||
|
{
|
||||||
|
return m_jobType == JobType::Saving;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool FileReader::isLoading() const
|
||||||
|
{
|
||||||
|
return m_jobType == JobType::Loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool FileReader::isSnapshot() const
|
||||||
|
{
|
||||||
|
return m_isSnapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileReader::done() const
|
||||||
|
{
|
||||||
|
return m_bDone.load(std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileReader::progress() const
|
||||||
|
{
|
||||||
|
return m_progress.load(std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int FileReader::size() const
|
||||||
|
{
|
||||||
|
return m_size.load(std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString& FileReader::filename() const
|
||||||
|
{
|
||||||
|
return m_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReader::load(const QString& _filename)
|
||||||
|
{
|
||||||
|
interrupt();
|
||||||
|
|
||||||
|
m_jobType = JobType::Loading;
|
||||||
|
m_isFile = true;
|
||||||
|
m_isSnapshot = false;
|
||||||
|
m_filename = _filename;
|
||||||
|
|
||||||
|
m_thread = std::thread([this] (bool _enableStatistics)
|
||||||
|
{
|
||||||
|
const auto size = fillTreesFromFile(m_progress, m_filename.toStdString().c_str(), m_beginEndTime, m_serializedBlocks,
|
||||||
|
m_serializedDescriptors, m_descriptors, m_blocks, m_blocksTree,
|
||||||
|
m_bookmarks, m_descriptorsNumberInFile, m_version, m_pid,
|
||||||
|
_enableStatistics, m_errorMessage);
|
||||||
|
|
||||||
|
m_size.store(size, std::memory_order_release);
|
||||||
|
m_progress.store(100, std::memory_order_release);
|
||||||
|
m_bDone.store(true, std::memory_order_release);
|
||||||
|
|
||||||
|
}, EASY_GLOBALS.enable_statistics);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReader::load(std::stringstream& _stream)
|
||||||
|
{
|
||||||
|
interrupt();
|
||||||
|
|
||||||
|
m_jobType = JobType::Loading;
|
||||||
|
m_isFile = false;
|
||||||
|
m_isSnapshot = false;
|
||||||
|
m_filename.clear();
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__llvm__)
|
||||||
|
// gcc 4 has a known bug which has been solved in gcc 5:
|
||||||
|
// std::stringstream has no swap() method :(
|
||||||
|
// have to copy all contents... Use gcc 5 or higher!
|
||||||
|
#pragma message "Warning: in gcc 4 and lower std::stringstream has no swap()! Memory consumption may increase! Better use gcc 5 or higher instead."
|
||||||
|
m_stream.str(_stream.str());
|
||||||
|
#else
|
||||||
|
m_stream.swap(_stream);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_thread = std::thread([this] (bool _enableStatistics)
|
||||||
|
{
|
||||||
|
std::ofstream cache_file(NETWORK_CACHE_FILE, std::fstream::binary);
|
||||||
|
if (cache_file.is_open())
|
||||||
|
{
|
||||||
|
cache_file << m_stream.str();
|
||||||
|
cache_file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto size = fillTreesFromStream(m_progress, m_stream, m_beginEndTime, m_serializedBlocks, m_serializedDescriptors,
|
||||||
|
m_descriptors, m_blocks, m_blocksTree, m_bookmarks, m_descriptorsNumberInFile,
|
||||||
|
m_version, m_pid, _enableStatistics, m_errorMessage);
|
||||||
|
|
||||||
|
m_size.store(size, std::memory_order_release);
|
||||||
|
m_progress.store(100, std::memory_order_release);
|
||||||
|
m_bDone.store(true, std::memory_order_release);
|
||||||
|
|
||||||
|
}, EASY_GLOBALS.enable_statistics);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReader::save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
|
||||||
|
const profiler::SerializedData& _serializedDescriptors,
|
||||||
|
const profiler::descriptors_list_t& _descriptors, profiler::block_id_t descriptors_count,
|
||||||
|
const profiler::thread_blocks_tree_t& _trees, const profiler::bookmarks_t& bookmarks,
|
||||||
|
profiler::block_getter_fn block_getter, profiler::processid_t _pid, bool snapshotMode)
|
||||||
|
{
|
||||||
|
interrupt();
|
||||||
|
|
||||||
|
m_jobType = JobType::Saving;
|
||||||
|
m_isFile = true;
|
||||||
|
m_isSnapshot = snapshotMode;
|
||||||
|
m_filename = _filename;
|
||||||
|
|
||||||
|
auto serializedDescriptors = std::ref(_serializedDescriptors);
|
||||||
|
auto descriptors = std::ref(_descriptors);
|
||||||
|
auto trees = std::ref(_trees);
|
||||||
|
auto bookmarksRef = std::ref(bookmarks);
|
||||||
|
|
||||||
|
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, bookmarksRef, 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReader::interrupt()
|
||||||
|
{
|
||||||
|
join();
|
||||||
|
|
||||||
|
m_bDone.store(false, std::memory_order_release);
|
||||||
|
m_size.store(0, std::memory_order_release);
|
||||||
|
m_serializedBlocks.clear();
|
||||||
|
m_serializedDescriptors.clear();
|
||||||
|
m_descriptors.clear();
|
||||||
|
m_blocks.clear();
|
||||||
|
m_blocksTree.clear();
|
||||||
|
m_bookmarks.clear();
|
||||||
|
m_descriptorsNumberInFile = 0;
|
||||||
|
m_version = 0;
|
||||||
|
m_pid = 0;
|
||||||
|
m_jobType = JobType::Idle;
|
||||||
|
m_isSnapshot = false;
|
||||||
|
|
||||||
|
profiler_gui::clear_stream(m_stream);
|
||||||
|
profiler_gui::clear_stream(m_errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReader::get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
|
||||||
|
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks,
|
||||||
|
profiler::thread_blocks_tree_t& _trees, profiler::bookmarks_t& bookmarks,
|
||||||
|
profiler::BeginEndTime& beginEndTime, uint32_t& _descriptorsNumberInFile, uint32_t& _version,
|
||||||
|
profiler::processid_t& _pid, QString& _filename)
|
||||||
|
{
|
||||||
|
if (done())
|
||||||
|
{
|
||||||
|
m_serializedBlocks.swap(_serializedBlocks);
|
||||||
|
m_serializedDescriptors.swap(_serializedDescriptors);
|
||||||
|
profiler::descriptors_list_t(std::move(m_descriptors)).swap(_descriptors);
|
||||||
|
m_blocks.swap(_blocks);
|
||||||
|
m_blocksTree.swap(_trees);
|
||||||
|
m_bookmarks.swap(bookmarks);
|
||||||
|
m_filename.swap(_filename);
|
||||||
|
beginEndTime = m_beginEndTime;
|
||||||
|
_descriptorsNumberInFile = m_descriptorsNumberInFile;
|
||||||
|
_version = m_version;
|
||||||
|
_pid = m_pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileReader::join()
|
||||||
|
{
|
||||||
|
m_progress.store(-100, std::memory_order_release);
|
||||||
|
if (m_thread.joinable())
|
||||||
|
{
|
||||||
|
m_thread.join();
|
||||||
|
}
|
||||||
|
m_progress.store(0, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileReader::getError() const
|
||||||
|
{
|
||||||
|
return QString(m_errorMessage.str().c_str());
|
||||||
|
}
|
88
profiler_gui/file_reader.h
Normal file
88
profiler_gui/file_reader.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
//
|
||||||
|
// Created by vzarubkin on 29.10.19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef EASY_PROFILER_FILE_READER_H
|
||||||
|
#define EASY_PROFILER_FILE_READER_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <easy/reader.h>
|
||||||
|
|
||||||
|
EASY_CONSTEXPR auto NETWORK_CACHE_FILE = "easy_profiler_stream.cache";
|
||||||
|
|
||||||
|
class FileReader Q_DECL_FINAL
|
||||||
|
{
|
||||||
|
enum class JobType : int8_t
|
||||||
|
{
|
||||||
|
Idle = 0,
|
||||||
|
Loading,
|
||||||
|
Saving,
|
||||||
|
};
|
||||||
|
|
||||||
|
profiler::SerializedData m_serializedBlocks; ///<
|
||||||
|
profiler::SerializedData m_serializedDescriptors; ///<
|
||||||
|
profiler::descriptors_list_t m_descriptors; ///<
|
||||||
|
profiler::blocks_t m_blocks; ///<
|
||||||
|
profiler::thread_blocks_tree_t m_blocksTree; ///<
|
||||||
|
profiler::bookmarks_t m_bookmarks; ///<
|
||||||
|
profiler::BeginEndTime m_beginEndTime; ///<
|
||||||
|
std::stringstream m_stream; ///<
|
||||||
|
std::stringstream m_errorMessage; ///<
|
||||||
|
QString m_filename; ///<
|
||||||
|
profiler::processid_t m_pid = 0; ///<
|
||||||
|
uint32_t m_descriptorsNumberInFile = 0; ///<
|
||||||
|
uint32_t m_version = 0; ///<
|
||||||
|
std::thread m_thread; ///<
|
||||||
|
std::atomic_bool m_bDone; ///<
|
||||||
|
std::atomic<int> m_progress; ///<
|
||||||
|
std::atomic<unsigned int> m_size; ///<
|
||||||
|
JobType m_jobType = JobType::Idle; ///<
|
||||||
|
bool m_isFile = false; ///<
|
||||||
|
bool m_isSnapshot = false; ///<
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
FileReader();
|
||||||
|
~FileReader();
|
||||||
|
|
||||||
|
const bool isFile() const;
|
||||||
|
const bool isSaving() const;
|
||||||
|
const bool isLoading() const;
|
||||||
|
const bool isSnapshot() const;
|
||||||
|
|
||||||
|
bool done() const;
|
||||||
|
int progress() const;
|
||||||
|
unsigned int size() const;
|
||||||
|
const QString& filename() const;
|
||||||
|
|
||||||
|
void load(const QString& _filename);
|
||||||
|
void load(std::stringstream& _stream);
|
||||||
|
|
||||||
|
/** \brief Save data to file.
|
||||||
|
*/
|
||||||
|
void save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
|
||||||
|
const profiler::SerializedData& _serializedDescriptors, const profiler::descriptors_list_t& _descriptors,
|
||||||
|
profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& _trees,
|
||||||
|
const profiler::bookmarks_t& bookmarks, profiler::block_getter_fn block_getter,
|
||||||
|
profiler::processid_t _pid, bool snapshotMode);
|
||||||
|
|
||||||
|
void interrupt();
|
||||||
|
|
||||||
|
void get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
|
||||||
|
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _trees,
|
||||||
|
profiler::bookmarks_t& bookmarks, profiler::BeginEndTime& beginEndTime, uint32_t& _descriptorsNumberInFile,
|
||||||
|
uint32_t& _version, profiler::processid_t& _pid, QString& _filename);
|
||||||
|
|
||||||
|
void join();
|
||||||
|
|
||||||
|
QString getError() const;
|
||||||
|
|
||||||
|
}; // END of class FileReader.
|
||||||
|
|
||||||
|
#endif //EASY_PROFILER_FILE_READER_H
|
File diff suppressed because it is too large
Load Diff
@ -55,6 +55,7 @@
|
|||||||
#define EASY_PROFILER_GUI__MAIN_WINDOW__H
|
#define EASY_PROFILER_GUI__MAIN_WINDOW__H
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -64,9 +65,8 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
#include <easy/easy_socket.h>
|
#include "file_reader.h"
|
||||||
#include <easy/reader.h>
|
#include "socket_listener.h"
|
||||||
#include "round_progress_widget.h"
|
|
||||||
|
|
||||||
#ifdef max
|
#ifdef max
|
||||||
#undef max
|
#undef max
|
||||||
@ -80,148 +80,6 @@
|
|||||||
|
|
||||||
#define EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW 0
|
#define EASY_GUI_USE_DESCRIPTORS_DOCK_WINDOW 0
|
||||||
|
|
||||||
namespace profiler { namespace net { struct EasyProfilerStatus; } }
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class FileReader Q_DECL_FINAL
|
|
||||||
{
|
|
||||||
enum class JobType : int8_t
|
|
||||||
{
|
|
||||||
Idle=0,
|
|
||||||
Loading,
|
|
||||||
Saving,
|
|
||||||
};
|
|
||||||
|
|
||||||
profiler::SerializedData m_serializedBlocks; ///<
|
|
||||||
profiler::SerializedData m_serializedDescriptors; ///<
|
|
||||||
profiler::descriptors_list_t m_descriptors; ///<
|
|
||||||
profiler::blocks_t m_blocks; ///<
|
|
||||||
profiler::thread_blocks_tree_t m_blocksTree; ///<
|
|
||||||
profiler::bookmarks_t m_bookmarks; ///<
|
|
||||||
profiler::BeginEndTime m_beginEndTime; ///<
|
|
||||||
std::stringstream m_stream; ///<
|
|
||||||
std::stringstream m_errorMessage; ///<
|
|
||||||
QString m_filename; ///<
|
|
||||||
profiler::processid_t m_pid = 0; ///<
|
|
||||||
uint32_t m_descriptorsNumberInFile = 0; ///<
|
|
||||||
uint32_t m_version = 0; ///<
|
|
||||||
std::thread m_thread; ///<
|
|
||||||
std::atomic_bool m_bDone; ///<
|
|
||||||
std::atomic<int> m_progress; ///<
|
|
||||||
std::atomic<unsigned int> m_size; ///<
|
|
||||||
JobType m_jobType = JobType::Idle; ///<
|
|
||||||
bool m_isFile = false; ///<
|
|
||||||
bool m_isSnapshot = false; ///<
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
FileReader();
|
|
||||||
~FileReader();
|
|
||||||
|
|
||||||
const bool isFile() const;
|
|
||||||
const bool isSaving() const;
|
|
||||||
const bool isLoading() const;
|
|
||||||
const bool isSnapshot() const;
|
|
||||||
|
|
||||||
bool done() const;
|
|
||||||
int progress() const;
|
|
||||||
unsigned int size() const;
|
|
||||||
const QString& filename() const;
|
|
||||||
|
|
||||||
void load(const QString& _filename);
|
|
||||||
void load(std::stringstream& _stream);
|
|
||||||
|
|
||||||
/** \brief Save data to file.
|
|
||||||
*/
|
|
||||||
void save(const QString& _filename, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime,
|
|
||||||
const profiler::SerializedData& _serializedDescriptors, const profiler::descriptors_list_t& _descriptors,
|
|
||||||
profiler::block_id_t descriptors_count, const profiler::thread_blocks_tree_t& _trees,
|
|
||||||
const profiler::bookmarks_t& bookmarks, profiler::block_getter_fn block_getter,
|
|
||||||
profiler::processid_t _pid, bool snapshotMode);
|
|
||||||
|
|
||||||
void interrupt();
|
|
||||||
void get(profiler::SerializedData& _serializedBlocks, profiler::SerializedData& _serializedDescriptors,
|
|
||||||
profiler::descriptors_list_t& _descriptors, profiler::blocks_t& _blocks, profiler::thread_blocks_tree_t& _trees,
|
|
||||||
profiler::bookmarks_t& bookmarks, profiler::BeginEndTime& beginEndTime, uint32_t& _descriptorsNumberInFile,
|
|
||||||
uint32_t& _version, profiler::processid_t& _pid, QString& _filename);
|
|
||||||
|
|
||||||
void join();
|
|
||||||
|
|
||||||
QString getError();
|
|
||||||
|
|
||||||
}; // END of class FileReader.
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
enum class ListenerRegime : uint8_t
|
|
||||||
{
|
|
||||||
Idle = 0,
|
|
||||||
Capture,
|
|
||||||
Capture_Receive,
|
|
||||||
Descriptors
|
|
||||||
};
|
|
||||||
|
|
||||||
class SocketListener Q_DECL_FINAL
|
|
||||||
{
|
|
||||||
EasySocket m_easySocket; ///<
|
|
||||||
std::string m_address; ///<
|
|
||||||
std::stringstream m_receivedData; ///<
|
|
||||||
std::thread m_thread; ///<
|
|
||||||
uint64_t m_receivedSize; ///<
|
|
||||||
uint16_t m_port; ///<
|
|
||||||
std::atomic<uint32_t> m_frameMax; ///<
|
|
||||||
std::atomic<uint32_t> m_frameAvg; ///<
|
|
||||||
std::atomic_bool m_bInterrupt; ///<
|
|
||||||
std::atomic_bool m_bConnected; ///<
|
|
||||||
std::atomic_bool m_bStopReceive; ///<
|
|
||||||
std::atomic_bool m_bCaptureReady; ///<
|
|
||||||
std::atomic_bool m_bFrameTimeReady; ///<
|
|
||||||
ListenerRegime m_regime; ///<
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
SocketListener();
|
|
||||||
~SocketListener();
|
|
||||||
|
|
||||||
bool connected() const;
|
|
||||||
bool captured() const;
|
|
||||||
ListenerRegime regime() const;
|
|
||||||
uint64_t size() const;
|
|
||||||
const std::string& address() const;
|
|
||||||
uint16_t port() const;
|
|
||||||
|
|
||||||
std::stringstream& data();
|
|
||||||
void clearData();
|
|
||||||
|
|
||||||
void disconnect();
|
|
||||||
void closeSocket();
|
|
||||||
bool connect(const char* _ipaddress, uint16_t _port, profiler::net::EasyProfilerStatus& _reply, bool _disconnectFirst = false);
|
|
||||||
bool reconnect(const char* _ipaddress, uint16_t _port, profiler::net::EasyProfilerStatus& _reply);
|
|
||||||
|
|
||||||
bool startCapture();
|
|
||||||
void stopCapture();
|
|
||||||
void finalizeCapture();
|
|
||||||
void requestBlocksDescription();
|
|
||||||
|
|
||||||
bool frameTime(uint32_t& _maxTime, uint32_t& _avgTime);
|
|
||||||
bool requestFrameTime();
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void send(const T& _message) {
|
|
||||||
m_easySocket.send(&_message, sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void listenCapture();
|
|
||||||
void listenDescription();
|
|
||||||
void listenFrameTime();
|
|
||||||
|
|
||||||
}; // END of class SocketListener.
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class DockWidget : public QDockWidget
|
class DockWidget : public QDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -285,6 +143,7 @@ protected:
|
|||||||
profiler::BeginEndTime m_beginEndTime;
|
profiler::BeginEndTime m_beginEndTime;
|
||||||
FileReader m_reader;
|
FileReader m_reader;
|
||||||
SocketListener m_listener;
|
SocketListener m_listener;
|
||||||
|
std::chrono::system_clock::time_point m_listenStartTime;
|
||||||
|
|
||||||
class QLineEdit* m_addressEdit = nullptr;
|
class QLineEdit* m_addressEdit = nullptr;
|
||||||
class QLineEdit* m_portEdit = nullptr;
|
class QLineEdit* m_portEdit = nullptr;
|
||||||
|
991
profiler_gui/socket_listener.cpp
Normal file
991
profiler_gui/socket_listener.cpp
Normal file
@ -0,0 +1,991 @@
|
|||||||
|
//
|
||||||
|
// Created by vzarubkin on 29.10.19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <easy/easy_net.h>
|
||||||
|
|
||||||
|
#include "common_functions.h"
|
||||||
|
#include "socket_listener.h"
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SocketListener::SocketListener() : m_receivedSize(0), m_port(0), m_regime(ListenerRegime::Idle)
|
||||||
|
{
|
||||||
|
m_bInterrupt = false;
|
||||||
|
m_bConnected = false;
|
||||||
|
m_bStopReceive = false;
|
||||||
|
m_bFrameTimeReady = false;
|
||||||
|
m_bCaptureReady = false;
|
||||||
|
m_frameMax = 0;
|
||||||
|
m_frameAvg = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketListener::~SocketListener()
|
||||||
|
{
|
||||||
|
m_bInterrupt.store(true, std::memory_order_release);
|
||||||
|
if (m_thread.joinable())
|
||||||
|
{
|
||||||
|
m_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketListener::connected() const
|
||||||
|
{
|
||||||
|
return m_bConnected.load(std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketListener::captured() const
|
||||||
|
{
|
||||||
|
return m_bCaptureReady.load(std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListenerRegime SocketListener::regime() const
|
||||||
|
{
|
||||||
|
return m_regime;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SocketListener::size() const
|
||||||
|
{
|
||||||
|
return m_receivedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream& SocketListener::data()
|
||||||
|
{
|
||||||
|
return m_receivedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& SocketListener::address() const
|
||||||
|
{
|
||||||
|
return m_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SocketListener::port() const
|
||||||
|
{
|
||||||
|
return m_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketListener::clearData()
|
||||||
|
{
|
||||||
|
profiler_gui::clear_stream(m_receivedData);
|
||||||
|
m_receivedSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketListener::disconnect()
|
||||||
|
{
|
||||||
|
if (connected())
|
||||||
|
{
|
||||||
|
m_bInterrupt.store(true, std::memory_order_release);
|
||||||
|
if (m_thread.joinable())
|
||||||
|
{
|
||||||
|
m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
m_bInterrupt.store(false, std::memory_order_release);
|
||||||
|
m_bCaptureReady.store(false, std::memory_order_release);
|
||||||
|
m_bStopReceive.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_address.clear();
|
||||||
|
m_port = 0;
|
||||||
|
|
||||||
|
closeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketListener::closeSocket()
|
||||||
|
{
|
||||||
|
m_easySocket.flush();
|
||||||
|
m_easySocket.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketListener::connect(
|
||||||
|
const char* _ipaddress,
|
||||||
|
uint16_t _port,
|
||||||
|
profiler::net::EasyProfilerStatus& _reply,
|
||||||
|
bool _disconnectFirst
|
||||||
|
) {
|
||||||
|
if (connected())
|
||||||
|
{
|
||||||
|
m_bInterrupt.store(true, std::memory_order_release);
|
||||||
|
if (m_thread.joinable())
|
||||||
|
{
|
||||||
|
m_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
m_bInterrupt.store(false, std::memory_order_release);
|
||||||
|
m_bCaptureReady.store(false, std::memory_order_release);
|
||||||
|
m_bStopReceive.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_address.clear();
|
||||||
|
m_port = 0;
|
||||||
|
|
||||||
|
if (_disconnectFirst)
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = m_easySocket.setAddress(_ipaddress, _port);
|
||||||
|
res = m_easySocket.connect();
|
||||||
|
|
||||||
|
const bool isConnected = res == 0;
|
||||||
|
if (isConnected)
|
||||||
|
{
|
||||||
|
EASY_CONSTEXPR size_t buffer_size = sizeof(profiler::net::EasyProfilerStatus) << 1;
|
||||||
|
char buffer[buffer_size] = {};
|
||||||
|
int bytes = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bytes = m_easySocket.receive(buffer, buffer_size);
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == 0)
|
||||||
|
{
|
||||||
|
m_address = _ipaddress;
|
||||||
|
m_port = _port;
|
||||||
|
m_bConnected.store(isConnected, std::memory_order_release);
|
||||||
|
return isConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t seek = bytes;
|
||||||
|
while (seek < sizeof(profiler::net::EasyProfilerStatus))
|
||||||
|
{
|
||||||
|
bytes = m_easySocket.receive(buffer + seek, buffer_size - seek);
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
seek += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto message = reinterpret_cast<const profiler::net::EasyProfilerStatus*>(buffer);
|
||||||
|
if (message->isEasyNetMessage() && message->type == profiler::net::MessageType::Connection_Accepted)
|
||||||
|
{
|
||||||
|
_reply = *message;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_address = _ipaddress;
|
||||||
|
m_port = _port;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bConnected.store(isConnected, std::memory_order_release);
|
||||||
|
|
||||||
|
return isConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketListener::reconnect(const char* _ipaddress, uint16_t _port, profiler::net::EasyProfilerStatus& _reply)
|
||||||
|
{
|
||||||
|
return connect(_ipaddress, _port, _reply, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketListener::startCapture()
|
||||||
|
{
|
||||||
|
//if (m_thread.joinable())
|
||||||
|
//{
|
||||||
|
// m_bInterrupt.store(true, std::memory_order_release);
|
||||||
|
// m_thread.join();
|
||||||
|
// m_bInterrupt.store(false, std::memory_order_release);
|
||||||
|
//}
|
||||||
|
|
||||||
|
clearData();
|
||||||
|
|
||||||
|
profiler::net::Message request(profiler::net::MessageType::Request_Start_Capture);
|
||||||
|
m_easySocket.send(&request, sizeof(request));
|
||||||
|
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_regime = ListenerRegime::Capture;
|
||||||
|
m_bCaptureReady.store(false, std::memory_order_release);
|
||||||
|
//m_thread = std::thread(&SocketListener::listenCapture, this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketListener::stopCapture()
|
||||||
|
{
|
||||||
|
//if (!m_thread.joinable() || m_regime != ListenerRegime::Capture)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
if (m_regime != ListenerRegime::Capture)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//m_bStopReceive.store(true, std::memory_order_release);
|
||||||
|
profiler::net::Message request(profiler::net::MessageType::Request_Stop_Capture);
|
||||||
|
m_easySocket.send(&request, sizeof(request));
|
||||||
|
|
||||||
|
//m_thread.join();
|
||||||
|
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
m_bStopReceive.store(false, std::memory_order_release);
|
||||||
|
m_regime = ListenerRegime::Idle;
|
||||||
|
m_bCaptureReady.store(true, std::memory_order_release);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_regime = ListenerRegime::Capture_Receive;
|
||||||
|
if (m_thread.joinable())
|
||||||
|
{
|
||||||
|
m_bInterrupt.store(true, std::memory_order_release);
|
||||||
|
m_thread.join();
|
||||||
|
m_bInterrupt.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_thread = std::thread(&SocketListener::listenCapture, this);
|
||||||
|
|
||||||
|
//m_regime = ListenerRegime::Idle;
|
||||||
|
//m_bStopReceive.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketListener::finalizeCapture()
|
||||||
|
{
|
||||||
|
if (m_thread.joinable())
|
||||||
|
{
|
||||||
|
m_bInterrupt.store(true, std::memory_order_release);
|
||||||
|
m_thread.join();
|
||||||
|
m_bInterrupt.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_regime = ListenerRegime::Idle;
|
||||||
|
m_bCaptureReady.store(false, std::memory_order_release);
|
||||||
|
m_bStopReceive.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketListener::requestBlocksDescription()
|
||||||
|
{
|
||||||
|
if (m_thread.joinable())
|
||||||
|
{
|
||||||
|
m_bInterrupt.store(true, std::memory_order_release);
|
||||||
|
m_thread.join();
|
||||||
|
m_bInterrupt.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearData();
|
||||||
|
|
||||||
|
profiler::net::Message request(profiler::net::MessageType::Request_Blocks_Description);
|
||||||
|
m_easySocket.send(&request, sizeof(request));
|
||||||
|
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_regime = ListenerRegime::Descriptors;
|
||||||
|
listenDescription();
|
||||||
|
m_regime = ListenerRegime::Idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketListener::frameTime(uint32_t& _maxTime, uint32_t& _avgTime)
|
||||||
|
{
|
||||||
|
if (m_bFrameTimeReady.exchange(false, std::memory_order_acquire))
|
||||||
|
{
|
||||||
|
_maxTime = m_frameMax.load(std::memory_order_acquire);
|
||||||
|
_avgTime = m_frameAvg.load(std::memory_order_acquire);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketListener::requestFrameTime()
|
||||||
|
{
|
||||||
|
if (m_regime != ListenerRegime::Idle && m_regime != ListenerRegime::Capture)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_thread.joinable())
|
||||||
|
{
|
||||||
|
m_bInterrupt.store(true, std::memory_order_release);
|
||||||
|
m_thread.join();
|
||||||
|
m_bInterrupt.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler::net::Message request(profiler::net::MessageType::Request_MainThread_FPS);
|
||||||
|
m_easySocket.send(&request, sizeof(request));
|
||||||
|
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bFrameTimeReady.store(false, std::memory_order_release);
|
||||||
|
m_thread = std::thread(&SocketListener::listenFrameTime, this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void SocketListener::listenCapture()
|
||||||
|
{
|
||||||
|
EASY_CONSTEXPR int buffer_size = 8 * 1024 * 1024;
|
||||||
|
|
||||||
|
char* buffer = new char[buffer_size];
|
||||||
|
int seek = 0, bytes = 0;
|
||||||
|
auto timeBegin = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
bool isListen = true, disconnected = false;
|
||||||
|
while (isListen && !m_bInterrupt.load(std::memory_order_acquire))
|
||||||
|
{
|
||||||
|
if (m_bStopReceive.load(std::memory_order_acquire))
|
||||||
|
{
|
||||||
|
profiler::net::Message request(profiler::net::MessageType::Request_Stop_Capture);
|
||||||
|
m_easySocket.send(&request, sizeof(request));
|
||||||
|
m_bStopReceive.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < 1)
|
||||||
|
{
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
else if (seek > 0)
|
||||||
|
{
|
||||||
|
if (bytes < seek)
|
||||||
|
{
|
||||||
|
memcpy(buffer, buffer + seek, static_cast<size_t>(bytes));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(buffer, buffer + seek, static_cast<size_t>(seek));
|
||||||
|
for (int i = seek; i < bytes; ++i)
|
||||||
|
{
|
||||||
|
buffer[i] = buffer[seek + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bytes < sizeof(profiler::net::Message))
|
||||||
|
{
|
||||||
|
int receivedBytes = m_easySocket.receive(buffer + seek + bytes, buffer_size);
|
||||||
|
if (receivedBytes < 1)
|
||||||
|
{
|
||||||
|
bytes = receivedBytes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes += receivedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
isListen = false;
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == 0)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
isListen = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto message = reinterpret_cast<const profiler::net::Message*>(buffer + seek);
|
||||||
|
while (!message->isEasyNetMessage())
|
||||||
|
{
|
||||||
|
seek += sizeof(uint32_t);
|
||||||
|
bytes -= sizeof(uint32_t);
|
||||||
|
|
||||||
|
if (seek >= buffer_size || bytes <= 0)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
bytes = 0;
|
||||||
|
message = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < sizeof(profiler::net::Message))
|
||||||
|
{
|
||||||
|
message = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
message = reinterpret_cast<const profiler::net::Message*>(buffer + seek);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < 1 || message == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message->type)
|
||||||
|
{
|
||||||
|
case profiler::net::MessageType::Connection_Accepted:
|
||||||
|
{
|
||||||
|
qInfo() << "Receive MessageType::Connection_Accepted";
|
||||||
|
//m_easySocket.send(&request, sizeof(request));
|
||||||
|
seek += sizeof(profiler::net::Message);
|
||||||
|
bytes -= sizeof(profiler::net::Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case profiler::net::MessageType::Reply_Capturing_Started:
|
||||||
|
{
|
||||||
|
qInfo() << "Receive MessageType::Reply_Capturing_Started";
|
||||||
|
seek += sizeof(profiler::net::Message);
|
||||||
|
bytes -= sizeof(profiler::net::Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case profiler::net::MessageType::Reply_Blocks_End:
|
||||||
|
{
|
||||||
|
qInfo() << "Receive MessageType::Reply_Blocks_End";
|
||||||
|
seek += sizeof(profiler::net::Message);
|
||||||
|
bytes -= sizeof(profiler::net::Message);
|
||||||
|
|
||||||
|
const auto dt = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - timeBegin);
|
||||||
|
const auto bytesNumber = m_receivedData.str().size();
|
||||||
|
qInfo() << "received " << bytesNumber << " bytes, " << dt.count() << " ms, average speed = "
|
||||||
|
<< double(bytesNumber) * 1e3 / double(dt.count()) / 1024. << " kBytes/sec";
|
||||||
|
|
||||||
|
isListen = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case profiler::net::MessageType::Reply_Blocks:
|
||||||
|
{
|
||||||
|
qInfo() << "Receive MessageType::Reply_Blocks";
|
||||||
|
|
||||||
|
while (bytes < sizeof(profiler::net::DataMessage))
|
||||||
|
{
|
||||||
|
int receivedBytes = m_easySocket.receive(buffer + seek + bytes, buffer_size);
|
||||||
|
if (receivedBytes < 1)
|
||||||
|
{
|
||||||
|
bytes = receivedBytes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes += receivedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
isListen = false;
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == 0)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
isListen = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seek += sizeof(profiler::net::DataMessage);
|
||||||
|
bytes -= sizeof(profiler::net::DataMessage);
|
||||||
|
auto dm = reinterpret_cast<const profiler::net::DataMessage*>(message);
|
||||||
|
|
||||||
|
timeBegin = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
int neededSize = dm->size;
|
||||||
|
const int bytesNumber = std::min(neededSize, bytes);
|
||||||
|
if (bytesNumber > 0)
|
||||||
|
{
|
||||||
|
char* buf = buffer + seek;
|
||||||
|
m_receivedSize += bytesNumber;
|
||||||
|
m_receivedData.write(buf, bytesNumber);
|
||||||
|
|
||||||
|
neededSize -= bytesNumber;
|
||||||
|
bytes -= bytesNumber;
|
||||||
|
seek += bytesNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < 1)
|
||||||
|
{
|
||||||
|
// this is possible only when (neededSize - bytesNumber) >= 0
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (neededSize > 0)
|
||||||
|
{
|
||||||
|
// We can get here only when neededSize > (bytes - seek). Therefore bytes == 0 and seek = 0 here.
|
||||||
|
|
||||||
|
bytes = m_easySocket.receive(buffer, buffer_size);
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int toWrite = std::min(bytes, neededSize);
|
||||||
|
m_receivedSize += toWrite;
|
||||||
|
m_receivedData.write(buffer, toWrite);
|
||||||
|
|
||||||
|
neededSize -= toWrite;
|
||||||
|
bytes -= toWrite;
|
||||||
|
|
||||||
|
if (bytes < 1)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seek = toWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
isListen = false;
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_bStopReceive.load(std::memory_order_acquire))
|
||||||
|
{
|
||||||
|
profiler::net::Message request(profiler::net::MessageType::Request_Stop_Capture);
|
||||||
|
m_easySocket.send(&request, sizeof(request));
|
||||||
|
m_bStopReceive.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
//qInfo() << "Receive unknown " << message->type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disconnected)
|
||||||
|
{
|
||||||
|
clearData();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] buffer;
|
||||||
|
|
||||||
|
m_bCaptureReady.store(true, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketListener::listenDescription()
|
||||||
|
{
|
||||||
|
EASY_CONSTEXPR int buffer_size = 8 * 1024 * 1024;
|
||||||
|
|
||||||
|
char* buffer = new char[buffer_size];
|
||||||
|
int seek = 0, bytes = 0;
|
||||||
|
|
||||||
|
bool isListen = true, disconnected = false;
|
||||||
|
while (isListen && !m_bInterrupt.load(std::memory_order_acquire))
|
||||||
|
{
|
||||||
|
if (bytes < 1)
|
||||||
|
{
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
else if (seek > 0)
|
||||||
|
{
|
||||||
|
if (bytes < seek)
|
||||||
|
{
|
||||||
|
memcpy(buffer, buffer + seek, static_cast<size_t>(bytes));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(buffer, buffer + seek, static_cast<size_t>(seek));
|
||||||
|
for (int i = seek; i < bytes; ++i)
|
||||||
|
{
|
||||||
|
buffer[i] = buffer[seek + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bytes < sizeof(profiler::net::Message))
|
||||||
|
{
|
||||||
|
int receivedBytes = m_easySocket.receive(buffer + seek + bytes, buffer_size);
|
||||||
|
if (receivedBytes < 1)
|
||||||
|
{
|
||||||
|
bytes = receivedBytes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes += receivedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
isListen = false;
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == 0)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
isListen = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto message = reinterpret_cast<const profiler::net::Message*>(buffer + seek);
|
||||||
|
while (!message->isEasyNetMessage())
|
||||||
|
{
|
||||||
|
seek += sizeof(uint32_t);
|
||||||
|
bytes -= sizeof(uint32_t);
|
||||||
|
|
||||||
|
if (seek >= buffer_size || bytes <= 0)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
bytes = 0;
|
||||||
|
message = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < sizeof(profiler::net::Message))
|
||||||
|
{
|
||||||
|
message = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
message = reinterpret_cast<const profiler::net::Message*>(buffer + seek);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < 1 || message == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message->type)
|
||||||
|
{
|
||||||
|
case profiler::net::MessageType::Connection_Accepted:
|
||||||
|
{
|
||||||
|
qInfo() << "Receive MessageType::Connection_Accepted";
|
||||||
|
seek += sizeof(profiler::net::Message);
|
||||||
|
bytes -= sizeof(profiler::net::Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case profiler::net::MessageType::Reply_Blocks_Description_End:
|
||||||
|
{
|
||||||
|
qInfo() << "Receive MessageType::Reply_Blocks_Description_End";
|
||||||
|
seek += sizeof(profiler::net::Message);
|
||||||
|
bytes -= sizeof(profiler::net::Message);
|
||||||
|
|
||||||
|
isListen = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case profiler::net::MessageType::Reply_Blocks_Description:
|
||||||
|
{
|
||||||
|
qInfo() << "Receive MessageType::Reply_Blocks_Description";
|
||||||
|
|
||||||
|
while (bytes < sizeof(profiler::net::DataMessage))
|
||||||
|
{
|
||||||
|
int receivedBytes = m_easySocket.receive(buffer + seek + bytes, buffer_size);
|
||||||
|
if (receivedBytes < 1)
|
||||||
|
{
|
||||||
|
bytes = receivedBytes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes += receivedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
isListen = false;
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == 0)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
isListen = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seek += sizeof(profiler::net::DataMessage);
|
||||||
|
bytes -= sizeof(profiler::net::DataMessage);
|
||||||
|
auto dm = reinterpret_cast<const profiler::net::DataMessage*>(message);
|
||||||
|
|
||||||
|
int neededSize = dm->size;
|
||||||
|
const int bytesNumber = std::min(neededSize, bytes);
|
||||||
|
if (bytesNumber > 0)
|
||||||
|
{
|
||||||
|
char* buf = buffer + seek;
|
||||||
|
m_receivedSize += bytesNumber;
|
||||||
|
m_receivedData.write(buf, bytesNumber);
|
||||||
|
|
||||||
|
neededSize -= bytesNumber;
|
||||||
|
bytes -= bytesNumber;
|
||||||
|
seek += bytesNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < 1)
|
||||||
|
{
|
||||||
|
// this is possible only when (neededSize - bytesNumber) >= 0
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (neededSize > 0)
|
||||||
|
{
|
||||||
|
// We can get here only when neededSize > (bytes - seek). Therefore bytes == 0 and seek = 0 here.
|
||||||
|
|
||||||
|
bytes = m_easySocket.receive(buffer, buffer_size);
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int toWrite = std::min(bytes, neededSize);
|
||||||
|
m_receivedSize += toWrite;
|
||||||
|
m_receivedData.write(buffer, toWrite);
|
||||||
|
|
||||||
|
neededSize -= toWrite;
|
||||||
|
bytes -= toWrite;
|
||||||
|
|
||||||
|
if (bytes < 1)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seek = toWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
isListen = false;
|
||||||
|
disconnected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disconnected)
|
||||||
|
{
|
||||||
|
clearData();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocketListener::listenFrameTime()
|
||||||
|
{
|
||||||
|
EASY_CONSTEXPR size_t buffer_size = sizeof(profiler::net::TimestampMessage) << 3;
|
||||||
|
|
||||||
|
char buffer[buffer_size] = {};
|
||||||
|
int seek = 0, bytes = 0;
|
||||||
|
|
||||||
|
bool isListen = true;
|
||||||
|
while (isListen && !m_bInterrupt.load(std::memory_order_acquire))
|
||||||
|
{
|
||||||
|
if (bytes < 1)
|
||||||
|
{
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
else if (seek > 0)
|
||||||
|
{
|
||||||
|
if (bytes < seek)
|
||||||
|
{
|
||||||
|
memcpy(buffer, buffer + seek, static_cast<size_t>(bytes));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(buffer, buffer + seek, static_cast<size_t>(seek));
|
||||||
|
for (int i = seek; i < bytes; ++i)
|
||||||
|
{
|
||||||
|
buffer[i] = buffer[seek + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seek = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bytes < sizeof(profiler::net::Message))
|
||||||
|
{
|
||||||
|
int receivedBytes = m_easySocket.receive(buffer + seek + bytes, buffer_size);
|
||||||
|
if (receivedBytes < 1)
|
||||||
|
{
|
||||||
|
bytes = receivedBytes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes += receivedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == -1)
|
||||||
|
{
|
||||||
|
if (m_easySocket.isDisconnected())
|
||||||
|
{
|
||||||
|
m_bConnected.store(false, std::memory_order_release);
|
||||||
|
isListen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = 0;
|
||||||
|
seek = 0;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == 0)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
isListen = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto message = reinterpret_cast<const profiler::net::Message*>(buffer + seek);
|
||||||
|
while (!message->isEasyNetMessage())
|
||||||
|
{
|
||||||
|
seek += sizeof(uint32_t);
|
||||||
|
bytes -= sizeof(uint32_t);
|
||||||
|
|
||||||
|
if (seek >= buffer_size || bytes <= 0)
|
||||||
|
{
|
||||||
|
seek = 0;
|
||||||
|
bytes = 0;
|
||||||
|
message = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < sizeof(profiler::net::Message))
|
||||||
|
{
|
||||||
|
message = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
message = reinterpret_cast<const profiler::net::Message*>(buffer + seek);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < 1 || message == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message->type)
|
||||||
|
{
|
||||||
|
case profiler::net::MessageType::Connection_Accepted:
|
||||||
|
case profiler::net::MessageType::Reply_Capturing_Started:
|
||||||
|
{
|
||||||
|
seek += sizeof(profiler::net::Message);
|
||||||
|
bytes -= sizeof(profiler::net::Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case profiler::net::MessageType::Reply_MainThread_FPS:
|
||||||
|
{
|
||||||
|
//qInfo() << "Receive MessageType::Reply_MainThread_FPS";
|
||||||
|
|
||||||
|
seek += sizeof(profiler::net::TimestampMessage);
|
||||||
|
bytes -= sizeof(profiler::net::TimestampMessage);
|
||||||
|
|
||||||
|
if (seek <= buffer_size)
|
||||||
|
{
|
||||||
|
auto timestampMessage = reinterpret_cast<const profiler::net::TimestampMessage*>(message);
|
||||||
|
m_frameMax.store(timestampMessage->maxValue, std::memory_order_release);
|
||||||
|
m_frameAvg.store(timestampMessage->avgValue, std::memory_order_release);
|
||||||
|
m_bFrameTimeReady.store(true, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
isListen = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
profiler_gui/socket_listener.h
Normal file
87
profiler_gui/socket_listener.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// Created by vzarubkin on 29.10.19.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef EASY_PROFILER_SOCKET_LISTENER_H
|
||||||
|
#define EASY_PROFILER_SOCKET_LISTENER_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <easy/easy_socket.h>
|
||||||
|
|
||||||
|
namespace profiler { namespace net { struct EasyProfilerStatus; } }
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
enum class ListenerRegime : uint8_t
|
||||||
|
{
|
||||||
|
Idle = 0,
|
||||||
|
Capture,
|
||||||
|
Capture_Receive,
|
||||||
|
Descriptors
|
||||||
|
};
|
||||||
|
|
||||||
|
class SocketListener Q_DECL_FINAL
|
||||||
|
{
|
||||||
|
EasySocket m_easySocket; ///<
|
||||||
|
std::string m_address; ///<
|
||||||
|
std::stringstream m_receivedData; ///<
|
||||||
|
std::thread m_thread; ///<
|
||||||
|
uint64_t m_receivedSize; ///<
|
||||||
|
uint16_t m_port; ///<
|
||||||
|
std::atomic<uint32_t> m_frameMax; ///<
|
||||||
|
std::atomic<uint32_t> m_frameAvg; ///<
|
||||||
|
std::atomic_bool m_bInterrupt; ///<
|
||||||
|
std::atomic_bool m_bConnected; ///<
|
||||||
|
std::atomic_bool m_bStopReceive; ///<
|
||||||
|
std::atomic_bool m_bCaptureReady; ///<
|
||||||
|
std::atomic_bool m_bFrameTimeReady; ///<
|
||||||
|
ListenerRegime m_regime; ///<
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
SocketListener();
|
||||||
|
~SocketListener();
|
||||||
|
|
||||||
|
bool connected() const;
|
||||||
|
bool captured() const;
|
||||||
|
ListenerRegime regime() const;
|
||||||
|
uint64_t size() const;
|
||||||
|
const std::string& address() const;
|
||||||
|
uint16_t port() const;
|
||||||
|
|
||||||
|
std::stringstream& data();
|
||||||
|
void clearData();
|
||||||
|
|
||||||
|
void disconnect();
|
||||||
|
void closeSocket();
|
||||||
|
bool connect(const char* _ipaddress, uint16_t _port, profiler::net::EasyProfilerStatus& _reply, bool _disconnectFirst = false);
|
||||||
|
bool reconnect(const char* _ipaddress, uint16_t _port, profiler::net::EasyProfilerStatus& _reply);
|
||||||
|
|
||||||
|
bool startCapture();
|
||||||
|
void stopCapture();
|
||||||
|
void finalizeCapture();
|
||||||
|
void requestBlocksDescription();
|
||||||
|
|
||||||
|
bool frameTime(uint32_t& _maxTime, uint32_t& _avgTime);
|
||||||
|
bool requestFrameTime();
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void send(const T& _message) {
|
||||||
|
m_easySocket.send(&_message, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void listenCapture();
|
||||||
|
void listenDescription();
|
||||||
|
void listenFrameTime();
|
||||||
|
|
||||||
|
}; // END of class SocketListener.
|
||||||
|
|
||||||
|
#endif //EASY_PROFILER_SOCKET_LISTENER_H
|
Loading…
x
Reference in New Issue
Block a user