diff options
Diffstat (limited to 'alloc.c')
-rw-r--r-- | alloc.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/alloc.c b/alloc.c new file mode 100644 index 000000000..12afadfac --- /dev/null +++ b/alloc.c @@ -0,0 +1,115 @@ +/* + * alloc.c - specialized allocator for internal objects + * + * Copyright (C) 2006 Linus Torvalds + * + * The standard malloc/free wastes too much space for objects, partly because + * it maintains all the allocation infrastructure (which isn't needed, since + * we never free an object descriptor anyway), but even more because it ends + * up with maximal alignment because it doesn't know what the object alignment + * for the new allocation is. + */ +#include "cache.h" +#include "object.h" +#include "blob.h" +#include "tree.h" +#include "commit.h" +#include "tag.h" + +#define BLOCKING 1024 + +union any_object { + struct object object; + struct blob blob; + struct tree tree; + struct commit commit; + struct tag tag; +}; + +struct alloc_state { + int count; /* total number of nodes allocated */ + int nr; /* number of nodes left in current allocation */ + void *p; /* first free node in current allocation */ +}; + +static inline void *alloc_node(struct alloc_state *s, size_t node_size) +{ + void *ret; + + if (!s->nr) { + s->nr = BLOCKING; + s->p = xmalloc(BLOCKING * node_size); + } + s->nr--; + s->count++; + ret = s->p; + s->p = (char *)s->p + node_size; + memset(ret, 0, node_size); + return ret; +} + +static struct alloc_state blob_state; +void *alloc_blob_node(void) +{ + struct blob *b = alloc_node(&blob_state, sizeof(struct blob)); + b->object.type = OBJ_BLOB; + return b; +} + +static struct alloc_state tree_state; +void *alloc_tree_node(void) +{ + struct tree *t = alloc_node(&tree_state, sizeof(struct tree)); + t->object.type = OBJ_TREE; + return t; +} + +static struct alloc_state tag_state; +void *alloc_tag_node(void) +{ + struct tag *t = alloc_node(&tag_state, sizeof(struct tag)); + t->object.type = OBJ_TAG; + return t; +} + +static struct alloc_state object_state; +void *alloc_object_node(void) +{ + struct object *obj = alloc_node(&object_state, sizeof(union any_object)); + obj->type = OBJ_NONE; + return obj; +} + +static struct alloc_state commit_state; + +unsigned int alloc_commit_index(void) +{ + static unsigned int count; + return count++; +} + +void *alloc_commit_node(void) +{ + struct commit *c = alloc_node(&commit_state, sizeof(struct commit)); + c->object.type = OBJ_COMMIT; + c->index = alloc_commit_index(); + return c; +} + +static void report(const char *name, unsigned int count, size_t size) +{ + fprintf(stderr, "%10s: %8u (%"PRIuMAX" kB)\n", + name, count, (uintmax_t) size); +} + +#define REPORT(name, type) \ + report(#name, name##_state.count, name##_state.count * sizeof(type) >> 10) + +void alloc_report(void) +{ + REPORT(blob, struct blob); + REPORT(tree, struct tree); + REPORT(commit, struct commit); + REPORT(tag, struct tag); + REPORT(object, union any_object); +} |