Skip to content

Commit 0295ef9

Browse files
committed
Fix up engine profiling
1 parent 7b42006 commit 0295ef9

9 files changed

Lines changed: 194 additions & 75 deletions

src/AdapterBrofiler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ uint32_t getRandColor() {
157157

158158
AdapterBrofiler::AdapterBrofiler() {
159159
type = AdapterType::Brofiler;
160+
161+
static Brofiler::ThreadScope mainThreadScope("Frame");
160162
}
161163

162164

src/AdapterTracy.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class ScopeInfoTracy final: public ScopeInfo {
1616
class ScopeTempStorageTracy final : public ScopeTempStorage {
1717
public:
1818
std::unique_ptr<tracy::ScopedZone> zone;
19+
std::thread::id origin;
1920
};
2021

2122
AdapterTracy::AdapterTracy() {
@@ -50,15 +51,21 @@ std::shared_ptr<ScopeInfo> AdapterTracy::createScope(intercept::types::r_string
5051
std::shared_ptr<ScopeTempStorage> AdapterTracy::enterScope(std::shared_ptr<ScopeInfo> scope) {
5152
auto info = std::dynamic_pointer_cast<ScopeInfoTracy>(scope);
5253
if (!info) return nullptr; //#TODO debugbreak? log error?
54+
ensureReady();
5355

5456
auto ret = std::make_shared<ScopeTempStorageTracy>();
57+
//ret->origin = std::this_thread::get_id();
5558
ret->zone = std::make_unique<tracy::ScopedZone>(&info->info, true);
5659
return ret;
5760
}
5861
void AdapterTracy::leaveScope(std::shared_ptr<ScopeTempStorage> tempStorage) {
5962
auto tmpStorage = std::dynamic_pointer_cast<ScopeTempStorageTracy>(tempStorage);
6063
if (!tmpStorage) return; //#TODO debugbreak? log error?
6164

65+
66+
//if (tmpStorage->origin != std::this_thread::get_id())
67+
// __debugbreak();
68+
6269
tmpStorage->zone.reset(); //zone destructor ends zone
6370
}
6471

@@ -77,3 +84,17 @@ std::shared_ptr<ScopeInfo> AdapterTracy::createScopeStatic(const char* name, con
7784
info->info = tracy::SourceLocationData{nullptr, name, filename,fileline, 0};
7885
return info;
7986
}
87+
88+
bool AdapterTracy::isConnected() {
89+
return tracy::s_profiler.IsConnected();
90+
}
91+
92+
void AdapterTracy::ensureReady() {
93+
if (tracy::s_token.ptr) return;
94+
95+
tracy::rpmalloc_thread_initialize();
96+
tracy::s_token_detail = tracy::moodycamel::ProducerToken(tracy::s_queue);
97+
tracy::s_token = tracy::ProducerWrapper{tracy::s_queue.get_explicit_producer(tracy::s_token_detail) };
98+
99+
100+
}

src/AdapterTracy.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ class AdapterTracy final : public ProfilerAdapter
1818
void setCounter(intercept::types::r_string name, float val) override;
1919

2020
std::shared_ptr<ScopeInfo> createScopeStatic(const char* name, const char* filename, uint32_t fileline);
21-
21+
bool isConnected();
2222

2323
private:
24-
24+
void ensureReady();
2525
using scopeCacheKey = std::tuple<intercept::types::r_string, intercept::types::r_string,uint32_t>;
2626

2727
struct ScopeCacheFastEqual {

src/EngineProfiling.cpp

Lines changed: 91 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
#include "EngineProfiling.h"
22
#include "ProfilerAdapter.hpp"
33
#include "AdapterTracy.hpp"
4+
#include <client.hpp>
5+
#include <shared_mutex>
46

57
extern std::shared_ptr<ProfilerAdapter> GProfilerAdapter;
6-
std::unordered_map<PCounter*, std::shared_ptr<ScopeTempStorage>> openScopes;
8+
9+
10+
struct CounterHasher {
11+
public:
12+
size_t operator()(const std::pair<PCounter*, int>& key) const {
13+
//intercept pairhash
14+
size_t _hash = std::hash<PCounter*>()(key.first);
15+
_hash ^= std::hash<uint64_t>()(key.second) + 0x9e3779b9 + (_hash << 6) + (_hash >> 2);
16+
return _hash;
17+
}
18+
};
19+
20+
thread_local std::unique_ptr<std::unordered_map<std::pair<PCounter*, int>, std::shared_ptr<ScopeTempStorage>, CounterHasher>> openScopes;
21+
thread_local bool openScopesInit;
722
std::unordered_map<PCounter*, std::shared_ptr<ScopeInfo>> scopeCache;
23+
std::shared_mutex scopeCacheMtx;
824

925
extern "C" {
1026
uintptr_t profEndJmpback;
@@ -13,42 +29,65 @@ extern "C" {
1329

1430
void shouldTime();
1531
void doEnd();
32+
void scopeCompleted();
1633
}
1734

1835
bool PCounter::shouldTime() {
36+
if (slot < 0) return false;
37+
//if (!boss) return false;
38+
//if (!boss->da) return false;
39+
//if (!boss->stuffzi) return false;
40+
//if (!boss->stuffzi[slot].enabled) return false;
1941

20-
if (GProfilerAdapter->getType() == AdapterType::Tracy) {
21-
auto tracyProf = std::dynamic_pointer_cast<AdapterTracy>(GProfilerAdapter);
22-
23-
auto found = scopeCache.find(this);
24-
if (found == scopeCache.end()) {
25-
auto res = scopeCache.insert({this, tracyProf->createScopeStatic(name, cat, 0)});
26-
found = res.first;
27-
}
28-
29-
//make sure the add is not inside the scope
30-
openScopes[this] = nullptr;
31-
auto ins = openScopes.find(this);
32-
33-
ins->second = tracyProf->enterScope(found->second);
42+
if (GProfilerAdapter->getType() != AdapterType::Tracy) return false;
43+
44+
auto tracyProf = std::dynamic_pointer_cast<AdapterTracy>(GProfilerAdapter);
45+
if (!tracyProf->isConnected()) return false;
46+
47+
48+
std::shared_lock lock(scopeCacheMtx);
49+
auto found = scopeCache.find(this);
50+
if (found == scopeCache.end()) {
51+
lock.unlock();
52+
std::unique_lock lockInternal(scopeCacheMtx);
53+
auto res = scopeCache.insert({ this, tracyProf->createScopeStatic(name, cat, 0) });
54+
lockInternal.unlock();//#TODO this is unsafe
55+
lock.lock();
56+
found = res.first;
3457
}
3558

59+
if (!openScopes)
60+
openScopes = std::make_unique<std::unordered_map<std::pair<PCounter*, int>, std::shared_ptr<ScopeTempStorage>, CounterHasher>>();
61+
62+
//make sure the add is not inside the scope
63+
auto p = std::make_pair(this, slot);
64+
auto ins = openScopes->insert_or_assign(p,nullptr);
65+
auto tmp = tracyProf->enterScope(found->second);
66+
//if (tmp)
67+
ins.first->second = tmp;
68+
//else
69+
// openScopes.erase(p);
70+
3671

37-
38-
39-
if (slot < 0) return false;
40-
if (!boss) return false;
41-
if (!boss->da) return false;
42-
if (!boss->stuffzi) return false;
43-
if (!boss->stuffzi[slot].enabled) return false;
4472
return true;
4573
}
4674

4775
void ScopeProf::doEnd() {
48-
auto found = openScopes.find(counter);
49-
if (found == openScopes.end()) return;
76+
if (!openScopes || openScopes->empty() || !counter) return;
77+
auto found = openScopes->find({ counter, counter->slot });
78+
if (found == openScopes->end()) return;
79+
GProfilerAdapter->leaveScope(found->second);
80+
openScopes->erase(found);
81+
}
82+
83+
void ArmaProf::scopeCompleted(int64_t start, int64_t end, intercept::types::r_string* stuff, PCounter* counter) {
84+
85+
if (!openScopes || openScopes->empty() || !counter) return;
86+
auto found = openScopes->find({ counter, counter->slot });
87+
if (found == openScopes->end()) return;
5088
GProfilerAdapter->leaveScope(found->second);
51-
openScopes.erase(found);
89+
openScopes->erase(found);
90+
5291
}
5392

5493

@@ -57,28 +96,48 @@ HookManager::Pattern pat_doEnd{
5796
"\x40\x53\x48\x83\xEC\x30\x80\x79\x11\x00\x48\x8B\xD9\x75\x09\x80\x3D\x00\x00\x00\x00\x00\x74\x38\x80\x3D\x00\x00\x00\x00\x00\x74\x0B\x0F\x31\x48\xC1\xE2\x20\x48\x0B\xC2\xEB\x05\xE8\x00\x00\x00\x00\x48\x8B\x13\x4C\x8B\xC0\x48\x8B\x43\x08\x4C\x8D\x4B\x18\x48\x8D\x0D\x00\x00\x00\x00\x48\x89\x44\x24\x00\xE8\x00\x00\x00\x00\x48\x8B\x53\x18\x48\x85\xD2\x74\x1A\xF0\xFF\x0A\x75\x0D\x48\x8B\x0D\x00\x00\x00\x00\x48\x8B\x01\xFF\x50\x18\x48\xC7\x43\x00\x00\x00\x00\x00\x48\x83\xC4\x30\x5B\xC3"
5897
};
5998

99+
HookManager::Pattern pat_scopeCompleted{
100+
"xxxx?xxxx?xxxxxxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx?xxxxxxxx????xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx????xxx????xxxxxx????xxxx?xx????xxx",
101+
"\x48\x89\x5C\x24\x00\x48\x89\x6C\x24\x00\x57\x41\x54\x41\x57\x48\x83\xEC\x20\x48\x8B\x81\x00\x00\x00\x00\x49\x8B\xF8\x4D\x8B\xE1\x48\x3B\xD0\x48\x8B\xD9\x48\x0F\x4C\xD0\x48\xC1\xF8\x04\x48\xC1\xFF\x04\x48\xC1\xFA\x04\x44\x8B\xFA\x2B\xFA\x44\x2B\xF8\x48\x8B\x44\x24\x00\x48\x63\x68\x18\x85\xED\x0F\x88\x00\x00\x00\x00\x8B\x41\x68\x66\x0F\x6E\xC7\x8B\xC8\xD1\xF9\x66\x0F\x6E\xD0\x8B\x43\x6C\x0F\x5B\xC0\x2B\xC1\x66\x0F\x6E\xC8\x0F\x5B\xD2\x42\x8D\x04\x3F\xF3\x0F\x59\xD0\x66\x0F\x6E\xC0\x0F\x5B\xC9\x0F\x5B\xC0\xF3\x0F\x59\xC8\x0F\x2F\xD1\x73\x48\x80\x3B\x00\x0F\x84\x00\x00\x00\x00\x4C\x69\xC5\x00\x00\x00\x00\x4C\x03\x43\x20\x0F\x84\x00\x00\x00\x00\x41\x0F\x0D\x48\x00\x41\xB9\x00\x00\x00\x00\x0F\x1F\x00"
102+
};
60103

61104
HookManager::Pattern pat_shouldTime{
62105
"xxxxxxxxxxxxxxxxxxxxxxxxxx????xxxxxxxxxxxxxxxxxxxx????xxxxxxx",
63106
"\x48\x63\x41\x18\x85\xC0\x78\x32\x4C\x8B\x01\x33\xD2\x4D\x85\xC0\x74\x12\x41\x38\x10\x74\x0D\x48\x69\xC8\x00\x00\x00\x00\x49\x03\x48\x20\xEB\x03\x48\x8B\xCA\x48\x85\xC9\x74\x0A\x38\x51\x4A\x74\x05\xBA\x00\x00\x00\x00\x0F\xB6\xC2\xC3\x32\xC0\xC3"
64107
};
65108

66109

67-
EngineProfiling::EngineProfiling()
68-
{
110+
EngineProfiling::EngineProfiling() {
111+
//order is important
112+
//hooks.placeHook(hookTypes::doEnd, pat_doEnd, reinterpret_cast<uintptr_t>(doEnd), profEndJmpback, 1, true);
113+
hooks.placeHook(hookTypes::scopeCompleted, pat_scopeCompleted, reinterpret_cast<uintptr_t>(scopeCompleted), profEndJmpback, 0);
114+
hooks.placeHook(hookTypes::shouldTime, pat_shouldTime, reinterpret_cast<uintptr_t>(shouldTime), shouldTimeJmpback, 0);
69115

70-
hooks.placeHook(hookTypes::shouldTime, pat_shouldTime, reinterpret_cast<uintptr_t>(shouldTime), shouldTimeJmpback, 0);
71-
hooks.placeHook(hookTypes::doEnd, pat_doEnd, reinterpret_cast<uintptr_t>(doEnd), profEndJmpback, 0);
116+
auto found = hooks.findPattern(pat_doEnd, 0xD);
72117

73118

74-
}
75119

120+
auto stuffByte = found + 0x2 + 2;
121+
uint32_t offs = *((uint32_t*)stuffByte);
122+
uint64_t addr = stuffByte + 4+1 + offs;
123+
uint64_t base = addr - 0x121;
76124

77-
EngineProfiling::~EngineProfiling()
78-
{
125+
armaP = reinterpret_cast<ArmaProf*>(base);
126+
armaP->blip.clear();
127+
armaP->forceCapture = true;
128+
armaP->capture = true;
129+
130+
//disable captureSlowFrame because it can set forceCapture to false
131+
static auto stuff = intercept::client::host::register_sqf_command("diag_captureSlowFrame", "", [](uintptr_t, game_value_parameter) -> game_value
132+
{
133+
return {};
134+
}, game_data_type::NOTHING, game_data_type::ARRAY);
79135
}
80136

81137

138+
EngineProfiling::~EngineProfiling() {}
139+
140+
82141
extern "C" {
83142

84143

src/EngineProfiling.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ class ArmaProf {
4040
friend class PCounter;
4141
public:
4242

43-
void scopeCompleted(int64_t start, int64_t end, intercept::types::r_string* stuff, void* stuff2);
43+
__declspec(noinline) void scopeCompleted(int64_t start, int64_t end, intercept::types::r_string* stuff, PCounter* stuff2);
4444

4545

46-
private:
46+
public:
4747
//This is engine stuff.
4848
bool da,db,dc;
4949
int dd,df;
@@ -78,7 +78,11 @@ class ArmaProf {
7878
int blios;
7979
intercept::types::r_string blip;
8080
float blop;
81-
bool asd,adasd;
81+
82+
float dummy, dummy2, dummy3;//no idea what dis is.. Stuff above is probably wrong somewhere
83+
84+
bool forceCapture;
85+
bool capture;
8286
int stuffiz;
8387

8488
int64_t framestart;
@@ -99,6 +103,6 @@ class EngineProfiling {
99103
EngineProfiling();
100104
~EngineProfiling();
101105

102-
106+
ArmaProf* armaP;
103107
HookManager hooks;
104108
};

src/HookManager.cpp

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ HookManager::HookManager() {
1212
engineSize = static_cast<uintptr_t>(modInfo.SizeOfImage);
1313
}
1414

15-
bool HookManager::placeHook(hookTypes type, const Pattern& pat, uintptr_t jmpTo, uintptr_t & jmpBackRef, uint8_t jmpBackOffset) {
15+
bool HookManager::placeHook(hookTypes type, const Pattern& pat, uintptr_t jmpTo, uintptr_t & jmpBackRef, uint8_t jmpBackOffset, bool taintRax) {
1616

1717
auto found = findPattern(pat);
1818
if (found == 0) {
@@ -21,7 +21,7 @@ bool HookManager::placeHook(hookTypes type, const Pattern& pat, uintptr_t jmpTo,
2121
//#endif
2222
return false;
2323
}
24-
jmpBackRef = placeHookTotalOffs(found, jmpTo) + jmpBackOffset;
24+
jmpBackRef = placeHookTotalOffs(found, jmpTo, taintRax) + jmpBackOffset;
2525
return true;
2626
}
2727

@@ -42,7 +42,7 @@ uintptr_t HookManager::placeHook(uintptr_t offset, uintptr_t jmpTo, uint8_t jmpB
4242
return placeHookTotalOffs(totalOffset, jmpTo) + jmpBackOffset;
4343
}
4444

45-
uintptr_t HookManager::placeHookTotalOffs(uintptr_t totalOffset, uintptr_t jmpTo) {
45+
uintptr_t HookManager::placeHookTotalOffs(uintptr_t totalOffset, uintptr_t jmpTo, bool taintRax) {
4646
DWORD dwVirtualProtectBackup;
4747

4848

@@ -53,19 +53,50 @@ uintptr_t HookManager::placeHookTotalOffs(uintptr_t totalOffset, uintptr_t jmpTo
5353
64bit
5454
FF 25 64bit relative
5555
*/
56-
#ifdef X64
56+
#ifdef _WIN64
5757
//auto distance = std::max(totalOffset, jmpTo) - std::min(totalOffset, jmpTo);
5858
// if distance < 2GB (2147483648) we could use the 32bit relative jmp
59-
VirtualProtect(reinterpret_cast<LPVOID>(totalOffset), 14u, 0x40u, &dwVirtualProtectBackup);
60-
auto jmpInstr = reinterpret_cast<unsigned char*>(totalOffset);
61-
auto addrOffs = reinterpret_cast<uint32_t*>(totalOffset + 1);
62-
*jmpInstr = 0x68; //push DWORD
63-
*addrOffs = static_cast<uint32_t>(jmpTo) /*- totalOffset - 6*/;//offset
64-
*reinterpret_cast<uint32_t*>(totalOffset + 5) = 0x042444C7; //MOV [RSP+4],
65-
*reinterpret_cast<uint32_t*>(totalOffset + 9) = static_cast<uint64_t>(jmpTo) >> 32;//DWORD
66-
*reinterpret_cast<unsigned char*>(totalOffset + 13) = 0xc3;//ret
67-
VirtualProtect(reinterpret_cast<LPVOID>(totalOffset), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup);
68-
return totalOffset + 14;
59+
60+
61+
if (taintRax) {
62+
//This is shorter, but messes up RAX
63+
64+
/*
65+
push rax; //to restore it inside out target
66+
moveabs rax, address
67+
push rax
68+
ret
69+
*/
70+
71+
VirtualProtect(reinterpret_cast<LPVOID>(totalOffset), 12u, 0x40u, &dwVirtualProtectBackup);
72+
auto memberRax = reinterpret_cast<unsigned char*>(totalOffset);
73+
auto jmpInstr1 = reinterpret_cast<unsigned char*>(totalOffset+1);
74+
auto jmpInstr2 = reinterpret_cast<unsigned char*>(totalOffset+2);
75+
auto addrOffs = reinterpret_cast<uint64_t*>(totalOffset + 3);
76+
*memberRax = 0x50; //push rax
77+
*jmpInstr1 = 0x48; //moveabs
78+
*jmpInstr2 = 0xb8; //into rax
79+
*addrOffs = static_cast<uint64_t>(jmpTo) /*- totalOffset - 6*/;//offset
80+
81+
auto pushInstr = reinterpret_cast<unsigned char*>(totalOffset + 11);
82+
*pushInstr = 0x50; //push rax
83+
*reinterpret_cast<unsigned char*>(totalOffset + 12) = 0xc3;//ret
84+
VirtualProtect(reinterpret_cast<LPVOID>(totalOffset), 12u, dwVirtualProtectBackup, &dwVirtualProtectBackup);
85+
return totalOffset + 12;
86+
} else {
87+
VirtualProtect(reinterpret_cast<LPVOID>(totalOffset), 14u, 0x40u, &dwVirtualProtectBackup);
88+
auto jmpInstr = reinterpret_cast<unsigned char*>(totalOffset);
89+
auto addrOffs = reinterpret_cast<uint32_t*>(totalOffset + 1);
90+
*jmpInstr = 0x68; //push DWORD
91+
*addrOffs = static_cast<uint32_t>(jmpTo) /*- totalOffset - 6*/;//offset
92+
*reinterpret_cast<uint32_t*>(totalOffset + 5) = 0x042444C7; //MOV [RSP+4],
93+
*reinterpret_cast<uint32_t*>(totalOffset + 9) = static_cast<uint64_t>(jmpTo) >> 32;//DWORD
94+
*reinterpret_cast<unsigned char*>(totalOffset + 13) = 0xc3;//ret
95+
VirtualProtect(reinterpret_cast<LPVOID>(totalOffset), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup);
96+
return totalOffset + 14;
97+
}
98+
99+
69100
#else
70101
VirtualProtect(reinterpret_cast<LPVOID>(totalOffset), 5u, 0x40u, &dwVirtualProtectBackup);
71102
auto jmpInstr = reinterpret_cast<unsigned char *>(totalOffset);

src/HookManager.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
enum class hookTypes {
1111
shouldTime, //FrameEnd/FrameStart
1212
doEnd,
13+
scopeCompleted,
1314
End
1415
};
1516

@@ -30,10 +31,10 @@ class HookManager {//Implementation in dllmain
3031

3132

3233
HookManager();
33-
bool placeHook(hookTypes, const Pattern& pat, uintptr_t jmpTo, uintptr_t& jmpBackRef, uint8_t jmpBackOffset = 0);
34+
bool placeHook(hookTypes, const Pattern& pat, uintptr_t jmpTo, uintptr_t& jmpBackRef, uint8_t jmpBackOffset = 0, bool taintRax = false);
3435
bool placeHook(hookTypes, const Pattern& pat, uintptr_t jmpTo);
3536
uintptr_t placeHook(uintptr_t offset, uintptr_t jmpTo, uint8_t jmpBackOffset = 0);
36-
uintptr_t placeHookTotalOffs(uintptr_t offset, uintptr_t jmpTo);
37+
uintptr_t placeHookTotalOffs(uintptr_t offset, uintptr_t jmpTo, bool taintRax = false);
3738
bool MatchPattern(uintptr_t addr, const char* pattern, const char* mask);
3839
uintptr_t findPattern(const char* pattern, const char* mask, uintptr_t offset = 0);
3940
uintptr_t findPattern(const Pattern& pat, uintptr_t offset = 0);

0 commit comments

Comments
 (0)