You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.6 KiB
115 lines
2.6 KiB
/* |
|
* 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); |
|
}
|
|
|