Skip to content

Commit 0f6f965

Browse files
committed
Return nanoseconds as zend_long on 64-bit, float on 32-bit, implement return array [s, ns]
Adjust tests Move and rename test Fix proto comment Return array by default Fix 32-bit and some more Still provide symbols even if functionality is unavailable Change typename Add AIX specific pieces, untested Improve 32-bit side once more Rework macros Few renames Add comment Remove unused code, a few other small things Add comment ws Reword
1 parent 868c098 commit 0f6f965

File tree

6 files changed

+181
-130
lines changed

6 files changed

+181
-130
lines changed

ext/standard/basic_functions.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,10 +1454,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_http_response_code, 0, 0, 0)
14541454
ZEND_END_ARG_INFO()
14551455
/* }}} */
14561456
/* {{{ hrtime.c */
1457-
#if HRTIME_AVAILABLE
14581457
ZEND_BEGIN_ARG_INFO(arginfo_hrtime, 0)
1458+
ZEND_ARG_INFO(0, get_as_numeric)
14591459
ZEND_END_ARG_INFO()
1460-
#endif
14611460
/* }}} */
14621461
/* {{{ html.c */
14631462
ZEND_BEGIN_ARG_INFO_EX(arginfo_htmlspecialchars, 0, 0, 1)
@@ -2992,9 +2991,7 @@ static const zend_function_entry basic_functions[] = { /* {{{ */
29922991
PHP_FE(getrusage, arginfo_getrusage)
29932992
#endif
29942993

2995-
#if HRTIME_AVAILABLE
29962994
PHP_FE(hrtime, arginfo_hrtime)
2997-
#endif
29982995

29992996
#ifdef HAVE_GETTIMEOFDAY
30002997
PHP_FE(uniqid, arginfo_uniqid)
@@ -3726,9 +3723,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */
37263723

37273724
BASIC_MINIT_SUBMODULE(random)
37283725

3729-
#if HRTIME_AVAILABLE
37303726
BASIC_MINIT_SUBMODULE(hrtime)
3731-
#endif
37323727

37333728
return SUCCESS;
37343729
}

ext/standard/hrtime.c

Lines changed: 125 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -22,153 +22,185 @@
2222
#include "zend_exceptions.h"
2323
#include "hrtime.h"
2424

25-
#if HRTIME_AVAILABLE
26-
27-
/* - timer.h ------------------------------------------------------------------------------------ */
28-
/* The following code is based on:
29-
timer.h - Cross-platform timer library - Public Domain - 2011 Mattias Jansson / Rampant Pixels */
25+
/* {{{ */
26+
/* This file reuses code parts from the cross-platform timer library
27+
Public Domain - 2011 Mattias Jansson / Rampant Pixels */
3028

31-
#define TIMER_PLATFORM_POSIX 0
32-
#define TIMER_PLATFORM_WINDOWS 0
33-
#define TIMER_PLATFORM_APPLE 0
34-
#define TIMER_PLATFORM_HPUX 0
29+
#if PHP_HRTIME_PLATFORM_POSIX
3530

36-
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(CLOCK_MONOTONIC)
31+
# include <unistd.h>
32+
# include <time.h>
33+
# include <string.h>
3734

38-
# undef TIMER_PLATFORM_POSIX
39-
# define TIMER_PLATFORM_POSIX 1
40-
# include <unistd.h>
41-
# include <time.h>
42-
# include <string.h>
35+
#elif PHP_HRTIME_PLATFORM_WINDOWS
4336

44-
#elif defined(_WIN32) || defined(_WIN64)
37+
# define WIN32_LEAN_AND_MEAN
38+
# include <windows.h>
4539

46-
# undef TIMER_PLATFORM_WINDOWS
47-
# define TIMER_PLATFORM_WINDOWS 1
48-
# define WIN32_LEAN_AND_MEAN
49-
# include <windows.h>
40+
static uint64_t _timer_freq = 0;
41+
static double _timer_int = .0;
5042

51-
#elif defined(__APPLE__)
43+
#elif PHP_HRTIME_PLATFORM_APPLE
5244

