From: Anatol Belski Date: Sun, 7 Jan 2018 14:55:12 +0000 (+0100) Subject: Implement high resolution monotonic timer function hrtime() X-Git-Tag: php-7.3.0alpha1~681^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=83497327e747703300d35831b4aa94adf1120165;p=php Implement high resolution monotonic timer function hrtime() --- diff --git a/UPGRADING b/UPGRADING index 7413f7b2d1..56b979be8e 100644 --- a/UPGRADING +++ b/UPGRADING @@ -95,6 +95,17 @@ PCRE: 6. New Functions ======================================== +Core: + . Added monotonic timer function hrtime([bool get_as_num]). It returns an + array of the form [seconds, nanoseconds] with the timestamp starting at + an unspecified point in the past. If the optional argument is passed as + true, the return value is an integer on 64-bit systems or float on + 32-bit systems, representing the nanoseconds. The timestamp is not + adjustable and is not related to wall clock or time of day. The timers + are available under Linux, FreeBSD, Windows, Mac, SunOS, AIX and their + derivatives. If no required timers are provided by a corresponding + platform, the function returns false. + Date: . Added the DateTime::createFromImmutable() method, which mirrors DateTimeImmutable::createFromMutable(). diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 040498e387..bf3a63b9b3 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -12,6 +12,7 @@ PHP 7.3 INTERNALS UPGRADE NOTES i. RAND_RANGE() j. cast_object() with _IS_NUMBER k. zend_fcall_info_cache.initialized + l. php_hrtime_current() 2. Build system changes a. Unix build system changes @@ -95,6 +96,9 @@ PHP 7.3 INTERNALS UPGRADE NOTES k. zend_fcall_info_cache.initialized is removed. zend_fcall_info_cache is initialized if zend_fcall_info_cache.function_handler is set. + l. php_hrtime_current() delivers the number of nanoseconds since an uncertain + point in the past. + ======================== 2. Build system changes ======================== diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 3ebf9bc775..2ae5cfb259 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -1453,6 +1453,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_http_response_code, 0, 0, 0) ZEND_ARG_INFO(0, response_code) ZEND_END_ARG_INFO() /* }}} */ +/* {{{ hrtime.c */ +ZEND_BEGIN_ARG_INFO(arginfo_hrtime, 0) + ZEND_ARG_INFO(0, get_as_number) +ZEND_END_ARG_INFO() +/* }}} */ /* {{{ html.c */ ZEND_BEGIN_ARG_INFO_EX(arginfo_htmlspecialchars, 0, 0, 1) ZEND_ARG_INFO(0, string) @@ -2986,6 +2991,8 @@ static const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(getrusage, arginfo_getrusage) #endif + PHP_FE(hrtime, arginfo_hrtime) + #ifdef HAVE_GETTIMEOFDAY PHP_FE(uniqid, arginfo_uniqid) #endif @@ -3716,6 +3723,8 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ BASIC_MINIT_SUBMODULE(random) + BASIC_MINIT_SUBMODULE(hrtime) + return SUCCESS; } /* }}} */ diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index a74df78a51..6a5915b80e 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -13,14 +13,14 @@ int main(int argc, char **argv) char *filename = tmpnam(NULL); char buffer[64]; int result = 0; - + FILE *fp = fopen(filename, "wb"); if (NULL == fp) return 0; fputs("line 1\n", fp); fputs("line 2\n", fp); fclose(fp); - + fp = fopen(filename, "rb+"); if (NULL == fp) return 0; @@ -58,7 +58,7 @@ if test "$ac_cv_func_crypt" = "no"; then AC_DEFINE(HAVE_CRYPT, 1, [ ]) ]) fi - + AC_CACHE_CHECK(for standard DES crypt, ac_cv_crypt_des,[ AC_TRY_RUN([ #if HAVE_UNISTD_H @@ -124,7 +124,7 @@ int main() { char salt[15], answer[40]; char *encrypted; - salt[0]='$'; salt[1]='1'; salt[2]='$'; + salt[0]='$'; salt[1]='1'; salt[2]='$'; salt[3]='r'; salt[4]='a'; salt[5]='s'; salt[6]='m'; salt[7]='u'; salt[8]='s'; salt[9]='l'; salt[10]='e'; salt[11]='$'; @@ -267,7 +267,7 @@ else AC_DEFINE_UNQUOTED(PHP_USE_PHP_CRYPT_R, 0, [Whether PHP has to use its own crypt_r for blowfish, des and ext des]) fi -dnl +dnl dnl Check for __attribute__ ((__aligned__)) support in the compiler dnl AC_CACHE_CHECK(whether the compiler supports aligned attribute, ac_cv_attribute_aligned,[ @@ -289,7 +289,7 @@ dnl dnl log2 could be used to improve the log function, however it requires C99. The check for log2 should be turned on, dnl as soon as we support C99. AC_CHECK_FUNCS(getcwd getwd asinh acosh atanh log1p hypot glob strfmon nice fpclass mempcpy strpncpy) -AC_FUNC_FNMATCH +AC_FUNC_FNMATCH dnl dnl Check if there is a support means of creating a new process @@ -490,7 +490,7 @@ PHP_NEW_EXTENSION(standard, array.c base64.c basic_functions.c browscap.c crc32. http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ filters.c proc_open.c streamsfuncs.c http.c password.c \ - random.c net.c,,, + random.c net.c hrtime.c,,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_MAKEFILE_FRAGMENT diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index fe519b8db9..e2fd7a28f1 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -36,12 +36,11 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \ url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ user_filters.c uuencode.c filters.c proc_open.c password.c \ - streamsfuncs.c http.c flock_compat.c random.c", false /* never shared */, + streamsfuncs.c http.c flock_compat.c random.c hrtime.c", false /* never shared */, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); PHP_INSTALL_HEADERS("", "ext/standard"); if (PHP_MBREGEX != "no") { - CHECK_HEADER_ADD_INCLUDE("oniguruma.h", "CFLAGS_STANDARD", PHP_MBREGEX + ";ext\\mbstring\\oniguruma") + CHECK_HEADER_ADD_INCLUDE("oniguruma.h", "CFLAGS_STANDARD", PHP_MBREGEX + ";ext\\mbstring\\oniguruma") } ADD_MAKEFILE_FRAGMENT(); PHP_INSTALL_HEADERS("", "ext/standard"); - diff --git a/ext/standard/hrtime.c b/ext/standard/hrtime.c new file mode 100644 index 0000000000..c32aef4e1a --- /dev/null +++ b/ext/standard/hrtime.c @@ -0,0 +1,206 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2017 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Niklas Keller | + | Author: Anatol Belski | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#include "php.h" +#include "hrtime.h" + +/* {{{ */ +/* This file reuses code parts from the cross-platform timer library + Public Domain - 2011 Mattias Jansson / Rampant Pixels */ + +#if PHP_HRTIME_PLATFORM_POSIX + +# include +# include +# include + +#elif PHP_HRTIME_PLATFORM_WINDOWS + +# define WIN32_LEAN_AND_MEAN + +static double _timer_scale = .0; + +#elif PHP_HRTIME_PLATFORM_APPLE + +# include +# include +static mach_timebase_info_data_t _timerlib_info; + +#elif PHP_HRTIME_PLATFORM_HPUX + +# include + +#elif PHP_HRTIME_PLATFORM_AIX + +# include +# include + +#endif + +#define NANO_IN_SEC 1000000000 +/* }}} */ + +static int _timer_init() +{/*{{{*/ +#if PHP_HRTIME_PLATFORM_WINDOWS + + LARGE_INTEGER tf = {0}; + if (!QueryPerformanceFrequency(&tf) || 0 == tf.QuadPart) { + return -1; + } + _timer_scale = (double)NANO_IN_SEC / (php_hrtime_t)tf.QuadPart; + +#elif PHP_HRTIME_PLATFORM_APPLE + + if (mach_timebase_info(&_timerlib_info)) { + return -1; + } + +#elif PHP_HRTIME_PLATFORM_POSIX + +#if !_POSIX_MONOTONIC_CLOCK +#ifdef _SC_MONOTONIC_CLOCK + if (0 >= sysconf(_SC_MONOTONIC_CLOCK)) { + return -1; + } +#endif +#endif + +#elif PHP_HRTIME_PLATFORM_HPUX + + /* pass */ + +#elif PHP_HRTIME_PLATFORM_AIX + + /* pass */ + +#else + /* Timer unavailable. */ + return -1; +#endif + + return 0; +}/*}}}*/ + +/* {{{ */ +PHP_MINIT_FUNCTION(hrtime) +{ + if (0 > _timer_init()) { + php_error_docref(NULL, E_WARNING, "Failed to initialize high-resolution timer"); + return FAILURE; + } + + return SUCCESS; +} +/* }}} */ + +static zend_always_inline php_hrtime_t _timer_current(void) +{/*{{{*/ +#if PHP_HRTIME_PLATFORM_WINDOWS + LARGE_INTEGER lt = {0}; + QueryPerformanceCounter(<); + return (php_hrtime_t)((php_hrtime_t)lt.QuadPart * _timer_scale); +#elif PHP_HRTIME_PLATFORM_APPLE + return (php_hrtime_t)mach_absolute_time() * _timerlib_info.numer / _timerlib_info.denom; +#elif PHP_HRTIME_PLATFORM_POSIX + struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; + if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) { + return ((php_hrtime_t) ts.tv_sec * (php_hrtime_t)NANO_IN_SEC) + ts.tv_nsec; + } + return 0; +#elif PHP_HRTIME_PLATFORM_HPUX + return (php_hrtime_t) gethrtime(); +#elif PHP_HRTIME_PLATFORM_AIX + timebasestruct_t t; + read_wall_time(&t, TIMEBASE_SZ); + time_base_to_time(&t, TIMEBASE_SZ); + return (php_hrtime_t) t.tb_high * (php_hrtime_t)NANO_IN_SEC + t.tb_low; +#else + return 0; +#endif +}/*}}}*/ + +#if ZEND_ENABLE_ZVAL_LONG64 +#define PHP_RETURN_HRTIME(t) RETURN_LONG((zend_long)t) +#else +#ifdef _WIN32 +# define HRTIME_U64A(i, s, len) _ui64toa_s(i, s, len, 10) +#else +# define HRTIME_U64A(i, s, len) \ + do { \ + int st = snprintf(s, len, "%llu", i); \ + s[st] = '\0'; \ + } while (0) +#endif +#define PHP_RETURN_HRTIME(t) do { \ + char _a[ZEND_LTOA_BUF_LEN]; \ + double _d; \ + HRTIME_U64A(t, _a, ZEND_LTOA_BUF_LEN); \ + _d = zend_strtod(_a, NULL); \ + RETURN_DOUBLE(_d); \ + } while (0) +#endif + +/* {{{ proto mixed hrtime([bool get_as_number = false]) + Returns an array of integers in form [seconds, nanoseconds] counted + from an arbitrary point in time. If an optional boolean argument is + passed, returns an integer on 64-bit platforms or float on 32-bit + containing the current high-resolution time in nanoseconds. The + delivered timestamp is monotonic and can not be adjusted. */ +PHP_FUNCTION(hrtime) +{ +#if HRTIME_AVAILABLE + zend_bool get_as_num = 0; + php_hrtime_t t = _timer_current(); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(get_as_num) + ZEND_PARSE_PARAMETERS_END(); + + if (UNEXPECTED(get_as_num)) { + PHP_RETURN_HRTIME(t); + } else { + array_init_size(return_value, 2); + zend_hash_real_init(Z_ARRVAL_P(return_value), 1); + add_next_index_long(return_value, (zend_long)(t / (php_hrtime_t)NANO_IN_SEC)); + add_next_index_long(return_value, (zend_long)(t % (php_hrtime_t)NANO_IN_SEC)); + } +#else + RETURN_FALSE +#endif +} +/* }}} */ + +PHPAPI php_hrtime_t php_hrtime_current(void) +{/*{{{*/ + return _timer_current(); +}/*}}}*/ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ + diff --git a/ext/standard/hrtime.h b/ext/standard/hrtime.h new file mode 100644 index 0000000000..f0681247d4 --- /dev/null +++ b/ext/standard/hrtime.h @@ -0,0 +1,58 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2017 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Niklas Keller | + | Author: Anatol Belski | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef HRTIME_H +#define HRTIME_H + +#define PHP_HRTIME_PLATFORM_POSIX 0 +#define PHP_HRTIME_PLATFORM_WINDOWS 0 +#define PHP_HRTIME_PLATFORM_APPLE 0 +#define PHP_HRTIME_PLATFORM_HPUX 0 +#define PHP_HRTIME_PLATFORM_AIX 0 + +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC) +# undef PHP_HRTIME_PLATFORM_POSIX +# define PHP_HRTIME_PLATFORM_POSIX 1 +#elif defined(_WIN32) || defined(_WIN64) +# undef PHP_HRTIME_PLATFORM_WINDOWS +# define PHP_HRTIME_PLATFORM_WINDOWS 1 +#elif defined(__APPLE__) +# undef PHP_HRTIME_PLATFORM_APPLE +# define PHP_HRTIME_PLATFORM_APPLE 1 +#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) +# undef PHP_HRTIME_PLATFORM_HPUX +# define PHP_HRTIME_PLATFORM_HPUX 1 +#elif defined(_AIX) +# undef PHP_HRTIME_PLATFORM_AIX +# define PHP_HRTIME_PLATFORM_AIX 1 +#endif + +#define HRTIME_AVAILABLE (PHP_HRTIME_PLATFORM_POSIX || PHP_HRTIME_PLATFORM_WINDOWS || PHP_HRTIME_PLATFORM_APPLE || PHP_HRTIME_PLATFORM_HPUX || PHP_HRTIME_PLATFORM_AIX) + +typedef uint64_t php_hrtime_t; + +PHPAPI php_hrtime_t php_hrtime_current(void); + +PHP_MINIT_FUNCTION(hrtime); + +PHP_FUNCTION(hrtime); + +#endif /* HRTIME_H */ diff --git a/ext/standard/php_standard.h b/ext/standard/php_standard.h index 750507688b..eb7f42b082 100644 --- a/ext/standard/php_standard.h +++ b/ext/standard/php_standard.h @@ -27,6 +27,7 @@ #include "php_mail.h" #include "md5.h" #include "sha1.h" +#include "hrtime.h" #include "html.h" #include "exec.h" #include "file.h" diff --git a/ext/standard/tests/hrtime/hrtime.phpt b/ext/standard/tests/hrtime/hrtime.phpt new file mode 100644 index 0000000000..bac127bf44 --- /dev/null +++ b/ext/standard/tests/hrtime/hrtime.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test hrtime() aligns with microtime() +--FILE-- + 0.05) { + print "FAIL, $d"; +} else { + print "OK, $d"; +} + +?> +--EXPECTF-- +OK, %f diff --git a/ext/standard/tests/hrtime/hrtime_array.phpt b/ext/standard/tests/hrtime/hrtime_array.phpt new file mode 100644 index 0000000000..c3b4b61258 --- /dev/null +++ b/ext/standard/tests/hrtime/hrtime_array.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test hrtime() return array +--FILE-- + +--EXPECTF-- +array(2) { + [0]=> + int(%d) + [1]=> + int(%d) +}