summaryrefslogtreecommitdiff
path: root/ext/mysqlnd/mysqlnd_alloc.c
diff options
context:
space:
mode:
authorMark A. Hershberger <mah@debian.(none)>2009-03-25 19:39:21 -0400
committerMark A. Hershberger <mah@debian.(none)>2009-03-25 19:39:21 -0400
commit6821b67124604da690c5e9276d5370d679c63ac8 (patch)
treebefb4ca2520eb577950cef6cb76d10b914cbf67a /ext/mysqlnd/mysqlnd_alloc.c
parentcd0b49c72aee33b3e44a9c589fcd93b9e1c7a64f (diff)
downloadphp-6821b67124604da690c5e9276d5370d679c63ac8.tar.gz
Imported Upstream version 5.3.0RC1upstream/5.3.0_RC1upstream/5.3.0RC1
Diffstat (limited to 'ext/mysqlnd/mysqlnd_alloc.c')
-rw-r--r--ext/mysqlnd/mysqlnd_alloc.c285
1 files changed, 285 insertions, 0 deletions
diff --git a/ext/mysqlnd/mysqlnd_alloc.c b/ext/mysqlnd/mysqlnd_alloc.c
new file mode 100644
index 000000000..dd72919e3
--- /dev/null
+++ b/ext/mysqlnd/mysqlnd_alloc.c
@@ -0,0 +1,285 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 6 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2009 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Georg Richter <georg@mysql.com> |
+ | Andrey Hristov <andrey@mysql.com> |
+ | Ulf Wendel <uwendel@mysql.com> |
+ +----------------------------------------------------------------------+
+
+*/
+
+/* $Id: mysqlnd_alloc.c,v 1.1.2.4 2008/12/31 11:15:39 sebastian Exp $ */
+#include "php.h"
+#include "mysqlnd.h"
+#include "mysqlnd_priv.h"
+#include "mysqlnd_palloc.h"
+
+
+#define MYSQLND_SILENT
+#define MYSQLND_DONT_DUMP_STATS
+
+#define MYSQLND_ZVALS_MAX_CACHE 5000
+
+
+#if A0
+/* Caching zval allocator */
+zval * mysqlnd_alloc_get_zval(MYSQLND_ZVAL_CACHE * const cache);
+void mysqlnd_alloc_zval_ptr_dtor(zval **zv, MYSQLND_ZVAL_CACHE * const cache);
+MYSQLND_ZVAL_CACHE* mysqlnd_alloc_init_cache();
+MYSQLND_ZVAL_CACHE* mysqlnd_alloc_get_cache_reference(MYSQLND_ZVAL_CACHE *cache);
+void mysqlnd_alloc_free_cache_reference(MYSQLND_ZVAL_CACHE **cache);
+#endif
+
+
+/*
+ The cache line is a big contiguous array of zval pointers.
+ Because the CPU cache will cache starting from an address, and not
+ before it, then we have to organize our structure according to this.
+ Thus, if 'last_added' is valid pointer (not NULL) then last_added is
+ increased. When zval is cached, if there is room, last_added is decreased
+ and then the zval pointer will be assigned to it. This means that some
+ positions may become hot points and stay in the cache.
+ Imagine we have 5 pointers in a line
+ 1. last_added = list_item->ptr_line + cache->max_items;
+ 2. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
+ 3. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
+ 4. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ ---
+ empty_position, always 0x0 <-- last_added
+
+ 5. free_zval -> if (free_items++ != max_items) {// we can add more
+ *(--last_added) = zval_ptr;
+ }
+ (memory addresses increase downwards)
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0xA <-- last_added
+ ---
+ 0x0
+
+ 6. free_zval -> if (free_items++ != max_items) {// we can add more
+ *(--last_added) = zval_ptr;
+ }
+ 0x0
+ 0x0
+ 0x0
+ 0xB <-- last_added
+ 0xA
+ ---
+ 0x0
+
+ 7. free_zval -> if (free_items++ != max_items) {// we can add more
+ *(--last_added) = zval_ptr;
+ }
+ 0x0
+ 0x0
+ 0xC <-- last_added
+ 0xB
+ 0xA
+ ---
+ 0x0
+
+ 8. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
+ 0x0
+ 0x0
+ 0x0
+ 0xB <-- last_added
+ 0xA
+ ---
+ 0x0
+
+ 9. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0xA <-- last_added
+ ---
+ 0x0
+
+10. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ 0x0
+ ---
+ 0x0 <-- last_added
+
+*/
+
+
+zval * mysqlnd_alloc_get_zval(MYSQLND_ZVAL_CACHE * const cache)
+{
+ zval *ret = NULL;
+
+#ifndef MYSQLND_SILENT
+ php_printf("[mysqlnd_alloc_get_zval %p] *last_added=%p free_items=%d ", cache, cache? cache->free_list->last_added:NULL, cache->free_items);
+#endif
+
+ if (cache) {
+ if ((ret = *cache->free_list->last_added)) {
+ *cache->free_list->last_added++ = NULL;
+
+ --cache->free_items;
+ ++cache->get_hits;
+ } else {
+ ++cache->get_misses;
+ }
+ }
+ if (!ret) {
+ ALLOC_ZVAL(ret);
+ }
+ INIT_PZVAL(ret);
+
+#ifndef MYSQLND_SILENT
+ php_printf("ret=%p\n", ret);
+#endif
+ return ret;
+}
+
+static
+void mysqlnd_alloc_cache_prealloc(MYSQLND_ZVAL_CACHE * const cache, unsigned int count)
+{
+ zval *data;
+ cache->free_items = count;
+ while (count--) {
+ MAKE_STD_ZVAL(data);
+ ZVAL_NULL(data);
+#ifndef MYSQLND_SILENT
+ php_printf("[mysqlnd_alloc_prealloc %p] items=%d data=%p\n", cache, cache->free_items, data);
+#endif
+
+ *(--cache->free_list->last_added) = data;
+ }
+}
+
+void mysqlnd_alloc_zval_ptr_dtor(zval **zv, MYSQLND_ZVAL_CACHE * const cache)
+{
+ if (!cache || Z_REFCOUNT_PP(zv) > 1 || cache->max_items == cache->free_items) {
+#ifndef MYSQLND_SILENT
+ php_printf("[mysqlnd_alloc_zval_ptr_dtor %p]1 last_added-1=%p *zv=%p\n", cache->free_list->last_added, *zv);
+#endif
+ /* We can't cache zval's with refcount > 1 */
+ zval_ptr_dtor(zv);
+ if (cache) {
+ if (cache->max_items == cache->free_items) {
+ ++cache->put_full_misses;
+ } else {
+ ++cache->put_refcount_misses;
+ }
+ }
+ } else {
+ /* refcount is 1 and there is place. Go, cache it! */
+ ++cache->free_items;
+ zval_dtor(*zv);
+ ZVAL_NULL(*zv);
+ *(--cache->free_list->last_added) = *zv;
+ ++cache->put_hits;
+ }
+#ifndef MYSQLND_SILENT
+ php_printf("[mysqlnd_alloc_zval_ptr_dtor %p] free_items=%d\n", cache, cache->free_items);
+#endif
+}
+
+
+MYSQLND_ZVAL_CACHE* mysqlnd_alloc_init_cache(void)
+{
+ MYSQLND_ZVAL_CACHE *ret = ecalloc(1, sizeof(MYSQLND_ZVAL_CACHE));
+
+#ifndef MYSQLND_SILENT
+ php_printf("[mysqlnd_alloc_init_cache %p]\n", ret);
+#endif
+
+ ret->max_items = MYSQLND_ZVALS_MAX_CACHE;
+ ret->free_items = 0;
+ ret->references = 1;
+
+ /* Let's have always one, so we don't need to do a check in get_zval */
+ ret->free_list = ecalloc(1, sizeof(struct st_mysqlnd_zval_list));
+
+ /* One more for empty position of last_added */
+ ret->free_list->ptr_line = ecalloc(ret->max_items + 1, sizeof(zval *));
+ ret->free_list->last_added = ret->free_list->ptr_line + ret->max_items;
+
+ mysqlnd_alloc_cache_prealloc(ret, (ret->max_items / 100) * 100);
+
+ return ret;
+}
+
+
+MYSQLND_ZVAL_CACHE* mysqlnd_alloc_get_cache_reference(MYSQLND_ZVAL_CACHE *cache)
+{
+ if (cache) {
+ cache->references++;
+ }
+ return cache;
+}
+
+
+static
+void mysqlnd_alloc_free_cache(MYSQLND_ZVAL_CACHE *cache)
+{
+#ifndef MYSQLND_SILENT
+ uint i = 0;
+ php_printf("[mysqlnd_alloc_free_cache %p]\n", cache);
+#endif
+
+ while (*cache->free_list->last_added) {
+#ifndef MYSQLND_SILENT
+ php_printf("\t[free_item %d %p]\n", i++, *cache->free_list->last_added);
+#endif
+ zval_ptr_dtor(cache->free_list->last_added);
+ cache->free_list->last_added++;
+ }
+#ifndef MYSQLND_DONT_DUMP_STATS
+ php_printf("CACHE STATS:\n\tGET\n\t\tHITS:%lu\n\t\tMISSES=%lu\n\t\tHIT RATIO=%1.3f\n\t"
+ "PUT\n\t\tHITS:%lu\n\t\tFULL_MISS=%lu\n\t\tREFC_MISS=%lu\n\t\tHIT RATIO=%1.3f\n\n",
+ cache->get_hits, cache->get_misses, (1.0*cache->get_hits/(cache->get_hits + cache->get_misses)),
+ cache->put_hits, cache->put_full_misses, cache->put_refcount_misses,
+ (1.0 * cache->put_hits / (cache->put_hits + cache->put_full_misses + cache->put_refcount_misses)));
+#endif
+ efree(cache->free_list->ptr_line);
+ efree(cache->free_list);
+ efree(cache);
+}
+
+
+
+void mysqlnd_alloc_free_cache_reference(MYSQLND_ZVAL_CACHE **cache)
+{
+#ifndef MYSQLND_SILENT
+ php_printf("[mysqlnd_alloc_free_cache_reference %p] refs=%d\n", *cache, (*cache)->references);
+#endif
+ if (*cache && --(*cache)->references == 0) {
+ mysqlnd_alloc_free_cache(*cache);
+ }
+ *cache = NULL;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */