[patch v2] manual: add remaining CPU_* macros
Mark Harris
mark.hsj@gmail.com
Tue May 13 04:31:07 GMT 2025
On Fri, Apr 25, 2025 at 1:14 PM DJ Delorie <dj@redhat.com> wrote:
>
>
> Adds remaining CPU_* macros, including the CPU_*_S macros
> for dynamic-sized cpu sets.
>
> diff --git a/manual/resource.texi b/manual/resource.texi
> index acdb1f3986..c824046d2d 100644
> --- a/manual/resource.texi
> +++ b/manual/resource.texi
> @@ -1362,26 +1362,73 @@ extent the Linux kernel interface.
> @standards{GNU, sched.h}
> This data set is a bitset where each bit represents a CPU. How the
> system's CPUs are mapped to bits in the bitset is system dependent.
> -The data type has a fixed size; in the unlikely case that the number
> -of bits are not sufficient to describe the CPUs of the system a
> -different interface has to be used.
> +The data type has a fixed size; it is strongly recommended to allocate
> +a dynamically sized set based on the actual number of CPUs detected,
> +such as via @code{get_nprocs()}, and use the @code{CPU_*_S} variants
> +instead of the fixed-size ones.
get_nprocs () returns the count of currently online CPUs. If you have
CPUs 0-127 with CPUs 0-63 offline (chcpu -d 0-63), then get_nprocs ()
will return 64, but a 128-bit bitmask is needed since the online CPUs
are numbered 64-127. It would be better to use get_nprocs_conf ().
>
> This type is a GNU extension and is defined in @file{sched.h}.
> @end deftp
>
> -To manipulate the bitset, to set and reset bits, a number of macros are
> -defined. Some of the macros take a CPU number as a parameter. Here
> -it is important to never exceed the size of the bitset. The following
> -macro specifies the number of bits in the @code{cpu_set_t} bitset.
> +To manipulate the bitset, to set and reset bits, and thus add and
> +remove CPUs from the sets, a number of macros are defined. Some of
> +the macros take a CPU number as a parameter. Here it is important to
> +never exceed the size of the bitset, either @code{CPU_SETSIZE} for
> +fixed sets or the allocated size for dynamic sets. For each macro
> +there is a fixed-size version (documented below) and a dynamic-sized
> +version (with a @code{_S} suffix).
>
> @deftypevr Macro int CPU_SETSIZE
> @standards{GNU, sched.h}
> The value of this macro is the maximum number of CPUs which can be
> -handled with a @code{cpu_set_t} object.
> +handled with a fixed @code{cpu_set_t} object.
> @end deftypevr
>
> +For applications that require CPU sets larger than the built-in size,
> +a set of macros that support dynamically-sized sets are defined.
> +
> +@deftypefn Macro size_t CPU_ALLOC_SIZE (size_t @var{count})
> +@standards{GNU, sched.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +@c CPU_ALLOC_SIZE ok
> +@c __CPU_ALLOC_SIZE ok
> +Given a count of CPUs to hold, returns the size of the set to
> +allocate. This return value is appropriate to be used in the *_S macros.
> +
> +This macro is a GNU extension and is defined in @file{sched.h}.
> +@end deftypefn
> +
> +@deftypefn Macro {cpu_set_t *} CPU_ALLOC (size_t @var{count})
> +@standards{GNU, sched.h}
> +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}}
> +@c CPU_ALLOC
> +@c __CPU_ALLOC
> +@c __sched_cpualloc
> +@c malloc
> +Given the count of CPUs to hold, returns a set large enough to hold
> +them; that is, the resulting set will be valid for CPUs numbered 0
> +through @var{count}-1, inclusive. This set must be freed via
> +@code{CPU_FREE} to avoid memory leaks. Warning: the argument is the
> +CPU @emph{count} and not the size returned by @code{CPU_ALLOC_SIZE}.
> +
> +This macro is a GNU extension and is defined in @file{sched.h}.
> +@end deftypefn
> +
> +@deftypefn Macro void CPU_FREE (cpu_set_t *@var{set})
> +@standards{GNU, sched.h}
> +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}}
> +@c CPU_FREE
> +@c __CPU_FREE
> +@c __sched_cpufree
> +@c free
> +Frees a CPU set previously allocated by @code{CPU_ALLOC}.
> +
> +This macro is a GNU extension and is defined in @file{sched.h}.
> +@end deftypefn
> +
> The type @code{cpu_set_t} should be considered opaque; all
> -manipulation should happen via the next four macros.
> +manipulation should happen via the @code{CPU_*} macros described
> +below.
>
> @deftypefn Macro void CPU_ZERO (cpu_set_t *@var{set})
> @standards{GNU, sched.h}
> @@ -1424,6 +1471,39 @@ evaluated more than once.
> This macro is a GNU extension and is defined in @file{sched.h}.
> @end deftypefn
>
> +@deftypefn Macro {cpu_set_t *} CPU_AND (cpu_set_t *@var{dest}, cpu_set_t *@var{src1}, cpu_set_t *@var{src2})
> +@standards{GNU, sched.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +@c CPU_AND ok
> +@c __CPU_OP_S ok
> +This macro populates @var{dest} with only those CPUs included in both
> +@var{src1} and @var{src2}. Its value is @var{dest}.
> +
> +This macro is a GNU extension and is defined in @file{sched.h}.
> +@end deftypefn
> +
> +@deftypefn Macro {cpu_set_t *} CPU_OR (cpu_set_t *@var{dest}, cpu_set_t *@var{src1}, cpu_set_t *@var{src2})
> +@standards{GNU, sched.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +@c CPU_OR ok
> +@c __CPU_OP_S ok
> +This macro populates @var{dest} with those CPUs included in either
> +@var{src1} or @var{src2}. Its value is @var{dest}.
> +
> +This macro is a GNU extension and is defined in @file{sched.h}.
> +@end deftypefn
> +
> +@deftypefn Macro {cpu_set_t *} CPU_XOR (cpu_set_t *@var{dest}, cpu_set_t *@var{src1}, cpu_set_t *@var{src2})
> +@standards{GNU, sched.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +@c CPU_XOR ok
> +@c __CPU_OP_S ok
> +This macro populates @var{dest} with those CPUs included in either
> +@var{src1} or @var{src2}, but not both. Its value is @var{dest}.
> +
> +This macro is a GNU extension and is defined in @file{sched.h}.
> +@end deftypefn
> +
> @deftypefn Macro int CPU_ISSET (int @var{cpu}, const cpu_set_t *@var{set})
> @standards{GNU, sched.h}
> @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> @@ -1440,6 +1520,54 @@ evaluated more than once.
> This macro is a GNU extension and is defined in @file{sched.h}.
> @end deftypefn
>
> +@deftypefn Macro int CPU_COUNT (const cpu_set_t *@var{set})
> +@standards{GNU, sched.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +@c CPU_COUNT ok
> +@c __CPU_COUNT_S ok
> +@c __sched_cpucount ok
> +@c countbits ok
> +This macro returns the count of CPUs (bits) set in @var{set}.
> +
> +This macro is a GNU extension and is defined in @file{sched.h}.
> +@end deftypefn
> +
> +@deftypefn Macro int CPU_EQUAL (cpu_set_t *@var{src1}, cpu_set_t *@var{src2})
> +@standards{GNU, sched.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +@c CPU_EQUAL ok
> +@c __CPU_EQUAL_S ok
> +@c memcmp ok
> +This macro returns nonzero if the two sets @var{set1} and @var{set2}
> +have the same contents; that is, the set of CPUs represented by both
> +sets is identical.
> +
> +This macro is a GNU extension and is defined in @file{sched.h}.
> +@end deftypefn
> +
> +@deftypefn Macro void CPU_ZERO_S (size_t @var{size}, cpu_set_t *@var{set})
> +@end deftypefn
> +@deftypefn Macro void CPU_SET_S (int @var{cpu}, size_t @var{size}, cpu_set_t *@var{set})
> +@end deftypefn
> +@deftypefn Macro void CPU_CLR_S (int @var{cpu}, size_t @var{size}, cpu_set_t *@var{set})
> +@end deftypefn
> +@deftypefn Macro {cpu_set_t *} CPU_AND_S (size_t @var{size}, cpu_set_t *@var{dest}, cpu_set_t *@var{src1}, cpu_set_t *@var{src2})
> +@end deftypefn
> +@deftypefn Macro {cpu_set_t *} CPU_OR_S (size_t @var{size}, cpu_set_t *@var{dest}, cpu_set_t *@var{src1}, cpu_set_t *@var{src2})
> +@end deftypefn
> +@deftypefn Macro {cpu_set_t *} CPU_XOR_S (size_t @var{size}, cpu_set_t *@var{dest}, cpu_set_t *@var{src1}, cpu_set_t *@var{src2})
> +@end deftypefn
> +@deftypefn Macro int CPU_ISSET_S (int @var{cpu}, size_t @var{size}, const cpu_set_t *@var{set})
> +@end deftypefn
> +@deftypefn Macro int CPU_COUNT_S (size_t @var{size}, const cpu_set_t *@var{set})
> +@end deftypefn
> +@deftypefn Macro int CPU_EQUAL_S (size_t @var{size}, cpu_set_t *@var{src1}, cpu_set_t *@var{src2})
> +@end deftypefn
> +
> +Each of these macros performs the same action as its non-@code{_S} variant,
> +but takes a @var{size} argument to specify the set size. This
> +@var{size} argument is as returned by the @code{CPU_ALLOC_SIZE} macro,
> +defined above.
>
> CPU bitsets can be constructed from scratch or the currently installed
> affinity mask can be retrieved from the system.
> @@ -1525,6 +1653,33 @@ The operating system does not support this function.
> This function is Linux-specific and is declared in @file{sched.h}.
> @end deftypefun
>
> +Here's an example of how to use most of the above to limit the number
> +of CPUs a process runs on, not including error handling or good logic
> +on CPU choices:
> +
> +@example
> +#include <sched.h>
get_nprocs () and get_nprocs_conf () require <sys/sysinfo.h>. getpid
() requires <unistd.h>. Also the CPU_* macros require _GNU_SOURCE to
be defined.
> +void limit_cpus (void)
> +@{
> + unsigned int mycpu;
> + size_t nproc, cssz, cpu;
> + cpu_set_t *cs, *cs1;
> + getcpu (&mycpu, NULL);
> + nproc = get_nprocs ();
This may result in too small of a bitmask to represent all CPUs. It
would be better to use get_nprocs_conf () for determining the size of
the bitmask, although get_nprocs () may be desirable later for
checking whether half of the currently online CPUs are in the affinity
mask.
> + cssz = CPU_ALLOC_SIZE (nproc);
> + cs = CPU_ALLOC (nproc);
> + sched_getaffinity (getpid(), cssz, cs1);
This is passing an uninitialized pointer variable cs1 to
sched_getaffinity (). It looks like all uses of cs1 should be cs, and
its definition can be removed.
It may be simpler to use 0 (current thread) instead of getpid() here
and in sched_setaffinity below.
> + if (CPU_COUNT_S (cssz, cs1) > nproc / 2)
> + @{
> + for (cpu = nproc / 2; cpu < nproc; cpu ++)
> + if (cpu != mycpu)
> + CPU_CLR_S (cpu, cssz, cs);
> + sched_setaffinity (getpid(), cssz, cs1);
> + @}
> + CPU_FREE (cs);
> +@}
> +@end example
> +
> @node Memory Resources
> @section Querying memory available resources
>
>
- Mark
More information about the Libc-alpha
mailing list