53-
# undef TIMER_PLATFORM_APPLE
54-
# define TIMER_PLATFORM_APPLE 1
55-
# include <mach/mach_time.h>
56-
# include <string.h>
45+
# include <mach/mach_time.h>
46+
# include <string.h>
5747
static mach_timebase_info_data_t _timerlib_info;
58-
static void absolutetime_to_nanoseconds (uint64_t mach_time, uint64_t* clock ) { *clock = mach_time * _timerlib_info.numer / _timerlib_info.denom; }
5948

60-
#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__)))
49+
#elif PHP_HRTIME_PLATFORM_HPUX
6150

62-
# undef TIMER_PLATFORM_HPUX
63-
# define TIMER_PLATFORM_HPUX 1
64-
# include <sys/time.h>
51+
# include <sys/time.h>
52+
53+
#elif PHP_HRTIME_PLATFORM_AIX
54+
55+
# include <sys/time.h>
56+
# include <sys/systemcfg.h>
6557

6658
#endif
6759

68-
static uint64_t _timer_freq = 0;
60+
#define NANO_IN_SEC 1000000000
61+
/* }}} */
6962

7063
static int _timer_init()
71-
{
72-
#if TIMER_PLATFORM_WINDOWS
64+
{/*{{{*/
65+
#if PHP_HRTIME_PLATFORM_WINDOWS
7366

7467
uint64_t unused;
7568
if (!QueryPerformanceFrequency((LARGE_INTEGER*) &_timer_freq) ||
7669
!QueryPerformanceCounter((LARGE_INTEGER*) &unused)) {
7770
return -1;
7871
}
72+
_timer_int = 1.0 / _timer_freq;
7973

80-
#elif TIMER_PLATFORM_APPLE
74+
#elif PHP_HRTIME_PLATFORM_APPLE
8175

8276
if (mach_timebase_info(&_timerlib_info)) {
8377
return -1;
8478
}
85-
_timer_freq = 1000000000ULL;
8679

87-
#elif TIMER_PLATFORM_POSIX
80+
#elif PHP_HRTIME_PLATFORM_POSIX
8881

8982
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
83+
9084
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
9185
return -1;
9286
}
93-
_timer_freq = 1000000000ULL;
9487

95-
#elif TIMER_PLATFORM_HPUX
96-
97-
_timer_freq = 1000000000ULL;
98-
99-
#endif
88+
#elif PHP_HRTIME_PLATFORM_HPUX
10089

101-
return 0;
102-
}
103-
104-
static uint64_t _timer_current()
105-
{
106-
#if TIMER_PLATFORM_WINDOWS
107-
108-
uint64_t curclock;
109-
QueryPerformanceCounter((LARGE_INTEGER*) &curclock);
110-
return curclock;
111-
112-
#elif TIMER_PLATFORM_APPLE
113-
114-
uint64_t curclock = 0;
115-
absolutetime_to_nanoseconds(mach_absolute_time(), &curclock);
116-
return curclock;
117-
118-
#elif TIMER_PLATFORM_POSIX
119-
120-
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
121-
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
122-
return -1;
123-
}
124-
return ((uint64_t) ts.tv_sec * 1000000000ULL) + ts.tv_nsec;
90+
/* pass */
12591

126-
#elif TIMER_PLATFORM_HPUX
92+
#elif PHP_HRTIME_PLATFORM_AIX
12793

128-
return (uint64_t) gethrtime();
94+
/* pass */
12995

96+
#else
97+
/* Timer unavailable. */
98+
return -1;
13099
#endif
131-
}
132100

133-
/* - end of timer.h ----------------------------------------------------------------------------- */
101+
return 0;
102+
}/*}}}*/
134103

