Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
4f0959a13This file is pinned to the selected release. Download the original to open it in your design tool.
#include "ChromeTraceUtil.h"
#include "b3Clock.h"
#include "LinearMath/btQuickprof.h"
#include "LinearMath/btAlignedObjectArray.h"
#include "Bullet3Common/b3Logging.h"
struct btTiming
{
const char* m_name;
int m_threadId;
unsigned long long int m_usStartTime;
unsigned long long int m_usEndTime;
};
FILE* gTimingFile = 0;
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif //__STDC_FORMAT_MACROS
//see http://stackoverflow.com/questions/18107426/printf-format-for-unsigned-int64-on-windows
#ifndef _WIN32
#include <inttypes.h>
#endif
#define BT_TIMING_CAPACITY 16*65536
static bool m_firstTiming = true;
struct btTimings
{
btTimings()
:m_numTimings(0),
m_activeBuffer(0)
{
}
void flush()
{
for (int i = 0; i<m_numTimings; i++)
{
const char* name = m_timings[m_activeBuffer][i].m_name;
int threadId = m_timings[m_activeBuffer][i].m_threadId;
unsigned long long int startTime = m_timings[m_activeBuffer][i].m_usStartTime;
unsigned long long int endTime = m_timings[m_activeBuffer][i].m_usEndTime;
if (!m_firstTiming)
{
fprintf(gTimingFile, ",\n");
}
m_firstTiming = false;
unsigned long long int startTimeDiv1000 = startTime / 1000;
unsigned long long int endTimeDiv1000 = endTime / 1000;
#if 0
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%" PRIu64 ".123 ,\"ph\":\"B\",\"name\":\"%s\",\"args\":{}},\n",
threadId, startTimeDiv1000, name);
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%" PRIu64 ".234 ,\"ph\":\"E\",\"name\":\"%s\",\"args\":{}}",
threadId, endTimeDiv1000, name);
#else
if (startTime>endTime)
{
endTime = startTime;
}
unsigned int startTimeRem1000 = startTime % 1000;
unsigned int endTimeRem1000 = endTime % 1000;
char startTimeRem1000Str[16];
char endTimeRem1000Str[16];
if (startTimeRem1000<10)
{
sprintf(startTimeRem1000Str, "00%d", startTimeRem1000);
}
else
{
if (startTimeRem1000<100)
{
sprintf(startTimeRem1000Str, "0%d", startTimeRem1000);
}
else
{
sprintf(startTimeRem1000Str, "%d", startTimeRem1000);
}
}
if (endTimeRem1000<10)
{
sprintf(endTimeRem1000Str, "00%d", endTimeRem1000);
}
else
{
if (endTimeRem1000<100)
{
sprintf(endTimeRem1000Str, "0%d", endTimeRem1000);
}
else
{
sprintf(endTimeRem1000Str, "%d", endTimeRem1000);
}
}
char newname[1024];
static int counter2 = 0;
sprintf(newname, "%s%d", name, counter2++);
#ifdef _WIN32
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%I64d.%s ,\"ph\":\"B\",\"name\":\"%s\",\"args\":{}},\n",
threadId, startTimeDiv1000, startTimeRem1000Str, newname);
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%I64d.%s ,\"ph\":\"E\",\"name\":\"%s\",\"args\":{}}",
threadId, endTimeDiv1000, endTimeRem1000Str, newname);
#else
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%" PRIu64 ".%s ,\"ph\":\"B\",\"name\":\"%s\",\"args\":{}},\n",
threadId, startTimeDiv1000, startTimeRem1000Str, newname);
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%" PRIu64 ".%s ,\"ph\":\"E\",\"name\":\"%s\",\"args\":{}}",
threadId, endTimeDiv1000, endTimeRem1000Str, newname);
#endif
#endif
}
m_numTimings = 0;
}
void addTiming(const char* name, int threadId, unsigned long long int startTime, unsigned long long int endTime)
{
if (m_numTimings >= BT_TIMING_CAPACITY)
{
return;
}
if (m_timings[0].size() == 0)
{
m_timings[0].resize(BT_TIMING_CAPACITY);
}
int slot = m_numTimings++;
m_timings[m_activeBuffer][slot].m_name = name;
m_timings[m_activeBuffer][slot].m_threadId = threadId;
m_timings[m_activeBuffer][slot].m_usStartTime = startTime;
m_timings[m_activeBuffer][slot].m_usEndTime = endTime;
}
int m_numTimings;
int m_activeBuffer;
btAlignedObjectArray<btTiming> m_timings[1];
};
#ifndef BT_NO_PROFILE
btTimings gTimings[BT_QUICKPROF_MAX_THREAD_COUNT];
#define MAX_NESTING 1024
int gStackDepths[BT_QUICKPROF_MAX_THREAD_COUNT] = { 0 };
const char* gFuncNames[BT_QUICKPROF_MAX_THREAD_COUNT][MAX_NESTING];
unsigned long long int gStartTimes[BT_QUICKPROF_MAX_THREAD_COUNT][MAX_NESTING];
#endif
btClock clk;
bool gProfileDisabled = true;
void MyDummyEnterProfileZoneFunc(const char* msg)
{
}
void MyDummyLeaveProfileZoneFunc()
{
}
void MyEnterProfileZoneFunc(const char* msg)
{
if (gProfileDisabled)
return;
#ifndef BT_NO_PROFILE
int threadId = btQuickprofGetCurrentThreadIndex2();
if (threadId<0 || threadId >= BT_QUICKPROF_MAX_THREAD_COUNT)
return;
if (gStackDepths[threadId] >= MAX_NESTING)
{
btAssert(0);
return;
}
gFuncNames[threadId][gStackDepths[threadId]] = msg;
gStartTimes[threadId][gStackDepths[threadId]] = clk.getTimeNanoseconds();
if (gStartTimes[threadId][gStackDepths[threadId]] <= gStartTimes[threadId][gStackDepths[threadId] - 1])
{
gStartTimes[threadId][gStackDepths[threadId]] = 1 + gStartTimes[threadId][gStackDepths[threadId] - 1];
}
gStackDepths[threadId]++;
#endif
}
void MyLeaveProfileZoneFunc()
{
if (gProfileDisabled)
return;
#ifndef BT_NO_PROFILE
int threadId = btQuickprofGetCurrentThreadIndex2();
if (threadId<0 || threadId >= BT_QUICKPROF_MAX_THREAD_COUNT)
return;
if (gStackDepths[threadId] <= 0)
{
return;
}
gStackDepths[threadId]--;
const char* name = gFuncNames[threadId][gStackDepths[threadId]];
unsigned long long int startTime = gStartTimes[threadId][gStackDepths[threadId]];
unsigned long long int endTime = clk.getTimeNanoseconds();
gTimings[threadId].addTiming(name, threadId, startTime, endTime);
#endif //BT_NO_PROFILE
}
void b3ChromeUtilsStartTimings()
{
m_firstTiming = true;
gProfileDisabled = false;//true;
b3SetCustomEnterProfileZoneFunc(MyEnterProfileZoneFunc);
b3SetCustomLeaveProfileZoneFunc(MyLeaveProfileZoneFunc);
//also for Bullet 2.x API
btSetCustomEnterProfileZoneFunc(MyEnterProfileZoneFunc);
btSetCustomLeaveProfileZoneFunc(MyLeaveProfileZoneFunc);
}
void b3ChromeUtilsStopTimingsAndWriteJsonFile(const char* fileNamePrefix)
{
b3SetCustomEnterProfileZoneFunc(MyDummyEnterProfileZoneFunc);
b3SetCustomLeaveProfileZoneFunc(MyDummyLeaveProfileZoneFunc);
//also for Bullet 2.x API
btSetCustomEnterProfileZoneFunc(MyDummyEnterProfileZoneFunc);
btSetCustomLeaveProfileZoneFunc(MyDummyLeaveProfileZoneFunc);
char fileName[1024];
static int fileCounter = 0;
sprintf(fileName,"%s_%d.json",fileNamePrefix, fileCounter++);
gTimingFile = fopen(fileName,"w");
if (gTimingFile)
{
fprintf(gTimingFile,"{\"traceEvents\":[\n");
//dump the content to file
for (int i=0;i<BT_QUICKPROF_MAX_THREAD_COUNT;i++)
{
if (gTimings[i].m_numTimings)
{
printf("Writing %d timings for thread %d\n", gTimings[i].m_numTimings, i);
gTimings[i].flush();
}
}
fprintf(gTimingFile,"\n],\n\"displayTimeUnit\": \"ns\"}");
fclose(gTimingFile);
} else
{
b3Printf("Error opening file");
b3Printf(fileName);
}
gTimingFile = 0;
}
void b3ChromeUtilsEnableProfiling()
{
gProfileDisabled = false;
}