1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00

r8126: - moved to 16 byte alignment for talloc. This is in response to a bug

report from robert collins.

- updated talloc guide to reflect the fact that over the last few
  months talloc overhead compared to malloc has dropped, probably due
  to a bunch of small changes. It now costs about 4% more than malloc
  on my box
(This used to be commit 689a9ccf91)
This commit is contained in:
Andrew Tridgell 2005-07-04 07:10:21 +00:00 committed by Gerald (Jerry) Carter
parent 65ae28dfa7
commit b9e8935188
2 changed files with 54 additions and 51 deletions

View File

@ -97,23 +97,26 @@ struct talloc_chunk {
struct talloc_chunk *next, *prev; struct talloc_chunk *next, *prev;
struct talloc_chunk *parent, *child; struct talloc_chunk *parent, *child;
struct talloc_reference_handle *refs; struct talloc_reference_handle *refs;
size_t size;
talloc_destructor_t destructor; talloc_destructor_t destructor;
const char *name; const char *name;
union { size_t size;
unsigned flags; unsigned flags;
double align_dummy;
} u;
}; };
/* 16 byte alignment seems to keep everyone happy */
#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
/* panic if we get a bad magic value */ /* panic if we get a bad magic value */
static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
{ {
struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1; const char *pp = ptr;
if ((tc->u.flags & ~0xF) != TALLOC_MAGIC) { pp -= TC_HDR_SIZE;
struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp);
if ((tc->flags & ~0xF) != TALLOC_MAGIC) {
TALLOC_ABORT("Bad talloc magic value - unknown value"); TALLOC_ABORT("Bad talloc magic value - unknown value");
} }
if (tc->u.flags & TALLOC_FLAG_FREE) { if (tc->flags & TALLOC_FLAG_FREE) {
TALLOC_ABORT("Bad talloc magic value - double free"); TALLOC_ABORT("Bad talloc magic value - double free");
} }
return tc; return tc;
@ -160,7 +163,7 @@ static struct talloc_chunk *talloc_parent_chunk(const void *ptr)
void *talloc_parent(const void *ptr) void *talloc_parent(const void *ptr)
{ {
struct talloc_chunk *tc = talloc_parent_chunk(ptr); struct talloc_chunk *tc = talloc_parent_chunk(ptr);
return (void *)(tc+1); return TC_PTR_FROM_CHUNK(tc);
} }
/* /*
@ -178,11 +181,11 @@ void *_talloc(const void *context, size_t size)
return NULL; return NULL;
} }
tc = malloc(sizeof(*tc)+size); tc = malloc(TC_HDR_SIZE+size);
if (tc == NULL) return NULL; if (tc == NULL) return NULL;
tc->size = size; tc->size = size;
tc->u.flags = TALLOC_MAGIC; tc->flags = TALLOC_MAGIC;
tc->destructor = NULL; tc->destructor = NULL;
tc->child = NULL; tc->child = NULL;
tc->name = NULL; tc->name = NULL;
@ -202,7 +205,7 @@ void *_talloc(const void *context, size_t size)
tc->next = tc->prev = tc->parent = NULL; tc->next = tc->prev = tc->parent = NULL;
} }
return (void *)(tc+1); return TC_PTR_FROM_CHUNK(tc);
} }
@ -287,7 +290,7 @@ static int talloc_unreference(const void *context, const void *ptr)
for (h=tc->refs;h;h=h->next) { for (h=tc->refs;h;h=h->next) {
struct talloc_chunk *p = talloc_parent_chunk(h); struct talloc_chunk *p = talloc_parent_chunk(h);
if ((p==NULL && context==NULL) || p+1 == context) break; if ((p==NULL && context==NULL) || TC_PTR_FROM_CHUNK(p) == context) break;
} }
if (h == NULL) { if (h == NULL) {
return -1; return -1;
@ -338,7 +341,7 @@ int talloc_unlink(const void *context, void *ptr)
new_p = talloc_parent_chunk(tc_p->refs); new_p = talloc_parent_chunk(tc_p->refs);
if (new_p) { if (new_p) {
new_parent = new_p+1; new_parent = TC_PTR_FROM_CHUNK(new_p);
} else { } else {
new_parent = NULL; new_parent = NULL;
} }
@ -497,16 +500,16 @@ void talloc_free_children(void *ptr)
choice is owner of any remaining reference to this choice is owner of any remaining reference to this
pointer, the second choice is our parent, and the pointer, the second choice is our parent, and the
final choice is the null context. */ final choice is the null context. */
void *child = tc->child+1; void *child = TC_PTR_FROM_CHUNK(tc->child);
const void *new_parent = null_context; const void *new_parent = null_context;
if (tc->child->refs) { if (tc->child->refs) {
struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
if (p) new_parent = p+1; if (p) new_parent = TC_PTR_FROM_CHUNK(p);
} }
if (talloc_free(child) == -1) { if (talloc_free(child) == -1) {
if (new_parent == null_context) { if (new_parent == null_context) {
struct talloc_chunk *p = talloc_parent_chunk(ptr); struct talloc_chunk *p = talloc_parent_chunk(ptr);
if (p) new_parent = p+1; if (p) new_parent = TC_PTR_FROM_CHUNK(p);
} }
talloc_steal(new_parent, child); talloc_steal(new_parent, child);
} }
@ -536,7 +539,7 @@ int talloc_free(void *ptr)
return -1; return -1;
} }
if (tc->u.flags & TALLOC_FLAG_LOOP) { if (tc->flags & TALLOC_FLAG_LOOP) {
/* we have a free loop - stop looping */ /* we have a free loop - stop looping */
return 0; return 0;
} }
@ -554,7 +557,7 @@ int talloc_free(void *ptr)
tc->destructor = NULL; tc->destructor = NULL;
} }
tc->u.flags |= TALLOC_FLAG_LOOP; tc->flags |= TALLOC_FLAG_LOOP;
talloc_free_children(ptr); talloc_free_children(ptr);
@ -568,7 +571,7 @@ int talloc_free(void *ptr)
if (tc->next) tc->next->prev = tc->prev; if (tc->next) tc->next->prev = tc->prev;
} }
tc->u.flags |= TALLOC_FLAG_FREE; tc->flags |= TALLOC_FLAG_FREE;
free(tc); free(tc);
return 0; return 0;
@ -608,24 +611,24 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
} }
/* by resetting magic we catch users of the old memory */ /* by resetting magic we catch users of the old memory */
tc->u.flags |= TALLOC_FLAG_FREE; tc->flags |= TALLOC_FLAG_FREE;
#if ALWAYS_REALLOC #if ALWAYS_REALLOC
new_ptr = malloc(size + sizeof(*tc)); new_ptr = malloc(size + TC_HDR_SIZE);
if (new_ptr) { if (new_ptr) {
memcpy(new_ptr, tc, tc->size + sizeof(*tc)); memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
free(tc); free(tc);
} }
#else #else
new_ptr = realloc(tc, size + sizeof(*tc)); new_ptr = realloc(tc, size + TC_HDR_SIZE);
#endif #endif
if (!new_ptr) { if (!new_ptr) {
tc->u.flags &= ~TALLOC_FLAG_FREE; tc->flags &= ~TALLOC_FLAG_FREE;
return NULL; return NULL;
} }
tc = new_ptr; tc = new_ptr;
tc->u.flags &= ~TALLOC_FLAG_FREE; tc->flags &= ~TALLOC_FLAG_FREE;
if (tc->parent) { if (tc->parent) {
tc->parent->child = new_ptr; tc->parent->child = new_ptr;
} }
@ -641,9 +644,9 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
} }
tc->size = size; tc->size = size;
talloc_set_name_const(tc+1, name); talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
return (void *)(tc+1); return TC_PTR_FROM_CHUNK(tc);
} }
/* /*
@ -720,18 +723,18 @@ off_t talloc_total_size(const void *ptr)
tc = talloc_chunk_from_ptr(ptr); tc = talloc_chunk_from_ptr(ptr);
if (tc->u.flags & TALLOC_FLAG_LOOP) { if (tc->flags & TALLOC_FLAG_LOOP) {
return 0; return 0;
} }
tc->u.flags |= TALLOC_FLAG_LOOP; tc->flags |= TALLOC_FLAG_LOOP;
total = tc->size; total = tc->size;
for (c=tc->child;c;c=c->next) { for (c=tc->child;c;c=c->next) {
total += talloc_total_size(c+1); total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
} }
tc->u.flags &= ~TALLOC_FLAG_LOOP; tc->flags &= ~TALLOC_FLAG_LOOP;
return total; return total;
} }
@ -744,18 +747,18 @@ off_t talloc_total_blocks(const void *ptr)
off_t total = 0; off_t total = 0;
struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
if (tc->u.flags & TALLOC_FLAG_LOOP) { if (tc->flags & TALLOC_FLAG_LOOP) {
return 0; return 0;
} }
tc->u.flags |= TALLOC_FLAG_LOOP; tc->flags |= TALLOC_FLAG_LOOP;
total++; total++;
for (c=tc->child;c;c=c->next) { for (c=tc->child;c;c=c->next) {
total += talloc_total_blocks(c+1); total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
} }
tc->u.flags &= ~TALLOC_FLAG_LOOP; tc->flags &= ~TALLOC_FLAG_LOOP;
return total; return total;
} }
@ -782,29 +785,29 @@ void talloc_report_depth(const void *ptr, FILE *f, int depth)
{ {
struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
if (tc->u.flags & TALLOC_FLAG_LOOP) { if (tc->flags & TALLOC_FLAG_LOOP) {
return; return;
} }
tc->u.flags |= TALLOC_FLAG_LOOP; tc->flags |= TALLOC_FLAG_LOOP;
for (c=tc->child;c;c=c->next) { for (c=tc->child;c;c=c->next) {
if (c->name == TALLOC_MAGIC_REFERENCE) { if (c->name == TALLOC_MAGIC_REFERENCE) {
struct talloc_reference_handle *handle = (void *)(c+1); struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
const char *name2 = talloc_get_name(handle->ptr); const char *name2 = talloc_get_name(handle->ptr);
fprintf(f, "%*sreference to: %s\n", depth*4, "", name2); fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
} else { } else {
const char *name = talloc_get_name(c+1); const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
depth*4, "", depth*4, "",
name, name,
(unsigned long)talloc_total_size(c+1), (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
(unsigned long)talloc_total_blocks(c+1), (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
talloc_reference_count(c+1)); talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
talloc_report_depth(c+1, f, depth+1); talloc_report_depth(TC_PTR_FROM_CHUNK(c), f, depth+1);
} }
} }
tc->u.flags &= ~TALLOC_FLAG_LOOP; tc->flags &= ~TALLOC_FLAG_LOOP;
} }
/* /*
@ -847,9 +850,9 @@ void talloc_report(const void *ptr, FILE *f)
for (c=tc->child;c;c=c->next) { for (c=tc->child;c;c=c->next) {
fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n", fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n",
talloc_get_name(c+1), talloc_get_name(TC_PTR_FROM_CHUNK(c)),
(unsigned long)talloc_total_size(c+1), (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
(unsigned long)talloc_total_blocks(c+1)); (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)));
} }
fflush(f); fflush(f);
} }
@ -1175,7 +1178,7 @@ void *talloc_find_parent_byname(const void *context, const char *name)
tc = talloc_chunk_from_ptr(context); tc = talloc_chunk_from_ptr(context);
while (tc) { while (tc) {
if (tc->name && strcmp(tc->name, name) == 0) { if (tc->name && strcmp(tc->name, name) == 0) {
return (void*)(tc+1); return TC_PTR_FROM_CHUNK(tc);
} }
while (tc && tc->prev) tc = tc->prev; while (tc && tc->prev) tc = tc->prev;
tc = tc->parent; tc = tc->parent;
@ -1198,7 +1201,7 @@ void talloc_show_parents(const void *context, FILE *file)
tc = talloc_chunk_from_ptr(context); tc = talloc_chunk_from_ptr(context);
fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context)); fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
while (tc) { while (tc) {
fprintf(file, "\t'%s'\n", talloc_get_name(tc+1)); fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
while (tc && tc->prev) tc = tc->prev; while (tc && tc->prev) tc = tc->prev;
tc = tc->parent; tc = tc->parent;
} }

View File

@ -43,7 +43,7 @@ Performance
All the additional features of talloc() over malloc() do come at a All the additional features of talloc() over malloc() do come at a
price. We have a simple performance test in Samba4 that measures price. We have a simple performance test in Samba4 that measures
talloc() versus malloc() performance, and it seems that talloc() is talloc() versus malloc() performance, and it seems that talloc() is
about 10% slower than malloc() on my x86 Debian Linux box. For Samba, about 4% slower than malloc() on my x86 Debian Linux box. For Samba,
the great reduction in code complexity that we get by using talloc the great reduction in code complexity that we get by using talloc
makes this worthwhile, especially as the total overhead of makes this worthwhile, especially as the total overhead of
talloc/malloc in Samba is already quite small. talloc/malloc in Samba is already quite small.