File: ProcessorCount.cmake

package info (click to toggle)
cmake 4.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 147,284 kB
  • sloc: ansic: 403,915; cpp: 290,772; sh: 4,102; python: 3,357; yacc: 3,106; lex: 1,189; f90: 532; asm: 471; lisp: 375; cs: 270; java: 266; fortran: 230; perl: 217; objc: 215; xml: 198; makefile: 97; javascript: 83; pascal: 63; tcl: 55; php: 25; ruby: 22
file content (271 lines) | stat: -rw-r--r-- 9,684 bytes parent folder | download
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file LICENSE.rst or https://cmake.org/licensing for details.

#[=======================================================================[.rst:
ProcessorCount
--------------

This module provides a command to determine the number of processors/cores.

Load this module in CMake with:

.. code-block:: cmake

  include(ProcessorCount)

Commands
^^^^^^^^

This module provides the following command:

.. command:: ProcessorCount

  Determines the number of logical CPU cores available on the machine:

  .. code-block:: cmake

    ProcessorCount(<variable>)

  This command sets a variable named ``<variable>`` to the number of logical
  CPU cores available on the machine, if the information can be determined.
  If successful, the variable is guaranteed to be set to a positive integer
  (>=1).  If the processor count cannot be determined, it is set to 0.

  Currently, this functionality is implemented for AIX, Cygwin, FreeBSD, Haiku,
  HPUX, Linux, macOS, QNX, Sun and Windows.

  This command provides an approximation of the number of compute cores
  available on the current machine, making it useful for parallel building and
  testing.  It is meant to help utilize as much of the machine as seems
  reasonable, though users should consider other workloads running on the
  machine before using its full capacity for parallel tasks.

  .. versionchanged:: 3.15
    On Linux, returns the container CPU count instead of the host CPU count.

.. note::

  This module relies on system-dependent commands to determine the number of
  processors, which may not always provide accurate information in certain
  environments.  A more generally accurate logical CPU count can be also
  obtained with the :command:`cmake_host_system_information`:

  .. code-block:: cmake

    cmake_host_system_information(RESULT n QUERY NUMBER_OF_LOGICAL_CORES)

Examples
^^^^^^^^

In the following example this module is used in a :option:`ctest -S`
dashboard script to determine number of cores to use for a parallel
:ref:`CTest Build Step`:

.. code-block:: cmake

  include(ProcessorCount)
  ProcessorCount(n)
  if(NOT n EQUAL 0)
    set(CTEST_BUILD_FLAGS -j${n})
    set(ctest_test_args ${ctest_test_args} PARALLEL_LEVEL ${n})
  endif()
#]=======================================================================]

# A more reliable way might be to compile a small C program that uses the CPUID
# instruction, but that again requires compiler support or compiling assembler
# code.

