isl_blk: don't reuse overly large blocks for small allocations
authorSven Verdoolaege <skimo@kotnet.org>
Sun, 10 Apr 2011 08:57:11 +0000 (10:57 +0200)
committerSven Verdoolaege <skimo@kotnet.org>
Thu, 21 Apr 2011 11:13:11 +0000 (13:13 +0200)
We usually allocate a large number of small objects, but occasionally
we may allocate one or more big objects.  The original caching code
could reuse a cached huge object for a small allocation.
This is fine if the object would grow later, but if it remains
small, then we may end up consuming and wasting a lot of memory,
especially if these objects are long-lived.

Now we only a memory block if it is at most twice as big as the desired
size.  This may result in some large objects sticking around in the cache,
so we evict objects from the cache after a while.
Finally, we don't reuse any cache elements for initially zero sized
allocations, but instead check the cache when the objects first growns
to a non-zero size.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
isl_blk.c
isl_ctx.c
isl_ctx_private.h

index d581f2d..0c1dae7 100644 (file)
--- a/isl_blk.c
+++ b/isl_blk.c
@@ -10,6 +10,9 @@
 #include <isl/blk.h>
 #include <isl_ctx_private.h>
 
+/* The maximal number of cache misses before first element is evicted */
+#define ISL_BLK_MAX_MISS       100
+
 struct isl_blk isl_blk_empty()
 {
        struct isl_blk block;
@@ -36,31 +39,7 @@ int isl_blk_is_error(struct isl_blk block)
        return block.size == -1 && block.data == NULL;
 }
 
-struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n)
-{
-       int i;
-       struct isl_blk block;
-
-       if (ctx->n_cached) {
-               int best = 0;
-               for (i = 1; ctx->cache[best].size != n && i < ctx->n_cached; ++i) {
-                       if (ctx->cache[best].size < n) {
-                               if (ctx->cache[i].size > ctx->cache[best].size)
-                                       best = i;
-                       } else if (ctx->cache[i].size >= n &&
-                                  ctx->cache[i].size < ctx->cache[best].size)
-                                       best = i;
-               }
-               block = ctx->cache[best];
-               if (--ctx->n_cached != best)
-                       ctx->cache[best] = ctx->cache[ctx->n_cached];
-       } else
-               block = isl_blk_empty();
-
-       return isl_blk_extend(ctx, block, n);
-}
-
-struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block,
+static struct isl_blk extend(struct isl_ctx *ctx, struct isl_blk block,
                                size_t new_n)
 {
        int i;
@@ -92,6 +71,48 @@ static void isl_blk_free_force(struct isl_ctx *ctx, struct isl_blk block)
        free(block.data);
 }
 
+struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n)
+{
+       int i;
+       struct isl_blk block;
+
+       block = isl_blk_empty();
+       if (n && ctx->n_cached) {
+               int best = 0;
+               for (i = 1; ctx->cache[best].size != n && i < ctx->n_cached; ++i) {
+                       if (ctx->cache[best].size < n) {
+                               if (ctx->cache[i].size > ctx->cache[best].size)
+                                       best = i;
+                       } else if (ctx->cache[i].size >= n &&
+                                  ctx->cache[i].size < ctx->cache[best].size)
+                                       best = i;
+               }
+               if (ctx->cache[best].size < 2 * n + 100) {
+                       block = ctx->cache[best];
+                       if (--ctx->n_cached != best)
+                               ctx->cache[best] = ctx->cache[ctx->n_cached];
+                       if (best == 0)
+                               ctx->n_miss = 0;
+               } else if (ctx->n_miss++ >= ISL_BLK_MAX_MISS) {
+                       isl_blk_free_force(ctx, ctx->cache[0]);
+                       if (--ctx->n_cached != 0)
+                               ctx->cache[0] = ctx->cache[ctx->n_cached];
+                       ctx->n_miss = 0;
+               }
+       }
+
+       return extend(ctx, block, n);
+}
+
+struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block,
+                               size_t new_n)
+{
+       if (isl_blk_is_empty(block))
+               return isl_blk_alloc(ctx, new_n);
+
+       return extend(ctx, block, new_n);
+}
+
 void isl_blk_free(struct isl_ctx *ctx, struct isl_blk block)
 {
        if (isl_blk_is_empty(block) || isl_blk_is_error(block))
index 4ea7a70..5b37bf5 100644 (file)
--- a/isl_ctx.c
+++ b/isl_ctx.c
@@ -93,6 +93,7 @@ isl_ctx *isl_ctx_alloc_with_options(struct isl_arg *arg, void *user_opt)
        isl_int_init(ctx->normalize_gcd);
 
        ctx->n_cached = 0;
+       ctx->n_miss = 0;
 
        ctx->error = isl_error_none;
 
index 45ff837..a943b24 100644 (file)
@@ -18,6 +18,7 @@ struct isl_ctx {
        isl_int                 normalize_gcd;
 
        int                     n_cached;
+       int                     n_miss;
        struct isl_blk          cache[ISL_BLK_CACHE_SIZE];
        struct isl_hash_table   name_hash;