summaryrefslogtreecommitdiff
path: root/pjlib
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2005-11-21 16:59:47 +0000
committerBenny Prijono <bennylp@teluu.com>2005-11-21 16:59:47 +0000
commit483dfa9a40e1818c9fd1cc1dd82884ddbf243778 (patch)
treeabc1e115673177003f0ad0d51ba495e4d9f05238 /pjlib
parent4a4fe6471b8a930ec49a28cced2f7a5ea55aee26 (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
Diffstat (limited to 'pjlib')
-rw-r--r--pjlib/include/pj/config.h24
-rw-r--r--pjlib/include/pj/os.h18
-rw-r--r--pjlib/src/pj/os_core_win32.c4
-rw-r--r--pjlib/src/pj/os_timestamp_common.c58
-rw-r--r--pjlib/src/pj/os_timestamp_win32.c71
-rw-r--r--pjlib/src/pjlib-test/sleep.c17
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;
}
}