You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
8.5 KiB
262 lines
8.5 KiB
commit 5653ccd847f0cd3a98906e44c97c71d68652d326 |
|
Author: Florian Weimer <fweimer@redhat.com> |
|
Date: Mon Apr 8 16:48:55 2024 +0200 |
|
|
|
elf: Add CPU iteration support for future use in ld.so diagnostics |
|
|
|
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com> |
|
|
|
diff --git a/elf/dl-iterate_cpu.h b/elf/dl-iterate_cpu.h |
|
new file mode 100644 |
|
index 0000000000..60db167b13 |
|
--- /dev/null |
|
+++ b/elf/dl-iterate_cpu.h |
|
@@ -0,0 +1,136 @@ |
|
+/* 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> |
|
+#include <stdbool.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 */
|
|
|