Recast: add dedicated double-precission time type

The library used signed 32bit integers and single precission floating points to represent build times, but on long build times this will overflow. Added a dedicated time type while promoting it to double precission and adjusting all use cases throughout the library.
This commit is contained in:
Kawe Mazidjatari 2024-11-03 12:25:11 +01:00
parent b41141018e
commit 7c3509fd34
13 changed files with 68 additions and 66 deletions

View File

@ -827,11 +827,11 @@ void CrowdToolState::updateTick(const float dt)
dtCrowd* crowd = m_editor->getCrowd();
if (!nav || !crowd) return;
TimeVal startTime = getPerfTime();
rdTimeType startTime = getPerfTime();
crowd->update(dt, &m_agentDebug);
TimeVal endTime = getPerfTime();
rdTimeType endTime = getPerfTime();
// Update agent trails
for (int i = 0; i < crowd->getAgentCount(); ++i)

View File

@ -22,22 +22,22 @@ void BuildContext::doResetLog()
m_textPoolSize = 0;
}
void BuildContext::doLog(const rcLogCategory category, const char* msg, const int len)
void BuildContext::doLog(const rcLogCategory category, const char* msg, const rdSizeType len)
{
if (!len) return;
if (m_messageCount >= MAX_MESSAGES)
return;
char* dst = &m_textPool[m_textPoolSize];
int n = TEXT_POOL_SIZE - m_textPoolSize;
const rdSizeType n = TEXT_POOL_SIZE - m_textPoolSize;
if (n < 2)
return;
char* cat = dst;
char* text = dst+1;
const int maxtext = n-1;
const rdSizeType maxtext = n-1;
// Store category
*cat = (char)category;
// Store message
const int count = rdMin(len+1, maxtext);
const rdSizeType count = rdMin(len+1, maxtext);
memcpy(text, msg, count);
text[count-1] = '\0';
m_textPoolSize += 1 + count;
@ -46,7 +46,7 @@ void BuildContext::doLog(const rcLogCategory category, const char* msg, const in
void BuildContext::doResetTimers()
{
for (int i = 0; i < RC_MAX_TIMERS; ++i)
for (rdSizeType i = 0; i < RC_MAX_TIMERS; ++i)
m_accTime[i] = -1;
}
@ -57,15 +57,15 @@ void BuildContext::doStartTimer(const rcTimerLabel label)
void BuildContext::doStopTimer(const rcTimerLabel label)
{
const TimeVal endTime = getPerfTime();
const TimeVal deltaTime = endTime - m_startTime[label];
const rdTimeType endTime = getPerfTime();
const rdTimeType deltaTime = endTime - m_startTime[label];
if (m_accTime[label] == -1)
m_accTime[label] = deltaTime;
else
m_accTime[label] += deltaTime;
}
int BuildContext::doGetAccumulatedTime(const rcTimerLabel label) const
rdTimeType BuildContext::doGetAccumulatedTime(const rcTimerLabel label) const
{
return getPerfTimeUsec(m_accTime[label]);
}
@ -80,16 +80,16 @@ void BuildContext::dumpLog(const char* format, ...)
printf("\n");
// Print messages
const int TAB_STOPS[4] = { 28, 36, 44, 52 };
const rdSizeType TAB_STOPS[4] = { 28, 36, 44, 52 };
for (int i = 0; i < m_messageCount; ++i)
{
const char* msg = m_messages[i]+1;
int n = 0;
rdSizeType n = 0;
while (*msg)
{
if (*msg == '\t')
{
int count = 1;
rdSizeType count = 1;
for (int j = 0; j < 4; ++j)
{
if (n < TAB_STOPS[j])
@ -120,7 +120,7 @@ int BuildContext::getLogCount() const
return m_messageCount;
}
const char* BuildContext::getLogText(const int i) const
const char* BuildContext::getLogText(const rdSizeType i) const
{
return m_messages[i]+1;
}

View File

@ -23,19 +23,19 @@
// Win32
#include <windows.h>
TimeVal getPerfTime()
rdTimeType getPerfTime()
{
__int64 count;
rdTimeType count;
QueryPerformanceCounter((LARGE_INTEGER*)&count);
return count;
}
int getPerfTimeUsec(const TimeVal duration)
rdTimeType getPerfTimeUsec(const rdTimeType duration)
{
static __int64 freq = 0;
static rdTimeType freq = 0;
if (freq == 0)
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
return (int)(duration*1000000 / freq);
return (rdTimeType)(duration*1000000 / freq);
}
#else
@ -44,16 +44,16 @@ int getPerfTimeUsec(const TimeVal duration)
#include <sys/time.h>
TimeVal getPerfTime()
rdTimeType getPerfTime()
{
timeval now;
gettimeofday(&now, 0);
return (TimeVal)now.tv_sec*1000000L + (TimeVal)now.tv_usec;
return (rdTimeType)now.tv_sec*1000000L + (rdTimeType)now.tv_usec;
}
int getPerfTimeUsec(const TimeVal duration)
rdTimeType getPerfTimeUsec(const rdTimeType duration)
{
return (int)duration;
return duration;
}
#endif

View File

@ -209,13 +209,13 @@ void TestCase::doTests(dtNavMesh* navmesh, dtNavMeshQuery* navquery)
filter.setExcludeFlags(iter->excludeFlags);
// Find start points
TimeVal findNearestPolyStart = getPerfTime();
rdTimeType findNearestPolyStart = getPerfTime();
dtPolyRef startRef, endRef;
navquery->findNearestPoly(iter->spos, polyPickExt, &filter, &startRef, iter->nspos);
navquery->findNearestPoly(iter->epos, polyPickExt, &filter, &endRef, iter->nepos);
TimeVal findNearestPolyEnd = getPerfTime();
rdTimeType findNearestPolyEnd = getPerfTime();
iter->findNearestPolyTime += getPerfTimeUsec(findNearestPolyEnd - findNearestPolyStart);
if (!startRef || ! endRef)
@ -224,21 +224,21 @@ void TestCase::doTests(dtNavMesh* navmesh, dtNavMeshQuery* navquery)
if (iter->type == TEST_PATHFIND)
{
// Find path
TimeVal findPathStart = getPerfTime();
rdTimeType findPathStart = getPerfTime();
navquery->findPath(startRef, endRef, iter->spos, iter->epos, &filter, polys, &iter->npolys, MAX_POLYS);
TimeVal findPathEnd = getPerfTime();
rdTimeType findPathEnd = getPerfTime();
iter->findPathTime += getPerfTimeUsec(findPathEnd - findPathStart);
// Find straight path
if (iter->npolys)
{
TimeVal findStraightPathStart = getPerfTime();
rdTimeType findStraightPathStart = getPerfTime();
navquery->findStraightPath(iter->spos, iter->epos, polys, jumps, iter->npolys,
straight, 0, 0, 0, &iter->nstraight, MAX_POLYS);
TimeVal findStraightPathEnd = getPerfTime();
rdTimeType findStraightPathEnd = getPerfTime();
iter->findStraightPathTime += getPerfTimeUsec(findStraightPathEnd - findStraightPathStart);
}
@ -266,11 +266,11 @@ void TestCase::doTests(dtNavMesh* navmesh, dtNavMeshQuery* navquery)
iter->straight[1] = iter->spos[1];
iter->straight[2] = iter->spos[2];
TimeVal findPathStart = getPerfTime();
rdTimeType findPathStart = getPerfTime();
navquery->raycast(startRef, iter->spos, iter->epos, &filter, &t, hitNormal, polys, &iter->npolys, MAX_POLYS);
TimeVal findPathEnd = getPerfTime();
rdTimeType findPathEnd = getPerfTime();
iter->findPathTime += getPerfTimeUsec(findPathEnd - findPathStart);
if (t > 1)
@ -302,14 +302,14 @@ void TestCase::doTests(dtNavMesh* navmesh, dtNavMeshQuery* navquery)
printf("Test Results:\n");
int n = 0;
rdSizeType n = 0;
for (Test* iter = m_tests; iter; iter = iter->next)
{
const int total = iter->findNearestPolyTime + iter->findPathTime + iter->findStraightPathTime;
printf(" - Path %02d: %.4f ms\n", n, (float)total/1000.0f);
printf(" - poly: %.4f ms\n", (float)iter->findNearestPolyTime/1000.0f);
printf(" - path: %.4f ms\n", (float)iter->findPathTime/1000.0f);
printf(" - straight: %.4f ms\n", (float)iter->findStraightPathTime/1000.0f);
const rdTimeType total = iter->findNearestPolyTime + iter->findPathTime + iter->findStraightPathTime;
printf(" - Path %02zd: %.4f ms\n", n, (double)total/1000.0);
printf(" - poly: %.4f ms\n", (double)iter->findNearestPolyTime/1000.0);
printf(" - path: %.4f ms\n", (double)iter->findPathTime/1000.0);
printf(" - straight: %.4f ms\n", (double)iter->findStraightPathTime/1000.0);
n++;
}
}
@ -421,7 +421,7 @@ bool TestCase::handleRenderOverlay(double* proj, double* model, int* view)
n = 0;
for (Test* iter = m_tests; iter; iter = iter->next)
{
const int total = iter->findNearestPolyTime + iter->findPathTime + iter->findStraightPathTime;
const rdTimeType total = iter->findNearestPolyTime + iter->findPathTime + iter->findStraightPathTime;
snprintf(text, sizeof(text), "Path %d %.4f ms", n, (float)total / 1000.0f);
if (ImGui::CollapsingHeader(text))

View File

@ -29,15 +29,15 @@
/// Recast build context.
class BuildContext : public rcContext
{
TimeVal m_startTime[RC_MAX_TIMERS];
TimeVal m_accTime[RC_MAX_TIMERS];
rdTimeType m_startTime[RC_MAX_TIMERS];
rdTimeType m_accTime[RC_MAX_TIMERS];
static const int MAX_MESSAGES = 1000;
const char* m_messages[MAX_MESSAGES];
int m_messageCount;
static const int TEXT_POOL_SIZE = 8000;
char m_textPool[TEXT_POOL_SIZE];
int m_textPoolSize;
rdSizeType m_textPoolSize;
public:
BuildContext();
@ -47,17 +47,17 @@ public:
/// Returns number of log messages.
int getLogCount() const;
/// Returns log message text.
const char* getLogText(const int i) const;
const char* getLogText(const rdSizeType i) const;
protected:
/// Virtual functions for custom implementations.
///@{
virtual void doResetLog();
virtual void doLog(const rcLogCategory category, const char* msg, const int len);
virtual void doLog(const rcLogCategory category, const char* msg, const rdSizeType len);
virtual void doResetTimers();
virtual void doStartTimer(const rcTimerLabel label);
virtual void doStopTimer(const rcTimerLabel label);
virtual int doGetAccumulatedTime(const rcTimerLabel label) const;
virtual rdTimeType doGetAccumulatedTime(const rcTimerLabel label) const;
///@}
};

View File

@ -53,7 +53,7 @@ protected:
float m_lastBuiltTileBmin[3];
float m_lastBuiltTileBmax[3];
float m_totalBuildTimeMs;
double m_totalBuildTimeMs;
bool m_drawActiveTile;
bool m_keepInterResults;
@ -78,7 +78,7 @@ protected:
struct FastLZCompressor* m_tcomp;
struct MeshProcess* m_tmproc;
float m_cacheBuildTimeMs;
double m_cacheBuildTimeMs;
int m_cacheCompressedSize;
int m_cacheRawSize;
int m_cacheLayerCount;

View File

@ -33,7 +33,7 @@ protected:
int m_maxTiles;
int m_maxPolysPerTile;
float m_tileBuildTime;
double m_tileBuildTime;
float m_tileMemUsage;
int m_tileTriCount;

View File

@ -19,14 +19,9 @@
#ifndef PERFTIMER_H
#define PERFTIMER_H
#ifdef __GNUC__
#include <stdint.h>
typedef int64_t TimeVal;
#else
typedef __int64 TimeVal;
#endif
#include "Recast/Shared/Include/SharedDefs.h"
TimeVal getPerfTime();
int getPerfTimeUsec(const TimeVal duration);
rdTimeType getPerfTime();
rdTimeType getPerfTimeUsec(const rdTimeType duration);
#endif // PERFTIMER_H

View File

@ -73,9 +73,9 @@ class TestCase
dtPolyRef* polys;
int npolys;
int findNearestPolyTime;
int findPathTime;
int findStraightPathTime;
rdTimeType findNearestPolyTime;
rdTimeType findPathTime;
rdTimeType findStraightPathTime;
Test* next;
private:

View File

@ -30,7 +30,7 @@ bool duReadContourSet(struct rcContourSet& cset, duFileIO* io);
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io);
bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io);
void duLogBuildTimes(rcContext& ctx, const int totalTileUsec);
void duLogBuildTimes(rcContext& ctx, const rdTimeType totalTileUsec);
#endif // RECAST_DUMP_H

View File

@ -404,16 +404,16 @@ bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
}
static void logLine(rcContext& ctx, rcTimerLabel label, const char* name, const float pc)
static void logLine(rcContext& ctx, rcTimerLabel label, const char* name, const double pc)
{
const int t = ctx.getAccumulatedTime(label);
const rdTimeType t = ctx.getAccumulatedTime(label);
if (t < 0) return;
ctx.log(RC_LOG_PROGRESS, "%s:\t%.2fms\t(%.1f%%)", name, t/1000.0f, t*pc);
}
void duLogBuildTimes(rcContext& ctx, const int totalTimeUsec)
void duLogBuildTimes(rcContext& ctx, const rdTimeType totalTimeUsec)
{
const float pc = 100.0f / totalTimeUsec;
const double pc = 100.0f / totalTimeUsec;
ctx.log(RC_LOG_PROGRESS, "Build Times");
logLine(ctx, RC_TIMER_RASTERIZE_TRIANGLES, "- Rasterize", pc);

View File

@ -152,7 +152,7 @@ public:
/// Returns the total accumulated time of the specified performance timer.
/// @param label The category of the timer.
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; }
inline rdTimeType getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; }
protected:
/// Clears all log entries.
@ -162,7 +162,7 @@ protected:
/// @param[in] category The category of the message.
/// @param[in] msg The formatted message.
/// @param[in] len The length of the formatted message.
virtual void doLog(const rcLogCategory category, const char* msg, const int len) { rdIgnoreUnused(category); rdIgnoreUnused(msg); rdIgnoreUnused(len); }
virtual void doLog(const rcLogCategory category, const char* msg, const rdSizeType len) { rdIgnoreUnused(category); rdIgnoreUnused(msg); rdIgnoreUnused(len); }
/// Clears all timers. (Resets all to unused.)
virtual void doResetTimers() {}
@ -178,7 +178,7 @@ protected:
/// Returns the total accumulated time of the specified performance timer.
/// @param[in] label The category of the timer.
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
virtual int doGetAccumulatedTime(const rcTimerLabel label) const { rdIgnoreUnused(label); return -1; }
virtual rdTimeType doGetAccumulatedTime(const rcTimerLabel label) const { rdIgnoreUnused(label); return -1; }
/// True if logging is enabled.
bool m_logEnabled;

View File

@ -19,6 +19,13 @@
#ifndef RECASTDETOURDEFS_H
#define RECASTDETOURDEFS_H
#if defined(__GNUC__) || defined(__clang__)
#include <stdint.h>
typedef int64_t rdTimeType;
#else
typedef __int64 rdTimeType;
#endif
/// Signed to avoid warnings when comparing to int loop indexes, and common error with comparing to zero.
/// MSVC2010 has a bug where ssize_t is unsigned (!!!).
typedef intptr_t rdSizeType;