godot/thirdparty/bullet/LinearMath/btQuickprof.cpp
Rémi Verschelde b7901c773c
bullet: Sync with upstream 3.17
Stop include Bullet headers using `-isystem` for GCC/Clang as it misleads
SCons into not properly rebuilding all files when headers change.

This means we also need to make sure Bullet builds without warning, and
current version fares fairly well, there were just a couple to fix (patch
included).

Increase minimum version for distro packages to 2.90 (this was never released
as the "next" version after 2.89 was 3.05... but that covers it too).
2021-09-29 16:30:34 +02:00

806 lines
23 KiB
C++

/*
***************************************************************************************************
**
** profile.cpp
**
** Real-Time Hierarchical Profiling for Game Programming Gems 3
**
** by Greg Hjelstrom & Byon Garrabrant
**
***************************************************************************************************/
// Credits: The Clock class was inspired by the Timer classes in
// Ogre (www.ogre3d.org).
#include "btQuickprof.h"
#include "btThreads.h"
#ifdef __CELLOS_LV2__
#include <sys/sys_time.h>
#include <sys/time_util.h>
#include <stdio.h>
#endif
#if defined(SUNOS) || defined(__SUNOS__)
#include <stdio.h>
#endif
#ifdef __APPLE__
#include <mach/mach_time.h>
#include <TargetConditionals.h>
#endif
#if defined(WIN32) || defined(_WIN32)
#define BT_USE_WINDOWS_TIMERS
#define WIN32_LEAN_AND_MEAN
#define NOWINRES
#define NOMCX
#define NOIME
#ifdef _XBOX
#include <Xtl.h>
#else //_XBOX
#include <windows.h>
#if WINVER < 0x0602
#define GetTickCount64 GetTickCount
#endif
#endif //_XBOX
#include <time.h>
#else //_WIN32
#include <sys/time.h>
#ifdef BT_LINUX_REALTIME
//required linking against rt (librt)
#include <time.h>
#endif //BT_LINUX_REALTIME
#endif //_WIN32
#define mymin(a, b) (a > b ? a : b)
struct btClockData
{
#ifdef BT_USE_WINDOWS_TIMERS
LARGE_INTEGER mClockFrequency;
LONGLONG mStartTick;
LARGE_INTEGER mStartTime;
#else
#ifdef __CELLOS_LV2__
uint64_t mStartTime;
#else
#ifdef __APPLE__
uint64_t mStartTimeNano;
#endif
struct timeval mStartTime;
#endif
#endif //__CELLOS_LV2__
};
///The btClock is a portable basic clock that measures accurate time in seconds, use for profiling.
btClock::btClock()
{
m_data = new btClockData;
#ifdef BT_USE_WINDOWS_TIMERS
QueryPerformanceFrequency(&m_data->mClockFrequency);
#endif
reset();
}
btClock::~btClock()
{
delete m_data;
}
btClock::btClock(const btClock& other)
{
m_data = new btClockData;
*m_data = *other.m_data;
}
btClock& btClock::operator=(const btClock& other)
{
*m_data = *other.m_data;
return *this;
}
/// Resets the initial reference time.
void btClock::reset()
{
#ifdef BT_USE_WINDOWS_TIMERS
QueryPerformanceCounter(&m_data->mStartTime);
m_data->mStartTick = GetTickCount64();
#else
#ifdef __CELLOS_LV2__
typedef uint64_t ClockSize;
ClockSize newTime;
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
SYS_TIMEBASE_GET(newTime);
m_data->mStartTime = newTime;
#else
#ifdef __APPLE__
m_data->mStartTimeNano = mach_absolute_time();
#endif
gettimeofday(&m_data->mStartTime, 0);
#endif
#endif
}
/// Returns the time in ms since the last call to reset or since
/// the btClock was created.
unsigned long long int btClock::getTimeMilliseconds()
{
#ifdef BT_USE_WINDOWS_TIMERS
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
LONGLONG elapsedTime = currentTime.QuadPart -
m_data->mStartTime.QuadPart;
// Compute the number of millisecond ticks elapsed.
unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
m_data->mClockFrequency.QuadPart);
return msecTicks;
#else
#ifdef __CELLOS_LV2__
uint64_t freq = sys_time_get_timebase_frequency();
double dFreq = ((double)freq) / 1000.0;
typedef uint64_t ClockSize;
ClockSize newTime;
SYS_TIMEBASE_GET(newTime);
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
return (unsigned long int)((double(newTime - m_data->mStartTime)) / dFreq);
#else
struct timeval currentTime;
gettimeofday(&currentTime, 0);
return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000 +
(currentTime.tv_usec - m_data->mStartTime.tv_usec) / 1000;
#endif //__CELLOS_LV2__
#endif
}
/// Returns the time in us since the last call to reset or since
/// the Clock was created.
unsigned long long int btClock::getTimeMicroseconds()
{
#ifdef BT_USE_WINDOWS_TIMERS
//see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
LARGE_INTEGER currentTime, elapsedTime;
QueryPerformanceCounter(&currentTime);
elapsedTime.QuadPart = currentTime.QuadPart -
m_data->mStartTime.QuadPart;
elapsedTime.QuadPart *= 1000000;
elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart;
return (unsigned long long)elapsedTime.QuadPart;
#else
#ifdef __CELLOS_LV2__
uint64_t freq = sys_time_get_timebase_frequency();
double dFreq = ((double)freq) / 1000000.0;
typedef uint64_t ClockSize;
ClockSize newTime;
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
SYS_TIMEBASE_GET(newTime);
return (unsigned long int)((double(newTime - m_data->mStartTime)) / dFreq);
#else
struct timeval currentTime;
gettimeofday(&currentTime, 0);
return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000000 +
(currentTime.tv_usec - m_data->mStartTime.tv_usec);
#endif //__CELLOS_LV2__
#endif
}
unsigned long long int btClock::getTimeNanoseconds()
{
#ifdef BT_USE_WINDOWS_TIMERS
//see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
LARGE_INTEGER currentTime, elapsedTime;
QueryPerformanceCounter(&currentTime);
elapsedTime.QuadPart = currentTime.QuadPart -
m_data->mStartTime.QuadPart;
elapsedTime.QuadPart *= 1000000000;
elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart;
return (unsigned long long)elapsedTime.QuadPart;
#else
#ifdef __CELLOS_LV2__
uint64_t freq = sys_time_get_timebase_frequency();
double dFreq = ((double)freq) / 1e9;
typedef uint64_t ClockSize;
ClockSize newTime;
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
SYS_TIMEBASE_GET(newTime);
return (unsigned long int)((double(newTime - m_data->mStartTime)) / dFreq);
#else
#ifdef __APPLE__
uint64_t ticks = mach_absolute_time() - m_data->mStartTimeNano;
static long double conversion = 0.0L;
if (0.0L == conversion)
{
// attempt to get conversion to nanoseconds
mach_timebase_info_data_t info;
int err = mach_timebase_info(&info);
if (err)
{
btAssert(0);
conversion = 1.;
}
conversion = info.numer / info.denom;
}
return (ticks * conversion);
#else //__APPLE__
#ifdef BT_LINUX_REALTIME
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return 1000000000 * ts.tv_sec + ts.tv_nsec;
#else
struct timeval currentTime;
gettimeofday(&currentTime, 0);
return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1e9 +
(currentTime.tv_usec - m_data->mStartTime.tv_usec) * 1000;
#endif //BT_LINUX_REALTIME
#endif //__APPLE__
#endif //__CELLOS_LV2__
#endif
}
/// Returns the time in s since the last call to reset or since
/// the Clock was created.
btScalar btClock::getTimeSeconds()
{
static const btScalar microseconds_to_seconds = btScalar(0.000001);
return btScalar(getTimeMicroseconds()) * microseconds_to_seconds;
}
#ifndef BT_NO_PROFILE
static btClock gProfileClock;
inline void Profile_Get_Ticks(unsigned long int* ticks)
{
*ticks = (unsigned long int)gProfileClock.getTimeMicroseconds();
}
inline float Profile_Get_Tick_Rate(void)
{
// return 1000000.f;
return 1000.f;
}
/***************************************************************************************************
**
** CProfileNode
**
***************************************************************************************************/
/***********************************************************************************************
* INPUT: *
* name - pointer to a static string which is the name of this profile node *
* parent - parent pointer *
* *
* WARNINGS: *
* The name is assumed to be a static pointer, only the pointer is stored and compared for *
* efficiency reasons. *
*=============================================================================================*/
CProfileNode::CProfileNode(const char* name, CProfileNode* parent) : Name(name),
TotalCalls(0),
TotalTime(0),
StartTime(0),
RecursionCounter(0),
Parent(parent),
Child(NULL),
Sibling(NULL),
m_userPtr(0)
{
Reset();
}
void CProfileNode::CleanupMemory()
{
delete (Child);
Child = NULL;
delete (Sibling);
Sibling = NULL;
}
CProfileNode::~CProfileNode(void)
{
CleanupMemory();
}
/***********************************************************************************************
* INPUT: *
* name - static string pointer to the name of the node we are searching for *
* *
* WARNINGS: *
* All profile names are assumed to be static strings so this function uses pointer compares *
* to find the named node. *
*=============================================================================================*/
CProfileNode* CProfileNode::Get_Sub_Node(const char* name)
{
// Try to find this sub node
CProfileNode* child = Child;
while (child)
{
if (child->Name == name)
{
return child;
}
child = child->Sibling;
}
// We didn't find it, so add it
CProfileNode* node = new CProfileNode(name, this);
node->Sibling = Child;
Child = node;
return node;
}
void CProfileNode::Reset(void)
{
TotalCalls = 0;
TotalTime = 0.0f;
if (Child)
{
Child->Reset();
}
if (Sibling)
{
Sibling->Reset();
}
}
void CProfileNode::Call(void)
{
TotalCalls++;
if (RecursionCounter++ == 0)
{
Profile_Get_Ticks(&StartTime);
}
}
bool CProfileNode::Return(void)
{
if (--RecursionCounter == 0 && TotalCalls != 0)
{
unsigned long int time;
Profile_Get_Ticks(&time);
time -= StartTime;
TotalTime += (float)time / Profile_Get_Tick_Rate();
}
return (RecursionCounter == 0);
}
/***************************************************************************************************
**
** CProfileIterator
**
***************************************************************************************************/
CProfileIterator::CProfileIterator(CProfileNode* start)
{
CurrentParent = start;
CurrentChild = CurrentParent->Get_Child();
}
void CProfileIterator::First(void)
{
CurrentChild = CurrentParent->Get_Child();
}
void CProfileIterator::Next(void)
{
CurrentChild = CurrentChild->Get_Sibling();
}
bool CProfileIterator::Is_Done(void)
{
return CurrentChild == NULL;
}
void CProfileIterator::Enter_Child(int index)
{
CurrentChild = CurrentParent->Get_Child();
while ((CurrentChild != NULL) && (index != 0))
{
index--;
CurrentChild = CurrentChild->Get_Sibling();
}
if (CurrentChild != NULL)
{
CurrentParent = CurrentChild;
CurrentChild = CurrentParent->Get_Child();
}
}
void CProfileIterator::Enter_Parent(void)
{
if (CurrentParent->Get_Parent() != NULL)
{
CurrentParent = CurrentParent->Get_Parent();
}
CurrentChild = CurrentParent->Get_Child();
}
/***************************************************************************************************
**
** CProfileManager
**
***************************************************************************************************/
CProfileNode gRoots[BT_QUICKPROF_MAX_THREAD_COUNT] = {
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL),
CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL), CProfileNode("Root", NULL)};
CProfileNode* gCurrentNodes[BT_QUICKPROF_MAX_THREAD_COUNT] =
{
&gRoots[0],
&gRoots[1],
&gRoots[2],
&gRoots[3],
&gRoots[4],
&gRoots[5],
&gRoots[6],
&gRoots[7],
&gRoots[8],
&gRoots[9],
&gRoots[10],
&gRoots[11],
&gRoots[12],
&gRoots[13],
&gRoots[14],
&gRoots[15],
&gRoots[16],
&gRoots[17],
&gRoots[18],
&gRoots[19],
&gRoots[20],
&gRoots[21],
&gRoots[22],
&gRoots[23],
&gRoots[24],
&gRoots[25],
&gRoots[26],
&gRoots[27],
&gRoots[28],
&gRoots[29],
&gRoots[30],
&gRoots[31],
&gRoots[32],
&gRoots[33],
&gRoots[34],
&gRoots[35],
&gRoots[36],
&gRoots[37],
&gRoots[38],
&gRoots[39],
&gRoots[40],
&gRoots[41],
&gRoots[42],
&gRoots[43],
&gRoots[44],
&gRoots[45],
&gRoots[46],
&gRoots[47],
&gRoots[48],
&gRoots[49],
&gRoots[50],
&gRoots[51],
&gRoots[52],
&gRoots[53],
&gRoots[54],
&gRoots[55],
&gRoots[56],
&gRoots[57],
&gRoots[58],
&gRoots[59],
&gRoots[60],
&gRoots[61],
&gRoots[62],
&gRoots[63],
};
int CProfileManager::FrameCounter = 0;
unsigned long int CProfileManager::ResetTime = 0;
CProfileIterator* CProfileManager::Get_Iterator(void)
{
int threadIndex = btQuickprofGetCurrentThreadIndex2();
if ((threadIndex < 0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT)
return 0;
return new CProfileIterator(&gRoots[threadIndex]);
}
void CProfileManager::CleanupMemory(void)
{
for (int i = 0; i < BT_QUICKPROF_MAX_THREAD_COUNT; i++)
{
gRoots[i].CleanupMemory();
}
}
/***********************************************************************************************
* CProfileManager::Start_Profile -- Begin a named profile *
* *
* Steps one level deeper into the tree, if a child already exists with the specified name *
* then it accumulates the profiling; otherwise a new child node is added to the profile tree. *
* *
* INPUT: *
* name - name of this profiling record *
* *
* WARNINGS: *
* The string used is assumed to be a static string; pointer compares are used throughout *
* the profiling code for efficiency. *
*=============================================================================================*/
void CProfileManager::Start_Profile(const char* name)
{
int threadIndex = btQuickprofGetCurrentThreadIndex2();
if ((threadIndex < 0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT)
return;
if (name != gCurrentNodes[threadIndex]->Get_Name())
{
gCurrentNodes[threadIndex] = gCurrentNodes[threadIndex]->Get_Sub_Node(name);
}
gCurrentNodes[threadIndex]->Call();
}
/***********************************************************************************************
* CProfileManager::Stop_Profile -- Stop timing and record the results. *
*=============================================================================================*/
void CProfileManager::Stop_Profile(void)
{
int threadIndex = btQuickprofGetCurrentThreadIndex2();
if ((threadIndex < 0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT)
return;
// Return will indicate whether we should back up to our parent (we may
// be profiling a recursive function)
if (gCurrentNodes[threadIndex]->Return())
{
gCurrentNodes[threadIndex] = gCurrentNodes[threadIndex]->Get_Parent();
}
}
/***********************************************************************************************
* CProfileManager::Reset -- Reset the contents of the profiling system *
* *
* This resets everything except for the tree structure. All of the timing data is reset. *
*=============================================================================================*/
void CProfileManager::Reset(void)
{
gProfileClock.reset();
int threadIndex = btQuickprofGetCurrentThreadIndex2();
if ((threadIndex < 0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT)
return;
gRoots[threadIndex].Reset();
gRoots[threadIndex].Call();
FrameCounter = 0;
Profile_Get_Ticks(&ResetTime);
}
/***********************************************************************************************
* CProfileManager::Increment_Frame_Counter -- Increment the frame counter *
*=============================================================================================*/
void CProfileManager::Increment_Frame_Counter(void)
{
FrameCounter++;
}
/***********************************************************************************************
* CProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset *
*=============================================================================================*/
float CProfileManager::Get_Time_Since_Reset(void)
{
unsigned long int time;
Profile_Get_Ticks(&time);
time -= ResetTime;
return (float)time / Profile_Get_Tick_Rate();
}
#include <stdio.h>
void CProfileManager::dumpRecursive(CProfileIterator* profileIterator, int spacing)
{
profileIterator->First();
if (profileIterator->Is_Done())
return;
float accumulated_time = 0, parent_time = profileIterator->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time();
int i;
int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset();
for (i = 0; i < spacing; i++) printf(".");
printf("----------------------------------\n");
for (i = 0; i < spacing; i++) printf(".");
printf("Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time);
float totalTime = 0.f;
int numChildren = 0;
for (i = 0; !profileIterator->Is_Done(); i++, profileIterator->Next())
{
numChildren++;
float current_total_time = profileIterator->Get_Current_Total_Time();
accumulated_time += current_total_time;
float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
{
int i;
for (i = 0; i < spacing; i++) printf(".");
}
printf("%d -- %s (%.2f %%) :: %.3f ms / frame (%d calls)\n", i, profileIterator->Get_Current_Name(), fraction, (current_total_time / (double)frames_since_reset), profileIterator->Get_Current_Total_Calls());
totalTime += current_total_time;
//recurse into children
}
if (parent_time < accumulated_time)
{
//printf("what's wrong\n");
}
for (i = 0; i < spacing; i++) printf(".");
printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:", parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
for (i = 0; i < numChildren; i++)
{
profileIterator->Enter_Child(i);
dumpRecursive(profileIterator, spacing + 3);
profileIterator->Enter_Parent();
}
}
void CProfileManager::dumpAll()
{
CProfileIterator* profileIterator = 0;
profileIterator = CProfileManager::Get_Iterator();
dumpRecursive(profileIterator, 0);
CProfileManager::Release_Iterator(profileIterator);
}
void btEnterProfileZoneDefault(const char* name)
{
}
void btLeaveProfileZoneDefault()
{
}
#else
void btEnterProfileZoneDefault(const char* name)
{
}
void btLeaveProfileZoneDefault()
{
}
#endif //BT_NO_PROFILE
// clang-format off
#if defined(_WIN32) && (defined(__MINGW32__) || defined(__MINGW64__))
#define BT_HAVE_TLS 1
#elif __APPLE__ && !TARGET_OS_IPHONE
// TODO: Modern versions of iOS support TLS now with updated version checking.
#define BT_HAVE_TLS 1
#elif __linux__
#define BT_HAVE_TLS 1
#elif defined(__FreeBSD__) || defined(__NetBSD__)
// TODO: At the moment disabling purposely OpenBSD, albeit tls support exists but not fully functioning
#define BT_HAVE_TLS 1
#endif
// __thread is broken on Andorid clang until r12b. See
// https://github.com/android-ndk/ndk/issues/8
#if defined(__ANDROID__) && defined(__clang__)
#if __has_include(<android/ndk-version.h>)
#include <android/ndk-version.h>
#endif // __has_include(<android/ndk-version.h>)
#if defined(__NDK_MAJOR__) && \
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
#undef BT_HAVE_TLS
#endif
#endif // defined(__ANDROID__) && defined(__clang__)
// clang-format on
unsigned int btQuickprofGetCurrentThreadIndex2()
{
const unsigned int kNullIndex = ~0U;
#if BT_THREADSAFE
return btGetCurrentThreadIndex();
#else
#if defined(BT_HAVE_TLS)
static __thread unsigned int sThreadIndex = kNullIndex;
#elif defined(_WIN32)
__declspec(thread) static unsigned int sThreadIndex = kNullIndex;
#else
unsigned int sThreadIndex = 0;
return -1;
#endif
static int gThreadCounter = 0;
if (sThreadIndex == kNullIndex)
{
sThreadIndex = gThreadCounter++;
}
return sThreadIndex;
#endif //BT_THREADSAFE
}
static btEnterProfileZoneFunc* bts_enterFunc = btEnterProfileZoneDefault;
static btLeaveProfileZoneFunc* bts_leaveFunc = btLeaveProfileZoneDefault;
void btEnterProfileZone(const char* name)
{
(bts_enterFunc)(name);
}
void btLeaveProfileZone()
{
(bts_leaveFunc)();
}
btEnterProfileZoneFunc* btGetCurrentEnterProfileZoneFunc()
{
return bts_enterFunc;
}
btLeaveProfileZoneFunc* btGetCurrentLeaveProfileZoneFunc()
{
return bts_leaveFunc;
}
void btSetCustomEnterProfileZoneFunc(btEnterProfileZoneFunc* enterFunc)
{
bts_enterFunc = enterFunc;
}
void btSetCustomLeaveProfileZoneFunc(btLeaveProfileZoneFunc* leaveFunc)
{
bts_leaveFunc = leaveFunc;
}
CProfileSample::CProfileSample(const char* name)
{
btEnterProfileZone(name);
}
CProfileSample::~CProfileSample(void)
{
btLeaveProfileZone();
}