summaryrefslogtreecommitdiff
path: root/src/shared/util.h
diff options
context:
space:
mode:
authorMichal Schmidt <mschmidt@redhat.com>2014-10-31 13:28:12 -0400
committerAnthony G. Basile <blueness@gentoo.org>2014-10-31 13:28:12 -0400
commit03221aa40a8529c0a2d1262d7a0ee54349ff38be (patch)
tree90eca73059405f7eacc32b0892df71c5d8d6cb37 /src/shared/util.h
parent11c32d3baa60f9919b7eba4f58841db0039403f2 (diff)
hashmap: rewrite the implementation
We reintroduce hashmap.{h,c}, list.h and set.h verbatim from upstream, before we punt dead code. The following is the upstream message: This is a rewrite of the hashmap implementation. Its advantage is lower memory usage. It uses open addressing (entries are stored in an array, as opposed to linked lists). Hash collisions are resolved with linear probing and Robin Hood displacement policy. See the references in hashmap.c. Some fun empirical findings about hashmap usage in systemd on my laptop: - 98 % of allocated hashmaps are Sets. - Sets contain 78 % of all entries, plain Hashmaps 17 %, and OrderedHashmaps 5 %. - 60 % of allocated hashmaps contain only 1 entry. - 90 % of allocated hashmaps contain 5 or fewer entries. - 75 % of all entries are in hashmaps that use trivial_hash_ops. Clearly it makes sense to: - store entries in distinct entry types. Especially for Sets - their entries are the most numerous and they require the least information to store an entry. - have a way to store small numbers of entries directly in the hashmap structs, and only allocate the usual entry arrays when the direct storage is full. The implementation has an optional debugging feature (enabled by defining the ENABLE_HASHMAP_DEBUG macro), where it: - tracks all allocated hashmaps in a linked list so that one can easily find them in gdb, - tracks which function/line allocated a given hashmap, and - checks for invalid mixing of hashmap iteration and modification. Since entries are not allocated one-by-one anymore, mempools are not used for entries. Originally I meant to drop mempools entirely, but it's still worth it to use them for the hashmap structs. My testing indicates that it makes loading of units about 5 % faster (a test with 10000 units where more than 200000 hashmaps are allocated - pure malloc: 449±4 ms, mempools: 427±7 ms). Here are some memory usage numbers, taken on my laptop with a more or less normal Fedora setup after booting with SELinux disabled (SELinux increases systemd's memory usage significantly): systemd (PID 1) Original New Change dirty memory (from pmap -x 1) [KiB] 2152 1264 -41 % total heap allocations (from gdb-heap) [KiB] 1623 756 -53 % Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'src/shared/util.h')
-rw-r--r--src/shared/util.h20
1 files changed, 20 insertions, 0 deletions
diff --git a/src/shared/util.h b/src/shared/util.h
index f57a73cec6..a25b2f5aec 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -369,12 +369,32 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
break; \
} else
+static inline void *mempset(void *s, int c, size_t n) {
+ memset(s, c, n);
+ return (uint8_t*)s + n;
+}
+
static inline void _reset_errno_(int *saved_errno) {
errno = *saved_errno;
}
#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno
+static inline unsigned log2u(unsigned x) {
+ assert(x > 0);
+
+ return sizeof(unsigned) * 8 - __builtin_clz(x) - 1;
+}
+
+static inline unsigned log2u_round_up(unsigned x) {
+ assert(x > 0);
+
+ if (x == 1)
+ return 0;
+
+ return log2u(x - 1) + 1;
+}
+
int unlink_noerrno(const char *path);
#define strappenda(a, ...) \