diff options
author | Benny Prijono <bennylp@teluu.com> | 2005-11-21 16:59:47 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2005-11-21 16:59:47 +0000 |
commit | 483dfa9a40e1818c9fd1cc1dd82884ddbf243778 (patch) | |
tree | abc1e115673177003f0ad0d51ba495e4d9f05238 | |
parent | 4a4fe6471b8a930ec49a28cced2f7a5ea55aee26 (diff) |
Added rdtsc option for win32 timestamp and added pj_elapsed_msec
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@70 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r-- | pjlib/include/pj/config.h | 24 | ||||
-rw-r--r-- | pjlib/include/pj/os.h | 18 | ||||
-rw-r--r-- | pjlib/src/pj/os_core_win32.c | 4 | ||||
-rw-r--r-- | pjlib/src/pj/os_timestamp_common.c | 58 | ||||
-rw-r--r-- | pjlib/src/pj/os_timestamp_win32.c | 71 | ||||
-rw-r--r-- | pjlib/src/pjlib-test/sleep.c | 17 |
6 files changed, 181 insertions, 11 deletions
diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h index 2a8d5c08..ec21a529 100644 --- a/pjlib/include/pj/config.h +++ b/pjlib/include/pj/config.h @@ -97,6 +97,7 @@ # undef PJ_HAS_SEMAPHORE # undef PJ_HAS_EVENT_OBJ # undef PJ_ENABLE_EXTRA_CHECK +# undef PJ_EXCEPTION_USE_WIN32_SEH #endif /** @@ -319,6 +320,27 @@ # define PJ_MAX_EXCEPTION_ID 16 #endif +/** + * Should we use Windows Structured Exception Handling (SEH) for the + * PJLIB exceptions. + * + * Default: 0 + */ +#ifndef PJ_EXCEPTION_USE_WIN32_SEH +# define PJ_EXCEPTION_USE_WIN32_SEH 0 +#endif + +/** + * Should we attempt to use Pentium's rdtsc for high resolution + * timestamp. + * + * Default: 0 + */ +#ifndef PJ_TIMESTAMP_USE_RDTSC +# define PJ_TIMESTAMP_USE_RDTSC 0 +#endif + + /** @} */ /******************************************************************** @@ -353,11 +375,13 @@ #ifdef __cplusplus # define PJ_DECL(type) type # define PJ_DECL_NO_RETURN(type) type PJ_NORETURN +# define PJ_IDECL_NO_RETURN(type) PJ_INLINE(type) PJ_NORETURN # define PJ_BEGIN_DECL extern "C" { # define PJ_END_DECL } #else # define PJ_DECL(type) extern type # define PJ_DECL_NO_RETURN(type) PJ_NORETURN type +# define PJ_IDECL_NO_RETURN(type) PJ_NORETURN PJ_INLINE(type) # define PJ_BEGIN_DECL # define PJ_END_DECL #endif diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h index 7b03c968..2917a2ab 100644 --- a/pjlib/include/pj/os.h +++ b/pjlib/include/pj/os.h @@ -922,6 +922,24 @@ PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start, const pj_timestamp *stop ); /** + * Calculate the elapsed time as 32-bit miliseconds. + * This function calculates the elapsed time using highest precision + * calculation that is available for current platform, considering + * whether floating point or 64-bit precision arithmetic is available. + * For maximum portability, application should prefer to use this function + * rather than calculating the elapsed time by itself. + * + * @param start The starting timestamp. + * @param stop The end timestamp. + * + * @return Elapsed time in milisecond. + * + * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec() + */ +PJ_DECL(pj_uint32_t) pj_elapsed_msec( const pj_timestamp *start, + const pj_timestamp *stop ); + +/** * Calculate the elapsed time in 32-bit microseconds. * This function calculates the elapsed time using highest precision * calculation that is available for current platform, considering diff --git a/pjlib/src/pj/os_core_win32.c b/pjlib/src/pj/os_core_win32.c index 91add770..756b88a8 100644 --- a/pjlib/src/pj/os_core_win32.c +++ b/pjlib/src/pj/os_core_win32.c @@ -161,8 +161,10 @@ PJ_DEF(pj_status_t) pj_init(void) #if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 { pj_timestamp dummy_ts; + if ((rc=pj_get_timestamp_freq(&dummy_ts)) != PJ_SUCCESS) { + return rc; + } if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) { - PJ_LOG(1, ("pj_init", "Unable to initialize timestamp")); return rc; } } diff --git a/pjlib/src/pj/os_timestamp_common.c b/pjlib/src/pj/os_timestamp_common.c index 4dc410f3..a86c1746 100644 --- a/pjlib/src/pj/os_timestamp_common.c +++ b/pjlib/src/pj/os_timestamp_common.c @@ -26,9 +26,14 @@ #define USEC (1000000UL) #define MSEC (1000) +#define u64tohighprec(u64) ((pj_highprec_t)((pj_int64_t)(u64))) + static pj_highprec_t get_elapsed( const pj_timestamp *start, const pj_timestamp *stop ) { +#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 + return u64tohighprec(stop->u64 - start->u64); +#else pj_highprec_t elapsed_hi, elapsed_lo; elapsed_hi = stop->u32.hi - start->u32.hi; @@ -38,6 +43,38 @@ static pj_highprec_t get_elapsed( const pj_timestamp *start, pj_highprec_mul(elapsed_hi, U32MAX); return elapsed_hi + elapsed_lo; +#endif +} + +static pj_highprec_t elapsed_msec( const pj_timestamp *start, + const pj_timestamp *stop ) +{ + pj_timestamp ts_freq; + pj_highprec_t freq, elapsed; + + if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS) + return 0; + + /* Convert frequency timestamp */ +#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 + freq = u64tohighprec(ts_freq.u64); +#else + freq = ts_freq.u32.hi; + pj_highprec_mul(freq, U32MAX); + freq += ts_freq.u32.lo; +#endif + + /* Avoid division by zero. */ + if (freq == 0) freq = 1; + + /* Get elapsed time in cycles. */ + elapsed = get_elapsed(start, stop); + + /* usec = elapsed * MSEC / freq */ + pj_highprec_mul(elapsed, MSEC); + pj_highprec_div(elapsed, freq); + + return elapsed; } static pj_highprec_t elapsed_usec( const pj_timestamp *start, @@ -50,9 +87,13 @@ static pj_highprec_t elapsed_usec( const pj_timestamp *start, return 0; /* Convert frequency timestamp */ +#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 + freq = u64tohighprec(ts_freq.u64); +#else freq = ts_freq.u32.hi; pj_highprec_mul(freq, U32MAX); freq += ts_freq.u32.lo; +#endif /* Avoid division by zero. */ if (freq == 0) freq = 1; @@ -77,9 +118,13 @@ PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start, return 0; /* Convert frequency timestamp */ +#if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 + freq = u64tohighprec(ts_freq.u64); +#else freq = ts_freq.u32.hi; pj_highprec_mul(freq, U32MAX); freq += ts_freq.u32.lo; +#endif /* Avoid division by zero. */ if (freq == 0) freq = 1; @@ -100,10 +145,16 @@ PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start, return (pj_uint32_t)elapsed_usec(start, stop); } +PJ_DEF(pj_uint32_t) pj_elapsed_msec( const pj_timestamp *start, + const pj_timestamp *stop ) +{ + return (pj_uint32_t)elapsed_msec(start, stop); +} + PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start, const pj_timestamp *stop ) { - pj_highprec_t elapsed = elapsed_usec(start, stop); + pj_highprec_t elapsed = elapsed_msec(start, stop); pj_time_val tv_elapsed; if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) { @@ -113,12 +164,11 @@ PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start, pj_highprec_t sec, msec; sec = elapsed; - pj_highprec_div(sec, USEC); + pj_highprec_div(sec, MSEC); tv_elapsed.sec = (long)sec; msec = elapsed; - pj_highprec_mod(msec, USEC); - pj_highprec_div(msec, 1000); + pj_highprec_mod(msec, MSEC); tv_elapsed.msec = (long)msec; return tv_elapsed; diff --git a/pjlib/src/pj/os_timestamp_win32.c b/pjlib/src/pj/os_timestamp_win32.c index eeff6c00..757a3000 100644 --- a/pjlib/src/pj/os_timestamp_win32.c +++ b/pjlib/src/pj/os_timestamp_win32.c @@ -20,6 +20,75 @@ #include <pj/errno.h> #include <windows.h> +#if defined(PJ_TIMESTAMP_USE_RDTSC) && PJ_TIMESTAMP_USE_RDTSC!=0 && \ + defined(PJ_M_I386) && PJ_M_I386 != 0 && \ + defined(_MSC_VER) +/* + * Use rdtsc to get the OS timestamp. + */ +static LONG CpuMhz; +static pj_int64_t CpuHz; + +static pj_status_t GetCpuHz(void) +{ + HKEY key; + LONG rc; + DWORD size; + + rc = RegOpenKey( HKEY_LOCAL_MACHINE, + "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", + &key); + if (rc != ERROR_SUCCESS) + return PJ_RETURN_OS_ERROR(rc); + + size = sizeof(CpuMhz); + rc = RegQueryValueEx(key, "~MHz", NULL, NULL, (BYTE*)&CpuMhz, &size); + RegCloseKey(key); + + if (rc != ERROR_SUCCESS) { + return PJ_RETURN_OS_ERROR(rc); + } + + CpuHz = CpuMhz; + CpuHz = CpuHz * 1000000; + + return PJ_SUCCESS; +} + +/* __int64 is nicely returned in EDX:EAX */ +__declspec(naked) __int64 rdtsc() +{ + __asm + { + RDTSC + RET + } +} + +PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) +{ + ts->u64 = rdtsc(); + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) +{ + pj_status_t status; + + if (CpuHz == 0) { + status = GetCpuHz(); + if (status != PJ_SUCCESS) + return status; + } + + freq->u64 = CpuHz; + return PJ_SUCCESS; +} + +#else +/* + * Use QueryPerformanceCounter and QueryPerformanceFrequency. + */ PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts) { LARGE_INTEGER val; @@ -42,3 +111,5 @@ PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq) return PJ_SUCCESS; } +#endif /* PJ_TIMESTAMP_USE_RDTSC */ + diff --git a/pjlib/src/pjlib-test/sleep.c b/pjlib/src/pjlib-test/sleep.c index 5732a165..2c735a33 100644 --- a/pjlib/src/pjlib-test/sleep.c +++ b/pjlib/src/pjlib-test/sleep.c @@ -124,9 +124,10 @@ static int sleep_duration_test(void) { pj_time_val t1, t2; pj_timestamp start, stop; - pj_time_val elapsed; pj_uint32_t msec; + pj_thread_sleep(0); + /* Mark start of test. */ rc = pj_get_timestamp(&start); if (rc != PJ_SUCCESS) { @@ -156,10 +157,8 @@ static int sleep_duration_test(void) return -75; } - /* Get elapsed time in time_val */ - elapsed = pj_elapsed_time(&start, &stop); - - msec = PJ_TIME_VAL_MSEC(elapsed); + /* Get elapsed time in msec */ + msec = pj_elapsed_msec(&start, &stop); /* Check if it's within range. */ if (msec < DURATION2 * (100-MIS)/100 || @@ -169,7 +168,13 @@ static int sleep_duration_test(void) "...error: slept for %d ms instead of %d ms " "(outside %d%% err window)", msec, DURATION2, MIS)); - return -30; + PJ_TIME_VAL_SUB(t2, t1); + PJ_LOG(3,(THIS_FILE, + "...info: gettimeofday() reported duration is " + "%d msec", + PJ_TIME_VAL_MSEC(t2))); + + return -76; } } |