Tweak avtab hash table parameters for better performance

Using the Fedora 20 targeted policy, running check_assertions requires
an avtab with around 22 million elements. With the default limit of 4096
buckets, performance is abysmal: it takes more than an hour to populate
the hash. Profiling shows most of that time under avtab_search_node.

This patch increases the hash from 13 to 20 bits and to a maximum of
1048576 buckets. The time for check_assertions on that policy is reduced
to about 3 minutes, which is enough to re-enable those checks as part of
the build process.

A full size table will allocate 4-8 MB of memory, up from 16-32 KB. In a
cursory review, these tables are usually short-lived and only 1-3 are
allocated together. Compared to the cost of entries in this table (up to
1 GB using the same policy), this isn't a significant increase.

Signed-off-by: John Brooks <john.brooks@jolla.com>
This commit is contained in:
John Brooks 2015-01-14 17:24:03 -07:00 committed by Stephen Smalley
parent 798950e055
commit acb2a9bede
2 changed files with 7 additions and 6 deletions

View File

@ -81,7 +81,7 @@ typedef struct avtab {
avtab_ptr_t *htable;
uint32_t nel; /* number of elements */
uint32_t nslot; /* number of hash slots */
uint16_t mask; /* mask to compute hash func */
uint32_t mask; /* mask to compute hash func */
} avtab_t;
extern int avtab_init(avtab_t *);
@ -117,10 +117,11 @@ extern avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key);
extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified);
#define MAX_AVTAB_HASH_BITS 13
#define MAX_AVTAB_HASH_BITS 20
#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
/* avtab_alloc uses one bucket per 2-4 elements, so adjust to get maximum buckets */
#define MAX_AVTAB_SIZE (MAX_AVTAB_HASH_BUCKETS << 1)
#endif /* _AVTAB_H_ */

View File

@ -333,7 +333,7 @@ int avtab_init(avtab_t * h)
int avtab_alloc(avtab_t *h, uint32_t nrules)
{
uint16_t mask = 0;
uint32_t mask = 0;
uint32_t shift = 0;
uint32_t work = nrules;
uint32_t nslot = 0;
@ -348,8 +348,8 @@ int avtab_alloc(avtab_t *h, uint32_t nrules)
if (shift > 2)
shift = shift - 2;
nslot = 1 << shift;
if (nslot > MAX_AVTAB_SIZE)
nslot = MAX_AVTAB_SIZE;
if (nslot > MAX_AVTAB_HASH_BUCKETS)
nslot = MAX_AVTAB_HASH_BUCKETS;
mask = nslot - 1;
h->htable = calloc(nslot, sizeof(avtab_ptr_t));