Commit ae623728 authored by Pekka Pessi's avatar Pekka Pessi

su_time.h, su_time.c, su_time0.c: added su_nanotime(), su_monotime()

darcs-hash:20070704094348-65a35-baec336c0d6fd7d4b6b78f92dff8032598127dc7.gz
parent e55460bf
......@@ -73,7 +73,7 @@ enum {
*/
typedef uint64_t su_ntp_t;
/** Represent NTP consttant */
/** Represent NTP constant */
#define SU_NTP_C(x) SU_U64_C(x)
#define SU_TIME_CMP(t1, t2) su_time_cmp(t1, t2)
......@@ -81,6 +81,13 @@ typedef uint64_t su_ntp_t;
/** Seconds from 1.1.1900 to 1.1.1970. @NEW_1_12_4 */
#define SU_TIME_EPOCH 2208988800UL
typedef uint64_t su_nanotime_t;
#define SU_E9 (1000000000U)
SOFIAPUBFUN su_nanotime_t su_nanotime(su_nanotime_t *return_time);
SOFIAPUBFUN su_nanotime_t su_monotime(su_nanotime_t *return_time);
SOFIAPUBFUN su_time_t su_now(void);
SOFIAPUBFUN void su_time(su_time_t *tv);
SOFIAPUBFUN long su_time_cmp(su_time_t const t1, su_time_t const t2);
......
......@@ -209,6 +209,8 @@ const su_t64_t su_res64 = (su_t64_t)1000000UL;
(su_res64 * (su_t64_t)(tv).tv_sec + (su_t64_t)(tv).tv_usec)
#define SU_DUR_TO_T64(d) (1000 * (int64_t)(d))
#define E9 (1000000000)
/** Get NTP timestamp.
*
* The function su_ntp_now() returns the current NTP timestamp. NTP
......@@ -219,22 +221,36 @@ const su_t64_t su_res64 = (su_t64_t)1000000UL;
*/
su_ntp_t su_ntp_now(void)
{
su_time_t t;
uint32_t sec, usec;
su_time(&t);
su_nanotime_t now;
sec = t.tv_sec;
usec = t.tv_usec;
su_nanotime(&now);
/*
* Multiply usec by 4294.967296 (ie. 2**32 / 1E6)
*
* Utilize fact that 4294.967296 == 4295 - 511 / 15625
*/
usec = 4295 * usec - (511 * usec + 7812) / 15625;
if (sizeof(long) == sizeof(now)) {
return ((now / E9) << 32) | ((((now % E9) << 32) + E9/2) / E9);
}
else {
su_nanotime_t usec;
int nsec;
unsigned rem;
usec = now / 1000;
nsec = now % 1000;
/*
* Multiply usec by 4294.967296 (ie. 2**32 / 1E6)
*
* Utilize fact that 4294.967296 == 4295 - 511 / 15625
*/
now = 4295 * usec - 511 * usec / 15625;
rem = (511U * usec) % 15625U;
return ((su_ntp_t)sec << 32) + (su_ntp_t)usec;
/* Multiply nsec by 4.294967296 */
nsec = 4295 * 125 * nsec - (511 * nsec) / 125;
nsec -= 8 * rem; /* usec rounding */
nsec = (nsec + (nsec < 0 ? -62499 : +62499)) / 125000;
return now + nsec;
}
}
/** Get NTP seconds.
......@@ -263,7 +279,6 @@ uint32_t su_ntp_hi(su_ntp_t ntp)
return (uint32_t) (ntp >> 32) & 0xffffffffLU;
}
su_ntp_t su_ntp_hilo(uint32_t hi, uint32_t lo)
{
return ((((su_ntp_t)hi) << 32)) | lo;
......@@ -464,8 +479,3 @@ uint64_t su_nanocounter(void)
}
#endif /* WIN32 */
......@@ -44,6 +44,8 @@
#include "sofia-sip/su_time.h"
#include "su_module_debug.h"
#include <time.h>
#if HAVE_SYS_TIME_H
#include <sys/time.h> /* Get struct timeval */
#endif
......@@ -60,6 +62,12 @@
/** Seconds from 1.1.1900 to 1.1.1970 */
#define NTP_EPOCH 2208988800UL
#define E9 (1000000000U)
#define E7 (10000000U)
/* Hooks for testing timing and timers */
void (*_su_time)(su_time_t *tv);
uint64_t (*_su_nanotime)(uint64_t *);
/** Get current time.
*
......@@ -83,11 +91,128 @@ void su_time(su_time_t *tv)
GetSystemTimeAsFileTime(date.ft);
tv->tv_usec = (unsigned long) ((date.ull->QuadPart % 10000000U) / 10);
tv->tv_sec = (unsigned long) ((date.ull->QuadPart / 10000000U) -
tv->tv_usec = (unsigned long) ((date.ull->QuadPart % E7) / 10);
tv->tv_sec = (unsigned long) ((date.ull->QuadPart / E7) -
/* 1900-Jan-01 - 1601-Jan-01: 299 years, 72 leap years */
(299 * 365 + 72) * 24 * 60 * (uint64_t)60);
#else
#error no su_time() implementation
#endif
if (_su_time)
return _su_time(tv);
}
/** Get current time as nanoseconds since epoch.
*
* Return the current NTP timestamp expressed as nanoseconds since epoch
* (January 1st 1900).
*
* @param return_time optional pointer to current time to return
*
* @return Nanoseconds since epoch
*/
su_nanotime_t su_nanotime(su_nanotime_t *return_time)
{
su_nanotime_t now;
if (!return_time)
return_time = &now;
#if HAVE_CLOCK_GETTIME
{
struct timespec tv;
if (clock_gettime(CLOCK_REALTIME, &tv) == 0) {
now = ((su_nanotime_t)tv.tv_sec + NTP_EPOCH) * E9 + tv.tv_nsec;
*return_time = now;
if (_su_nanotime)
return _su_nanotime(return_time);
return now;
}
}
#endif
#if HAVE_FILETIME
{
union {
FILETIME ft[1];
ULARGE_INTEGER ull[1];
} date;
GetSystemTimeAsFileTime(date.ft);
now = 100 *
(date.ull->QuadPart -
/* 1900-Jan-01 - 1601-Jan-01: 299 years, 72 leap years */
((su_nanotime_t)(299 * 365 + 72) * 24 * 60 * 60) * E7);
}
#elif HAVE_GETTIMEOFDAY
{
struct timeval tv;
gettimeofday(&tv, NULL);
now = ((su_nanotime_t)tv.tv_sec + NTP_EPOCH) * E9 + tv.tv_usec * 1000;
}
#else
now = ((su_nanotime_t)time() + NTP_EPOCH) * E9;
#endif
*return_time = now;
if (_su_nanotime)
return _su_nanotime(return_time);
return now;
}
/** Get current time as nanoseconds.
*
* Return the current time expressed as nanoseconds. The time returned is
* monotonic and never goes back - if the underlying system supports such a
* clock.
*
* @param return_time optional pointer to return the current time
*
* @return Current time as nanoseconds
*/
su_nanotime_t su_monotime(su_nanotime_t *return_time)
{
#if HAVE_CLOCK_GETTIME
{
struct timespec tv;
if (clock_gettime(CLOCK_MONOTONIC, &tv) == 0) {
su_nanotime_t now = (su_nanotime_t)tv.tv_sec * E9 + tv.tv_nsec;
if (return_time)
*return_time = now;
return now;
}
}
#endif
#if HAVE_NANOUPTIME
{
struct timespec tv;
nanouptime(&tv);
now = (su_nanotime_t)tv.tv_sec * E9 + tv.tv_nsec;
if (return_time)
*return_time = now;
return now;
}
#elif HAVE_MICROUPTIME
{
struct timeval tv;
microuptime(&tv);
now = (su_nanotime_t)tv.tv_sec * E9 + tv.tv_usec * 1000;
if (return_time)
*return_time = now;
return now;
}
#else
return su_nanotime(return_time);
#endif
}
......@@ -50,62 +50,37 @@
char const *name = "torture_su_time.c";
int expensive_tests = 0;
static int test1(int flags);
static int test2(int flags);
static int test3(int flags);
void usage(int exitcode)
{
fprintf(stderr,
"usage: %s [-v] [-a]\n",
name);
exit(exitcode);
}
char *lastpart(char *path)
{
if (strchr(path, '/'))
return strrchr(path, '/') + 1;
else
return path;
}
su_time_t tv0;
int main(int argc, char *argv[])
void su_time0(su_time_t *tv)
{
int flags = 0;
int retval = 0;
int i;
name = lastpart(argv[0]); /* Set our name */
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
flags |= tst_verbatim;
else if (strcmp(argv[i], "-a") == 0)
flags |= tst_abort;
else
usage(1);
}
retval |= test1(flags); fflush(stdout);
retval |= test2(flags); fflush(stdout);
retval |= test3(flags); fflush(stdout);
return retval;
*tv = tv0;
}
su_time_t tv0;
uint64_t nanotime;
void su_time(su_time_t *tv)
uint64_t su_nanotime0(uint64_t *retval)
{
*tv = tv0;
if (nanotime)
return *retval = nanotime;
else
return *retval = (uint64_t)tv0.tv_sec * 1000000000U + tv0.tv_usec * 1000U;
}
#define E9 (1000000000U)
int test1(int flags)
{
uint32_t ntp_hi, ntp_lo, ntp_mw;
su_time_t now;
su_ntp_t ntp, ntp0, ntp1;
uint64_t increment = 3019;
BEGIN();
......@@ -136,8 +111,20 @@ int test1(int flags)
TEST64(su_ntp_hi(ntp), ntp_hi);
TEST64(su_ntp_lo(ntp), 0);
TEST64(su_ntp_mw(ntp), (ntp_hi & 0xffff) << 16);
TEST(su_ntp_fraq(tv0), su_ntp_mw(ntp));
if (expensive_tests)
increment = 1;
for (nanotime = 1; nanotime <= 2 * E9; nanotime += increment) {
ntp = su_ntp_now();
ntp0 = ((nanotime / E9) << 32) | ((((nanotime % E9) << 32) + E9/2) / E9);
TEST(ntp, ntp0);
}
nanotime = 0;
END();
}
......@@ -157,6 +144,7 @@ int test2(int flags)
BEGIN();
nanotime = 0;
tv0.tv_sec = 268435455;
tv0.tv_usec = 98765;
......@@ -165,10 +153,10 @@ int test2(int flags)
su_guid_generate(g1);
seq1 = ((g1->s.clock_seq_hi_and_reserved & 0x3f) << 8) + g1->s.clock_seq_low;
TEST(g1->s.time_low, htonl(tl & 0xffffFFFFU));
TEST(g1->s.time_mid, htons((tl >> 32) & 0xffffU));
TEST(g1->s.time_high_and_version, htons(((tl >> 48) & 0xfffU) | 0x1000));
TEST(g1->s.clock_seq_hi_and_reserved & 0xc0, 0x80);
TEST(g1->s.time_high_and_version, htons(((tl >> 48) & 0xfffU) | 0x1000));
TEST(ntohs(g1->s.time_mid), (tl >> 32) & 0xffffU);
//TEST(ntohl(g1->s.time_low), tl & 0xffffFFFFU);
TEST(i = su_guid_sprintf(buf, sizeof(buf), g1), su_guid_strlen);
TEST_SIZE(strlen(buf), i);
......@@ -219,3 +207,56 @@ int test3(int flags)
END();
}
void su_time0(su_time_t *tv);
uint64_t su_nanotime0(uint64_t *);
extern void (*_su_time)(su_time_t *tv);
extern uint64_t (*_su_nanotime)(uint64_t *);
void usage(int exitcode)
{
fprintf(stderr,
"usage: %s [-v] [-a]\n",
name);
exit(exitcode);
}
char *lastpart(char *path)
{
if (strchr(path, '/'))
return strrchr(path, '/') + 1;
else
return path;
}
int main(int argc, char *argv[])
{
int flags = 0;
int retval = 0;
int i;
name = lastpart(argv[0]); /* Set our name */
for (i = 1; argv[i]; i++) {
if (strcmp(argv[i], "-v") == 0)
flags |= tst_verbatim;
else if (strcmp(argv[i], "-x") == 0)
expensive_tests = 1;
else if (strcmp(argv[i], "-a") == 0)
flags |= tst_abort;
else
usage(1);
}
if (getenv("EXPENSIVE_CHECKS"))
expensive_tests = 1;
_su_time = su_time0, _su_nanotime = su_nanotime0;
retval |= test1(flags); fflush(stdout);
retval |= test2(flags); fflush(stdout);
retval |= test3(flags); fflush(stdout);
return retval;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment