summaryrefslogtreecommitdiff
path: root/src/shared/set.c
diff options
context:
space:
mode:
authorMichal Schmidt <mschmidt@redhat.com>2014-10-15 01:27:16 +0200
committerMichal Schmidt <mschmidt@redhat.com>2014-10-30 19:50:51 +0100
commit89439d4fc0d29f04ac68432fd06ab84bc4e36e20 (patch)
tree45cfb719ba5dd1e1d54678ca1f4159e0dd3b0c1f /src/shared/set.c
parentce79279bff6e7a1a17070509a039ab635796f129 (diff)
hashmap: rewrite the implementation
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 %
Diffstat (limited to 'src/shared/set.c')
-rw-r--r--src/shared/set.c166
1 files changed, 0 insertions, 166 deletions
diff --git a/src/shared/set.c b/src/shared/set.c
deleted file mode 100644
index 84ab82a701..0000000000
--- a/src/shared/set.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-
-#include "set.h"
-#include "hashmap.h"
-#include "strv.h"
-
-#define MAKE_SET(h) ((Set*) (h))
-#define MAKE_HASHMAP(s) ((Hashmap*) (s))
-
-/* For now this is not much more than a wrapper around a hashmap */
-
-Set *set_new(const struct hash_ops *hash_ops) {
- return MAKE_SET(hashmap_new(hash_ops));
-}
-
-void set_free(Set* s) {
- hashmap_free(MAKE_HASHMAP(s));
-}
-
-void set_free_free(Set *s) {
- hashmap_free_free(MAKE_HASHMAP(s));
-}
-
-int set_ensure_allocated(Set **s, const struct hash_ops *hash_ops) {
- return hashmap_ensure_allocated((Hashmap**) s, hash_ops);
-}
-
-int set_put(Set *s, void *value) {
- return hashmap_put(MAKE_HASHMAP(s), value, value);
-}
-
-int set_consume(Set *s, void *value) {
- int r;
-
- r = set_put(s, value);
- if (r < 0)
- free(value);
-
- return r;
-}
-
-int set_put_strdup(Set *s, const char *p) {
- char *c;
- int r;
-
- assert(s);
- assert(p);
-
- c = strdup(p);
- if (!c)
- return -ENOMEM;
-
- r = set_consume(s, c);
- if (r == -EEXIST)
- return 0;
-
- return r;
-}
-
-int set_put_strdupv(Set *s, char **l) {
- int n = 0, r;
- char **i;
-
- STRV_FOREACH(i, l) {
- r = set_put_strdup(s, *i);
- if (r < 0)
- return r;
-
- n += r;
- }
-
- return n;
-}
-
-int set_replace(Set *s, void *value) {
- return hashmap_replace(MAKE_HASHMAP(s), value, value);
-}
-
-void *set_get(Set *s, void *value) {
- return hashmap_get(MAKE_HASHMAP(s), value);
-}
-
-bool set_contains(Set *s, void *value) {
- return hashmap_contains(MAKE_HASHMAP(s), value);
-}
-
-void *set_remove(Set *s, void *value) {
- return hashmap_remove(MAKE_HASHMAP(s), value);
-}
-
-int set_remove_and_put(Set *s, void *old_value, void *new_value) {
- return hashmap_remove_and_put(MAKE_HASHMAP(s), old_value, new_value, new_value);
-}
-
-unsigned set_size(Set *s) {
- return hashmap_size(MAKE_HASHMAP(s));
-}
-
-bool set_isempty(Set *s) {
- return hashmap_isempty(MAKE_HASHMAP(s));
-}
-
-void *set_iterate(Set *s, Iterator *i) {
- return hashmap_iterate(MAKE_HASHMAP(s), i, NULL);
-}
-
-void *set_steal_first(Set *s) {
- return hashmap_steal_first(MAKE_HASHMAP(s));
-}
-
-void* set_first(Set *s) {
- return hashmap_first(MAKE_HASHMAP(s));
-}
-
-int set_merge(Set *s, Set *other) {
- return hashmap_merge(MAKE_HASHMAP(s), MAKE_HASHMAP(other));
-}
-
-int set_reserve(Set *s, unsigned entries_add) {
- return hashmap_reserve(MAKE_HASHMAP(s), entries_add);
-}
-
-int set_move(Set *s, Set *other) {
- return hashmap_move(MAKE_HASHMAP(s), MAKE_HASHMAP(other));
-}
-
-int set_move_one(Set *s, Set *other, void *value) {
- return hashmap_move_one(MAKE_HASHMAP(s), MAKE_HASHMAP(other), value);
-}
-
-Set* set_copy(Set *s) {
- return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s)));
-}
-
-void set_clear(Set *s) {
- hashmap_clear(MAKE_HASHMAP(s));
-}
-
-void set_clear_free(Set *s) {
- hashmap_clear_free(MAKE_HASHMAP(s));
-}
-
-char **set_get_strv(Set *s) {
- return hashmap_get_strv(MAKE_HASHMAP(s));
-}