From 83848ad41c3855ba64fb142f32c24028d9c042d7 Mon Sep 17 00:00:00 2001 From: Dedmen Miller Date: Wed, 23 Jan 2019 12:54:21 +0100 Subject: [PATCH] Add optional instruction level profiling --- src/scriptProfiler.cpp | 168 +++++++++++++++++++++++++++-------------- 1 file changed, 111 insertions(+), 57 deletions(-) diff --git a/src/scriptProfiler.cpp b/src/scriptProfiler.cpp index 098bfa6..c4918f4 100644 --- a/src/scriptProfiler.cpp +++ b/src/scriptProfiler.cpp @@ -15,7 +15,7 @@ using namespace std::chrono_literals; static sqf_script_type GameDataProfileScope_type; std::shared_ptr GProfilerAdapter; //Needs to be above!! profiler scriptProfiler profiler{}; - +bool instructionLevelProfiling = false; class GameDataProfileScope : public game_data { @@ -581,7 +581,7 @@ game_value callExtensionRedirect(uintptr_t st, game_value_parameter ext, game_va } -std::string getCommandLineParam(std::string_view needle) { +std::optional getCommandLineParam(std::string_view needle) { std::string commandLine = GetCommandLineA(); auto found = commandLine.find(needle); if (found != std::string::npos) { @@ -597,21 +597,26 @@ std::string getCommandLineParam(std::string_view needle) { scriptProfiler::scriptProfiler() { std::string commandLine = GetCommandLineA(); + + if (getCommandLineParam("-profilerEnableInstruction"sv)) { + instructionLevelProfiling = true; + } + auto startAdapter = getCommandLineParam("-profilerAdapter"sv); - if (!startAdapter.empty()) { - if (startAdapter == "Chrome"sv) { + if (startAdapter) { + if (*startAdapter == "Chrome"sv) { auto chromeAdapter = std::make_shared(); GProfilerAdapter = chromeAdapter; auto chromeOutput = getCommandLineParam("-profilerOutput"sv); - if (!chromeOutput.empty()) - chromeAdapter->setTargetFile(chromeOutput); - } else if (startAdapter == "Brofiler"sv) { + if (chromeOutput) + chromeAdapter->setTargetFile(*chromeOutput); + } else if (*startAdapter == "Brofiler"sv) { GProfilerAdapter = std::make_shared(); - } else if (startAdapter == "Arma"sv) { + } else if (*startAdapter == "Arma"sv) { GProfilerAdapter = std::make_shared(); - } else if (startAdapter == "Tracy"sv) { + } else if (*startAdapter == "Tracy"sv) { GProfilerAdapter = std::make_shared(); } } else { @@ -719,15 +724,27 @@ namespace intercept::__internal { class GameInstructionVariable : public game_instruction { public: r_string name; + static inline std::unordered_map> descriptions; virtual bool exec(game_state& state, vm_context& t) { - //static const r_string InstrName = "I_Variable"sv; - //static Brofiler::EventDescription* autogenerated_description = ::Brofiler::EventDescription::Create(InstrName, __FILE__, __LINE__); - //Brofiler::Event autogenerated_event_639(*autogenerated_description); - // - //if (autogenerated_event_639.data) - // autogenerated_event_639.data->altName = name; - typedef bool(__thiscall *OrigEx)(game_instruction*, game_state&, vm_context&); + + if (instructionLevelProfiling) { + static r_string setVar("getVar"); + + auto found = descriptions.find(reinterpret_cast(name.data())); + if (found == descriptions.end()) { + + auto newStuff = GProfilerAdapter->createScope(setVar,name,0); + auto ret = descriptions.insert({reinterpret_cast(name.data()), newStuff}); + found = ret.first; + } + + auto temp = GProfilerAdapter->enterScope(found->second); + auto res = reinterpret_cast(oldFunc.vt_GameInstructionVariable)(this, state, t); + GProfilerAdapter->leaveScope(temp); + return res; + } + return reinterpret_cast(oldFunc.vt_GameInstructionVariable)(this, state, t); } virtual int stack_size(void* t) const { return 0; } @@ -738,7 +755,7 @@ class GameInstructionOperator : public game_instruction { public: const intercept::__internal::game_operators *_operators; - //static inline std::map descriptions; + static inline std::unordered_map> descriptions; virtual bool exec(game_state& state, vm_context& t) { /* @@ -772,7 +789,26 @@ class GameInstructionOperator : public game_instruction { } */ + typedef bool(__thiscall *OrigEx)(game_instruction*, game_state&, vm_context&); + + if (instructionLevelProfiling) { + auto instructionName = _operators->_name; + + auto found = descriptions.find(reinterpret_cast(instructionName.data())); + if (found == descriptions.end()) { + + auto newStuff = GProfilerAdapter->createScope(instructionName,{},0); + auto ret = descriptions.insert({reinterpret_cast(instructionName.data()), newStuff}); + found = ret.first; + } + + auto temp = GProfilerAdapter->enterScope(found->second); + auto res = reinterpret_cast(oldFunc.vt_GameInstructionOperator)(this, state, t); + GProfilerAdapter->leaveScope(temp); + return res; + } + return reinterpret_cast(oldFunc.vt_GameInstructionOperator)(this, state, t); } virtual int stack_size(void* t) const { return 0; } @@ -783,23 +819,29 @@ class GameInstructionFunction : public game_instruction { public: const intercept::__internal::game_functions *_functions; - //static inline std::map descriptions; + static inline std::unordered_map> descriptions; virtual bool exec(game_state& state, vm_context& t) { - //auto found = descriptions.find(_functions->_name.data()); - //if (found == descriptions.end()) { - // found = descriptions.insert({ _functions->_name.data(),::Brofiler::EventDescription::Create(_functions->_name, __FILE__, __LINE__) }).first; - //} - // - ////static const r_string InstrName = "I_Function"sv; - ////static Brofiler::EventDescription* autogenerated_description = ::Brofiler::EventDescription::Create(InstrName, __FILE__, __LINE__); - //Brofiler::Event autogenerated_event_639(*(found->second)); - // - //if (autogenerated_event_639.data) - // autogenerated_event_639.data->sourceCode = t.sdoc._content; + typedef bool(__thiscall *OrigEx)(game_instruction*, game_state&, vm_context&); + + if (instructionLevelProfiling) { + auto instructionName = _functions->_name; + + auto found = descriptions.find(reinterpret_cast(instructionName.data())); + if (found == descriptions.end()) { + + auto newStuff = GProfilerAdapter->createScope(instructionName,{},0); + auto ret = descriptions.insert({reinterpret_cast(instructionName.data()), newStuff}); + found = ret.first; + } + + auto temp = GProfilerAdapter->enterScope(found->second); + auto res = reinterpret_cast(oldFunc.vt_GameInstructionFunction)(this, state, t); + GProfilerAdapter->leaveScope(temp); + return res; + } - typedef bool(__thiscall *OrigEx)(game_instruction*, game_state&, vm_context&); return reinterpret_cast(oldFunc.vt_GameInstructionFunction)(this, state, t); } virtual int stack_size(void* t) const { return 0; } @@ -825,15 +867,27 @@ class GameInstructionAssignment : public game_instruction { public: r_string name; bool forceLocal; + static inline std::unordered_map> descriptions; virtual bool exec(game_state& state, vm_context& t) { - //static const r_string InstrName = "I_Assignment"sv; - //static Brofiler::EventDescription* autogenerated_description = ::Brofiler::EventDescription::Create(InstrName, __FILE__, __LINE__); - //Brofiler::Event autogenerated_event_639(*autogenerated_description); - // - //if (autogenerated_event_639.data) - // autogenerated_event_639.data->altName = name; - typedef bool(__thiscall *OrigEx)(game_instruction*, game_state&, vm_context&); + + if (instructionLevelProfiling) { + static r_string setVar("assignVar"); + + auto found = descriptions.find(reinterpret_cast(name.data())); + if (found == descriptions.end()) { + + auto newStuff = GProfilerAdapter->createScope(setVar,name,0); + auto ret = descriptions.insert({reinterpret_cast(name.data()), newStuff}); + found = ret.first; + } + + auto temp = GProfilerAdapter->enterScope(found->second); + auto res = reinterpret_cast(oldFunc.vt_GameInstructionAssignment)(this, state, t); + GProfilerAdapter->leaveScope(temp); + return res; + } + return reinterpret_cast(oldFunc.vt_GameInstructionAssignment)(this, state, t); } virtual int stack_size(void* t) const { return 0; } @@ -910,7 +964,7 @@ void scriptProfiler::preStart() { GVt = *static_cast(*iface); DWORD dwVirtualProtectBackup; - + //#TODO only do if instruction profiling startparameter is present game_instruction* ins; //ins = new GameInstructionConst(); //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionConst), 14u, 0x40u, &dwVirtualProtectBackup); @@ -919,13 +973,13 @@ void scriptProfiler::preStart() { //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionConst), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); //delete ins; // - //ins = new GameInstructionVariable(); - //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionVariable), 14u, 0x40u, &dwVirtualProtectBackup); - //oldFunc.vt_GameInstructionVariable = GVt.vt_GameInstructionVariable[3]; - //GVt.vt_GameInstructionVariable[3] = (*reinterpret_cast(ins))[3]; - //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionVariable), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); - //delete ins; - // + ins = new GameInstructionVariable(); + VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionVariable), 14u, 0x40u, &dwVirtualProtectBackup); + oldFunc.vt_GameInstructionVariable = GVt.vt_GameInstructionVariable[3]; + GVt.vt_GameInstructionVariable[3] = (*reinterpret_cast(ins))[3]; + VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionVariable), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); + delete ins; + ins = new GameInstructionOperator(); VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionOperator), 14u, 0x40u, &dwVirtualProtectBackup); oldFunc.vt_GameInstructionOperator = GVt.vt_GameInstructionOperator[3]; @@ -933,12 +987,12 @@ void scriptProfiler::preStart() { VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionOperator), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); delete ins; - //ins = new GameInstructionFunction(); - //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionFunction), 14u, 0x40u, &dwVirtualProtectBackup); - //oldFunc.vt_GameInstructionFunction = GVt.vt_GameInstructionFunction[3]; - //GVt.vt_GameInstructionFunction[3] = (*reinterpret_cast(ins))[3]; - //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionFunction), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); - //delete ins; + ins = new GameInstructionFunction(); + VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionFunction), 14u, 0x40u, &dwVirtualProtectBackup); + oldFunc.vt_GameInstructionFunction = GVt.vt_GameInstructionFunction[3]; + GVt.vt_GameInstructionFunction[3] = (*reinterpret_cast(ins))[3]; + VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionFunction), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); + delete ins; //ins = new GameInstructionArray(); //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionArray), 14u, 0x40u, &dwVirtualProtectBackup); @@ -947,12 +1001,12 @@ void scriptProfiler::preStart() { //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionArray), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); //delete ins; // - //ins = new GameInstructionAssignment(); - //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionAssignment), 14u, 0x40u, &dwVirtualProtectBackup); - //oldFunc.vt_GameInstructionAssignment = GVt.vt_GameInstructionAssignment[3]; - //GVt.vt_GameInstructionAssignment[3] = (*reinterpret_cast(ins))[3]; - //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionAssignment), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); - //delete ins; + ins = new GameInstructionAssignment(); + VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionAssignment), 14u, 0x40u, &dwVirtualProtectBackup); + oldFunc.vt_GameInstructionAssignment = GVt.vt_GameInstructionAssignment[3]; + GVt.vt_GameInstructionAssignment[3] = (*reinterpret_cast(ins))[3]; + VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionAssignment), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); + delete ins; //ins = new GameInstructionNewExpression(); //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionNewExpression), 14u, 0x40u, &dwVirtualProtectBackup);