forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
691
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/Telemetry.cpp
Normal file
691
Kha/Backends/Kinc-hxcpp/khacpp/src/hx/Telemetry.cpp
Normal file
@ -0,0 +1,691 @@
|
||||
#include <hxcpp.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <hx/Debug.h>
|
||||
#include <hx/Thread.h>
|
||||
#include <hx/Telemetry.h>
|
||||
#include <hx/OS.h>
|
||||
|
||||
|
||||
namespace hx
|
||||
{
|
||||
|
||||
|
||||
inline unsigned int __hxt_ptr_id(void* obj)
|
||||
{
|
||||
#if defined(HXCPP_M64)
|
||||
size_t h64 = (size_t)obj;
|
||||
// Note, using >> 1 since Strings can be small, down to 2 bytes, causing collisions
|
||||
return (unsigned int)(h64>>1) ^ (unsigned int)(h64>>32);
|
||||
#else
|
||||
// Note, using >> 1 since Strings can be small, down to 2 bytes, causing collisions
|
||||
return ((unsigned int)obj) >> 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct AllocStackIdMapEntry
|
||||
{
|
||||
int terminationStackId;
|
||||
std::map<int, AllocStackIdMapEntry*> children;
|
||||
};
|
||||
|
||||
|
||||
// Telemetry functionality
|
||||
class Telemetry
|
||||
{
|
||||
public:
|
||||
|
||||
Telemetry(StackContext *inStack, bool profiler_en, bool allocs_en)
|
||||
: mT0(0)
|
||||
{
|
||||
stack = inStack;
|
||||
names.push_back("1-indexed");
|
||||
namesStashed = 1;
|
||||
ignoreAllocs = allocs_en ? 0 : 1;
|
||||
allocStacksStashed = 0;
|
||||
allocStackIdNext = 0;
|
||||
allocStackIdMapRoot.terminationStackId = 0;
|
||||
gcTimer = 0;
|
||||
gcTimerTemp = 0;
|
||||
gcOverhead = 0;
|
||||
_last_obj = 0;
|
||||
|
||||
profiler_enabled = profiler_en;
|
||||
allocations_enabled = profiler_en && allocs_en;
|
||||
|
||||
samples = 0;
|
||||
allocation_data = 0;
|
||||
|
||||
// Push a blank (destroyed on first Dump)
|
||||
Stash();
|
||||
|
||||
// When a profiler exists, the profiler thread needs to exist
|
||||
gThreadMutex.Lock();
|
||||
|
||||
gThreadRefCount += 1;
|
||||
if (gThreadRefCount == 1) {
|
||||
HxCreateDetachedThread(ProfileMainLoop, 0);
|
||||
}
|
||||
|
||||
gThreadMutex.Unlock();
|
||||
}
|
||||
|
||||
~Telemetry()
|
||||
{
|
||||
gThreadMutex.Lock();
|
||||
|
||||
gThreadRefCount -= 1;
|
||||
|
||||
gThreadMutex.Unlock();
|
||||
}
|
||||
|
||||
// todo
|
||||
void attach(StackContext *ctx) { stack = ctx; }
|
||||
void detach() { }
|
||||
|
||||
void StackUpdate(StackFrame *frame);
|
||||
inline void sampleEnter(StackFrame *frame)
|
||||
{
|
||||
StackUpdate(frame);
|
||||
}
|
||||
inline void sampleExit()
|
||||
{
|
||||
StackUpdate(0);
|
||||
}
|
||||
|
||||
void HXTAllocation(void* obj, size_t inSize, const char* type=0);
|
||||
void HXTRealloc(void* old_obj, void* new_obj, int new_Size);
|
||||
|
||||
void Stash()
|
||||
{
|
||||
TelemetryFrame *stash = new TelemetryFrame();
|
||||
|
||||
IgnoreAllocs(1);
|
||||
|
||||
stash->gctime = gcTimer*1000000; // usec
|
||||
gcTimer = 0;
|
||||
|
||||
stash->gcoverhead = gcOverhead*1000000; // usec
|
||||
gcOverhead = 0;
|
||||
|
||||
alloc_mutex.Lock();
|
||||
|
||||
if (_last_obj!=0) lookup_last_object_type();
|
||||
|
||||
stash->allocation_data = allocation_data;
|
||||
stash->samples = samples;
|
||||
|
||||
samples = profiler_enabled ? new std::vector<int>() : 0;
|
||||
if (allocations_enabled) {
|
||||
allocation_data = new std::vector<int>();
|
||||
}
|
||||
|
||||
alloc_mutex.Unlock();
|
||||
|
||||
int i,size;
|
||||
stash->names = 0;
|
||||
if (profiler_enabled) {
|
||||
stash->names = new std::vector<const char*>();
|
||||
size = names.size();
|
||||
for (i=namesStashed; i<size; i++) {
|
||||
stash->names->push_back(names.at(i));
|
||||
}
|
||||
//printf("Stash pushed %d names, %d\n", (size-namesStashed), stash->names->size());
|
||||
namesStashed = names.size();
|
||||
}
|
||||
|
||||
stash->stacks = 0;
|
||||
if (allocations_enabled) {
|
||||
stash->stacks = new std::vector<int>();
|
||||
size = allocStacks.size();
|
||||
for (i=allocStacksStashed; i<size; i++) {
|
||||
stash->stacks->push_back(allocStacks.at(i));
|
||||
}
|
||||
allocStacksStashed = allocStacks.size();
|
||||
}
|
||||
|
||||
gStashMutex.Lock();
|
||||
stashed.push_back(*stash);
|
||||
gStashMutex.Unlock();
|
||||
|
||||
IgnoreAllocs(-1);
|
||||
}
|
||||
|
||||
TelemetryFrame* Dump()
|
||||
{
|
||||
gStashMutex.Lock();
|
||||
if (stashed.size()<1) {
|
||||
gStashMutex.Unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Destroy item that was dumped last call
|
||||
TelemetryFrame *front = &stashed.front();
|
||||
if (front->samples!=0) delete front->samples;
|
||||
if (front->names!=0) delete front->names;
|
||||
if (front->allocation_data!=0) delete front->allocation_data;
|
||||
if (front->stacks!=0) delete front->stacks;
|
||||
//delete front; // delete happens via pop_front:
|
||||
stashed.pop_front(); // Destroy item that was Dumped last call
|
||||
|
||||
front = &stashed.front();
|
||||
gStashMutex.Unlock();
|
||||
|
||||
//printf(" -- dumped stash, allocs=%d, alloc[max]=%d\n", front->allocations->size(), front->allocations->size()>0 ? front->allocations->at(front->allocations->size()-1) : 0);
|
||||
|
||||
return front;
|
||||
}
|
||||
|
||||
void IgnoreAllocs(int delta)
|
||||
{
|
||||
ignoreAllocs += delta;
|
||||
}
|
||||
|
||||
void GCStart()
|
||||
{
|
||||
gcTimerTemp = __hxcpp_time_stamp();
|
||||
}
|
||||
|
||||
void GCEnd()
|
||||
{
|
||||
gcTimer += __hxcpp_time_stamp() - gcTimerTemp;
|
||||
}
|
||||
|
||||
void lookup_last_object_type()
|
||||
{
|
||||
if (_last_obj==0) return;
|
||||
|
||||
const char* type = "_uninitialized";
|
||||
|
||||
int obj_id = __hxt_ptr_id(_last_obj);
|
||||
alloc_mutex.Lock();
|
||||
std::map<void*, hx::Telemetry*>::iterator exist = alloc_map.find(_last_obj);
|
||||
if (exist != alloc_map.end() && _last_obj!=(NULL)) {
|
||||
type = "_unknown";
|
||||
int vtt = _last_obj->__GetType();
|
||||
if (vtt==vtInt || vtt==vtFloat || vtt==vtBool) type = "_non_class";
|
||||
else if (vtt==vtObject ||
|
||||
vtt==vtString ||
|
||||
vtt==vtArray ||
|
||||
vtt==vtClass ||
|
||||
vtt==vtFunction ||
|
||||
vtt==vtEnum ||
|
||||
vtt==vtAbstractBase) {
|
||||
//printf("About to resolve...\n");
|
||||
type = _last_obj->__GetClass()->mName; //__CStr();
|
||||
//printf("Updating last allocation %016lx type to %s\n", _last_obj, type);
|
||||
}
|
||||
}
|
||||
alloc_mutex.Unlock();
|
||||
allocation_data->at(_last_loc+2) = GetNameIdx(type);
|
||||
_last_obj = 0;
|
||||
}
|
||||
|
||||
void reclaim(int id)
|
||||
{
|
||||
if (!allocations_enabled) return;
|
||||
|
||||
allocation_data->push_back(1); // collect flag
|
||||
allocation_data->push_back(id);
|
||||
}
|
||||
|
||||
static void HXTReclaimInternal(void* obj)
|
||||
{
|
||||
int obj_id = __hxt_ptr_id(obj);
|
||||
std::map<void*, hx::Telemetry*>::iterator exist = alloc_map.find(obj);
|
||||
if (exist != alloc_map.end()) {
|
||||
Telemetry* telemetry = exist->second;
|
||||
if (telemetry) {
|
||||
telemetry->reclaim(obj_id);
|
||||
alloc_map.erase(exist);
|
||||
//printf("Tracking collection %016lx, id=%016lx\n", obj, obj_id);
|
||||
} else {
|
||||
printf("HXT ERR: we shouldn't get: Telemetry lookup failed!\n");
|
||||
}
|
||||
} else {
|
||||
// Ignore, assume object was already reclaimed
|
||||
//printf("HXT ERR: we shouldn't get: Reclaim a non-tracked object %016lx, id=%016lx -- was there an object ID collision?\n", obj, obj_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void HXTAfterMark(int gByteMarkID, int ENDIAN_MARK_ID_BYTE)
|
||||
{
|
||||
double t0 = __hxcpp_time_stamp();
|
||||
|
||||
Telemetry* telemetry = 0;
|
||||
alloc_mutex.Lock();
|
||||
std::map<void*, hx::Telemetry*>::iterator iter = alloc_map.begin();
|
||||
while (iter != alloc_map.end()) {
|
||||
void* obj = iter->first;
|
||||
unsigned char mark = ((unsigned char *)obj)[ENDIAN_MARK_ID_BYTE];
|
||||
if ( mark!=gByteMarkID ) {
|
||||
// not marked, deallocated
|
||||
telemetry = iter->second;
|
||||
if (telemetry) {
|
||||
int obj_id = __hxt_ptr_id(obj);
|
||||
telemetry->reclaim(obj_id);
|
||||
}
|
||||
alloc_map.erase(iter++);
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
alloc_mutex.Unlock();
|
||||
|
||||
// Report overhead on one of the telemetry instances
|
||||
// TODO: something better?
|
||||
if (telemetry) {
|
||||
telemetry->gcOverhead += __hxcpp_time_stamp() - t0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void push_callstack_ids_into(std::vector<int> *list);
|
||||
int GetNameIdx(const char *fullName);
|
||||
int ComputeCallStackId();
|
||||
|
||||
static THREAD_FUNC_TYPE ProfileMainLoop(void *)
|
||||
{
|
||||
int millis = 1;
|
||||
|
||||
while (gThreadRefCount > 0) {
|
||||
#ifdef HX_WINDOWS
|
||||
Sleep(millis);
|
||||
#else
|
||||
struct timespec t;
|
||||
struct timespec tmp;
|
||||
t.tv_sec = 0;
|
||||
t.tv_nsec = millis * 1000000;
|
||||
nanosleep(&t, &tmp);
|
||||
#endif
|
||||
|
||||
int count = gProfileClock + 1;
|
||||
gProfileClock = (count < 0) ? 0 : count;
|
||||
}
|
||||
|
||||
THREAD_FUNC_RET
|
||||
}
|
||||
|
||||
StackContext *stack;
|
||||
int mT0;
|
||||
|
||||
std::list<TelemetryFrame> stashed;
|
||||
|
||||
std::map<const char *, int> nameMap;
|
||||
std::vector<const char *> names;
|
||||
std::vector<int> *samples;
|
||||
int namesStashed;
|
||||
|
||||
bool profiler_enabled;
|
||||
bool allocations_enabled;
|
||||
|
||||
std::vector<int> allocStacks;
|
||||
int allocStacksStashed;
|
||||
int allocStackIdNext;
|
||||
AllocStackIdMapEntry allocStackIdMapRoot;
|
||||
|
||||
double gcTimer;
|
||||
double gcTimerTemp;
|
||||
double gcOverhead;
|
||||
|
||||
int ignoreAllocs;
|
||||
|
||||
hx::Object* _last_obj;
|
||||
int _last_loc;
|
||||
|
||||
std::vector<int> *allocation_data;
|
||||
|
||||
static HxMutex gStashMutex;
|
||||
static HxMutex gThreadMutex;
|
||||
static int gThreadRefCount;
|
||||
static int gProfileClock;
|
||||
|
||||
static HxMutex alloc_mutex;
|
||||
static std::map<void*, Telemetry*> alloc_map;
|
||||
};
|
||||
/* static */ HxMutex Telemetry::gStashMutex;
|
||||
/* static */ HxMutex Telemetry::gThreadMutex;
|
||||
/* static */ int Telemetry::gThreadRefCount;
|
||||
/* static */ int Telemetry::gProfileClock;
|
||||
/* static */ HxMutex Telemetry::alloc_mutex;
|
||||
/* static */ std::map<void*, Telemetry*> Telemetry::alloc_map;
|
||||
|
||||
|
||||
|
||||
Telemetry *tlmCreate(StackContext *inStack)
|
||||
{
|
||||
return new Telemetry(inStack, true, false);
|
||||
}
|
||||
|
||||
void tlmDestroy(Telemetry *inTelemetry)
|
||||
{
|
||||
delete inTelemetry;
|
||||
}
|
||||
|
||||
void tlmAttach(Telemetry *inTelemetry, StackContext *inStack)
|
||||
{
|
||||
inTelemetry->attach(inStack);
|
||||
}
|
||||
|
||||
void tlmDetach(Telemetry *inTelemetry)
|
||||
{
|
||||
inTelemetry->detach();
|
||||
}
|
||||
|
||||
void tlmSampleEnter(Telemetry *inTelemetry, StackFrame *inFrame)
|
||||
{
|
||||
inTelemetry->sampleEnter(inFrame);
|
||||
}
|
||||
|
||||
void tlmSampleExit(Telemetry *inTelemetry)
|
||||
{
|
||||
inTelemetry->sampleExit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void hx::Telemetry::push_callstack_ids_into(std::vector<int> *list)
|
||||
{
|
||||
int size = stack->getDepth();
|
||||
for (int i = 0; i < size; i++) {
|
||||
const char *fullName = stack->getFullNameAtDepth(i);
|
||||
list->push_back(GetNameIdx(fullName));
|
||||
}
|
||||
}
|
||||
|
||||
int hx::Telemetry::GetNameIdx(const char *fullName) {
|
||||
int idx = nameMap[fullName];
|
||||
if (idx==0) {
|
||||
idx = names.size();
|
||||
nameMap[fullName] = idx;
|
||||
names.push_back(fullName);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
int hx::Telemetry::ComputeCallStackId() {
|
||||
std::vector<int> callstack;
|
||||
int stackId;
|
||||
|
||||
push_callstack_ids_into(&callstack);
|
||||
int size = callstack.size();
|
||||
|
||||
AllocStackIdMapEntry *asime = &allocStackIdMapRoot;
|
||||
|
||||
int i=0;
|
||||
while (i<size) {
|
||||
int name_id = callstack.at(i++);
|
||||
//printf("Finding child with id=%d, asime now %#010x\n", name_id, asime);
|
||||
std::map<int, AllocStackIdMapEntry*>::iterator lb = asime->children.lower_bound(name_id);
|
||||
|
||||
if (lb != asime->children.end() && !(asime->children.key_comp()(name_id, lb->first)))
|
||||
{ // key already exists
|
||||
asime = lb->second;
|
||||
} else {
|
||||
// the key does not exist in the map, add it
|
||||
AllocStackIdMapEntry *newEntry = new AllocStackIdMapEntry();
|
||||
newEntry->terminationStackId = -1;
|
||||
asime->children.insert(lb, std::map<int, AllocStackIdMapEntry*>::value_type(name_id, newEntry));
|
||||
asime = newEntry;
|
||||
}
|
||||
}
|
||||
|
||||
if (asime->terminationStackId == -1) {
|
||||
// This is a new stackId, store call stack id's in allocStacks
|
||||
stackId = asime->terminationStackId = allocStackIdNext;
|
||||
allocStacks.push_back(size);
|
||||
int i = size-1;
|
||||
while (i>=0) allocStacks.push_back(callstack.at(i--));
|
||||
//printf("new callstackid %d\n", allocStackIdNext);
|
||||
allocStackIdNext++;
|
||||
} else {
|
||||
stackId = asime->terminationStackId;
|
||||
//printf("existing callstackid %d\n", stackId);
|
||||
}
|
||||
|
||||
return stackId;
|
||||
}
|
||||
|
||||
void hx::Telemetry::StackUpdate(StackFrame *pushed_frame)
|
||||
{
|
||||
if (mT0 == gProfileClock || !profiler_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Latch the profile clock and calculate the time since the last profile
|
||||
// clock tick
|
||||
int clock = gProfileClock;
|
||||
int delta = clock - mT0;
|
||||
if (delta < 0) {
|
||||
delta = 1;
|
||||
}
|
||||
mT0 = clock;
|
||||
|
||||
int size = stack->getDepth();
|
||||
|
||||
// Collect function names and callstacks (as indexes into the names vector)
|
||||
samples->push_back(size);
|
||||
push_callstack_ids_into(samples);
|
||||
samples->push_back(delta);
|
||||
}
|
||||
|
||||
void hx::Telemetry::HXTAllocation(void* obj, size_t inSize, const char* type)
|
||||
{
|
||||
if (ignoreAllocs>0 || !allocations_enabled) return;
|
||||
|
||||
// Optionally ignore from extern::cffi - very expensive to track allocs
|
||||
// for every external call, hashes for every SDL event (Lime's
|
||||
// ExternalInterface.external_handler()), etc
|
||||
#ifndef HXCPP_PROFILE_EXTERNS
|
||||
if (stack->getCurrentStackFrame()->position->className==hx::EXTERN_CLASS_NAME) {
|
||||
alloc_mutex.Unlock();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int obj_id = __hxt_ptr_id(obj);
|
||||
|
||||
alloc_mutex.Lock();
|
||||
|
||||
// HXT debug: Check for id collision
|
||||
#ifdef HXCPP_TELEMETRY_DEBUG
|
||||
std::map<void*, hx::Telemetry*>::iterator exist = alloc_map.find(obj);
|
||||
if (exist != alloc_map.end()) {
|
||||
printf("HXT ERR: Object id collision! at on %016lx, id=%016lx\n", obj, obj_id);
|
||||
throw "uh oh";
|
||||
alloc_mutex.Unlock();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int stackid = ComputeCallStackId();
|
||||
|
||||
if (_last_obj!=0) lookup_last_object_type();
|
||||
if (type==0) {
|
||||
_last_obj = (hx::Object*)obj;
|
||||
_last_loc = allocation_data->size();
|
||||
type = "_unresolved";
|
||||
}
|
||||
|
||||
allocation_data->push_back(0); // alloc flag
|
||||
allocation_data->push_back(obj_id);
|
||||
allocation_data->push_back(GetNameIdx(type)); // defer lookup
|
||||
allocation_data->push_back((int)inSize);
|
||||
allocation_data->push_back(stackid);
|
||||
|
||||
alloc_map[obj] = this;
|
||||
|
||||
//__hxcpp_set_hxt_finalizer(obj, (void*)Telemetry::HXTReclaim);
|
||||
|
||||
//printf("Tracking alloc %s at %016lx, id=%016lx, s=%d for telemetry %016lx, ts=%f\n", type, obj, obj_id, inSize, this, __hxcpp_time_stamp());
|
||||
|
||||
alloc_mutex.Unlock();
|
||||
}
|
||||
|
||||
void hx::Telemetry::HXTRealloc(void* old_obj, void* new_obj, int new_size)
|
||||
{
|
||||
if (!allocations_enabled) return;
|
||||
int old_obj_id = __hxt_ptr_id(old_obj);
|
||||
int new_obj_id = __hxt_ptr_id(new_obj);
|
||||
|
||||
alloc_mutex.Lock();
|
||||
|
||||
// Only track reallocations of objects currently known to be allocated
|
||||
std::map<void*, hx::Telemetry*>::iterator exist = alloc_map.find(old_obj);
|
||||
if (exist != alloc_map.end()) {
|
||||
Telemetry* t = exist->second;
|
||||
t->allocation_data->push_back(2); // realloc flag (necessary?)
|
||||
t->allocation_data->push_back(old_obj_id);
|
||||
t->allocation_data->push_back(new_obj_id);
|
||||
t->allocation_data->push_back(new_size);
|
||||
|
||||
//printf("Object at %016lx moving to %016lx, new_size = %d bytes\n", old_obj, new_obj, new_size);
|
||||
|
||||
// HXT debug: Check for id collision
|
||||
#ifdef HXCPP_TELEMETRY_DEBUG
|
||||
std::map<void*, hx::Telemetry*>::iterator exist_new = alloc_map.find(new_obj);
|
||||
if (exist_new != alloc_map.end()) {
|
||||
printf("HXT ERR: Object id collision (reloc)! at on %016lx, id=%016lx\n", (unsigned long)new_obj, (unsigned long)new_obj_id);
|
||||
throw "uh oh";
|
||||
}
|
||||
#endif
|
||||
|
||||
//__hxcpp_set_hxt_finalizer(old_obj, (void*)0); // remove old finalizer -- should GCInternal.InternalRealloc do this?
|
||||
HXTReclaimInternal(old_obj); // count old as reclaimed
|
||||
} else {
|
||||
//printf("Not tracking re-alloc of untracked %016lx, id=%016lx\n", old_obj, old_obj_id);
|
||||
alloc_mutex.Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
alloc_map[new_obj] = this;
|
||||
//__hxcpp_set_hxt_finalizer(new_obj, (void*)HXTReclaim);
|
||||
|
||||
//printf("Tracking re-alloc from %016lx, id=%016lx to %016lx, id=%016lx at %f\n", old_obj, old_obj_id, new_obj, new_obj_id, __hxcpp_time_stamp());
|
||||
|
||||
alloc_mutex.Unlock();
|
||||
}
|
||||
|
||||
} // end namespace hx
|
||||
|
||||
// These globals are called by HXTelemetry.hx
|
||||
|
||||
int __hxcpp_hxt_start_telemetry(bool profiler, bool allocations)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
delete stack->mTelemetry;
|
||||
stack->mTelemetry = new hx::Telemetry(stack, profiler, allocations);
|
||||
return stack->mThreadId;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __hxcpp_hxt_stash_telemetry()
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
// Operates on the current thread, no mutexes needed
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->Stash();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Operates on the socket writer thread
|
||||
TelemetryFrame* __hxcpp_hxt_dump_telemetry(int thread_num)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getStackForId(thread_num);
|
||||
if (!stack || !stack->mTelemetry)
|
||||
return 0;
|
||||
return stack->mTelemetry->Dump();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __hxcpp_hxt_ignore_allocs(int delta)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->IgnoreAllocs(delta);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// These globals are called by other cpp files
|
||||
|
||||
|
||||
|
||||
|
||||
void __hxt_new_string(void* obj, int inSize)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTAllocation(obj, inSize, (const char *)"String");
|
||||
#endif
|
||||
}
|
||||
void __hxt_new_array(void* obj, int inSize)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTAllocation(obj, inSize, (const char *)"Array");
|
||||
#endif
|
||||
}
|
||||
void __hxt_new_hash(void* obj, int inSize)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTAllocation(obj, inSize, (const char *)"Hash");
|
||||
#endif
|
||||
}
|
||||
void __hxt_gc_new(hx::StackContext *stack, void* obj, int inSize, const char* name)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTAllocation(obj, inSize, name);
|
||||
#endif
|
||||
}
|
||||
void __hxt_gc_realloc(void* old_obj, void* new_obj, int new_size)
|
||||
{
|
||||
#ifdef HXCPP_STACK_TRACE
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->HXTRealloc(old_obj, new_obj, new_size);
|
||||
#endif
|
||||
}
|
||||
void __hxt_gc_start()
|
||||
{
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->GCStart();
|
||||
}
|
||||
void __hxt_gc_end()
|
||||
{
|
||||
hx::StackContext *stack = hx::StackContext::getCurrent();
|
||||
if (stack->mTelemetry)
|
||||
stack->mTelemetry->GCEnd();
|
||||
}
|
||||
|
||||
void __hxt_gc_after_mark(int gByteMarkID, int ENDIAN_MARK_ID_BYTE)
|
||||
{
|
||||
hx::Telemetry::HXTAfterMark(gByteMarkID, ENDIAN_MARK_ID_BYTE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user