From c3a46234bc997b7ec7189668b1a3f74415535732 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Wed, 10 Jul 2024 01:18:19 +0900 Subject: [PATCH 1/7] Optimized getBytes loop processing --- ext/random/php_random.h | 41 ++++++++++++++++++++++++++++ ext/random/randomizer.c | 59 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 94 insertions(+), 6 deletions(-) diff --git a/ext/random/php_random.h b/ext/random/php_random.h index e4aa32126671e..d8ac9fcebe08a 100644 --- a/ext/random/php_random.h +++ b/ext/random/php_random.h @@ -214,4 +214,45 @@ PHPAPI ZEND_EXTERN_MODULE_GLOBALS(random) # define RANDOM_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(random, v) +/* Bytes swap */ +#ifdef _MSC_VER +# include +# define RANDOM_BSWAP32(u) _byteswap_ulong(u) +# define RANDOM_BSWAP64(u) _byteswap_uint64(u) +#else +# ifdef __GNUC__ +# define RANDOM_BSWAP32(u) __builtin_bswap32(u) +# define RANDOM_BSWAP64(u) __builtin_bswap64(u) +# elif defined(__has_builtin) +# if __has_builtin(__builtin_bswap32) +# define RANDOM_BSWAP32(u) __builtin_bswap32(u) +# endif // __has_builtin(__builtin_bswap32) +# if __has_builtin(__builtin_bswap64) +# define RANDOM_BSWAP64(u) __builtin_bswap64(u) +# endif // __has_builtin(__builtin_bswap64) +# endif // __GNUC__ +#endif // _MSC_VER +#ifndef RANDOM_BSWAP32 +static inline uint32_t RANDOM_BSWAP32(uint32_t u) +{ + return (((u & 0xff000000) >> 24) + | ((u & 0x00ff0000) >> 8) + | ((u & 0x0000ff00) << 8) + | ((u & 0x000000ff) << 24)); +} +#endif +#ifndef RANDOM_BSWAP64 +static inline uint64_t RANDOM_BSWAP64(uint64_t u) +{ + return (((u & 0xff00000000000000ULL) >> 56) + | ((u & 0x00ff000000000000ULL) >> 40) + | ((u & 0x0000ff0000000000ULL) >> 24) + | ((u & 0x000000ff00000000ULL) >> 8) + | ((u & 0x00000000ff000000ULL) << 8) + | ((u & 0x0000000000ff0000ULL) << 24) + | ((u & 0x000000000000ff00ULL) << 40) + | ((u & 0x00000000000000ffULL) << 56)); +} +#endif + #endif /* PHP_RANDOM_H */ diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index 76ff5bf590a88..787edabd65f5d 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -270,6 +270,43 @@ PHP_METHOD(Random_Randomizer, getInt) } /* }}} */ +static zend_always_inline char *bulk_convert_generated_result_to_char_32(char *ptr, uint64_t result, size_t *to_read) +{ + if (*to_read >= sizeof(uint32_t)) { + uint32_t tmp = (uint32_t) result; +#ifdef WORDS_BIGENDIAN + tmp = RANDOM_BSWAP32(tmp); +#endif + memcpy(ptr, &tmp, sizeof(uint32_t)); + ptr += sizeof(uint32_t); + *to_read -= sizeof(uint32_t); + } else { + while (*to_read > 0) { + *ptr++ = result & 0xff; + result >>= 8; + *to_read -= 1; + } + } + + return ptr; +} + +static zend_always_inline char *bulk_convert_generated_result_to_char_64(char *ptr, uint64_t result, size_t *to_read) +{ + if (*to_read >= sizeof(uint64_t)) { +#ifdef WORDS_BIGENDIAN + result = RANDOM_BSWAP64(result); +#endif + memcpy(ptr, &result, sizeof(uint64_t)); + ptr += sizeof(uint64_t); + *to_read -= sizeof(uint64_t); + } else { + ptr = bulk_convert_generated_result_to_char_32(ptr, result, to_read); + } + + return ptr; +} + /* {{{ Generate random bytes string in ordered length */ PHP_METHOD(Random_Randomizer, getBytes) { @@ -278,7 +315,6 @@ PHP_METHOD(Random_Randomizer, getBytes) zend_string *retval; zend_long user_length; - size_t total_size = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(user_length) @@ -291,17 +327,28 @@ PHP_METHOD(Random_Randomizer, getBytes) size_t length = (size_t)user_length; retval = zend_string_alloc(length, 0); + char *rptr = ZSTR_VAL(retval); - while (total_size < length) { + size_t to_read = length; + while (to_read > 0) { php_random_result result = engine.algo->generate(engine.state); if (EG(exception)) { zend_string_free(retval); RETURN_THROWS(); } - for (size_t i = 0; i < result.size; i++) { - ZSTR_VAL(retval)[total_size++] = (result.result >> (i * 8)) & 0xff; - if (total_size >= length) { - break; + if (EXPECTED(result.size == sizeof(uint64_t))) { + rptr = bulk_convert_generated_result_to_char_64(rptr, result.result, &to_read); + } else if (EXPECTED(result.size == sizeof(uint32_t))){ + rptr = bulk_convert_generated_result_to_char_32(rptr, result.result, &to_read); + } else { + uint64_t tmp_ret = result.result; + for (size_t i = 0; i < result.size; i++) { + *rptr++ = tmp_ret & 0xff; + tmp_ret >>= 8; + to_read--; + if (to_read == 0) { + break; + } } } } From 6a17d327642dea3ca11d499f1723e40163746ea7 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Wed, 10 Jul 2024 10:20:51 +0900 Subject: [PATCH 2/7] version 2 --- ext/random/php_random.h | 14 ----------- ext/random/randomizer.c | 51 ++++++++--------------------------------- 2 files changed, 9 insertions(+), 56 deletions(-) diff --git a/ext/random/php_random.h b/ext/random/php_random.h index d8ac9fcebe08a..37f3d8e564fbb 100644 --- a/ext/random/php_random.h +++ b/ext/random/php_random.h @@ -217,30 +217,16 @@ PHPAPI ZEND_EXTERN_MODULE_GLOBALS(random) /* Bytes swap */ #ifdef _MSC_VER # include -# define RANDOM_BSWAP32(u) _byteswap_ulong(u) # define RANDOM_BSWAP64(u) _byteswap_uint64(u) #else # ifdef __GNUC__ -# define RANDOM_BSWAP32(u) __builtin_bswap32(u) # define RANDOM_BSWAP64(u) __builtin_bswap64(u) # elif defined(__has_builtin) -# if __has_builtin(__builtin_bswap32) -# define RANDOM_BSWAP32(u) __builtin_bswap32(u) -# endif // __has_builtin(__builtin_bswap32) # if __has_builtin(__builtin_bswap64) # define RANDOM_BSWAP64(u) __builtin_bswap64(u) # endif // __has_builtin(__builtin_bswap64) # endif // __GNUC__ #endif // _MSC_VER -#ifndef RANDOM_BSWAP32 -static inline uint32_t RANDOM_BSWAP32(uint32_t u) -{ - return (((u & 0xff000000) >> 24) - | ((u & 0x00ff0000) >> 8) - | ((u & 0x0000ff00) << 8) - | ((u & 0x000000ff) << 24)); -} -#endif #ifndef RANDOM_BSWAP64 static inline uint64_t RANDOM_BSWAP64(uint64_t u) { diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index 787edabd65f5d..ef62f202b84c2 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -270,43 +270,6 @@ PHP_METHOD(Random_Randomizer, getInt) } /* }}} */ -static zend_always_inline char *bulk_convert_generated_result_to_char_32(char *ptr, uint64_t result, size_t *to_read) -{ - if (*to_read >= sizeof(uint32_t)) { - uint32_t tmp = (uint32_t) result; -#ifdef WORDS_BIGENDIAN - tmp = RANDOM_BSWAP32(tmp); -#endif - memcpy(ptr, &tmp, sizeof(uint32_t)); - ptr += sizeof(uint32_t); - *to_read -= sizeof(uint32_t); - } else { - while (*to_read > 0) { - *ptr++ = result & 0xff; - result >>= 8; - *to_read -= 1; - } - } - - return ptr; -} - -static zend_always_inline char *bulk_convert_generated_result_to_char_64(char *ptr, uint64_t result, size_t *to_read) -{ - if (*to_read >= sizeof(uint64_t)) { -#ifdef WORDS_BIGENDIAN - result = RANDOM_BSWAP64(result); -#endif - memcpy(ptr, &result, sizeof(uint64_t)); - ptr += sizeof(uint64_t); - *to_read -= sizeof(uint64_t); - } else { - ptr = bulk_convert_generated_result_to_char_32(ptr, result, to_read); - } - - return ptr; -} - /* {{{ Generate random bytes string in ordered length */ PHP_METHOD(Random_Randomizer, getBytes) { @@ -336,12 +299,16 @@ PHP_METHOD(Random_Randomizer, getBytes) zend_string_free(retval); RETURN_THROWS(); } - if (EXPECTED(result.size == sizeof(uint64_t))) { - rptr = bulk_convert_generated_result_to_char_64(rptr, result.result, &to_read); - } else if (EXPECTED(result.size == sizeof(uint32_t))){ - rptr = bulk_convert_generated_result_to_char_32(rptr, result.result, &to_read); + + uint64_t tmp_ret = result.result; + if (to_read >= result.size && result.size == sizeof(uint64_t)) { +#ifdef WORDS_BIGENDIAN + tmp_ret = RANDOM_BSWAP64(tmp_ret); +#endif + memcpy(rptr, &tmp_ret, sizeof(uint64_t)); + to_read -= sizeof(uint64_t); + rptr += sizeof(uint64_t); } else { - uint64_t tmp_ret = result.result; for (size_t i = 0; i < result.size; i++) { *rptr++ = tmp_ret & 0xff; tmp_ret >>= 8; From 4d9b51c88534b7f94a2e3a659e096c6371304c4e Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Fri, 12 Jul 2024 00:18:06 +0900 Subject: [PATCH 3/7] restore it once --- ext/random/randomizer.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index ef62f202b84c2..76ff5bf590a88 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -278,6 +278,7 @@ PHP_METHOD(Random_Randomizer, getBytes) zend_string *retval; zend_long user_length; + size_t total_size = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(user_length) @@ -290,32 +291,17 @@ PHP_METHOD(Random_Randomizer, getBytes) size_t length = (size_t)user_length; retval = zend_string_alloc(length, 0); - char *rptr = ZSTR_VAL(retval); - size_t to_read = length; - while (to_read > 0) { + while (total_size < length) { php_random_result result = engine.algo->generate(engine.state); if (EG(exception)) { zend_string_free(retval); RETURN_THROWS(); } - - uint64_t tmp_ret = result.result; - if (to_read >= result.size && result.size == sizeof(uint64_t)) { -#ifdef WORDS_BIGENDIAN - tmp_ret = RANDOM_BSWAP64(tmp_ret); -#endif - memcpy(rptr, &tmp_ret, sizeof(uint64_t)); - to_read -= sizeof(uint64_t); - rptr += sizeof(uint64_t); - } else { - for (size_t i = 0; i < result.size; i++) { - *rptr++ = tmp_ret & 0xff; - tmp_ret >>= 8; - to_read--; - if (to_read == 0) { - break; - } + for (size_t i = 0; i < result.size; i++) { + ZSTR_VAL(retval)[total_size++] = (result.result >> (i * 8)) & 0xff; + if (total_size >= length) { + break; } } } From 6b7400f3dd77b3589edc8909db6d962568a6e970 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Fri, 12 Jul 2024 00:21:13 +0900 Subject: [PATCH 4/7] Optimized bit shifting --- ext/random/randomizer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index 76ff5bf590a88..a15d1fbb69683 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -298,8 +298,10 @@ PHP_METHOD(Random_Randomizer, getBytes) zend_string_free(retval); RETURN_THROWS(); } + uint64_t tmp_ret = result.result; for (size_t i = 0; i < result.size; i++) { - ZSTR_VAL(retval)[total_size++] = (result.result >> (i * 8)) & 0xff; + ZSTR_VAL(retval)[total_size++] = tmp_ret & 0xff; + tmp_ret >>= 8; if (total_size >= length) { break; } From 0cacff8e3da10295ad5546b2078808aeecc2f892 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Fri, 12 Jul 2024 01:02:59 +0900 Subject: [PATCH 5/7] Changed to use memcpy when possible --- ext/random/randomizer.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index a15d1fbb69683..d88d07891a506 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -291,6 +291,7 @@ PHP_METHOD(Random_Randomizer, getBytes) size_t length = (size_t)user_length; retval = zend_string_alloc(length, 0); + char *rptr = ZSTR_VAL(retval); while (total_size < length) { php_random_result result = engine.algo->generate(engine.state); @@ -299,16 +300,25 @@ PHP_METHOD(Random_Randomizer, getBytes) RETURN_THROWS(); } uint64_t tmp_ret = result.result; - for (size_t i = 0; i < result.size; i++) { - ZSTR_VAL(retval)[total_size++] = tmp_ret & 0xff; - tmp_ret >>= 8; - if (total_size >= length) { - break; + if (length - total_size >= sizeof(uint64_t) && result.size == sizeof(uint64_t)) { +#ifdef WORDS_BIGENDIAN + tmp_ret = RANDOM_BSWAP64(tmp_ret); +#endif + memcpy(rptr, &tmp_ret, sizeof(uint64_t)); + total_size += sizeof(uint64_t); + rptr += sizeof(uint64_t); + } else { + for (size_t i = 0; i < result.size; i++) { + rptr[total_size++] = tmp_ret & 0xff; + tmp_ret >>= 8; + if (total_size >= length) { + break; + } } } } - ZSTR_VAL(retval)[length] = '\0'; + rptr[length] = '\0'; RETURN_STR(retval); } /* }}} */ From 7873e603d3786f87ccd5cd7ef551d754b6d30b24 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Fri, 12 Jul 2024 01:09:38 +0900 Subject: [PATCH 6/7] Loop optimization --- ext/random/randomizer.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index d88d07891a506..f2be6b0ee869f 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -278,7 +278,6 @@ PHP_METHOD(Random_Randomizer, getBytes) zend_string *retval; zend_long user_length; - size_t total_size = 0; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(user_length) @@ -293,32 +292,34 @@ PHP_METHOD(Random_Randomizer, getBytes) retval = zend_string_alloc(length, 0); char *rptr = ZSTR_VAL(retval); - while (total_size < length) { + size_t to_read = length; + while (to_read > 0) { php_random_result result = engine.algo->generate(engine.state); if (EG(exception)) { zend_string_free(retval); RETURN_THROWS(); } uint64_t tmp_ret = result.result; - if (length - total_size >= sizeof(uint64_t) && result.size == sizeof(uint64_t)) { + if (to_read >= sizeof(uint64_t) && result.size == sizeof(uint64_t)) { #ifdef WORDS_BIGENDIAN tmp_ret = RANDOM_BSWAP64(tmp_ret); #endif memcpy(rptr, &tmp_ret, sizeof(uint64_t)); - total_size += sizeof(uint64_t); + to_read -= sizeof(uint64_t); rptr += sizeof(uint64_t); } else { for (size_t i = 0; i < result.size; i++) { - rptr[total_size++] = tmp_ret & 0xff; + *rptr++ = tmp_ret & 0xff; tmp_ret >>= 8; - if (total_size >= length) { + to_read--; + if (to_read == 0) { break; } } } } - rptr[length] = '\0'; + *rptr = '\0'; RETURN_STR(retval); } /* }}} */ From c78d5a7105574f6c1e462b6d7eea721609afd8f0 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 22 Jul 2024 22:30:11 +0900 Subject: [PATCH 7/7] Changed RANDOM_BSWAP64 to ZEND_BYTES_SWAP64 --- ext/random/php_random.h | 27 --------------------------- ext/random/randomizer.c | 3 ++- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/ext/random/php_random.h b/ext/random/php_random.h index 37f3d8e564fbb..e4aa32126671e 100644 --- a/ext/random/php_random.h +++ b/ext/random/php_random.h @@ -214,31 +214,4 @@ PHPAPI ZEND_EXTERN_MODULE_GLOBALS(random) # define RANDOM_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(random, v) -/* Bytes swap */ -#ifdef _MSC_VER -# include -# define RANDOM_BSWAP64(u) _byteswap_uint64(u) -#else -# ifdef __GNUC__ -# define RANDOM_BSWAP64(u) __builtin_bswap64(u) -# elif defined(__has_builtin) -# if __has_builtin(__builtin_bswap64) -# define RANDOM_BSWAP64(u) __builtin_bswap64(u) -# endif // __has_builtin(__builtin_bswap64) -# endif // __GNUC__ -#endif // _MSC_VER -#ifndef RANDOM_BSWAP64 -static inline uint64_t RANDOM_BSWAP64(uint64_t u) -{ - return (((u & 0xff00000000000000ULL) >> 56) - | ((u & 0x00ff000000000000ULL) >> 40) - | ((u & 0x0000ff0000000000ULL) >> 24) - | ((u & 0x000000ff00000000ULL) >> 8) - | ((u & 0x00000000ff000000ULL) << 8) - | ((u & 0x0000000000ff0000ULL) << 24) - | ((u & 0x000000000000ff00ULL) << 40) - | ((u & 0x00000000000000ffULL) << 56)); -} -#endif - #endif /* PHP_RANDOM_H */ diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index f2be6b0ee869f..d732628a98d2d 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -26,6 +26,7 @@ #include "Zend/zend_enum.h" #include "Zend/zend_exceptions.h" +#include "zend_portability.h" static inline void randomizer_common_init(php_random_randomizer *randomizer, zend_object *engine_object) { if (engine_object->ce->type == ZEND_INTERNAL_CLASS) { @@ -302,7 +303,7 @@ PHP_METHOD(Random_Randomizer, getBytes) uint64_t tmp_ret = result.result; if (to_read >= sizeof(uint64_t) && result.size == sizeof(uint64_t)) { #ifdef WORDS_BIGENDIAN - tmp_ret = RANDOM_BSWAP64(tmp_ret); + tmp_ret = ZEND_BYTES_SWAP64(tmp_ret); #endif memcpy(rptr, &tmp_ret, sizeof(uint64_t)); to_read -= sizeof(uint64_t);