
Throughout the reftable library we have many cases where we need to grow arrays. In order to avoid too many reallocations, we roughly double the capacity of the array on each iteration. The resulting code pattern is duplicated across many sites. We have similar patterns in our main codebase, which is why we have eventually introduced an `ALLOC_GROW()` macro to abstract it away and avoid some code duplication. We cannot easily reuse this macro here though because `ALLOC_GROW()` uses `REALLOC_ARRAY()`, which in turn will call realloc(3P) to grow the array. The reftable code is structured as a library though (even if the boundaries are fuzzy), and one property this brings with it is that it is possible to plug in your own allocators. So instead of using realloc(3P), we need to use `reftable_realloc()` that knows to use the user-provided implementation. So let's introduce two new macros `REFTABLE_REALLOC_ARRAY()` and `REFTABLE_ALLOC_GROW()` that mirror what we do in our main codebase, with two modifications: - They use `reftable_realloc()`, as explained above. - They use a different growth factor of `2 * cap + 1` instead of `(cap + 16) * 3 / 2`. The second change is because we know a bit more about the allocation patterns in the reftable library. In most cases, we end up only having a handful of items in the array and don't end up growing them. The initial capacity that our normal growth factor uses (which is 24) would thus end up over-allocating in a lot of code paths. This effect is measurable: - Before change: HEAP SUMMARY: in use at exit: 671,983 bytes in 152 blocks total heap usage: 3,843,446 allocs, 3,843,294 frees, 223,761,402 bytes allocated - After change with a growth factor of `(2 * alloc + 1)`: HEAP SUMMARY: in use at exit: 671,983 bytes in 152 blocks total heap usage: 3,843,446 allocs, 3,843,294 frees, 223,761,410 bytes allocated - After change with a growth factor of `(alloc + 16)* 2 / 3`: HEAP SUMMARY: in use at exit: 671,983 bytes in 152 blocks total heap usage: 3,833,673 allocs, 3,833,521 frees, 4,728,251,742 bytes allocated While the total heap usage is roughly the same, we do end up allocating significantly more bytes with our usual growth factor (in fact, roughly 21 times as many). Convert the reftable library to use these new macros. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
72 lines
1.9 KiB
C
72 lines
1.9 KiB
C
/*
|
|
Copyright 2020 Google LLC
|
|
|
|
Use of this source code is governed by a BSD-style
|
|
license that can be found in the LICENSE file or at
|
|
https://developers.google.com/open-source/licenses/bsd
|
|
*/
|
|
|
|
#ifndef BASICS_H
|
|
#define BASICS_H
|
|
|
|
/*
|
|
* miscellaneous utilities that are not provided by Git.
|
|
*/
|
|
|
|
#include "system.h"
|
|
|
|
/* Bigendian en/decoding of integers */
|
|
|
|
void put_be24(uint8_t *out, uint32_t i);
|
|
uint32_t get_be24(uint8_t *in);
|
|
void put_be16(uint8_t *out, uint16_t i);
|
|
|
|
/*
|
|
* find smallest index i in [0, sz) at which f(i) is true, assuming
|
|
* that f is ascending. Return sz if f(i) is false for all indices.
|
|
*
|
|
* Contrary to bsearch(3), this returns something useful if the argument is not
|
|
* found.
|
|
*/
|
|
int binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
|
|
|
|
/*
|
|
* Frees a NULL terminated array of malloced strings. The array itself is also
|
|
* freed.
|
|
*/
|
|
void free_names(char **a);
|
|
|
|
/* parse a newline separated list of names. `size` is the length of the buffer,
|
|
* without terminating '\0'. Empty names are discarded. */
|
|
void parse_names(char *buf, int size, char ***namesp);
|
|
|
|
/* compares two NULL-terminated arrays of strings. */
|
|
int names_equal(char **a, char **b);
|
|
|
|
/* returns the array size of a NULL-terminated array of strings. */
|
|
int names_length(char **names);
|
|
|
|
/* Allocation routines; they invoke the functions set through
|
|
* reftable_set_alloc() */
|
|
void *reftable_malloc(size_t sz);
|
|
void *reftable_realloc(void *p, size_t sz);
|
|
void reftable_free(void *p);
|
|
void *reftable_calloc(size_t sz);
|
|
|
|
#define REFTABLE_REALLOC_ARRAY(x, alloc) (x) = reftable_realloc((x), st_mult(sizeof(*(x)), (alloc)))
|
|
#define REFTABLE_ALLOC_GROW(x, nr, alloc) \
|
|
do { \
|
|
if ((nr) > alloc) { \
|
|
alloc = 2 * (alloc) + 1; \
|
|
if (alloc < (nr)) \
|
|
alloc = (nr); \
|
|
REFTABLE_REALLOC_ARRAY(x, alloc); \
|
|
} \
|
|
} while (0)
|
|
|
|
/* Find the longest shared prefix size of `a` and `b` */
|
|
struct strbuf;
|
|
int common_prefix_size(struct strbuf *a, struct strbuf *b);
|
|
|
|
#endif
|