diff --git a/intercept b/intercept index 19b7bdc..74d3d0d 160000 --- a/intercept +++ b/intercept @@ -1 +1 @@ -Subproject commit 19b7bdcf08deffa3accf7a25548c86bb046c9cb2 +Subproject commit 74d3d0d3639176488eba94fe091edfbcff9de10e diff --git a/src/AdapterTracy.cpp b/src/AdapterTracy.cpp index f7dc2d2..06b568e 100644 --- a/src/AdapterTracy.cpp +++ b/src/AdapterTracy.cpp @@ -18,7 +18,7 @@ class ScopeTempStorageTracy final : public ScopeTempStorage { public: ScopeTempStorageTracy(const tracy::SourceLocationData* srcloc) : zone(srcloc) {} - ScopeTempStorageTracy(const tracy::SourceLocationData* srcloc, uint64_t threadID) : zone(srcloc, threadID) {} + //ScopeTempStorageTracy(const tracy::SourceLocationData* srcloc, uint64_t threadID) : zone(srcloc, threadID) {} tracy::ScopedZone zone; }; @@ -63,12 +63,13 @@ std::shared_ptr AdapterTracy::enterScope(std::shared_ptr AdapterTracy::enterScope(std::shared_ptr scope, uint64_t threadID) { - auto info = std::dynamic_pointer_cast(scope); - if (!info || !isConnected()) return nullptr; //#TODO debugbreak? log error? - ensureReady(); - - auto ret = std::make_shared(&info->info, threadID); - return ret; + return enterScope(scope); + //auto info = std::dynamic_pointer_cast(scope); + //if (!info || !isConnected()) return nullptr; //#TODO debugbreak? log error? + //ensureReady(); + // + //auto ret = std::make_shared(&info->info, threadID); + //return ret; } void AdapterTracy::leaveScope(std::shared_ptr tempStorage) { @@ -114,6 +115,70 @@ bool AdapterTracy::isConnected() { return tracy::s_profiler.IsConnected(); } + +struct CallstackStruct { + intercept::types::auto_array> data; +}; + +void DestructCallstackStruct(void* data) { + auto str = (CallstackStruct*)data; + + str->data.clear(); + delete str; +} + +void AdapterTracy::sendCallstack(intercept::types::auto_array>& cs) { + if (cs.size() > 63) + cs.resize(63); + + uint32_t depth = cs.size(); + + const char* func[64]; + uint32_t fsz[64]; + uint32_t ssz[64]; + uint32_t spaceNeeded = 4; // cnt + + uint32_t cnt = 0; + for (auto& [file, line] : cs) { + func[cnt] = file.c_str(); + fsz[cnt] = uint32_t(strlen(func[cnt])); + ssz[cnt] = uint32_t(file.length()); + spaceNeeded += fsz[cnt] + ssz[cnt]; + cnt++; + } + + spaceNeeded += cnt * (4 + 4 + 4); // source line, function string length, source string length + + auto ptr = (char*)tracy::tracy_malloc(spaceNeeded + 4); + auto dst = ptr; + memcpy(dst, &spaceNeeded, 4); dst += 4; + memcpy(dst, &cnt, 4); dst += 4; + + + cnt = 0; + for (auto& [file, line] : cs) { + memcpy(dst, &line, 4); dst += 4; + memcpy(dst, fsz + cnt, 4); dst += 4; + memcpy(dst, func[cnt], fsz[cnt]); dst += fsz[cnt]; + memcpy(dst, ssz + cnt, 4); dst += 4; + memcpy(dst, file.c_str(), ssz[cnt]), dst += ssz[cnt]; + cnt++; + } + assert(dst - ptr == spaceNeeded + 4); + + tracy::Magic magic; + auto token = tracy::GetToken(); + auto& tail = token->get_tail_index(); + auto item = token->enqueue_begin(magic); + tracy::MemWrite(&item->hdr.type, tracy::QueueType::CallstackArma); + tracy::MemWrite(&item->callstackAlloc.ptr, (uint64_t)ptr); + auto str = new CallstackStruct(); + str->data = cs; + tracy::MemWrite(&item->callstackAlloc.nativePtr, (uint64_t)str); + tail.store(magic + 1, std::memory_order_release); + +} + void AdapterTracy::ensureReady() { if (tracy::s_token.ptr) return; diff --git a/src/AdapterTracy.hpp b/src/AdapterTracy.hpp index 9d31f14..c054fc9 100644 --- a/src/AdapterTracy.hpp +++ b/src/AdapterTracy.hpp @@ -24,6 +24,7 @@ class AdapterTracy final : public ProfilerAdapter std::shared_ptr createScopeStatic(const char* name, const char* filename, uint32_t fileline) const; static bool isConnected(); + static void sendCallstack(intercept::types::auto_array>& cs); private: static void ensureReady(); using scopeCacheKey = std::tuple; diff --git a/src/ArmaScriptProfiler.vcxproj b/src/ArmaScriptProfiler.vcxproj index d509067..0cdcd15 100644 --- a/src/ArmaScriptProfiler.vcxproj +++ b/src/ArmaScriptProfiler.vcxproj @@ -164,6 +164,7 @@ + @@ -218,6 +219,7 @@ + diff --git a/src/ArmaScriptProfiler.vcxproj.filters b/src/ArmaScriptProfiler.vcxproj.filters index d314834..61efad1 100644 --- a/src/ArmaScriptProfiler.vcxproj.filters +++ b/src/ArmaScriptProfiler.vcxproj.filters @@ -60,6 +60,9 @@ Headerdateien + + Headerdateien + @@ -194,6 +197,9 @@ Quelldateien + + Quelldateien + diff --git a/src/NetworkProfiler.cpp b/src/NetworkProfiler.cpp new file mode 100644 index 0000000..64cd4f4 --- /dev/null +++ b/src/NetworkProfiler.cpp @@ -0,0 +1,520 @@ +#include "NetworkProfiler.hpp" + +#include "AdapterTracy.hpp" +#include "scriptProfiler.hpp" + +#define TRACY_ENABLE +#define TRACY_ON_DEMAND +#include +#include + +extern void diag_log(r_string msg); + +class ClassEntrySizeCounter : public param_archive_entry { + friend class ClassEntryRef; +public: + r_string name; + uint64_t* sizeCounter; + ClassEntrySizeCounter* parent = nullptr; + std::vector activeSubs; + std::string* data; + + ClassEntrySizeCounter(r_string name_, uint64_t* size) : sizeCounter(size) { + *sizeCounter += name_.length(); + }; + + ClassEntrySizeCounter(r_string name_, uint64_t* size, std::string* data_) : sizeCounter(size), data(data_) { + *sizeCounter += name_.length(); + if (data) { + *data += name_; + data->push_back('/'); + } + }; + + ClassEntrySizeCounter(r_string name_, ClassEntrySizeCounter* parent_) : sizeCounter(parent_->sizeCounter), parent(parent_), data(parent_->data) { + *sizeCounter += name_.length(); + parent->activeSubs.push_back(this); + }; + + //! virtual destructor + virtual ~ClassEntrySizeCounter() { + if (parent) { + auto newEnd = std::remove(parent->activeSubs.begin(), parent->activeSubs.end(), this); + parent->activeSubs.erase(newEnd, parent->activeSubs.end()); + } + auto copy = activeSubs; + for (auto& it : copy) + delete it; + } + + // generic entry + int entry_count() const override { return 0; } + + + param_archive_entry* get_entry_by_index(int i) const override { return nullptr; } + + r_string current_entry_name() override { return ""sv; } + + + param_archive_entry* get_entry_by_name(const r_string& name) const override { return nullptr; } + operator float() const override { return 0; } + operator int() const override { return 0; } + + operator int64_t() const override { return 0; } + + operator r_string() const override { return ""sv; } + + operator bool() const override { return false; } + //GetContext + r_string _placeholder1(uint32_t member = NULL) const override { return ""sv; } + + // array + void reserve(int count) override {} + + void add_array_entry(float val) override { + if (data) { + *data += std::to_string(val); + data->push_back('/'); + } + *sizeCounter += 4; + } + + void add_array_entry(int val) override { + if (data) { + *data += std::to_string(val); + data->push_back('/'); + } + *sizeCounter += 4; + } + + void add_array_entry(int64_t val) override { + if (data) { + *data += std::to_string(val); + data->push_back('/'); + } + *sizeCounter += 8; + } + + //void add_array_entry(bool val) override { + // std::stringstream str; + // str << this << " AddValue " << val << "\n"; + // OutputDebugStringA(str.str().c_str()); + //} + void add_array_entry(const r_string& val) override { + if (data) { + *data += val; + data->push_back('/'); + } + *sizeCounter += val.length(); + } + + int count() const override { return 0; } + + param_archive_array_entry* operator [](int i) const override { return nullptr; } + + param_archive_entry* add_entry_class(const r_string& name, bool guaranteedUnique = false) override { + if (data) { + *data += name; + data->push_back('/'); + } + *sizeCounter += name.length(); + return new ClassEntrySizeCounter(""sv, this); + } + + param_archive_entry* add_entry_array(const r_string& name) override { + if (data) { + *data += name; + data->push_back('/'); + } + *sizeCounter += name.length(); + return new ClassEntrySizeCounter(""sv, this); + } + + void add_entry(const r_string& name, const r_string& val) override { + if (data) { + *data += name; + data->push_back('='); + *data += val; + data->push_back('/'); + } + *sizeCounter += name.length() + val.length(); + } + + void add_entry(const r_string& name, float val) override { + if (data) { + *data += name; + data->push_back('='); + *data += std::to_string(val); + data->push_back('/'); + } + *sizeCounter += name.length() + 4; } + + void add_entry(const r_string& name, int val) override { + if (data) { + *data += name; + data->push_back('='); + *data += std::to_string(val); + data->push_back('/'); + } + *sizeCounter += name.length() + 4; + } + + void add_entry(const r_string& name, int64_t val) override { + if (data) { + *data += name; + data->push_back('='); + *data += std::to_string(val); + data->push_back('/'); + } + *sizeCounter += name.length() + 8; + } + + void compress() override {}; + + //! Delete the entry. Note: it could be used in rare cases only! + void _placeholder(const r_string& name) override {}; +}; + +void NetworkProfiler::init() { + auto iface = client::host::request_plugin_interface("BIDebugEngine_getCallstack", 1); + if (!iface) { + diag_log("ASP: Network statistics failed to enable because ArmaDebugEngine is missing"sv); + return; + } + getCallstackRaw = reinterpret_cast(*iface); + + static auto _pubVar = client::host::register_sqf_command("publicVariable", "Profiler redirect", [](game_state& gs, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "publicVariable", + "publicVariable", + "", + 0 + }; + static int64_t publicVarSize; + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + r_string varName = arg; + auto varValue = sqf::get_variable(sqf::current_namespace(), varName); + + std::string data; + publicVarSize += getVariableSize(varValue, logPacketContent ? &data : nullptr); + publicVarSize += varName.size(); + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(varName.c_str(), varName.size()); + + tracy::Profiler::PlotData("publicVariable", publicVarSize); + + sqf::public_variable(arg); + + return {}; + }, game_data_type::NOTHING, game_data_type::STRING); + + static auto _pubVarCli = client::host::register_sqf_command("publicVariableClient", "Profiler redirect", [](game_state& gs, game_value_parameter cli, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "publicVariableClient", + "publicVariableClient", + "", + 0 + }; + static int64_t publicVarSize; + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + r_string varName = arg; + auto varValue = sqf::get_variable(sqf::current_namespace(), varName); + + std::string data; + publicVarSize += getVariableSize(varValue, logPacketContent ? &data : nullptr); + publicVarSize += varName.size(); + publicVarSize += 4; //clientID + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(varName.c_str(), varName.size()); + + tracy::Profiler::PlotData("publicVariableClient", publicVarSize); + + sqf::public_variable_client(cli, arg); + + return {}; + }, game_data_type::NOTHING, game_data_type::SCALAR, game_data_type::STRING); + + static auto _pubVarSrv = client::host::register_sqf_command("publicVariableServer", "Profiler redirect", [](game_state& gs, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "publicVariableServer", + "publicVariableServer", + "", + 0 + }; + static int64_t publicVarSize; + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + r_string varName = arg; + auto varValue = sqf::get_variable(sqf::current_namespace(), varName); + + std::string data; + publicVarSize += getVariableSize(varValue, logPacketContent ? &data : nullptr); + publicVarSize += varName.size(); + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(varName.c_str(), varName.size()); + + tracy::Profiler::PlotData("publicVariableServer", publicVarSize); + + sqf::public_variable_server(arg); + + return {}; + }, game_data_type::NOTHING, game_data_type::STRING); + + static auto _remoteExecUn = client::host::register_sqf_command("remoteExec", "Profiler redirect", [](game_state& gs, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "remoteExec", + "remoteExec", + "", + 0 + }; + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + std::string data; + remoteExecSize += getVariableSize(arg, logPacketContent ? &data : nullptr); + + r_string name = arg[0]; + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(name.c_str(), name.size()); + + tracy::Profiler::PlotData("remoteExec", remoteExecSize); + + return client::host::functions.invoke_raw_unary(__sqf::unary__remoteexec__array__ret__any, arg); + }, game_data_type::ANY, game_data_type::ARRAY); + + static auto _remoteExecBin = client::host::register_sqf_command("remoteExec", "Profiler redirect", [](game_state& gs, game_value_parameter par, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "remoteExec", + "remoteExec", + "", + 0 + }; + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + std::string data; + remoteExecSize += getVariableSize(par, logPacketContent ? &data : nullptr); + remoteExecSize += getVariableSize(arg, logPacketContent ? &data : nullptr); + + r_string name = arg[0]; + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(name.c_str(), name.size()); + + tracy::Profiler::PlotData("remoteExec", remoteExecSize); + return host::functions.invoke_raw_binary(__sqf::binary__remoteexec__any__array__ret__any, par, arg); + }, game_data_type::ANY, game_data_type::ANY, game_data_type::ARRAY); + + static auto _remoteExecCallUn = client::host::register_sqf_command("remoteExecCall", "Profiler redirect", [](game_state& gs, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "remoteExecCall", + "remoteExecCall", + "", + 0 + }; + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + std::string data; + remoteExecSize += getVariableSize(arg, logPacketContent ? &data : nullptr); + + r_string name = arg[0]; + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(name.c_str(), name.size()); + + tracy::Profiler::PlotData("remoteExec", remoteExecSize); + + return client::host::functions.invoke_raw_unary(__sqf::unary__remoteexeccall__array__ret__any, arg); + }, game_data_type::ANY, game_data_type::ARRAY); + + static auto _remoteExecCallBin = client::host::register_sqf_command("remoteExecCall", "Profiler redirect", [](game_state& gs, game_value_parameter par, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "remoteExecCall", + "remoteExecCall", + "", + 0 + }; + + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + std::string data; + remoteExecSize += getVariableSize(par, logPacketContent ? &data : nullptr); + remoteExecSize += getVariableSize(arg, logPacketContent ? &data : nullptr); + + r_string name = arg[0]; + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(name.c_str(), name.size()); + + tracy::Profiler::PlotData("remoteExec", remoteExecSize); + return host::functions.invoke_raw_binary(__sqf::binary__remoteexeccall__any__array__ret__any, par, arg); + }, game_data_type::ANY, game_data_type::ANY, game_data_type::ARRAY); + + static auto _setVariableObj = client::host::register_sqf_command("setVariable", "Profiler redirect", [](game_state& gs, game_value_parameter par, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "setVariable", + "setVariable", + "", + 0 + }; + + if (arg.size() != 3 || arg[2].type_enum() != game_data_type::BOOL || !static_cast(arg[2])) + return host::functions.invoke_raw_binary(__sqf::binary__setvariable__object__array__ret__nothing, par, arg); + + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + std::string data; + setVariableSize += getVariableSize(par, logPacketContent ? &data : nullptr); + setVariableSize += getVariableSize(arg, logPacketContent ? &data : nullptr); + + r_string name = arg[0]; + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(name.c_str(), name.size()); + + tracy::Profiler::PlotData("setVariable", setVariableSize); + return host::functions.invoke_raw_binary(__sqf::binary__setvariable__object__array__ret__nothing, par, arg); + }, game_data_type::NOTHING, game_data_type::OBJECT, game_data_type::ARRAY); + + static auto _setVariableNS = client::host::register_sqf_command("setVariable", "Profiler redirect", [](game_state& gs, game_value_parameter par, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "setVariable", + "setVariable", + "", + 0 + }; + + if (arg.size() != 3 || arg[2].type_enum() != game_data_type::BOOL || !static_cast(arg[2])) + return host::functions.invoke_raw_binary(__sqf::binary__setvariable__namespace__array__ret__nothing, par, arg); + + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + std::string data; + setVariableSize += getVariableSize(par, logPacketContent ? &data : nullptr); + setVariableSize += getVariableSize(arg, logPacketContent ? &data : nullptr); + + r_string name = arg[0]; + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(name.c_str(), name.size()); + + tracy::Profiler::PlotData("setVariable", setVariableSize); + return host::functions.invoke_raw_binary(__sqf::binary__setvariable__namespace__array__ret__nothing, par, arg); + }, game_data_type::NOTHING, game_data_type::NAMESPACE, game_data_type::ARRAY); + + static auto _setVariableLoc = client::host::register_sqf_command("setVariable", "Profiler redirect", [](game_state& gs, game_value_parameter par, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info { + "setVariable", + "setVariable", + "", + 0 + }; + + if (arg.size() != 3 || arg[2].type_enum() != game_data_type::BOOL || !static_cast(arg[2])) + return host::functions.invoke_raw_binary(__sqf::binary__setvariable__location__array__ret__nothing, par, arg); + + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + std::string data; + setVariableSize += getVariableSize(par, logPacketContent ? &data : nullptr); + setVariableSize += getVariableSize(arg, logPacketContent ? &data : nullptr); + + r_string name = arg[0]; + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(name.c_str(), name.size()); + + tracy::Profiler::PlotData("setVariable", setVariableSize); + return host::functions.invoke_raw_binary(__sqf::binary__setvariable__location__array__ret__nothing, par, arg); + }, game_data_type::NOTHING, game_data_type::LOCATION, game_data_type::ARRAY); + + static auto _setVariableGrp = client::host::register_sqf_command("setVariable", "Profiler redirect", [](game_state& gs, game_value_parameter par, game_value_parameter arg) -> game_value { + static tracy::SourceLocationData info{ + "setVariable", + "setVariable", + "", + 0 + }; + + if (arg.size() != 3 || arg[2].type_enum() != game_data_type::BOOL || !static_cast(arg[2])) + return host::functions.invoke_raw_binary(__sqf::binary__setvariable__group__array__ret__nothing, par, arg); + + auto callstack = NetworkProfiler::getCallstackRaw(&gs); + + std::string data; + setVariableSize += getVariableSize(par, logPacketContent ? &data : nullptr); + setVariableSize += getVariableSize(arg, logPacketContent ? &data : nullptr); + + r_string name = arg[0]; + + tracy::ScopedZone zone(&info, tracy::t_withCallstack{}); + AdapterTracy::sendCallstack(callstack); + if (logPacketContent) + zone.Text(data.c_str(), data.size()); + else + zone.Text(name.c_str(), name.size()); + + tracy::Profiler::PlotData("setVariable", setVariableSize); + return host::functions.invoke_raw_binary(__sqf::binary__setvariable__group__array__ret__nothing, par, arg); + }, game_data_type::NOTHING, game_data_type::GROUP, game_data_type::ARRAY); +} + +uint32_t NetworkProfiler::getVariableSize(const game_value& var, std::string* data) { + auto ncnst = const_cast(var); + uint64_t size = 0; + if (data) { + param_archive ar(rv_allocator::create_single(""sv, &size, data)); + + (&ncnst)->serialize(ar); + } else { + param_archive ar(rv_allocator::create_single(""sv, &size)); + + (&ncnst)->serialize(ar); + } + + return size; +} diff --git a/src/NetworkProfiler.hpp b/src/NetworkProfiler.hpp new file mode 100644 index 0000000..5d23b92 --- /dev/null +++ b/src/NetworkProfiler.hpp @@ -0,0 +1,16 @@ +#pragma once +#include +using namespace intercept; +using namespace std::chrono_literals; + +class NetworkProfiler { +public: + void init(); + static inline auto_array> (*getCallstackRaw)(game_state* gs) = nullptr; + static uint32_t getVariableSize(const game_value& var, std::string* data); + static inline int64_t remoteExecSize = 0; + static inline int64_t setVariableSize = 0; + static inline bool logPacketContent = false; +}; + +static inline NetworkProfiler GNetworkProfiler = NetworkProfiler(); \ No newline at end of file diff --git a/src/ProfilerAdapter.hpp b/src/ProfilerAdapter.hpp index 890a339..178a161 100644 --- a/src/ProfilerAdapter.hpp +++ b/src/ProfilerAdapter.hpp @@ -50,4 +50,6 @@ class ProfilerAdapter { bool supportsScheduled = false; bool omitFilePaths = false; AdapterType type = AdapterType::invalid; -}; \ No newline at end of file +}; + +static inline std::shared_ptr GProfilerAdapter; \ No newline at end of file diff --git a/src/scriptProfiler.cpp b/src/scriptProfiler.cpp index 8ebf09f..5dd5df0 100644 --- a/src/scriptProfiler.cpp +++ b/src/scriptProfiler.cpp @@ -18,13 +18,15 @@ #include "AdapterTracy.hpp" #include #include +#include "NetworkProfiler.hpp" +#include using namespace intercept; using namespace std::chrono_literals; std::chrono::high_resolution_clock::time_point startTime; static sqf_script_type GameDataProfileScope_type; -std::shared_ptr GProfilerAdapter; //Needs to be above!! profiler + scriptProfiler profiler{}; bool instructionLevelProfiling = false; @@ -1153,8 +1155,7 @@ void scriptProfiler::preStart() { GProfilerAdapter = std::make_shared(); sqf::diag_log("ASP: Selected Tracy Adapter"sv); } - } - else { + } else { GProfilerAdapter = std::make_shared(); sqf::diag_log("ASP: Selected Tracy Adapter"sv); } @@ -1261,6 +1262,19 @@ void scriptProfiler::preStart() { return res; }, game_data_type::STRING, game_data_type::STRING); } + + if (getCommandLineParam("-profilerNetwork"sv)) { + if (std::dynamic_pointer_cast(GProfilerAdapter)) { + diag_log("ASP: Network statistics enabled"sv); + GNetworkProfiler.init(); + } else { + diag_log("ASP: Network statistics could NOT be enabled because it requires Tracy mode"sv); + } + + } + + + #ifndef __linux__ auto iface = client::host::request_plugin_interface("sqf_asm_devIf", 1); if (iface) { diff --git a/tracy b/tracy index ceb798e..c65f9fb 160000 --- a/tracy +++ b/tracy @@ -1 +1 @@ -Subproject commit ceb798e8c69b44d99f50a78f7225878ac155cd48 +Subproject commit c65f9fba8651afd4097dae47c0a1bce89856e5b7