目录

include/AK/Tools/Win32/AkPlatformFuncs.h

Go to the documentation of this file.
00001 
00002 //
00003 // AkPlatformFuncs.h
00004 //
00005 // Audiokinetic platform-dependent functions definition.
00006 //
00007 // Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
00008 //
00010 
00011 #ifndef _AK_PLATFORM_FUNCS_H_
00012 #define _AK_PLATFORM_FUNCS_H_
00013 
00014 #include "malloc.h"
00015 #include <AK/Tools/Common/AkAssert.h>
00016 #include <AK/SoundEngine/Common/AkTypes.h>
00017 #include <windows.h>
00018 //#define AK_ENABLE_PERF_RECORDING
00019 #if defined(AK_ENABLE_PERF_RECORDING)
00020 #include <stdio.h>
00021 #endif
00022 
00023 #ifdef AK_USE_THREAD_EMULATION
00024     #include <AK/Tools/Win32/ThreadEmulation.h>
00025 #endif
00026 
00027 #if defined(_WIN64)
00028 // on 64 bit, removes warning C4985: 'ceil': attributes not present on previous declaration.
00029 // see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=294649
00030 #include <math.h>
00031 #endif // _WIN64
00032 #include <intrin.h>
00033 
00034 //-----------------------------------------------------------------------------
00035 // Platform-specific thread properties definition.
00036 //-----------------------------------------------------------------------------
00037 struct AkThreadProperties
00038 {
00039     int                 nPriority;      
00040     AkUInt32            dwAffinityMask; 
00041     AkUInt32            uStackSize;     
00042 };
00043 
00044 //-----------------------------------------------------------------------------
00045 // External variables.
00046 //-----------------------------------------------------------------------------
00047 // g_fFreqRatio is used by time helpers to return time values in milliseconds.
00048 // It is declared and updated by the sound engine.
00049 namespace AK
00050 {
00051     extern AkReal32 g_fFreqRatio;
00052 }
00053 
00054 //-----------------------------------------------------------------------------
00055 // Defines for Win32.
00056 //-----------------------------------------------------------------------------
00057 #define AK_DECLARE_THREAD_ROUTINE( FuncName )   DWORD WINAPI FuncName(LPVOID lpParameter)
00058 #define AK_THREAD_RETURN( _param_ )             return (_param_);
00059 #define AK_THREAD_ROUTINE_PARAMETER             lpParameter
00060 #define AK_GET_THREAD_ROUTINE_PARAMETER_PTR(type) reinterpret_cast<type*>( AK_THREAD_ROUTINE_PARAMETER )
00061 #define AK_RETURN_THREAD_OK                     0x00000000
00062 #define AK_RETURN_THREAD_ERROR                  0x00000001
00063 #if defined AK_CPU_X86_64
00064 #define AK_DEFAULT_STACK_SIZE                   (65536)
00065 #else
00066 #define AK_DEFAULT_STACK_SIZE                   (32768)
00067 #endif
00068 #define AK_THREAD_PRIORITY_NORMAL               THREAD_PRIORITY_NORMAL
00069 #define AK_THREAD_PRIORITY_ABOVE_NORMAL         THREAD_PRIORITY_ABOVE_NORMAL
00070 
00071 // NULL objects
00072 #define AK_NULL_THREAD                          NULL
00073 
00074 #define AK_INFINITE                             INFINITE
00075 
00076 #define AkMakeLong(a,b)                         MAKELONG((a),(b))
00077 
00078 #define AkMax(x1, x2)   (((x1) > (x2))? (x1): (x2))
00079 #define AkMin(x1, x2)   (((x1) < (x2))? (x1): (x2))
00080 #define AkClamp(x, min, max)  ((x) < (min)) ? (min) : (((x) > (max) ? (max) : (x)))
00081 
00082 namespace AKPLATFORM
00083 {
00084     // Simple automatic event API
00085     // ------------------------------------------------------------------
00086     
00088     inline void AkClearEvent( AkEvent & out_event )
00089     {
00090         out_event = NULL;
00091     }
00092 
00094     inline AKRESULT AkCreateEvent( AkEvent & out_event )
00095     {
00096 #ifdef AK_USE_METRO_API
00097         out_event = CreateEventEx(nullptr, nullptr, 0, STANDARD_RIGHTS_ALL|EVENT_MODIFY_STATE);
00098 #else
00099         out_event = ::CreateEvent( NULL,                    // No security attributes
00100                                     false,                  // Reset type: automatic
00101                                     false,                  // Initial signaled state: not signaled
00102                                     NULL                    // No name
00103                                    );
00104 #endif
00105         return ( out_event ) ? AK_Success : AK_Fail;
00106     }
00107 
00109     inline void AkDestroyEvent( AkEvent & io_event )
00110     {
00111         if ( io_event )
00112             ::CloseHandle( io_event );
00113         io_event = NULL;
00114     }
00115 
00117     inline void AkWaitForEvent( AkEvent & in_event )
00118     {
00119 #ifdef AK_USE_METRO_API
00120 #ifdef AK_ENABLE_ASSERTS
00121         DWORD dwWaitResult = 
00122 #endif // AK_ENABLE_ASSERTS
00123             ::WaitForSingleObjectEx( in_event, INFINITE, FALSE );
00124         AKASSERT( dwWaitResult == WAIT_OBJECT_0 );
00125 #else
00126         AKVERIFY( ::WaitForSingleObject( in_event, INFINITE ) == WAIT_OBJECT_0 );
00127 #endif
00128     }
00129 
00131     inline void AkSignalEvent( const AkEvent & in_event )
00132     {
00133         AKVERIFY( ::SetEvent( in_event ) );
00134     }
00135 
00136     
00137     // Atomic Operations
00138     // ------------------------------------------------------------------
00139 
00141     inline AkInt32 AkInterlockedIncrement( AkInt32 * pValue )
00142     {
00143         return InterlockedIncrement( pValue );
00144     }
00145 
00147     inline AkInt32 AkInterlockedDecrement( AkInt32 * pValue )
00148     {
00149         return InterlockedDecrement( pValue );
00150     }
00151 
00152 #ifdef AK_CPU_X86_64
00153     inline bool AkInterlockedCompareExchange( volatile AkInt64* io_pDest, AkInt64 in_newValue, AkInt64 in_expectedOldVal )
00154     {
00155         return _InterlockedCompareExchange64(io_pDest, in_newValue, in_expectedOldVal) == in_expectedOldVal;
00156     }
00157 #endif
00158 
00159     inline bool AkInterlockedCompareExchange( volatile AkInt32* io_pDest, AkInt32 in_newValue, AkInt32 in_expectedOldVal )
00160     {
00161         return InterlockedCompareExchange(io_pDest, in_newValue, in_expectedOldVal) == in_expectedOldVal;
00162     }
00163 
00164 #if defined AK_CPU_X86 || defined AK_CPU_ARM
00165     inline bool AkInterlockedCompareExchange( volatile AkIntPtr* io_pDest, AkIntPtr in_newValue, AkIntPtr in_expectedOldVal )
00166     {
00167         return InterlockedCompareExchange((volatile LONG_PTR*)io_pDest, (LONG_PTR)in_newValue, (LONG_PTR)in_expectedOldVal) == in_expectedOldVal;
00168     }
00169 #endif      
00170 
00171     //Ensure that all write operations are complete.  Necessary only on platforms that don't garentee the order of writes.
00172     inline void AkMemoryBarrier() 
00173     {
00174         _ReadWriteBarrier();
00175     }
00176 
00177     // Threads
00178     // ------------------------------------------------------------------
00179 
00181     inline bool AkIsValidThread( AkThread * in_pThread )
00182     {
00183         return (*in_pThread != AK_NULL_THREAD);
00184     }
00185 
00187     inline void AkClearThread( AkThread * in_pThread )
00188     {
00189         *in_pThread = AK_NULL_THREAD;
00190     }
00191 
00193     inline void AkCloseThread( AkThread * in_pThread )
00194     {
00195         AKASSERT( in_pThread );
00196         AKASSERT( *in_pThread );
00197         AKVERIFY( ::CloseHandle( *in_pThread ) );
00198         AkClearThread( in_pThread );
00199     }
00200 
00201 #define AkExitThread( _result ) return _result;
00202 
00204     inline void AkGetDefaultThreadProperties( AkThreadProperties & out_threadProperties )
00205     {
00206         out_threadProperties.nPriority = AK_THREAD_PRIORITY_NORMAL;
00207         out_threadProperties.uStackSize= AK_DEFAULT_STACK_SIZE;
00208         out_threadProperties.dwAffinityMask = 0;
00209     }
00210 
00212     inline void AkSetThreadName( DWORD in_dwThreadID, LPCSTR in_szThreadName )
00213     {
00214 #if defined AK_USE_THREAD_EMULATION
00215         UNREFERENCED_PARAMETER( in_dwThreadID );
00216         UNREFERENCED_PARAMETER( in_szThreadName );
00217 #else
00218         const DWORD MS_VC_EXCEPTION=0x406D1388;
00219 
00220 #pragma pack(push,8)
00221         typedef struct tagTHREADNAME_INFO
00222         {
00223             DWORD dwType;
00224             LPCSTR szName;
00225             DWORD dwThreadID;
00226             DWORD dwFlags;
00227         } THREADNAME_INFO;
00228 #pragma pack(pop)
00229 
00230         THREADNAME_INFO info;
00231         info.dwType = 0x1000;
00232         info.szName = in_szThreadName;
00233         info.dwThreadID = in_dwThreadID;
00234         info.dwFlags = 0;
00235 
00236         __try
00237         {
00238             RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
00239         }
00240 #pragma warning(suppress: 6312 6322)
00241         __except(EXCEPTION_CONTINUE_EXECUTION)
00242         {
00243         }
00244 #endif
00245     }
00246 
00248     inline void AkCreateThread( 
00249         AkThreadRoutine pStartRoutine,                  // Thread routine.
00250         void * pParams,                                 // Routine params.
00251         const AkThreadProperties & in_threadProperties, // Properties. NULL for default.
00252         AkThread * out_pThread,                         // Returned thread handle.
00253         const char * in_szThreadName )                      // Opt thread name.
00254     {
00255         AKASSERT( out_pThread != NULL );
00256         AKASSERT( (in_threadProperties.nPriority >= THREAD_PRIORITY_LOWEST && in_threadProperties.nPriority <= THREAD_PRIORITY_HIGHEST)
00257             || ( in_threadProperties.nPriority == THREAD_PRIORITY_TIME_CRITICAL ) );
00258 
00259 #ifdef AK_USE_THREAD_EMULATION
00260         UNREFERENCED_PARAMETER( in_threadProperties );
00261         UNREFERENCED_PARAMETER( in_szThreadName );
00262        *out_pThread = AK::ThreadEmulation::CreateThread( pStartRoutine,                   // Thread start routine
00263                                        pParams,                         // Thread function parameter
00264                                        0 );                             // Creation flags: create running
00265 #else
00266         DWORD dwThreadID;
00267         *out_pThread = ::CreateThread( NULL,                            // No security attributes
00268                                        in_threadProperties.uStackSize,  // StackSize (0 uses system default)
00269                                        pStartRoutine,                   // Thread start routine
00270                                        pParams,                         // Thread function parameter
00271                                        0,                               // Creation flags: create running
00272                                        &dwThreadID );
00273 
00274         // ::CreateThread() return NULL if it fails.
00275         if ( !*out_pThread )
00276         {
00277             AkClearThread( out_pThread );
00278             return;
00279         }
00280 
00281         // Set thread name.
00282         AkSetThreadName( dwThreadID, in_szThreadName );
00283 
00284         // Set properties.
00285         if ( !::SetThreadPriority( *out_pThread, in_threadProperties.nPriority ) )
00286         {
00287             AKASSERT( !"Failed setting IO thread priority" );
00288             AkCloseThread( out_pThread );
00289             return;
00290         }
00291         if ( in_threadProperties.dwAffinityMask )
00292         {
00293 #ifndef AK_XBOXONE_ADK
00294             if ( !::SetThreadAffinityMask( *out_pThread, in_threadProperties.dwAffinityMask ) )
00295             {
00296                 AKASSERT( !"Failed setting IO thread affinity mask" );
00297                 AkCloseThread( out_pThread );
00298             }
00299 #endif
00300         }
00301 #endif
00302     }
00303 
00305     inline void AkWaitForSingleThread( AkThread * in_pThread )
00306     {
00307         AKASSERT( in_pThread );
00308         AKASSERT( *in_pThread );
00309 #ifdef AK_USE_METRO_API
00310         ::WaitForSingleObjectEx( *in_pThread, INFINITE, FALSE );
00311 #else
00312         ::WaitForSingleObject( *in_pThread, INFINITE );
00313 #endif
00314     }
00315 
00317     inline AkThreadID CurrentThread()
00318     {
00319         return ::GetCurrentThreadId();
00320     }
00321 
00323     inline void AkSleep( AkUInt32 in_ulMilliseconds )
00324     {
00325 #ifdef AK_USE_THREAD_EMULATION
00326         AK::ThreadEmulation::Sleep( in_ulMilliseconds );
00327 #else
00328 		::Sleep( in_ulMilliseconds );
00329 #endif
00330     }
00331 
00332     // Optimized memory functions
00333     // --------------------------------------------------------------------
00334 
00336     inline void AkMemCpy( void * pDest, const void * pSrc, AkUInt32 uSize )
00337     {
00338         memcpy( pDest, pSrc, uSize );
00339     }
00340 
00342     inline void AkMemSet( void * pDest, AkInt32 iVal, AkUInt32 uSize )
00343     {
00344         memset( pDest, iVal, uSize );
00345     }
00346 
00347     // Time functions
00348     // ------------------------------------------------------------------
00349 
00351     inline void PerformanceCounter( AkInt64 * out_piLastTime )
00352     {
00353         ::QueryPerformanceCounter( (LARGE_INTEGER*)out_piLastTime );
00354     }
00355 
00357     inline void PerformanceFrequency( AkInt64 * out_piFreq )
00358     {
00359         ::QueryPerformanceFrequency( (LARGE_INTEGER*)out_piFreq );
00360     }
00361 
00363     inline void UpdatePerformanceFrequency()
00364     {
00365         AkInt64 iFreq;
00366         PerformanceFrequency( &iFreq );
00367         AK::g_fFreqRatio = (AkReal32)( iFreq / 1000 );
00368     }
00369 
00371     inline AkReal32 Elapsed( const AkInt64 & in_iNow, const AkInt64 & in_iStart )
00372     {
00373         return ( in_iNow - in_iStart ) / AK::g_fFreqRatio;
00374     }
00375 
00377     inline AkInt32 AkWideCharToChar( const wchar_t* in_pszUnicodeString,
00378                                      AkUInt32   in_uiOutBufferSize,
00379                                      char*  io_pszAnsiString )
00380     {
00381         int iWritten = ::WideCharToMultiByte(CP_ACP,                                                                    // code page
00382                                     0,                                                                      // performance and mapping flags
00383                                     in_pszUnicodeString,                                                    // wide-character string
00384                                     (int)AkMin( ( (AkUInt32)wcslen( in_pszUnicodeString )), in_uiOutBufferSize-1 ), // number of chars in string : -1 = NULL terminated string.
00385                                     io_pszAnsiString,                                                       // buffer for new string
00386                                     in_uiOutBufferSize,                                                     // size of buffer
00387                                     NULL,                                                                   // default for unmappable chars
00388                                     NULL);                                                                  // set when default char used
00389         io_pszAnsiString[iWritten] = 0;
00390         return iWritten;
00391     }
00392 
00394     inline AkInt32 AkCharToWideChar( const char*    in_pszAnsiString,
00395                                      AkUInt32       in_uiOutBufferSize,
00396                                      void*          io_pvUnicodeStringBuffer )
00397     {
00398         return ::MultiByteToWideChar(   CP_ACP,                             // code page
00399                                         0,                                  // performance and mapping flags
00400                                         in_pszAnsiString,                   // wide-character string
00401                                         -1,                                 // number of chars in string : -1 = NULL terminated string.
00402                                         (wchar_t*)io_pvUnicodeStringBuffer, // buffer for new string
00403                                         in_uiOutBufferSize);                // size of buffer
00404     }
00405 
00407     inline AkInt32 AkUtf8ToWideChar( const char*    in_pszUtf8String,
00408                                      AkUInt32       in_uiOutBufferSize,
00409                                      void*          io_pvUnicodeStringBuffer )
00410     {
00411         return ::MultiByteToWideChar(   CP_UTF8,                            // code page
00412                                         0,                                  // performance and mapping flags
00413                                         in_pszUtf8String,                   // wide-character string
00414                                         -1,                                 // number of chars in string : -1 = NULL terminated string.
00415                                         (wchar_t*)io_pvUnicodeStringBuffer, // buffer for new string
00416                                         in_uiOutBufferSize);                // size of buffer
00417     }
00418 
00420     inline void SafeStrCpy( wchar_t * in_pDest, const wchar_t* in_pSrc, size_t in_uDestMaxNumChars )
00421     {
00422         size_t iSizeCopy = AkMin( in_uDestMaxNumChars - 1, wcslen( in_pSrc ) + 1 );
00423         wcsncpy_s( in_pDest, in_uDestMaxNumChars, in_pSrc, iSizeCopy );
00424         in_pDest[iSizeCopy] = '\0';
00425     }
00426 
00428     inline void SafeStrCpy( char * in_pDest, const char* in_pSrc, size_t in_uDestMaxNumChars )
00429     {
00430         size_t iSizeCopy = AkMin( in_uDestMaxNumChars - 1, strlen( in_pSrc ) + 1 );
00431         strncpy_s( in_pDest, in_uDestMaxNumChars, in_pSrc, iSizeCopy );
00432         in_pDest[iSizeCopy] = '\0';
00433     }
00434 
00436     inline void SafeStrCat( wchar_t * in_pDest, const wchar_t* in_pSrc, size_t in_uDestMaxNumChars )
00437     {
00438         int iAvailableSize = (int)( in_uDestMaxNumChars - wcslen( in_pDest ) - 1 );
00439         wcsncat_s( in_pDest, in_uDestMaxNumChars, in_pSrc, AkMin( iAvailableSize, (int)wcslen( in_pSrc ) ) );
00440     }
00441 
00443     inline void SafeStrCat( char * in_pDest, const char* in_pSrc, size_t in_uDestMaxNumChars )
00444     {
00445         int iAvailableSize = (int)( in_uDestMaxNumChars - strlen( in_pDest ) - 1 );
00446         strncat_s( in_pDest, in_uDestMaxNumChars, in_pSrc, AkMin( iAvailableSize, (int)strlen( in_pSrc ) ) );
00447     }
00448 
00450     #define AkAlloca( _size_ ) _alloca( _size_ )
00451 
00453 #if ! ( defined(AK_USE_METRO_API) || defined(AK_OPTIMIZED) )
00454     inline void OutputDebugMsg( const wchar_t* in_pszMsg )
00455     {
00456         OutputDebugStringW( in_pszMsg );
00457     }
00458 
00460     inline void OutputDebugMsg( const char* in_pszMsg )
00461     {
00462         OutputDebugStringA( in_pszMsg );
00463     }
00464 #else
00465     inline void OutputDebugMsg( const wchar_t* ){}
00466     inline void OutputDebugMsg( const char* ){}
00467 #endif
00468 
00477     #define CONVERT_WIDE_TO_OSCHAR( _wstring_, _oscharstring_ ) ( _oscharstring_ ) = (AkOSChar*)( _wstring_ )
00478 
00487     #define CONVERT_CHAR_TO_OSCHAR( _astring_, _oscharstring_ ) \
00488            _oscharstring_ = (AkOSChar*)AkAlloca( (1 + strlen( _astring_ )) * sizeof(AkOSChar)); \
00489            AKPLATFORM::AkCharToWideChar( _astring_, (AkUInt32)(1 + strlen(_astring_ )), (AkOSChar*)( _oscharstring_ ) )
00490 
00499     #define CONVERT_OSCHAR_TO_WIDE( _osstring_, _wstring_ ) _wstring_ = _osstring_
00500 
00509     #define CONVERT_OSCHAR_TO_CHAR( _osstring_, _astring_ ) \
00510             _astring_ = (char*)AkAlloca( 1 + wcslen( _osstring_ )); \
00511             AKPLATFORM::AkWideCharToChar( _osstring_, AkUInt32(1 + wcslen( _osstring_ )), _astring_ );
00512 
00515     inline size_t AkUtf16StrLen( const AkUtf16* in_pStr )
00516     {
00517         return ( wcslen( in_pStr ) );
00518     }
00519 
00522     inline size_t OsStrLen( const AkOSChar* in_pszString )
00523     {
00524         return ( wcslen( in_pszString ) );
00525     }
00526 
00528     #define AK_OSPRINTF swprintf_s
00529 
00536     inline int OsStrCmp( const AkOSChar* in_pszString1, const AkOSChar* in_pszString2 )
00537     {
00538         return ( wcscmp( in_pszString1,  in_pszString2 ) );
00539     }
00540     
00541     #define AK_UTF16_TO_WCHAR(  in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::SafeStrCpy(     in_pdDest, in_pSrc, in_MaxSize )
00542     #define AK_WCHAR_TO_UTF16(  in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::SafeStrCpy(     in_pdDest, in_pSrc, in_MaxSize )
00543     #define AK_UTF16_TO_OSCHAR( in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::SafeStrCpy(     in_pdDest, in_pSrc, in_MaxSize )
00544     #define AK_UTF16_TO_CHAR(   in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::AkWideCharToChar( in_pSrc, in_MaxSize, in_pdDest )
00545     #define AK_CHAR_TO_UTF16(   in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::AkCharToWideChar( in_pSrc, in_MaxSize, in_pdDest )
00546     #define AK_OSCHAR_TO_UTF16( in_pdDest, in_pSrc, in_MaxSize )    AKPLATFORM::SafeStrCpy(     in_pdDest, in_pSrc, in_MaxSize )
00547 
00548     // Use with AkOSChar.
00549     #define AK_PATH_SEPARATOR   (L"\\")
00550 
00551     #if defined(AK_ENABLE_PERF_RECORDING)
00552     
00553         static AkUInt32 g_uAkPerfRecExecCount = 0;  
00554         static AkReal32 g_fAkPerfRecExecTime = 0.f;
00555 
00556         #define AK_PERF_RECORDING_RESET()   \
00557             AKPLATFORM::g_uAkPerfRecExecCount = 0;\
00558             AKPLATFORM::g_fAkPerfRecExecTime = 0.f;
00559 
00560         #define AK_PERF_RECORDING_START( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ )                       \
00561             AkInt64 iAkPerfRecTimeBefore;                                                                                           \
00562             if ( (AKPLATFORM::g_uAkPerfRecExecCount >= (__uExecutionCountStart__)) && (AKPLATFORM::g_uAkPerfRecExecCount <= (__uExecutionCountStop__)) )    \
00563                 AKPLATFORM::PerformanceCounter( &iAkPerfRecTimeBefore );
00564 
00565         #define AK_PERF_RECORDING_STOP( __StorageName__, __uExecutionCountStart__, __uExecutionCountStop__ )                        \
00566         if ( (AKPLATFORM::g_uAkPerfRecExecCount >= (__uExecutionCountStart__)) && (AKPLATFORM::g_uAkPerfRecExecCount <= (__uExecutionCountStop__)) )    \
00567             {                                                                                                                       \
00568                 AkInt64 iAkPerfRecTimeAfter;                                                                                        \
00569                 AKPLATFORM::PerformanceCounter( &iAkPerfRecTimeAfter );                                                             \
00570                 AKPLATFORM::g_fAkPerfRecExecTime += AKPLATFORM::Elapsed( iAkPerfRecTimeAfter, iAkPerfRecTimeBefore );                           \
00571                 if ( AKPLATFORM::g_uAkPerfRecExecCount == (__uExecutionCountStop__) )                                                           \
00572                 {                                                                                                                   \
00573                     AkReal32 fAverageExecutionTime = AKPLATFORM::g_fAkPerfRecExecTime/((__uExecutionCountStop__)-(__uExecutionCountStart__));   \
00574                     char str[256];                                                                                                  \
00575                     sprintf_s(str, 256, "%s average execution time: %f\n", __StorageName__, fAverageExecutionTime);                 \
00576                     AKPLATFORM::OutputDebugMsg( str );                                                                              \
00577                 }                                                                                                                   \
00578             }                                                                                                                       \
00579             AKPLATFORM::g_uAkPerfRecExecCount++;
00580     #endif // AK_ENABLE_PERF_RECORDING
00581 }
00582 
00583 #endif  // _AK_PLATFORM_FUNCS_H_