diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2015-11-15 01:50:06 +0300 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2015-11-28 21:21:51 +0300 |
commit | ed970748b600313306657de6e5447e5447790766 (patch) | |
tree | 56ae1ff4bf10a47036e7dce570eb482d861f82fd | |
parent | 7132150ddf7a883c1f12a89c2518c1a07c0dc94c (diff) |
tree: pool the entry memory allocations
These are rather small allocations, so we end up spending a non-trivial
amount of time asking the OS for memory. Since these entries are tied to
the lifetime of their tree, we can give the tree a pool so we speed up
the allocations.
-rw-r--r-- | src/tree.c | 34 | ||||
-rw-r--r-- | src/tree.h | 5 |
2 files changed, 33 insertions, 6 deletions
diff --git a/src/tree.c b/src/tree.c index 3504452c2..22505d23a 100644 --- a/src/tree.c +++ b/src/tree.c @@ -81,6 +81,30 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2) git__strncasecmp); } +/** + * Allocate a tree entry, borrowing the filename from the tree which + * owns it. This is useful when reading trees, so we don't allocate a + * ton of small strings but can use the pool. + */ +static git_tree_entry *alloc_entry_pooled(git_pool *pool, const char *filename) +{ + git_tree_entry *entry = NULL; + size_t filename_len = strlen(filename), tree_len; + + if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) || + GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) || + !(entry = git_pool_malloc(pool, tree_len))) + return NULL; + + memset(entry, 0x0, sizeof(git_tree_entry)); + memcpy(entry->filename, filename, filename_len); + entry->filename[filename_len] = 0; + entry->filename_len = filename_len; + entry->pooled = true; + + return entry; +} + static git_tree_entry *alloc_entry(const char *filename) { git_tree_entry *entry = NULL; @@ -198,7 +222,7 @@ static int tree_key_search( void git_tree_entry_free(git_tree_entry *entry) { - if (entry == NULL) + if (entry == NULL || entry->pooled) return; git__free(entry); @@ -233,6 +257,7 @@ void git_tree__free(void *_tree) git_tree_entry_free(e); git_vector_free(&tree->entries); + git_pool_clear(&tree->pool); git__free(tree); } @@ -385,6 +410,7 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj) const char *buffer = git_odb_object_data(odb_obj); const char *buffer_end = buffer + git_odb_object_size(odb_obj); + git_pool_init(&tree->pool, 1); if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) return -1; @@ -403,13 +429,11 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj) /** Allocate the entry and store it in the entries vector */ { - entry = alloc_entry(buffer); + entry = alloc_entry_pooled(&tree->pool, buffer); GITERR_CHECK_ALLOC(entry); - if (git_vector_insert(&tree->entries, entry) < 0) { - git__free(entry); + if (git_vector_insert(&tree->entries, entry) < 0) return -1; - } entry->attr = attr; } diff --git a/src/tree.h b/src/tree.h index d01b6fd41..51f42ca32 100644 --- a/src/tree.h +++ b/src/tree.h @@ -12,17 +12,20 @@ #include "odb.h" #include "vector.h" #include "strmap.h" +#include "pool.h" struct git_tree_entry { uint16_t attr; git_oid oid; + bool pooled; size_t filename_len; - char filename[1]; + char filename[GIT_FLEX_ARRAY]; }; struct git_tree { git_object object; git_vector entries; + git_pool pool; }; struct git_treebuilder { |