The hwloc_cpuset_next() will calculate the next cpu behind a given one. Use hwloc_cpuset_first() and hwloc_cpuset_next() in hwloc_cpuset_foreach() to sparsely iterate over a cpuset.
Regards, Bert --- doc/Makefile.am | 1 + include/hwloc/cpuset.h | 9 ++++++--- include/hwloc/rename.h | 1 + src/cpuset.c | 24 ++++++++++++++++++++++++ tests/hwloc_cpuset_first_last_weight.c | 28 +++++++++++++++++++++++++++- 5 files changed, 59 insertions(+), 4 deletions(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 9c7bcf7..6fed82c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -266,6 +266,7 @@ man3_MANS = \ $(DOX_MAN_DIR)/man3/hwloc_cpuset_isset.3 \ $(DOX_MAN_DIR)/man3/hwloc_cpuset_iszero.3 \ $(DOX_MAN_DIR)/man3/hwloc_cpuset_last.3 \ + $(DOX_MAN_DIR)/man3/hwloc_cpuset_next.3 \ $(DOX_MAN_DIR)/man3/hwloc_cpuset_notset.3 \ $(DOX_MAN_DIR)/man3/hwloc_cpuset_orset.3 \ $(DOX_MAN_DIR)/man3/hwloc_cpuset_set.3 \ diff --git a/include/hwloc/cpuset.h b/include/hwloc/cpuset.h index ad2dab4..5a629e9 100644 --- a/include/hwloc/cpuset.h +++ b/include/hwloc/cpuset.h @@ -156,6 +156,9 @@ HWLOC_DECLSPEC int hwloc_cpuset_first(hwloc_const_cpuset_t set) __hwloc_attribut /** \brief Compute the last CPU (most significant bit) in CPU set \p set */ HWLOC_DECLSPEC int hwloc_cpuset_last(hwloc_const_cpuset_t set) __hwloc_attribute_pure; +/** \brief Compute the next CPU in CPU set \p set which is after CPU \p prev_cpu */ +HWLOC_DECLSPEC int hwloc_cpuset_next(hwloc_const_cpuset_t set, unsigned prev_cpu) __hwloc_attribute_pure; + /** \brief Keep a single CPU among those set in CPU set \p set * * Might be used before binding so that the process does not @@ -188,13 +191,13 @@ HWLOC_DECLSPEC int hwloc_cpuset_weight(hwloc_const_cpuset_t set) __hwloc_attribu */ #define hwloc_cpuset_foreach_begin(cpu, set) \ do { \ - for (cpu = 0; cpu < HWLOC_NBMAXCPUS; cpu++) { \ - if (hwloc_cpuset_isset(set, cpu)) { + for (cpu = hwloc_cpuset_first(set); \ + cpu != -1; \ + cpu = hwloc_cpuset_next(set, cpu)) { \ /** \brief End of loop. Needs a terminating ';'. * * \sa hwloc_cpuset_foreach_begin */ #define hwloc_cpuset_foreach_end() \ - } \ } \ } while (0) diff --git a/include/hwloc/rename.h b/include/hwloc/rename.h index 6ebb454..bf1b600 100644 --- a/include/hwloc/rename.h +++ b/include/hwloc/rename.h @@ -165,6 +165,7 @@ #define hwloc_cpuset_notset HWLOC_NAME(cpuset_notset) #define hwloc_cpuset_first HWLOC_NAME(cpuset_first) #define hwloc_cpuset_last HWLOC_NAME(cpuset_last) +#define hwloc_cpuset_next HWLOC_NAME(cpuset_next) #define hwloc_cpuset_singlify HWLOC_NAME(cpuset_singlify) #define hwloc_cpuset_compare_first HWLOC_NAME(cpuset_compare_first) #define hwloc_cpuset_compare HWLOC_NAME(cpuset_compare) diff --git a/src/cpuset.c b/src/cpuset.c index 1787489..e2f9b16 100644 --- a/src/cpuset.c +++ b/src/cpuset.c @@ -510,6 +510,30 @@ int hwloc_cpuset_last(const struct hwloc_cpuset_s * set) return -1; } +int hwloc_cpuset_next(const struct hwloc_cpuset_s * set, unsigned prev_cpu) +{ + int i = HWLOC_CPUSUBSET_INDEX(prev_cpu + 1); + + HWLOC__CPUSET_CHECK(set); + + for(; i<HWLOC_CPUSUBSET_COUNT; i++) { + unsigned long w = HWLOC_CPUSUBSET_SUBSET(*set,i); + + /* if the prev cpu is in the same word as the possible next one, + we need to mask out previous cpus */ + if (HWLOC_CPUSUBSET_INDEX(prev_cpu) == i) { + w &= ~((HWLOC_CPUSUBSET_VAL(prev_cpu) << 1) - 1); + } + + /* subsets are unsigned longs, use ffsl */ + int _ffs = hwloc_ffsl(w); + if (_ffs>0) + return _ffs - 1 + HWLOC_CPUSUBSET_SIZE*i; + } + + return -1; +} + void hwloc_cpuset_singlify(struct hwloc_cpuset_s * set) { int i,found = 0; diff --git a/tests/hwloc_cpuset_first_last_weight.c b/tests/hwloc_cpuset_first_last_weight.c index 093aea1..8a65d8e 100644 --- a/tests/hwloc_cpuset_first_last_weight.c +++ b/tests/hwloc_cpuset_first_last_weight.c @@ -8,22 +8,27 @@ #include <assert.h> -/* check hwloc_cpuset_first(), _last() and _weight() */ +/* check hwloc_cpuset_first(), _last(), _next() and _weight() */ int main(void) { hwloc_cpuset_t set; + int i, cpu, expected_cpu; /* empty set */ set = hwloc_cpuset_alloc(); assert(hwloc_cpuset_first(set) == -1); assert(hwloc_cpuset_last(set) == -1); + assert(hwloc_cpuset_next(set, 0) == -1); assert(hwloc_cpuset_weight(set) == 0); /* full set */ hwloc_cpuset_fill(set); assert(hwloc_cpuset_first(set) == 0); assert(hwloc_cpuset_last(set) == HWLOC_NBMAXCPUS-1); + assert(hwloc_cpuset_next(set, 0) == 1); + assert(hwloc_cpuset_next(set, HWLOC_NBMAXCPUS-2) == HWLOC_NBMAXCPUS-1); + assert(hwloc_cpuset_next(set, HWLOC_NBMAXCPUS-1) == -1); assert(hwloc_cpuset_weight(set) == HWLOC_NBMAXCPUS); /* custom sets */ @@ -31,16 +36,37 @@ int main(void) hwloc_cpuset_set_range(set, 36, 59); assert(hwloc_cpuset_first(set) == 36); assert(hwloc_cpuset_last(set) == 59); + assert(hwloc_cpuset_next(set, 0) == 36); + assert(hwloc_cpuset_next(set, 36) == 37); + assert(hwloc_cpuset_next(set, 59) == -1); assert(hwloc_cpuset_weight(set) == 24); hwloc_cpuset_set_range(set, 136, 259); assert(hwloc_cpuset_first(set) == 36); assert(hwloc_cpuset_last(set) == 259); + assert(hwloc_cpuset_next(set, 59) == 136); + assert(hwloc_cpuset_next(set, 259) == -1); assert(hwloc_cpuset_weight(set) == 148); hwloc_cpuset_clr(set, 199); assert(hwloc_cpuset_first(set) == 36); assert(hwloc_cpuset_last(set) == 259); + assert(hwloc_cpuset_next(set, 198) == 200); + assert(hwloc_cpuset_next(set, 199) == 200); assert(hwloc_cpuset_weight(set) == 147); + i = 0; + hwloc_cpuset_foreach_begin(cpu, set) { + if (0 <= i && i < 24) + expected_cpu = i + 36; + else if (24 <= i && i < 87) + expected_cpu = i + 112; + else if (87 <= i && i < 147) + expected_cpu = i + 113; + + assert(expected_cpu == cpu); + + i++; + } hwloc_cpuset_foreach_end(); + hwloc_cpuset_free(set); return 0; -- tg: (1926bee..) bw/sparse-cpuset-foreach (depends on: bw/semi-colon-safe-foreach)