Welcome! Log In Create A New Profile

Advanced

Re: change growth factor of array

Vladimir Shebordaev
October 19, 2012 11:24AM
Hi!

You might wish to try this patch if you do need really large arrays in nginx that would be fast and memory efficient on insertion at cost of rather slow read access.

--- /dev/null 2012-10-18 19:22:00.714822120 +0400
+++ src/core/ngx_vector.h 2012-07-13 05:57:58.000000000 +0400
@@ -0,0 +1,140 @@
+#ifndef _NGX_VECTOR_H_INCLUDED_
+#define _NGX_VECTOR_H_INCLUDED_
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+typedef struct ngx_vector_s ngx_vector_t;
+
+struct ngx_vector_s {
+ size_t size;
+ ngx_int_t last;
+ /* data blocks */
+ size_t d;
+ size_t db_size;
+ size_t d_free;
+ /* superblocks */
+ size_t s;
+ size_t sb_size;
+ size_t s_free;
+ /* index block */
+ void **index;
+ size_t ib_size;
+
+ ngx_pool_t *pool;
+};
+
+#ifdef __GNUC__
+#define ngx_clz(n) __builtin_clz(n)
+#else
+#error "You have to define ngx_clz() for your compiler"
+#endif
+
+static ngx_inline
+ngx_int_t ngx_vector_bound_check(const ngx_vector_t *vec, ngx_int_t idx)
+{
+ return idx > vec->last;
+}
+
+static ngx_inline
+void *__ngx_vector_locate(const ngx_vector_t *vec, size_t idx)
+{
+ ngx_uint_t k, msb, half, mask, b, e, p;
+
+ ++idx;
+ k = (NGX_PTR_SIZE << 3) - 1 - ngx_clz(idx);
+
+ msb = 1 << k;
+ half = (k + 1) >> 1;
+ mask = (1 << half) - 1;
+
+ p = mask + (1 << (k - half)) - 1;
+ b = (idx ^ msb) >> half;
+ e = idx & mask;
+
+ return (char *)vec->index[p + b] + e * vec->size;
+}
+
+static ngx_inline
+void *ngx_vector_read(const ngx_vector_t *vec, size_t idx)
+{
+ return ngx_vector_bound_check(vec, idx) ? NULL : __ngx_vector_locate(vec, idx);
+}
+
+static ngx_inline
+void *ngx_vector_write(const ngx_vector_t *vec, size_t idx, void *value)
+{
+ void *ret;
+
+ if (ngx_vector_bound_check(vec, idx))
+ return NULL;
+
+ ret = __ngx_vector_locate(vec, idx);
+ if (ret && value)
+ ngx_memcpy(ret, value, vec->size);
+
+ return ret;
+}
+
+extern ngx_int_t __ngx_vector_grow_by(ngx_vector_t *vec, size_t nelts);
+extern ngx_int_t __ngx_vector_alloc_block(ngx_vector_t *vec);
+
+static ngx_inline ngx_int_t
+ngx_vector_grow_by(ngx_vector_t *vec, size_t nelts)
+{
+ if (nelts <= vec->d_free) {
+ vec->d_free -= nelts;
+ vec->last += nelts;
+
+ return NGX_OK;
+ }
+
+ vec->last += vec->d_free;
+ nelts -= vec->d_free;
+
+ return __ngx_vector_grow_by(vec, nelts);
+}
+
+static ngx_inline ngx_int_t
+ngx_vector_grow(ngx_vector_t *vec)
+{
+ ngx_int_t ret;
+
+ ret = vec->d_free ? NGX_OK : __ngx_vector_alloc_block(vec);
+ if (ret != NGX_OK)
+ goto out;
+
+ vec->d_free--;
+ vec->last++;
+out:
+ return ret;
+}
+
+static ngx_inline size_t
+ngx_vector_size(ngx_vector_t *vec)
+{
+ return vec->last + 1;
+}
+
+static ngx_inline void *
+ngx_vector_push_back(ngx_vector_t *vec, void *value)
+{
+ void *ret;
+
+ if (ngx_vector_grow(vec) != NGX_OK) {
+ ret = NULL;
+ goto out;
+ }
+
+ ret = __ngx_vector_locate(vec, ngx_vector_size(vec) - 1);
+ if (ret && value)
+ ngx_memcpy(ret, value, vec->size);
+out:
+ return ret;
+}
+
+extern ngx_vector_t *ngx_vector_init(size_t size, ngx_pool_t *pool);
+extern void ngx_vector_destroy(ngx_vector_t *vec);
+
+#endif /* _NGX_VECTOR_H_INCLUDED_ */
+
--- /dev/null 2012-10-18 19:22:00.714822120 +0400
+++ src/core/ngx_vector.c 2012-07-13 05:36:28.000000000 +0400
@@ -0,0 +1,134 @@
+#include <ngx_vector.h>
+
+ngx_vector_t *
+ngx_vector_init(size_t size, ngx_pool_t *pool)
+{
+ ngx_vector_t *ret;
+
+ ret = NULL;
+
+ if (!pool)
+ goto out;
+
+ ret = ngx_palloc(pool, sizeof(ngx_vector_t));
+ if (!ret)
+ goto out;
+
+ ret->pool = pool;
+
+ ret->size = size;
+ ret->last = -1;
+
+ ret->index = ngx_palloc(pool, ngx_pagesize);
+ if (!ret->index)
+ goto out_free;
+
+ ngx_memzero(ret->index, ngx_pagesize);
+ ret->ib_size = ngx_pagesize / sizeof(ret->index[0]);
+
+ ret->d = 0;
+ ret->db_size = 1;
+ ret->d_free = 1;
+
+ ret->s = 0;
+ ret->sb_size = 1;
+ ret->s_free = 0;
+
+ ret->index[0] = ngx_palloc(pool, size);
+ if (!ret->index[0])
+ goto out_free_index;
+out:
+ return ret;
+
+out_free_index:
+ ngx_pfree(pool, ret->index);
+out_free:
+ ngx_pfree(pool, ret);
+ return NULL;
+}
+
+void
+ngx_vector_destroy(ngx_vector_t *vec)
+{
+ size_t i;
+
+ for (i = 0; i <= vec->d; i++)
+ ngx_pfree(vec->pool, (void *)vec->index[i]);
+
+ ngx_pfree(vec->pool, vec->index);
+ ngx_pfree(vec->pool, vec);
+}
+
+ngx_int_t
+__ngx_vector_grow_by(ngx_vector_t *vec, size_t nelts)
+{
+ ngx_int_t ret;
+
+ for(;;) {
+ ret = __ngx_vector_alloc_block(vec);
+ if (ret != NGX_OK)
+ goto out;
+
+ if (nelts < vec->d_free)
+ break;
+
+ nelts -= vec->db_size;
+ vec->last += vec->db_size;
+ }
+ vec->d_free -= nelts;
+ vec->last += nelts;
+
+ ret = NGX_OK;
+out:
+ return ret;
+}
+
+ngx_int_t
+__ngx_vector_alloc_block(ngx_vector_t *vec)
+{
+ ngx_int_t ret;
+
+ ret = NGX_ERROR;
+
+ if (!vec->s_free) {
+ vec->s++;
+
+ if (vec->s & 1)
+ vec->db_size *= 2;
+ else
+ vec->sb_size *= 2;
+
+ vec->s_free = vec->sb_size;
+ }
+
+ vec->d++;
+ vec->s_free--;
+
+ if (vec->d >= vec->ib_size) {
+ void **index;
+ size_t size;
+
+ size = 2 * vec->ib_size * sizeof(void *);
+ index = ngx_palloc(vec->pool, size);
+ if (!index)
+ goto out;
+
+ ngx_memzero(index, size);
+ ngx_memcpy(index, vec->index, vec->ib_size * sizeof(void *));
+ ngx_pfree(vec->pool, vec->index);
+
+ vec->index = index;
+ vec->ib_size *= 2;
+ }
+
+ vec->index[vec->d] = ngx_palloc(vec->pool, vec->db_size * vec->size);
+ if (!vec->index[vec->d])
+ goto out;
+
+ vec->d_free = vec->db_size;
+
+ ret = NGX_OK;
+out:
+ return ret;
+}
+

This code implements the algorithms described here 

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.36.9607

They say about square root of array size .

It used to work for me a few months ago. Sure, it is possible to optimize read access code  but the element size is known just at run-time, so it seems hard to be done without register parameters and inline assembler.

Hope it helps.

Regards,
Vladimir

Fri, 19 Oct 2012 20:06:15 +0800 от Simon Liu <simohayha.bobo@gmail.com>:
>
>In this document ( https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md ) ,  It is to suggest use factor 1.5 (when you'd push into
>a array without there being room)  in dynamically-allocated arrays. the factor is 2 in array of Nginx, and so I think may be change factor to 1.5 is be better in Nginx's array.
>
>Thanks.
>
>
>
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

change growth factor of array

Simon Liu 1149 October 19, 2012 08:08AM

Re: change growth factor of array

Maxim Dounin 508 October 19, 2012 09:26AM

Re: change growth factor of array

Vladimir Shebordaev 575 October 19, 2012 11:24AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 199
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready