[v3,1/3] elf: Add CPU iteration support for future use in ld.so diagnostics
Checks
Context |
Check |
Description |
redhat-pt-bot/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_glibc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_glibc_check--master-arm |
fail
|
Patch failed to apply
|
Commit Message
---
elf/dl-iterate_cpu.h | 135 ++++++++++++++++++++++++++
sysdeps/generic/dl-affinity.h | 54 +++++++++++
sysdeps/unix/sysv/linux/dl-affinity.h | 46 +++++++++
3 files changed, 235 insertions(+)
create mode 100644 elf/dl-iterate_cpu.h
create mode 100644 sysdeps/generic/dl-affinity.h
create mode 100644 sysdeps/unix/sysv/linux/dl-affinity.h
Comments
On Fri, Apr 5, 2024 at 3:17 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> ---
> elf/dl-iterate_cpu.h | 135 ++++++++++++++++++++++++++
> sysdeps/generic/dl-affinity.h | 54 +++++++++++
> sysdeps/unix/sysv/linux/dl-affinity.h | 46 +++++++++
> 3 files changed, 235 insertions(+)
> create mode 100644 elf/dl-iterate_cpu.h
> create mode 100644 sysdeps/generic/dl-affinity.h
> create mode 100644 sysdeps/unix/sysv/linux/dl-affinity.h
>
> diff --git a/elf/dl-iterate_cpu.h b/elf/dl-iterate_cpu.h
> new file mode 100644
> index 0000000000..772efffae1
> --- /dev/null
> +++ b/elf/dl-iterate_cpu.h
> @@ -0,0 +1,135 @@
> +/* Iterate over all CPUs, for CPU-specific diagnostics.
> + Copyright (C) 2024 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#ifndef DL_ITERATE_CPU_H
> +#define DL_ITERATE_CPU_H
> +
> +#include <dl-affinity.h>
> +
> +struct dl_iterate_cpu
> +{
> + /* Sequential iteration count, starting at 0. */
> + unsigned int processor_index;
> +
> + /* Requested CPU. Can be -1 if affinity could not be set. */
> + int requested_cpu;
> +
> + /* Observed current CPU. -1 if unavailable. */
> + int actual_cpu;
> +
> + /* Observed node ID for the CPU. -1 if unavailable. */
> + int actual_node;
> +
> + /* Internal fields to implement the iteration. */
> +
> + /* Affinity as obtained by _dl_iterate_cpu_init, using
> + _dl_getaffinity. Space for 8,192 CPUs. */
> + unsigned long int mask_reference[8192 / sizeof (unsigned long int) / 8];
> +
> + /* This array is used by _dl_setaffinity calls. */
> + unsigned long int mask_request[8192 / sizeof (unsigned long int) / 8];
> +
> + /* Return value from the initial _dl_getaffinity call. */
> + int length_reference;
> +};
> +
> +static void
> +_dl_iterate_cpu_init (struct dl_iterate_cpu *dic)
> +{
> + dic->length_reference
> + = _dl_getaffinity (dic->mask_reference, sizeof (dic->mask_reference));
> + /* Prepare for the first _dl_iterate_cpu_next call. */
> + dic->processor_index = -1;
> + dic->requested_cpu = -1;
> +}
> +
> +static bool
> +_dl_iterate_cpu_next (struct dl_iterate_cpu *dic)
> +{
> + ++dic->processor_index;
> +
> + if (dic->length_reference > 0)
> + {
> + /* Search for the next CPU to switch to. */
> + while (true)
> + {
> + ++dic->requested_cpu;
> +
> + /* Array index and bit number within the array. */
> + unsigned int long_index
> + = dic->requested_cpu / sizeof (unsigned long int) / 8;
> + unsigned int bit_index
> + = dic->requested_cpu % (sizeof (unsigned long int) * 8);
> +
> + if (long_index * sizeof (unsigned long int) >= dic->length_reference)
> + /* All possible CPUs have been covered. */
> + return false;
> +
> + unsigned long int bit = 1UL << bit_index;
> + if (dic->mask_reference[long_index] & bit)
> + {
> + /* The CPU is available. Try to select it. */
> + dic->mask_request[long_index] = bit;
> + if (_dl_setaffinity (dic->mask_request,
> + (long_index + 1)
> + * sizeof (unsigned long int)) < 0)
> + {
> + /* Record that we could not perform a CPU request. */
> + dic->length_reference = -1;
> +
> + if (dic->processor_index > 0)
> + /* We already reported something. There is no need to
> + continue because the new data is probably not useful. */
> + return false;
> + }
> +
> + /* Clear the bit in case the next iteration switches to the
> + next long value. */
> + dic->mask_request[long_index] = 0;
> +
> + /* We found a CPU to run on. */
> + break;
> + }
> + }
> + }
> + else
> + {
> + /* No way to set CPU affinity. Iterate just once. */
> + if (dic->processor_index > 0)
> + return false;
> + }
> +
> + /* Fill in the actual CPU information. CPU pinning may not actually
> + be effective, depending on the container host. */
> + unsigned int cpu, node;
> + if (_dl_getcpu (&cpu, &node) < 0)
> + {
> + /* No CPU information available. */
> + dic->actual_cpu = -1;
> + dic->actual_node = -1;
> + }
> + else
> + {
> + dic->actual_cpu = cpu;
> + dic->actual_node = node;
> + }
> +
> + return true;
> +}
> +
> +#endif /* DL_ITERATE_CPU_H */
> diff --git a/sysdeps/generic/dl-affinity.h b/sysdeps/generic/dl-affinity.h
> new file mode 100644
> index 0000000000..d117f737e9
> --- /dev/null
> +++ b/sysdeps/generic/dl-affinity.h
> @@ -0,0 +1,54 @@
> +/* CPU affinity handling for the dynamic linker. Stub version.
> + Copyright (C) 2024 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#ifndef DL_AFFINITY_H
> +#define DL_AFFINITY_H
> +
> +#include <errno.h>
> +#include <stddef.h>
> +
> +/* On success, write the current CPU ID to *CPU, and the current node
> + ID to *NODE, and return 0. Return a negative error code on
> + failure. */
> +static inline int
> +_dl_getcpu (unsigned int *cpu, unsigned int *node)
> +{
> + return -ENOSYS;
> +}
> +
> +/* On success, write CPU ID affinity bits for the current thread to
> + *BITS, which must be SIZE bytes long, and return the number of
> + bytes updated, a multiple of sizeof (unsigned long int). On
> + failure, return a negative error code. */
> +static int
> +_dl_getaffinity (unsigned long int *bits, size_t size)
> +{
> + return -ENOSYS;
> +}
> +
> +/* Set the CPU affinity mask for the current thread to *BITS, using
> + the SIZE bytes from that array, which should be a multiple of
> + sizeof (unsigned long int). Return 0 on success, and a negative
> + error code on failure. */
> +static int
> +_dl_setaffinity (const unsigned long int *bits, size_t size)
> +{
> + return -ENOSYS;
> +}
> +
> +#endif /* DL_AFFINITY_H */
> diff --git a/sysdeps/unix/sysv/linux/dl-affinity.h b/sysdeps/unix/sysv/linux/dl-affinity.h
> new file mode 100644
> index 0000000000..bbfede7750
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/dl-affinity.h
> @@ -0,0 +1,46 @@
> +/* CPU affinity handling for the dynamic linker. Linux version.
> + Copyright (C) 2024 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +/* See sysdeps/generic/dl-affinity.h for documentation of these interfaces. */
> +
> +#ifndef DL_AFFINITY_H
> +#define DL_AFFINITY_H
> +
> +#include <sysdep.h>
> +#include <stddef.h>
> +#include <unistd.h>
> +
> +static inline int
> +_dl_getcpu (unsigned int *cpu, unsigned int *node)
> +{
> + return INTERNAL_SYSCALL_CALL (getcpu, cpu, node);
> +}
> +
> +static int
> +_dl_getaffinity (unsigned long int *bits, size_t size)
> +{
> + return INTERNAL_SYSCALL_CALL (sched_getaffinity, /* TID */ 0, size, bits);
> +}
> +
> +static int
> +_dl_setaffinity (const unsigned long int *bits, size_t size)
> +{
> + return INTERNAL_SYSCALL_CALL (sched_setaffinity, /* TID */ 0, size, bits);
> +}
> +
> +#endif /* DL_AFFINITY_H */
> --
> 2.44.0
>
>
LGTM.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
Thanks.
new file mode 100644
@@ -0,0 +1,135 @@
+/* Iterate over all CPUs, for CPU-specific diagnostics.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef DL_ITERATE_CPU_H
+#define DL_ITERATE_CPU_H
+
+#include <dl-affinity.h>
+
+struct dl_iterate_cpu
+{
+ /* Sequential iteration count, starting at 0. */
+ unsigned int processor_index;
+
+ /* Requested CPU. Can be -1 if affinity could not be set. */
+ int requested_cpu;
+
+ /* Observed current CPU. -1 if unavailable. */
+ int actual_cpu;
+
+ /* Observed node ID for the CPU. -1 if unavailable. */
+ int actual_node;
+
+ /* Internal fields to implement the iteration. */
+
+ /* Affinity as obtained by _dl_iterate_cpu_init, using
+ _dl_getaffinity. Space for 8,192 CPUs. */
+ unsigned long int mask_reference[8192 / sizeof (unsigned long int) / 8];
+
+ /* This array is used by _dl_setaffinity calls. */
+ unsigned long int mask_request[8192 / sizeof (unsigned long int) / 8];
+
+ /* Return value from the initial _dl_getaffinity call. */
+ int length_reference;
+};
+
+static void
+_dl_iterate_cpu_init (struct dl_iterate_cpu *dic)
+{
+ dic->length_reference
+ = _dl_getaffinity (dic->mask_reference, sizeof (dic->mask_reference));
+ /* Prepare for the first _dl_iterate_cpu_next call. */
+ dic->processor_index = -1;
+ dic->requested_cpu = -1;
+}
+
+static bool
+_dl_iterate_cpu_next (struct dl_iterate_cpu *dic)
+{
+ ++dic->processor_index;
+
+ if (dic->length_reference > 0)
+ {
+ /* Search for the next CPU to switch to. */
+ while (true)
+ {
+ ++dic->requested_cpu;
+
+ /* Array index and bit number within the array. */
+ unsigned int long_index
+ = dic->requested_cpu / sizeof (unsigned long int) / 8;
+ unsigned int bit_index
+ = dic->requested_cpu % (sizeof (unsigned long int) * 8);
+
+ if (long_index * sizeof (unsigned long int) >= dic->length_reference)
+ /* All possible CPUs have been covered. */
+ return false;
+
+ unsigned long int bit = 1UL << bit_index;
+ if (dic->mask_reference[long_index] & bit)
+ {
+ /* The CPU is available. Try to select it. */
+ dic->mask_request[long_index] = bit;
+ if (_dl_setaffinity (dic->mask_request,
+ (long_index + 1)
+ * sizeof (unsigned long int)) < 0)
+ {
+ /* Record that we could not perform a CPU request. */
+ dic->length_reference = -1;
+
+ if (dic->processor_index > 0)
+ /* We already reported something. There is no need to
+ continue because the new data is probably not useful. */
+ return false;
+ }
+
+ /* Clear the bit in case the next iteration switches to the
+ next long value. */
+ dic->mask_request[long_index] = 0;
+
+ /* We found a CPU to run on. */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* No way to set CPU affinity. Iterate just once. */
+ if (dic->processor_index > 0)
+ return false;
+ }
+
+ /* Fill in the actual CPU information. CPU pinning may not actually
+ be effective, depending on the container host. */
+ unsigned int cpu, node;
+ if (_dl_getcpu (&cpu, &node) < 0)
+ {
+ /* No CPU information available. */
+ dic->actual_cpu = -1;
+ dic->actual_node = -1;
+ }
+ else
+ {
+ dic->actual_cpu = cpu;
+ dic->actual_node = node;
+ }
+
+ return true;
+}
+
+#endif /* DL_ITERATE_CPU_H */
new file mode 100644
@@ -0,0 +1,54 @@
+/* CPU affinity handling for the dynamic linker. Stub version.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef DL_AFFINITY_H
+#define DL_AFFINITY_H
+
+#include <errno.h>
+#include <stddef.h>
+
+/* On success, write the current CPU ID to *CPU, and the current node
+ ID to *NODE, and return 0. Return a negative error code on
+ failure. */
+static inline int
+_dl_getcpu (unsigned int *cpu, unsigned int *node)
+{
+ return -ENOSYS;
+}
+
+/* On success, write CPU ID affinity bits for the current thread to
+ *BITS, which must be SIZE bytes long, and return the number of
+ bytes updated, a multiple of sizeof (unsigned long int). On
+ failure, return a negative error code. */
+static int
+_dl_getaffinity (unsigned long int *bits, size_t size)
+{
+ return -ENOSYS;
+}
+
+/* Set the CPU affinity mask for the current thread to *BITS, using
+ the SIZE bytes from that array, which should be a multiple of
+ sizeof (unsigned long int). Return 0 on success, and a negative
+ error code on failure. */
+static int
+_dl_setaffinity (const unsigned long int *bits, size_t size)
+{
+ return -ENOSYS;
+}
+
+#endif /* DL_AFFINITY_H */
new file mode 100644
@@ -0,0 +1,46 @@
+/* CPU affinity handling for the dynamic linker. Linux version.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* See sysdeps/generic/dl-affinity.h for documentation of these interfaces. */
+
+#ifndef DL_AFFINITY_H
+#define DL_AFFINITY_H
+
+#include <sysdep.h>
+#include <stddef.h>
+#include <unistd.h>
+
+static inline int
+_dl_getcpu (unsigned int *cpu, unsigned int *node)
+{
+ return INTERNAL_SYSCALL_CALL (getcpu, cpu, node);
+}
+
+static int
+_dl_getaffinity (unsigned long int *bits, size_t size)
+{
+ return INTERNAL_SYSCALL_CALL (sched_getaffinity, /* TID */ 0, size, bits);
+}
+
+static int
+_dl_setaffinity (const unsigned long int *bits, size_t size)
+{
+ return INTERNAL_SYSCALL_CALL (sched_setaffinity, /* TID */ 0, size, bits);
+}
+
+#endif /* DL_AFFINITY_H */