135104
/* {{{ */
136105
PHP_MINIT_FUNCTION(hrtime)
137106
{
138-
if (_timer_init()) {
139-
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to initialize internal timer");
107+
if (0 > _timer_init()) {
108+
php_error_docref(NULL, E_WARNING, "Failed to initialize high-resolution timer");
140109
return FAILURE;
141110
}
142111

143112
return SUCCESS;
144113
}
145114
/* }}} */
146115

147-
/* {{{ */
148-
PHP_MSHUTDOWN_FUNCTION(hrtime)
149-
{
150-
return SUCCESS;
151-
}
152-
/* }}} */
116+
static zend_always_inline php_hrtime_t _timer_current(void)
117+
{/*{{{*/
118+
#if PHP_HRTIME_PLATFORM_WINDOWS
119+
uint64_t cur;
120+
QueryPerformanceCounter((LARGE_INTEGER*) &cur);
121+
return (php_hrtime_t)((double)cur * _timer_int * (double)NANO_IN_SEC);
122+
#elif PHP_HRTIME_PLATFORM_APPLE
123+
return (php_hrtime_t)mach_absolute_time() * _timerlib_info.numer / _timerlib_info.denom;
124+
#elif PHP_HRTIME_PLATFORM_POSIX
125+
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
126+
if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) {
127+
return ((php_hrtime_t) ts.tv_sec * (php_hrtime_t)NANO_IN_SEC) + ts.tv_nsec;
128+
}
129+
return 0;
130+
#elif PHP_HRTIME_PLATFORM_HPUX
131+
return (php_hrtime_t) gethrtime();
132+
#elif PHP_HRTIME_PLATFORM_AIX
133+
timebasestruct_t t;
134+
read_wall_time(&t, TIMEBASE_SZ);
135+
time_base_to_time(&t, TIMEBASE_SZ);
136+
return (php_hrtime_t) t.tb_high * (php_hrtime_t)NANO_IN_SEC + t.tb_low;
137+
#else
138+
return 0;
139+
#endif
140+
}/*}}}*/
141+
142+
#if ZEND_ENABLE_ZVAL_LONG64
143+
#define PHP_RETURN_HRTIME(t) RETURN_LONG((zend_long)t)
144+
#else
145+
#ifdef _WIN32
146+
# define HRTIME_U64A(i, s, len) _ui64toa_s(i, s, len, 10)
147+
#else
148+
# define HRTIME_U64A(i, s, len) \
149+
do { \
150+
int st = snprintf(s, len, "%llu", i); \
151+
s[st] = '\0'; \
152+
} while (0)
153+
#endif
154+
#define PHP_RETURN_HRTIME(t) do { \
155+
char _a[ZEND_LTOA_BUF_LEN]; \
156+
double _d; \
157+
HRTIME_U64A(t, _a, ZEND_LTOA_BUF_LEN); \
158+
_d = zend_strtod(_a, NULL); \
159+
RETURN_DOUBLE(_d); \
160+
} while (0)
161+
#endif
153162

