libsepol: make ebitmap_cardinality() of linear complexity

As ebitmap_get_bit() complexity is linear in the size of the bitmap, the
complexity of ebitmap_cardinality() is quadratic. This can be optimized
by browsing the nodes of the bitmap directly in ebitmap_cardinality().

While at it, use built-in function __builtin_popcountll() to count the
ones in the 64-bit value n->map for each bitmap node. This seems better
suited than "count++". This seems to work on gcc and clang on x86,
x86_64, ARM and ARM64 but if it causes compatibility issues with some
compilers or architectures (or with older versions of gcc or clang),
the use of __builtin_popcountll() can be replaced by a C implementation
of a popcount algorithm.

Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
This commit is contained in:
Nicolas Iooss 2020-02-25 23:48:41 +01:00
parent a41dfeb55d
commit 6968ea9775
No known key found for this signature in database
GPG Key ID: C191415F340DAAA0

View File

@ -128,14 +128,15 @@ int ebitmap_andnot(ebitmap_t *dst, ebitmap_t *e1, ebitmap_t *e2, unsigned int ma
unsigned int ebitmap_cardinality(ebitmap_t *e1) unsigned int ebitmap_cardinality(ebitmap_t *e1)
{ {
unsigned int i, count = 0; unsigned int count = 0;
ebitmap_node_t *n;
if (e1->cardinality || e1->highbit == 0) if (e1->cardinality || e1->highbit == 0)
return e1->cardinality; return e1->cardinality;
for (i=ebitmap_startbit(e1); i < ebitmap_length(e1); i++) for (n = e1->node; n; n = n->next) {
if (ebitmap_get_bit(e1, i)) count += __builtin_popcountll(n->map);
count++; }
e1->cardinality = count; e1->cardinality = count;
return count; return count;
} }