hrtime.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Niklas Keller <kelunik@php.net> |
  14. | Author: Anatol Belski <ab@php.net> |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "php.h"
  18. #include "hrtime.h"
  19. /* {{{ */
  20. /* This file reuses code parts from the cross-platform timer library
  21. Public Domain - 2011 Mattias Jansson / Rampant Pixels */
  22. #if PHP_HRTIME_PLATFORM_POSIX
  23. # include <unistd.h>
  24. # include <time.h>
  25. # include <string.h>
  26. #elif PHP_HRTIME_PLATFORM_WINDOWS
  27. # define WIN32_LEAN_AND_MEAN
  28. static double _timer_scale = .0;
  29. #elif PHP_HRTIME_PLATFORM_APPLE
  30. # include <mach/mach_time.h>
  31. # include <string.h>
  32. static mach_timebase_info_data_t _timerlib_info;
  33. #elif PHP_HRTIME_PLATFORM_HPUX
  34. # include <sys/time.h>
  35. #elif PHP_HRTIME_PLATFORM_AIX
  36. # include <sys/time.h>
  37. # include <sys/systemcfg.h>
  38. #endif
  39. #define NANO_IN_SEC 1000000000
  40. /* }}} */
  41. static int _timer_init(void)
  42. {/*{{{*/
  43. #if PHP_HRTIME_PLATFORM_WINDOWS
  44. LARGE_INTEGER tf = {0};
  45. if (!QueryPerformanceFrequency(&tf) || 0 == tf.QuadPart) {
  46. return -1;
  47. }
  48. _timer_scale = (double)NANO_IN_SEC / (php_hrtime_t)tf.QuadPart;
  49. #elif PHP_HRTIME_PLATFORM_APPLE
  50. if (mach_timebase_info(&_timerlib_info)) {
  51. return -1;
  52. }
  53. #elif PHP_HRTIME_PLATFORM_POSIX
  54. #if !_POSIX_MONOTONIC_CLOCK
  55. #ifdef _SC_MONOTONIC_CLOCK
  56. if (0 >= sysconf(_SC_MONOTONIC_CLOCK)) {
  57. return -1;
  58. }
  59. #endif
  60. #endif
  61. #elif PHP_HRTIME_PLATFORM_HPUX
  62. /* pass */
  63. #elif PHP_HRTIME_PLATFORM_AIX
  64. /* pass */
  65. #else
  66. /* Timer unavailable. */
  67. return -1;
  68. #endif
  69. return 0;
  70. }/*}}}*/
  71. /* {{{ */
  72. PHP_MINIT_FUNCTION(hrtime)
  73. {
  74. if (0 > _timer_init()) {
  75. php_error_docref(NULL, E_WARNING, "Failed to initialize high-resolution timer");
  76. return FAILURE;
  77. }
  78. return SUCCESS;
  79. }
  80. /* }}} */
  81. static zend_always_inline php_hrtime_t _timer_current(void)
  82. {/*{{{*/
  83. #if PHP_HRTIME_PLATFORM_WINDOWS
  84. LARGE_INTEGER lt = {0};
  85. QueryPerformanceCounter(&lt);
  86. return (php_hrtime_t)((php_hrtime_t)lt.QuadPart * _timer_scale);
  87. #elif PHP_HRTIME_PLATFORM_APPLE
  88. return (php_hrtime_t)mach_absolute_time() * _timerlib_info.numer / _timerlib_info.denom;
  89. #elif PHP_HRTIME_PLATFORM_POSIX
  90. struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
  91. if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) {
  92. return ((php_hrtime_t) ts.tv_sec * (php_hrtime_t)NANO_IN_SEC) + ts.tv_nsec;
  93. }
  94. return 0;
  95. #elif PHP_HRTIME_PLATFORM_HPUX
  96. return (php_hrtime_t) gethrtime();
  97. #elif PHP_HRTIME_PLATFORM_AIX
  98. timebasestruct_t t;
  99. read_wall_time(&t, TIMEBASE_SZ);
  100. time_base_to_time(&t, TIMEBASE_SZ);
  101. return (php_hrtime_t) t.tb_high * (php_hrtime_t)NANO_IN_SEC + t.tb_low;
  102. #else
  103. return 0;
  104. #endif
  105. }/*}}}*/
  106. #if ZEND_ENABLE_ZVAL_LONG64
  107. #define PHP_RETURN_HRTIME(t) RETURN_LONG((zend_long)t)
  108. #else
  109. #ifdef _WIN32
  110. # define HRTIME_U64A(i, s, len) _ui64toa_s(i, s, len, 10)
  111. #else
  112. # define HRTIME_U64A(i, s, len) \
  113. do { \
  114. int st = snprintf(s, len, "%llu", i); \
  115. s[st] = '\0'; \
  116. } while (0)
  117. #endif
  118. #define PHP_RETURN_HRTIME(t) do { \
  119. char _a[ZEND_LTOA_BUF_LEN]; \
  120. double _d; \
  121. HRTIME_U64A(t, _a, ZEND_LTOA_BUF_LEN); \
  122. _d = zend_strtod(_a, NULL); \
  123. RETURN_DOUBLE(_d); \
  124. } while (0)
  125. #endif
  126. /* {{{ Returns an array of integers in form [seconds, nanoseconds] counted
  127. from an arbitrary point in time. If an optional boolean argument is
  128. passed, returns an integer on 64-bit platforms or float on 32-bit
  129. containing the current high-resolution time in nanoseconds. The
  130. delivered timestamp is monotonic and can not be adjusted. */
  131. PHP_FUNCTION(hrtime)
  132. {
  133. #if HRTIME_AVAILABLE
  134. bool get_as_num = 0;
  135. php_hrtime_t t = _timer_current();
  136. ZEND_PARSE_PARAMETERS_START(0, 1)
  137. Z_PARAM_OPTIONAL
  138. Z_PARAM_BOOL(get_as_num)
  139. ZEND_PARSE_PARAMETERS_END();
  140. if (UNEXPECTED(get_as_num)) {
  141. PHP_RETURN_HRTIME(t);
  142. } else {
  143. array_init_size(return_value, 2);
  144. zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
  145. add_next_index_long(return_value, (zend_long)(t / (php_hrtime_t)NANO_IN_SEC));
  146. add_next_index_long(return_value, (zend_long)(t % (php_hrtime_t)NANO_IN_SEC));
  147. }
  148. #else
  149. RETURN_FALSE;
  150. #endif
  151. }
  152. /* }}} */
  153. PHPAPI php_hrtime_t php_hrtime_current(void)
  154. {/*{{{*/
  155. return _timer_current();
  156. }/*}}}*/