mirror of
https://github.com/php/php-src.git
synced 2024-11-27 03:44:07 +08:00
Remove zend_strtod mutex (#13974)
`zend_strtod.c` uses a global state (mostly an allocation freelist) protected by a mutex in ZTS builds. This state is used by `zend_dtoa()`, `zend_strtod()`, and variants. This creates a lot of contention in concurrent loads. `zend_dtoa()` is used to format floats to string, e.g. in sprintf, json_encode, serialize, uniqid. Here I move the global state to the thread specific `executor_globals` and remove the mutex. The impact on non-concurrent environments is null or negligible, but there is a considerable speed up on concurrent environments, especially on Alpine/Musl.
This commit is contained in:
parent
07337df1d7
commit
9bbc195d11
@ -823,6 +823,10 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{
|
||||
executor_globals->pid = 0;
|
||||
executor_globals->oldact = (struct sigaction){0};
|
||||
#endif
|
||||
memset(executor_globals->strtod_state.freelist, 0,
|
||||
sizeof(executor_globals->strtod_state.freelist));
|
||||
executor_globals->strtod_state.p5s = NULL;
|
||||
executor_globals->strtod_state.result = NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -918,7 +922,6 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
|
||||
#endif
|
||||
|
||||
zend_startup_hrtime();
|
||||
zend_startup_strtod();
|
||||
zend_startup_extensions_mechanism();
|
||||
|
||||
/* Set up utility functions and values */
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "zend_arena.h"
|
||||
#include "zend_call_stack.h"
|
||||
#include "zend_max_execution_timer.h"
|
||||
#include "zend_strtod.h"
|
||||
|
||||
/* Define ZTS if you want a thread-safe Zend */
|
||||
/*#undef ZTS*/
|
||||
@ -304,6 +305,8 @@ struct _zend_executor_globals {
|
||||
struct sigaction oldact;
|
||||
#endif
|
||||
|
||||
zend_strtod_state strtod_state;
|
||||
|
||||
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
|
||||
};
|
||||
|
||||
|
@ -189,6 +189,7 @@
|
||||
#include <zend_operators.h>
|
||||
#include <zend_strtod.h>
|
||||
#include "zend_strtod_int.h"
|
||||
#include "zend_globals.h"
|
||||
|
||||
#ifndef Long
|
||||
#define Long int32_t
|
||||
@ -197,6 +198,16 @@
|
||||
#define ULong uint32_t
|
||||
#endif
|
||||
|
||||
#undef Bigint
|
||||
#undef freelist
|
||||
#undef p5s
|
||||
#undef dtoa_result
|
||||
|
||||
#define Bigint _zend_strtod_bigint
|
||||
#define freelist (EG(strtod_state).freelist)
|
||||
#define p5s (EG(strtod_state).p5s)
|
||||
#define dtoa_result (EG(strtod_state).result)
|
||||
|
||||
#ifdef DEBUG
|
||||
static void Bug(const char *message) {
|
||||
fprintf(stderr, "%s\n", message);
|
||||
@ -224,6 +235,7 @@ extern void *MALLOC(size_t);
|
||||
#endif
|
||||
#else
|
||||
#define MALLOC malloc
|
||||
#define FREE free
|
||||
#endif
|
||||
|
||||
#ifndef Omit_Private_Memory
|
||||
@ -522,7 +534,7 @@ BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflc
|
||||
#define FREE_DTOA_LOCK(n) /*nothing*/
|
||||
#endif
|
||||
|
||||
#define Kmax 7
|
||||
#define Kmax ZEND_STRTOD_K_MAX
|
||||
|
||||
struct
|
||||
Bigint {
|
||||
@ -533,37 +545,23 @@ Bigint {
|
||||
|
||||
typedef struct Bigint Bigint;
|
||||
|
||||
#ifndef Bigint
|
||||
static Bigint *freelist[Kmax+1];
|
||||
#endif
|
||||
|
||||
static void destroy_freelist(void);
|
||||
static void free_p5s(void);
|
||||
|
||||
#ifdef ZTS
|
||||
#ifdef MULTIPLE_THREADS
|
||||
static MUTEX_T dtoa_mutex;
|
||||
static MUTEX_T pow5mult_mutex;
|
||||
#endif /* ZTS */
|
||||
|
||||
ZEND_API int zend_startup_strtod(void) /* {{{ */
|
||||
{
|
||||
#ifdef ZTS
|
||||
dtoa_mutex = tsrm_mutex_alloc();
|
||||
pow5mult_mutex = tsrm_mutex_alloc();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
/* }}} */
|
||||
ZEND_API int zend_shutdown_strtod(void) /* {{{ */
|
||||
{
|
||||
destroy_freelist();
|
||||
free_p5s();
|
||||
|
||||
#ifdef ZTS
|
||||
tsrm_mutex_free(dtoa_mutex);
|
||||
dtoa_mutex = NULL;
|
||||
|
||||
tsrm_mutex_free(pow5mult_mutex);
|
||||
pow5mult_mutex = NULL;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
/* }}} */
|
||||
@ -627,11 +625,7 @@ Bfree
|
||||
{
|
||||
if (v) {
|
||||
if (v->k > Kmax)
|
||||
#ifdef FREE
|
||||
FREE((void*)v);
|
||||
#else
|
||||
free((void*)v);
|
||||
#endif
|
||||
else {
|
||||
ACQUIRE_DTOA_LOCK(0);
|
||||
v->next = freelist[v->k];
|
||||
@ -947,7 +941,9 @@ mult
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifndef p5s
|
||||
static Bigint *p5s;
|
||||
#endif
|
||||
|
||||
static Bigint *
|
||||
pow5mult
|
||||
@ -3602,7 +3598,7 @@ zend_strtod
|
||||
return sign ? -dval(&rv) : dval(&rv);
|
||||
}
|
||||
|
||||
#ifndef MULTIPLE_THREADS
|
||||
#if !defined(MULTIPLE_THREADS) && !defined(dtoa_result)
|
||||
ZEND_TLS char *dtoa_result;
|
||||
#endif
|
||||
|
||||
@ -4616,7 +4612,7 @@ static void destroy_freelist(void)
|
||||
Bigint **listp = &freelist[i];
|
||||
while ((tmp = *listp) != NULL) {
|
||||
*listp = tmp->next;
|
||||
free(tmp);
|
||||
FREE(tmp);
|
||||
}
|
||||
freelist[i] = NULL;
|
||||
}
|
||||
@ -4631,7 +4627,8 @@ static void free_p5s(void)
|
||||
listp = &p5s;
|
||||
while ((tmp = *listp) != NULL) {
|
||||
*listp = tmp->next;
|
||||
free(tmp);
|
||||
FREE(tmp);
|
||||
}
|
||||
p5s = NULL;
|
||||
FREE_DTOA_LOCK(1)
|
||||
}
|
||||
|
@ -23,6 +23,13 @@
|
||||
#include <zend.h>
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
#define ZEND_STRTOD_K_MAX 7
|
||||
typedef struct _zend_strtod_bigint zend_strtod_bigint;
|
||||
typedef struct _zend_strtod_state {
|
||||
zend_strtod_bigint *freelist[ZEND_STRTOD_K_MAX+1];
|
||||
zend_strtod_bigint *p5s;
|
||||
char *result;
|
||||
} zend_strtod_state;
|
||||
ZEND_API void zend_freedtoa(char *s);
|
||||
ZEND_API char *zend_dtoa(double _d, int mode, int ndigits, int *decpt, bool *sign, char **rve);
|
||||
ZEND_API char *zend_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf);
|
||||
@ -30,7 +37,6 @@ ZEND_API double zend_strtod(const char *s00, const char **se);
|
||||
ZEND_API double zend_hex_strtod(const char *str, const char **endptr);
|
||||
ZEND_API double zend_oct_strtod(const char *str, const char **endptr);
|
||||
ZEND_API double zend_bin_strtod(const char *str, const char **endptr);
|
||||
ZEND_API int zend_startup_strtod(void);
|
||||
ZEND_API int zend_shutdown_strtod(void);
|
||||
END_EXTERN_C()
|
||||
|
||||
|
@ -104,24 +104,4 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ZTS
|
||||
#define MULTIPLE_THREADS 1
|
||||
|
||||
#define ACQUIRE_DTOA_LOCK(x) \
|
||||
if (0 == x) { \
|
||||
tsrm_mutex_lock(dtoa_mutex); \
|
||||
} else if (1 == x) { \
|
||||
tsrm_mutex_lock(pow5mult_mutex); \
|
||||
}
|
||||
|
||||
#define FREE_DTOA_LOCK(x) \
|
||||
if (0 == x) { \
|
||||
tsrm_mutex_unlock(dtoa_mutex); \
|
||||
} else if (1 == x) { \
|
||||
tsrm_mutex_unlock(pow5mult_mutex); \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* ZEND_STRTOD_INT_H */
|
||||
|
Loading…
Reference in New Issue
Block a user