Skip to content

Commit

Permalink
libidset: improve efficiency of idset intersection
Browse files Browse the repository at this point in the history
Problem: idset_intersect(3) and idset_has_intersection(3) always
iterate one idset fully to determine the result, but the code doesn't
check to ensure it is iterating the smaller of the two provided idsets.
This could lead to wasted cycles, especially when the idset being
iterated has many more entries than the other argument.

If both idsets do not have the IDSET_FLAG_COUNT_LAZY flag set, then
swap arguments in both idset_intersect(3) and idset_has_intersection(3)
such that the idset with the smaller number of entries is iterated.

Before this change, to intersect the idsets 1-10000 and 1-100 took
an average of 4.5ms, with this change, that drops to .02 ms.
  • Loading branch information
grondo committed Jun 18, 2024
1 parent c3c1838 commit b9bf62c
Showing 1 changed file with 23 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/common/libidset/idset.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,18 @@ bool idset_has_intersection (const struct idset *a, const struct idset *b)
if (a && b) {
unsigned int id;

/* If there isn't a penalty for idset_count(3), then ensure
* we're going to iterate the smaller of the provided idsets
* for efficiency:
*/
if (!(a->flags & IDSET_FLAG_COUNT_LAZY)
&& !(b->flags & IDSET_FLAG_COUNT_LAZY)
&& idset_count (a) < idset_count (b)) {
const struct idset *tmp = a;
a = b;
b = tmp;
}

id = idset_first (b);
while (id != IDSET_INVALID_ID) {
if (idset_test (a, id))
Expand Down Expand Up @@ -542,6 +554,17 @@ struct idset *idset_intersect (const struct idset *a, const struct idset *b)
errno = EINVAL;
return NULL;
}
/* If there isn't a penalty for idset_count(3), then ensure
* we start with the smaller of the two idsets for efficiency:
*/
if (!(a->flags & IDSET_FLAG_COUNT_LAZY)
&& !(b->flags & IDSET_FLAG_COUNT_LAZY)
&& idset_count (b) < idset_count (a)) {
const struct idset *tmp = a;
a = b;
b = tmp;
}

if (!(result = idset_copy (a)))
return NULL;
id = idset_first (a);
Expand Down

0 comments on commit b9bf62c

Please sign in to comment.