com php-src: Fixed bug #74851: Improve uniqid() performance: NEWS ext/standard/uniqid.c
| From: | Nikita Popov | Date: | Wed, 19 Jul 2017 17:54:19 +0000 |
| Subject: | com php-src: Fixed bug #74851: Improve uniqid() performance: NEWS ext/standard/uniqid.c | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-98641@lists.php.net to get a copy of this message | ||
Commit: d25049cc1b74ae445d6521997a421a7462f1ad5b
Author: Emmanuel Dreyfus <manu@netbsd.org> Wed, 19 Jul 2017 04:36:55 +0200
Committer: Nikita Popov <nikita.ppv@gmail.com> Wed, 19 Jul 2017 19:54:19 +0200
Parents: 6fcc7134f1d4aaf60e24202ed316c61636c5a95d
Branches: PHP-7.2 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=d25049cc1b74ae445d6521997a421a7462f1ad5b
Log:
Fixed bug #74851: Improve uniqid() performance
uniqid() relies on microsecond-precise system clock to produce an
unique identifier. In order to avoid using the same value, the
original implementation calls usleep(1) to wait for the next microsecond.
Unfortunately, usleep() specification says "The suspension time may be
longer than requested due to the scheduling of other activity by the
system." Indeed, the pause may as as long as an entire execution slice,
causing a uniqid() call to last more than 10 ms.
This is fixed by replacing the usleep() call by time polling using
gettimeofday() until the microsecond changes. Since the getttimeoday()
system call lasts around a microsecond, only a small time is wasted
calling multiple gettimeofday. On the benefit side, uniqid() performance
in increased 10000 fold without changing its behavior.
Bugs:
https://bugs.php.net/74851
Changed paths:
M NEWS
M ext/standard/uniqid.c
Diff:
diff --git a/NEWS b/NEWS
index 7ef1302..a1a9b4e 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,10 @@ PHP NEWS
- SPL:
. Fixed bug #74669 (Unserialize ArrayIterator broken). (Andrew Nester)
+- Standard:
+ .. Fixed bug #74851 (uniqid() without more_entropy performs badly).
+ (Emmanuel Dreyfus)
+
20 Jul 2017, PHP 7.2.0beta1
- Core:
diff --git a/ext/standard/uniqid.c b/ext/standard/uniqid.c
index 22173ae..e8f2f19 100644
--- a/ext/standard/uniqid.c
+++ b/ext/standard/uniqid.c
@@ -38,17 +38,15 @@
#include "php_lcg.h"
#include "uniqid.h"
+#ifdef HAVE_GETTIMEOFDAY
+ZEND_TLS struct timeval prev_tv = { 0, 0 };
+
/* {{{ proto string uniqid([string prefix [, bool more_entropy]])
Generates a unique ID */
-#ifdef HAVE_GETTIMEOFDAY
PHP_FUNCTION(uniqid)
{
char *prefix = "";
-#if defined(__CYGWIN__)
- zend_bool more_entropy = 1;
-#else
zend_bool more_entropy = 0;
-#endif
zend_string *uniqid;
int sec, usec;
size_t prefix_len = 0;
@@ -60,17 +58,20 @@ PHP_FUNCTION(uniqid)
Z_PARAM_BOOL(more_entropy)
ZEND_PARSE_PARAMETERS_END();
-#if HAVE_USLEEP && !defined(PHP_WIN32)
if (!more_entropy) {
-#if defined(__CYGWIN__)
- php_error_docref(NULL, E_WARNING, "You must use 'more entropy' under
CYGWIN");
- RETURN_FALSE;
-#else
- usleep(1);
-#endif
+ /* This implementation needs current microsecond to change,
+ * hence we poll time until it does. This is much faster than
+ * calling usleep(1) which may cause the kernel to schedule
+ * another process, causing a pause of around 10ms.
+ */
+ do {
+ (void)gettimeofday((struct timeval *) &tv, (struct timezone *) NULL);
+ } while (tv.tv_sec == prev_tv.tv_sec && tv.tv_usec == prev_tv.tv_usec);
+
+ prev_tv.tv_sec = tv.tv_sec;
+ prev_tv.tv_usec = tv.tv_usec;
}
-#endif
- gettimeofday((struct timeval *) &tv, (struct timezone *) NULL);
+
sec = (int) tv.tv_sec;
usec = (int) (tv.tv_usec % 0x100000);