function(ProcessorCount var)
  # Unknown:
  set(count 0)

  if(WIN32)
    # Windows:
    set(count "$ENV{NUMBER_OF_PROCESSORS}")
    #message("ProcessorCount: WIN32, trying environment variable")
  endif()

  if(NOT count)
    # Mac, FreeBSD, OpenBSD (systems with sysctl):
    find_program(ProcessorCount_cmd_sysctl sysctl
      PATHS /usr/sbin /sbin)
    mark_as_advanced(ProcessorCount_cmd_sysctl)
    if(ProcessorCount_cmd_sysctl)
      execute_process(COMMAND ${ProcessorCount_cmd_sysctl} -n hw.ncpu
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE count)
      #message("ProcessorCount: trying sysctl '${ProcessorCount_cmd_sysctl}'")
    endif()
  endif()

  if(NOT count)
    # Linux (systems with nproc):
    # Prefer nproc to getconf if available as getconf may return the host CPU count in Linux containers
    find_program(ProcessorCount_cmd_nproc nproc)
    mark_as_advanced(ProcessorCount_cmd_nproc)
    if(ProcessorCount_cmd_nproc)
      execute_process(COMMAND ${ProcessorCount_cmd_nproc}
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE count)
      #message("ProcessorCount: trying nproc '${ProcessorCount_cmd_nproc}'")
    endif()
  endif()

  if(NOT count)
    # Linux (systems with getconf):
    find_program(ProcessorCount_cmd_getconf getconf)
    mark_as_advanced(ProcessorCount_cmd_getconf)
    if(ProcessorCount_cmd_getconf)
      execute_process(COMMAND ${ProcessorCount_cmd_getconf} _NPROCESSORS_ONLN
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE count)
      #message("ProcessorCount: trying getconf '${ProcessorCount_cmd_getconf}'")
    endif()
  endif()

  if(NOT count)
    # HPUX (systems with machinfo):
    find_program(ProcessorCount_cmd_machinfo machinfo
      PATHS /usr/contrib/bin)
    mark_as_advanced(ProcessorCount_cmd_machinfo)
    if(ProcessorCount_cmd_machinfo)
      execute_process(COMMAND ${ProcessorCount_cmd_machinfo}
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE machinfo_output)
      string(REGEX MATCHALL "Number of CPUs = ([0-9]+)" procs "${machinfo_output}")
      set(count "${CMAKE_MATCH_1}")
      if(NOT count)
        string(REGEX MATCHALL "([0-9]+) logical processors" procs "${machinfo_output}")
        set(count "${CMAKE_MATCH_1}")
      endif()
      #message("ProcessorCount: trying machinfo '${ProcessorCount_cmd_machinfo}'")
    else()
      find_program(ProcessorCount_cmd_mpsched mpsched)
      mark_as_advanced(ProcessorCount_cmd_mpsched)
      if(ProcessorCount_cmd_mpsched)
        execute_process(COMMAND ${ProcessorCount_cmd_mpsched} -s
          OUTPUT_QUIET
          ERROR_STRIP_TRAILING_WHITESPACE
          ERROR_VARIABLE mpsched_output)
        string(REGEX MATCHALL "Processor Count *: *([0-9]+)" procs "${mpsched_output}")
        set(count "${CMAKE_MATCH_1}")
        #message("ProcessorCount: trying mpsched -s '${ProcessorCount_cmd_mpsched}'")
      endif()
    endif()
  endif()

  if(NOT count)
    # AIX (systems with lsconf):
    find_program(ProcessorCount_cmd_lsconf lsconf
      PATHS /usr/sbin)
    mark_as_advanced(ProcessorCount_cmd_lsconf)
    if(ProcessorCount_cmd_lsconf)
      execute_process(COMMAND ${ProcessorCount_cmd_lsconf}
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE lsconf_output)
      string(REGEX MATCHALL "Number Of Processors: ([0-9]+)" procs "${lsconf_output}")
      set(count "${CMAKE_MATCH_1}")
      #message("ProcessorCount: trying lsconf '${ProcessorCount_cmd_lsconf}'")
    endif()
  endif()

  if(NOT count)
    # QNX (systems with pidin):
    find_program(ProcessorCount_cmd_pidin pidin)
    mark_as_advanced(ProcessorCount_cmd_pidin)
    if(ProcessorCount_cmd_pidin)
      execute_process(COMMAND ${ProcessorCount_cmd_pidin} info
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE pidin_output)
      string(REGEX MATCHALL "Processor[0-9]+: " procs "${pidin_output}")
      list(LENGTH procs count)
      #message("ProcessorCount: trying pidin '${ProcessorCount_cmd_pidin}'")
    endif()
  endif()

  if(NOT count)
    # Sun (systems where psrinfo tool is available)
    find_program(ProcessorCount_cmd_psrinfo psrinfo PATHS /usr/sbin /sbin)
    mark_as_advanced(ProcessorCount_cmd_psrinfo)
    if (ProcessorCount_cmd_psrinfo)
      execute_process(COMMAND ${ProcessorCount_cmd_psrinfo} -p -v
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE psrinfo_output)
      string(REGEX MATCHALL "has [0-9]+ virtual processor" procs "${psrinfo_output}")
      set(count "")
      foreach(proc ${procs})
        string(REGEX MATCH "has ([0-9]+) virtual" res ${proc})
        math(EXPR count "${count} + ${CMAKE_MATCH_1}")
      endforeach()
      #message("ProcessorCount: trying '${ProcessorCount_cmd_psrinfo}' -p -v")
    else()
      # Sun (systems where uname -X emits "NumCPU" in its output):
      find_program(ProcessorCount_cmd_uname uname)
      mark_as_advanced(ProcessorCount_cmd_uname)
      if(ProcessorCount_cmd_uname)
        execute_process(COMMAND ${ProcessorCount_cmd_uname} -X
          ERROR_QUIET
          OUTPUT_STRIP_TRAILING_WHITESPACE
          OUTPUT_VARIABLE uname_X_output)
        string(REGEX MATCHALL "NumCPU = ([0-9]+)" procs "${uname_X_output}")
        set(count "${CMAKE_MATCH_1}")
        #message("ProcessorCount: trying uname -X '${ProcessorCount_cmd_uname}'")
      endif()
    endif()
  endif()

  # Execute this code when all previously attempted methods return empty
  # output:
  #
  if(NOT count)
    # Systems with /proc/cpuinfo:
    set(cpuinfo_file /proc/cpuinfo)
    if(EXISTS "${cpuinfo_file}")
      cmake_policy(PUSH)
      cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n>
      file(STRINGS "${cpuinfo_file}" procs REGEX "^processor.: [0-9]+$")
      cmake_policy(POP)
      list(LENGTH procs count)
      #message("ProcessorCount: trying cpuinfo '${cpuinfo_file}'")
    endif()
  endif()

  if(NOT count)
    # Haiku
    find_program(ProcessorCount_cmd_sysinfo sysinfo)
    mark_as_advanced(ProcessorCount_cmd_sysinfo)
    if(ProcessorCount_cmd_sysinfo)
      execute_process(COMMAND ${ProcessorCount_cmd_sysinfo}
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE
        OUTPUT_VARIABLE sysinfo_X_output)
      string(REGEX MATCHALL "\nCPU #[0-9]+:" procs "\n${sysinfo_X_output}")
      list(LENGTH procs count)
      #message("ProcessorCount: trying sysinfo '${ProcessorCount_cmd_sysinfo}'")
    endif()
  endif()

  # Since cygwin builds of CMake do not define WIN32 anymore, but they still
  # run on Windows, and will still have this env var defined:
  #
  if(NOT count)
    set(count "$ENV{NUMBER_OF_PROCESSORS}")
    #message("ProcessorCount: last fallback, trying environment variable")
  endif()

  # Ensure an integer return (avoid inadvertently returning an empty string
  # or an error string)... If it's not a decimal integer, return 0:
  #
  if(NOT count MATCHES "^[0-9]+$")
    set(count 0)
  endif()

  set(${var} ${count} PARENT_SCOPE)
endfunction()