11#include " EngineProfiling.h"
22#include " ProfilerAdapter.hpp"
33#include " AdapterTracy.hpp"
4+ #include < client.hpp>
5+ #include < shared_mutex>
46
57extern 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;
722std::unordered_map<PCounter*, std::shared_ptr<ScopeInfo>> scopeCache;
23+ std::shared_mutex scopeCacheMtx;
824
925extern " C" {
1026 uintptr_t profEndJmpback;
@@ -13,42 +29,65 @@ extern "C" {
1329
1430 void shouldTime ();
1531 void doEnd ();
32+ void scopeCompleted ();
1633}
1734
1835bool 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
4775void 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
61104HookManager::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+
82141extern " C" {
83142
84143
0 commit comments