Doing some tests regarding memory allocation, I have discovered that the
implementation of smart strings (php_smart_str.h), user in spprintf and
everything above it, is kind of sub-optimal with regard to memory
allocation. That's why:
The initial string buffer is allocated of size at least 128 bytes. This
leads to the effect that the allocation is not served by Zend malloc
cache, but each time is malloced from the system. Also, the size of 128
(for which 148 bytes is really allocated due to various rounding and
overheads) is way too big, the final size of 90% strings in real tests is
below 80 bytes (I did the testing on 'make test', but I guess the most
other applications behave the similiar way).
So, my proposal is to make initial allocation of smart string memory block
of 79 bytes. This number is not round on purpose - so it fits the 80-byte
cache block, which is currently the biggest cached memory block. The
reallocation can be done in 128-byte incerements or any other increments,
the tests show 'big' sizes show no obvious pattern to make any incerement
better than others. People who wrote this code (I guess that would be
Sacha, but maybe others too) are especially welcome to comment on this,
and anybody else who has something to say on the matter is welcome either.
The patch is below:
--- php_smart_str.h 10 Jun 2003 20:03:38 -0000 1.26
+++ php_smart_str.h 18 Jun 2003 08:34:20 -0000
@@ -36,6 +36,10 @@
#define SMART_STR_PREALLOC 128
#endif
+#ifndef SMART_STR_START_SIZE
+#define SMART_STR_START_SIZE 78
+#endif
#ifdef SMART_STR_USE_REALLOC
#define SMART_STR_REALLOC(a,b,c) realloc((a),(b))
#else
@@ -47,7 +51,11 @@
if (!(d)->c) (d)->len = (d)->a = 0;
newlen = (d)->len + (n);
if (newlen >= (d)->a) { \
-
if((d)->a == 0 && newlen < SMART_STR_START_SIZE) { \ -
(d)->a = SMART_STR_START_SIZE; \ -
} else { \ (d)->a = newlen + SMART_STR_PREALLOC; \ -
}} \ (d)->c = SMART_STR_REALLOC((d)->c, (d)->a + 1, (what)); \
} while (0)
--
Stanislav Malyshev, Zend Products Engineer
stas@zend.com http://www.zend.com/ +972-3-6139665 ext.109
Fine with the concept.
If you move the additional check (newlen <
SMART_STR_START_SIZE) and preallocation into the if (!(d)->c)
branch, the changes won't affect the common code path.
@@ -47,7 +51,11 @@
if (!(d)->c) (d)->len = (d)->a = 0;
newlen = (d)->len + (n);
if (newlen >= (d)->a) { \
if((d)->a == 0 && newlen < SMART_STR_START_SIZE) { \(d)->a = SMART_STR_START_SIZE; \} else { \ (d)->a = newlen + SMART_STR_PREALLOC; \ }} \ (d)->c = SMART_STR_REALLOC((d)->c, (d)->a + 1, (what)); \
} while (0)
- Sascha