mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
elf: Add CPU iteration support for future use in ld.so diagnostics
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
This commit is contained in:
parent
1f94147a79
commit
5653ccd847
136
elf/dl-iterate_cpu.h
Normal file
136
elf/dl-iterate_cpu.h
Normal file
@ -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 */
|
54
sysdeps/generic/dl-affinity.h
Normal file
54
sysdeps/generic/dl-affinity.h
Normal file
@ -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 */
|
46
sysdeps/unix/sysv/linux/dl-affinity.h
Normal file
46
sysdeps/unix/sysv/linux/dl-affinity.h
Normal file
@ -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 */
|
Loading…
Reference in New Issue
Block a user