about summary refs log tree commit diff
path: root/elf/dl-iterate_cpu.h
blob: 60db167b13e2d377cd1c1d452505ec94e08a24ac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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 */