154-
/* {{{ proto float hrtime()
155-
Returns a float containing the current high-resolution time in seconds
156-
counted from an arbitrary point in time */
163+
/* {{{ proto mixed hrtime([bool get_as_numu = false])
164+
Returns an array of integers in form [seconds, nanoseconds] counted
165+
from an arbitrary point in time. If an optional boolean argument is
166+
passed, returns an integer on 64-bit platforms or float on 32-bit
167+
containing the current high-resolution time in nanoseconds */
157168
PHP_FUNCTION(hrtime)
158169
{
159-
if (zend_parse_parameters_none() == FAILURE) {
160-
return;
161-
}
162-
163-
uint64_t current_time = _timer_current();
164-
165-
if (UNEXPECTED(current_time == -1)) {
166-
zend_throw_exception(zend_ce_error, "Failed to get current system time", 0);
167-
return;
170+
#if HRTIME_AVAILABLE
171+
zend_bool get_as_num = 0;
172+
php_hrtime_t t = _timer_current();
173+
174+
ZEND_PARSE_PARAMETERS_START(0, 1)
175+
Z_PARAM_OPTIONAL
176+
Z_PARAM_BOOL(get_as_num)
177+
ZEND_PARSE_PARAMETERS_END();
178+
179+
if (!get_as_num) {
180+
/* TODO On 32-bit care about millenium bug. */
181+
array_init(return_value);
182+
add_next_index_long(return_value, (zend_long)(t / (php_hrtime_t)NANO_IN_SEC));
183+
add_next_index_long(return_value, (zend_long)(t % (php_hrtime_t)NANO_IN_SEC));
184+
} else {
185+
PHP_RETURN_HRTIME(t);
168186
}
169-
170-
RETURN_DOUBLE((double) current_time / _timer_freq);
187+
#else
188+
RETURN_LONG(0);
189+
#endif
171190
}
172191
/* }}} */
173192

174-
#endif /* HRTIME_AVAILABLE */
193+
PHPAPI php_hrtime_t php_hrtime_current(void)
194+
{/*{{{*/
195+
return _timer_current();
196+
}/*}}}*/
197+
198+
/*
199+
* Local variables:
200+
* tab-width: 4
201+
* c-basic-offset: 4
202+
* End:
203+
* vim600: sw=4 ts=4 fdm=marker
204+
* vim<600: sw=4 ts=4
205+
*/
206+

ext/standard/hrtime.h

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,38 @@
2121
#ifndef HRTIME_H
2222
#define HRTIME_H
2323

24+
#define PHP_HRTIME_PLATFORM_POSIX 0
25+
#define PHP_HRTIME_PLATFORM_WINDOWS 0
26+
#define PHP_HRTIME_PLATFORM_APPLE 0
27+
#define PHP_HRTIME_PLATFORM_HPUX 0
28+
#define PHP_HRTIME_PLATFORM_AIX 0
29+
2430
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(CLOCK_MONOTONIC)
25-
#define HRTIME_AVAILABLE 1
31+
/* XXX might need additional sysconf check. */
32+
# undef PHP_HRTIME_PLATFORM_POSIX
33+
# define PHP_HRTIME_PLATFORM_POSIX 1
2634
#elif defined(_WIN32) || defined(_WIN64)
27-
#define HRTIME_AVAILABLE 1
35+
# undef PHP_HRTIME_PLATFORM_WINDOWS
36+
# define PHP_HRTIME_PLATFORM_WINDOWS 1
2837
#elif defined(__APPLE__)
29-
#define HRTIME_AVAILABLE 1
38+
# undef PHP_HRTIME_PLATFORM_APPLE
39+
# define PHP_HRTIME_PLATFORM_APPLE 1
3040
#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__)))
31-
#define HRTIME_AVAILABLE 1
32-
#else
33-
#define HRTIME_AVAILABLE 0
41+
# undef PHP_HRTIME_PLATFORM_HPUX
42+
# define PHP_HRTIME_PLATFORM_HPUX 1
43+
#elif defined(_AIX)
44+
# undef PHP_HRTIME_PLATFORM_AIX
45+
# define PHP_HRTIME_PLATFORM_AIX 1
3446
#endif
3547

36-
#if HRTIME_AVAILABLE
37-
PHP_MINIT_FUNCTION(hrtime);
38-
PHP_MSHUTDOWN_FUNCTION(hrtime);
48+
#define HRTIME_AVAILABLE (PHP_HRTIME_PLATFORM_POSIX || PHP_HRTIME_PLATFORM_WINDOWS || PHP_HRTIME_PLATFORM_APPLE || PHP_HRTIME_PLATFORM_HPUX || PHP_HRTIME_PLATFORM_AIX)
49+
50+
typedef uint64_t php_hrtime_t;
51+
52+
PHPAPI php_hrtime_t php_hrtime_current(void);
53+
54+
PHP_MINIT_FUNCTION(hrtime);
3955

40-
PHP_FUNCTION(hrtime);
41-
#endif /* HRTIME_AVAILABLE */
56+
PHP_FUNCTION(hrtime);
4257

4358
#endif /* HRTIME_H */

ext/standard/tests/hrtime/hrtime.phpt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,24 @@ Test hrtime() aligns with microtime()
33
--FILE--
44
<?php
55

6-
$hrtime = hrtime();
7-
$microtime = microtime(1);
6+
$m0 = microtime(true);
7+
$h0 = hrtime(true);
8+
for ($i = 0; $i < 1024*1024; $i++);
9+
$h1 = hrtime(true);
10+
$m1 = microtime(true);
811

9-
usleep(500000);
12+
$d0 = ($m1 - $m0)*1000000000.0;
13+
$d1 = $h1 - $h0;
1014

11-
$hrdiff = hrtime() - $hrtime;
12-
$microdiff = microtime(1) - $microtime;
15+
/* Relative uncertainty. */
16+
$d = abs($d0 - $d1)/$d1;
1317

14-
if (abs($hrdiff - $microdiff) > 0.0001) {
15-
print "fail";
18+
if ($d > 0.05) {
19+
print "FAIL, $d";
1620
} else {
17-
print "OK";
21+
print "OK, $d";
1822
}
1923

2024
?>
21-
--EXPECT--
22-
OK
25+
--EXPECTF--
26+
OK, %f

0 commit comments

Comments
 (0)