rfc:num_available_processors

PHP RFC: num_available_processors

Introduction

Knowing the number of CPU cores can be useful in various applications. For example, in Nextcloud, we use it to limit the number of previews generated simultaneously (using sysvsem). Tools like php-cs-fixer or Psalm use it to check multiple files in parallel.

My motivation for exploring this topic, aside from personal interest, was the complexity involved in obtaining the CPU core count for a PHP application that supports Linux, FreeBSD, and potentially Windows. Therefore, I think it would be beneficial for PHP to provide this information natively.

If executing shell commands is an option, calling nproc usually works on Linux and FreeBSD. On Linux, there is also an alternative method: reading /proc/cpuinfo and counting the 'processor' entries, but this requires safeguards to ensure we are allowed to read /proc. On Windows, running a shell command is necessary.

Proposal

This RFC proposes the addition of a new function that retrieves the number of available processors:

function num_available_processors(): ?int

Limitations

The current patch does not take into account the CPU affinity mask. This means that it reports the total number of logical processors available on the system, rather than the number of processors that are actually available to the current process. In comparison, the implementations for Go's NumCPU and Rust's num_cpus respect the CPU affinity mask.

Naming

Choosing a function name that aligns with PHP conventions, is self-explanatory, and technically accurate is quite challenging. Below is a table summarizing the feedback received from internals and GitHub regarding potential names:

Name Comments
num_available_processors The function uses _SC_NPROCESSORS_ONLN (Linux/BSD) and dwNumberOfProcessors (Windows), so it makes sense to include “processor” in the name. Ilija suggested using “num” as a prefix, leading to the choices num_cpus and later num_available_processors. There are no other PHP functions that start with “num_”.
num_cpus Rust https://docs.rs/num_cpus/latest/num_cpus/
NumCPU Go https://pkg.go.dev/runtime#NumCPU
cpu_count Python https://docs.python.org/3/library/os.html#os.cpu_count
cpu_core_counter Inspired by https://github.com/theofidry/cpu-core-counter
cpu_core_count https://github.com/php/php-src/pull/11137/files#r2106157863
sys_available_processors Tim's suggesting to prefix the function with sys_

Handling of unsupported platforms / Return type on error

The function currently returns null if the operating system is unsupported (1) or if the value returned by the OS function is invalid (2).

The initial version of the patch was available only for Linux/BSD and did not return null. Jakub and Ilija suggested on GitHub to support Windows and return null if we are unable to obtain a valid value.

Nils and Derick recommended that the function should not be available when the platform is unsupported and should throw an error when obtaining the count fails.

Handling of unsupported platforms

The current implementation, without supporting CPU affinity masks, should work on many platforms already. However, I see the point about continuing the existing pattern, and a function_exists check is something we can easily do in userland.

Return type

If the underlying functions return a value greater than 0, it is used as the return value; otherwise, it falls back to null. I agree we could handle the returns from sysconf more carefully.

If the function returns null, then PHP applications know it was not possible to obtain a value and should fall back to a sane default. There is nothing the application can do to recover from this, and it is unlikely that the application will attempt a fallback to obtain the value using a different approach.

Backward Incompatible Changes

None.

Proposed PHP Version(s)

Next PHP 8.x

RFC Impact

This RFC introduces a new function, which might affect existing userland extensions if developers have already created helper functions with the same name. Since the proposed function has a clear and meaningful name, any custom functions should ideally do the same thing and be easy to replace.

There is no impact on SAPIs or the opcache.

Future Scope

There has already been some discussion on the GitHub pull request. While not currently proposed, a valuable addition could be the introduction of a class such as ReflectionServer or, OS (similar to Node.js, https://nodejs.org/api/os.html) to provide information about the underlying system. Existing functions like sys_getloadavg or php_uname could be integrated into this class.

Proposed Voting Choices

Include these so readers know where you are heading and can discuss the proposed voting options.

Patches and Tests

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged into
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature
  4. a link to the language specification section (if any)

References

Links to external references, discussions or RFCs

Rejected Features

Keep this updated with features that were discussed on the mail lists.

rfc/num_available_processors.txt · Last modified: by kesselb