Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu_count_physical() always returns None on arm devices #1359

Open
mtreinish opened this issue Nov 5, 2018 · 18 comments
Open

cpu_count_physical() always returns None on arm devices #1359

mtreinish opened this issue Nov 5, 2018 · 18 comments

Comments

@mtreinish
Copy link

Similar to what was reported in #200 about arm systems not having the same /proc/cpuinfo format as x86 systems (and likely other arches too) and cpu_count_physical() for linux systems with arm will always return None.

We should either teach cpu_count_physical() about the different cpuinfo format, or in the alternative use /proc/stat like what is done in cpu_count_logical(). Arm doesn't have logical cores, so the parsing can be the same as cpu_count_logical() for an arm cpu.

@giampaolo
Copy link
Owner

Can you paste the output of cat /proc/cpuinfo on ARM?

@mtreinish
Copy link
Author

Sure, on the aarch64 system I'm running the /proc/cpuinfo contents:

Processor	: AArch64 Processor rev 4 (aarch64)
processor	: 0
model name	: AArch64 Processor rev 4 (aarch64)
BogoMIPS	: 26.00
BogoMIPS	: 26.00
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 1
model name	: AArch64 Processor rev 4 (aarch64)
BogoMIPS	: 26.00
BogoMIPS	: 26.00
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 2
model name	: AArch64 Processor rev 4 (aarch64)
BogoMIPS	: 26.00
BogoMIPS	: 26.00
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 3
model name	: AArch64 Processor rev 4 (aarch64)
BogoMIPS	: 26.00
BogoMIPS	: 26.00
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

Hardware	: MT6797X

@giampaolo
Copy link
Owner

...so the right number to return in this case is supposed to be 4?

@mtreinish
Copy link
Author

Yes I believe so, there were 4 active physical cores on that device when I read /proc/cpuinfo. (The CPU actually has more cores, but switches between them dynamically based on load and battery)

@giampaolo
Copy link
Owner

Can you paste the output of python -c "print(repr(open('/proc/cpuinfo').read()))"?

@mtreinish
Copy link
Author

Sure, no problem:

'Processor\t: AArch64 Processor rev 4 (aarch64)\nprocessor\t: 4\nmodel name\t: AArch64 Processor rev 4 (aarch64)\nBogoMIPS\t: 26.00\nBogoMIPS\t: 26.00\nFeatures\t: fp asimd evtstrm aes pmull sha1 sha2 crc32\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nprocessor\t: 5\nmodel name\t: AArch64 Processor rev 4 (aarch64)\nBogoMIPS\t: 26.00\nBogoMIPS\t: 26.00\nFeatures\t: fp asimd evtstrm aes pmull sha1 sha2 crc32\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nHardware\t: MT6797X\n'

@fungi
Copy link

fungi commented Nov 5, 2018

I've confirmed this is the case on an AArch64/arm64 Linux 4.15 (not Android) virtual machine to which I have access as well. The contents of /proc/cpuinfo indicate 8 physical processors and psutil.cpu_count() returns 8 but psutil.cpu_count(logical=False) returns None.

@giampaolo
Copy link
Owner

So, this is a patch which relies on lines such as processor: 1 and assume they are physical cores. I'm gonna put it here and do not commit this yet because I am not 100% convinced this is the right approach.

diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index ecc4c703..faf954cb 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -642,8 +642,26 @@ def cpu_count_physical():
                     key, value = line.split(b'\t:', 1)
                     current_info[key] = int(value)
 
+    found = sum(mapping.values())
+    if not found:
+        # Perhaps an ARM system, see:
+        # https://github.com/giampaolo/psutil/issues/1359
+        found = set()
+        with open_binary('%s/cpuinfo' % get_procfs_path()) as f:
+            for line in f:
+                line = line.strip().lower()
+                if line.startswith(b'processor'):
+                    key, value = line.split(b'\t:', 1)
+                    try:
+                        value = int(value)
+                    except ValueError:
+                        pass
+                    else:
+                        found.add(value)
+        found = len(found)
+
     # mimic os.cpu_count()
-    return sum(mapping.values()) or None
+    return found or None
 
 
 def cpu_stats():
diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py
index 4b72f725..042d1a7d 100755
--- a/psutil/tests/test_linux.py
+++ b/psutil/tests/test_linux.py
@@ -679,6 +679,44 @@ class TestSystemCPU(unittest.TestCase):
             self.assertIsNone(psutil._pslinux.cpu_count_physical())
             assert m.called
 
+    def test_cpu_count_physical_arm_mocked(self):
+        # See: https://github.com/giampaolo/psutil/issues/1359
+        def open_mock(name, *args, **kwargs):
+            if name == '/proc/cpuinfo':
+                return io.BytesIO(textwrap.dedent("""\
+                    Processor\t: AArch64 Processor rev 4 (aarch64)
+                    processor\t: 4
+                    model name\t: AArch64 Processor rev 4 (aarch64)
+                    BogoMIPS\t: 26.00
+                    BogoMIPS\t: 26.00
+                    Features\t: fp asimd evtstrm aes pmull sha1 sha2 crc32
+                    CPU implementer\t: 0x41
+                    CPU architecture: 8
+                    CPU variant\t: 0x0
+                    CPU part\t: 0xd03
+                    CPU revision\t: 4
+
+                    processor\t: 5
+                    model name\t: AArch64 Processor rev 4 (aarch64)
+                    BogoMIPS\t: 26.00
+                    BogoMIPS\t: 26.00
+                    Features\t: fp asimd evtstrm aes pmull sha1 sha2 crc32
+                    CPU implementer\t: 0x41
+                    CPU architecture: 8
+                    CPU variant\t: 0x0
+                    CPU part\t: 0xd03
+                    CPU revision\t: 4
+                    """).encode())
+            else:
+                return orig_open(name, *args, **kwargs)
+
+        orig_open = open
+        patch_point = 'builtins.open' if PY3 else '__builtin__.open'
+        with mock.patch(patch_point, create=True, side_effect=open_mock) as m:
+            ret = psutil.cpu_count(logical=False)
+            assert m.called
+            self.assertEqual(ret, 2)
+
     @unittest.skipIf(not HAS_CPU_FREQ, "not supported")
     def test_cpu_freq_no_result(self):
         with mock.patch("psutil._pslinux.glob.glob", return_value=[]):

@giampaolo
Copy link
Owner

What's the output of lscpu?

@fungi
Copy link

fungi commented Nov 8, 2018

This is from an 8 processor Linux AArch64/arm64 virtual machine:

Architecture: aarch64
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 1
Core(s) per socket: 8
Socket(s): 1
NUMA node(s): 1
NUMA node0 CPU(s): 0-7

@giampaolo
Copy link
Owner

That is weird. I don't see how it could determine "8" given the content of your /proc/cpuinfo file. Maybe that means lscpu relies on something else other than /proc/cpuinfo? Could you please strace it, put the output in a txt file and attach it here?

strace lscpu > out.txt

@fungi
Copy link

fungi commented Nov 8, 2018

I suspect you also want 2>&1 but it's a few hundred lines of text. Clearly indicates it's reading from lots of things under the /sys/devices/system/cpu/ tree. Do you really want the full strace posted into an issue comment?

@mtreinish
Copy link
Author

@giampaolo the machine @fungi is using is a different arm system than mine. I expect if I ran lscpu on mine it would return 4 cpus. I just don't have that box handy right now. When I do I'll paste the contents of lscpu from it too.

@giampaolo
Copy link
Owner

I suspect you also want 2>&1 but it's a few hundred lines of text.

Correct. Thanks.

Do you really want the full strace posted into an issue comment?

I think github allows you to attach it as a text file.

@fungi
Copy link

fungi commented Nov 8, 2018

strace-lscpu.txt

@mtreinish
Copy link
Author

@giampaolo I just ran lscpu on my system and got:

Architecture:         aarch64
Byte Order:           Little Endian
CPU(s):               10
On-line CPU(s) list:  0-3
Off-line CPU(s) list: 4-9
Thread(s) per core:   0
Core(s) per socket:   2
Socket(s):            2
Vendor ID:            ARM
Model:                4
Model name:           Cortex-A53
Stepping:             r0p4
CPU max MHz:          2002.0000
CPU min MHz:          221.0000
BogoMIPS:             26.00
Flags:                fp asimd evtstrm aes pmull sha1 sha2 crc32

@mtreinish
Copy link
Author

I also just spun up a raspberry pi 3 b+ running a current aarch64 kernel (v4.19.1) and ran the commands on that too for comparison:

  • /proc/cpuinfo contents:
processor	: 0
BogoMIPS	: 38.40
Features	: fp asimd evtstrm crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 1
BogoMIPS	: 38.40
Features	: fp asimd evtstrm crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 2
BogoMIPS	: 38.40
Features	: fp asimd evtstrm crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 3
BogoMIPS	: 38.40
Features	: fp asimd evtstrm crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4
  • python -c "print(repr(open('/proc/cpuinfo').read()))":

'processor\t: 0\nBogoMIPS\t: 38.40\nFeatures\t: fp asimd evtstrm crc32 cpuid\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nprocessor\t: 1\nBogoMIPS\t: 38.40\nFeatures\t: fp asimd evtstrm crc32 cpuid\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nprocessor\t: 2\nBogoMIPS\t: 38.40\nFeatures\t: fp asimd evtstrm crc32 cpuid\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\nprocessor\t: 3\nBogoMIPS\t: 38.40\nFeatures\t: fp asimd evtstrm crc32 cpuid\nCPU implementer\t: 0x41\nCPU architecture: 8\nCPU variant\t: 0x0\nCPU part\t: 0xd03\nCPU revision\t: 4\n\n'

  • lscpu:
Architecture:        aarch64
Byte Order:          Little Endian
CPU(s):              4
On-line CPU(s) list: 0-3
Thread(s) per core:  1
Core(s) per socket:  4
Socket(s):           1
Vendor ID:           ARM
Model:               4
Model name:          Cortex-A53
Stepping:            r0p4
BogoMIPS:            38.40
Flags:               fp asimd evtstrm crc32 cpuid

moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Dec 19, 2018
psutil has a bug on arm systems where it will return None for physical_cores:
giampaolo/psutil#1359

This causes us to generate invalid telemetry data which raises an error. Fix
this by simply omitting the field in this case.

Differential Revision: https://phabricator.services.mozilla.com/D14969

--HG--
extra : moz-landing-system : lando
mykmelez pushed a commit to mykmelez/gecko that referenced this issue Dec 20, 2018
psutil has a bug on arm systems where it will return None for physical_cores:
giampaolo/psutil#1359

This causes us to generate invalid telemetry data which raises an error. Fix
this by simply omitting the field in this case.

Differential Revision: https://phabricator.services.mozilla.com/D14969
nlevitt added a commit to nlevitt/psutil that referenced this issue Apr 9, 2019
* origin/master: (182 commits)
  giampaolo#1394 / windows / process exe(): convert errno 0 into ERROR_ACCESS_DENIED; errno 0 occurs when the Python process runs in 'Virtual Secure Mode'
  pre-release
  fix win num_handles() test
  update readme
  fix giampaolo#1111: use a lock to make Process.oneshot() thread safe
  pdate HISTORY
  giampaolo#1373: different approach to oneshot() cache (pass Process instances around - which is faster)
  use PROCESS_QUERY_LIMITED_INFORMATION also for username()
  Linux: refactor _parse_stat_file() and return a dict instead of a list (+ maintainability)
  fix giampaolo#1357: do not expose Process' memory_maps() and io_counters() methods if not supported by the kernel
  giampaolo#1376 Windows: check if variable is NULL before free()ing it
  enforce lack of support for Win XP
  fix giampaolo#1370: improper usage of CloseHandle() may lead to override the original error code resulting in raising a wrong exception
  update HISTORY
  (Windows) use PROCESS_QUERY_LIMITED_INFORMATION access rights (giampaolo#1376)
  update HISTORY
  revert 5398c48; let's do it in a separate branch
  giampaolo#1111 make Process.oneshot() thread-safe
  sort HISTORY
  give CREDITS to @EccoTheFlintstone for giampaolo#1368
  fix ionice set not working on windows x64 due to LENGTH_MISMATCH  (giampaolo#1368)
  make flake8 happy
  give CREDITS to @amanusk for giampaolo#1369 / giampaolo#1352 and update doc
  Add CPU frequency support for FreeBSD (giampaolo#1369)
  giampaolo#1359: add test case for cpu_count(logical=False) against lscpu utility
  disable false positive mem test on travis + osx
  fix PEP8 style mistakes
  give credits to @koenkooi for giampaolo#1360
  Fix giampaolo#1354 [Linux] disk_io_counters() fails on Linux kernel 4.18+ (giampaolo#1360)
  giampaolo#1350: give credits to @amanusk
  FreeBSD adding temperature sensors (WIP) (giampaolo#1350)
  pre release
  sensors_temperatures() / linux: convert defaultdict to dict
  fix giampaolo#1004: Process.io_counters() may raise ValueError
  fix giampaolo#1307: [Linux] disk_partitions() does not honour PROCFS_PATH
  refactor hasattr() checks as global constants
  giampaolo#1197 / linux / cpu_freq(): parse /proc/cpuinfo in case /sys/devices/system/cpu fs is not available
  fix giampaolo#1277 / osx / virtual_memory: 'available' and 'used' memory were not calculated properly
  travis / osx: set py 3.6
  travis: disable pypy; se py 3.7 on osx
  skip test on PYPY + Travis
  fix travis
  fix giampaolo#715: do not print exception on import time in case cpu_times() fails.
  fix different travis failures
  give CREDITS for giampaolo#1320 to @truthbk
  [aix] improve compilation on AIX, better support for gcc/g++ + fix cpu metrics (giampaolo#1320)
  give credits to @alxchk for giampaolo#1346 (sunOS)
  Fix giampaolo#1346 (giampaolo#1347)
  giampaolo#1284, giampaolo#1345 - give credits to @amanusk
  Add parsing for /sys/class/thermal (giampaolo#1345)
  Fix decoding error in tests
  catch UnicodeEncodeError on print()
  use memory tolerance in occasionally failing test
  Fix random 0xC0000001 errors when querying for Connections (giampaolo#1335)
  Correct capitalization of PyPI (giampaolo#1337)
  giampaolo#1341: move open() utilities/wrappers in _common.py
  Refactored ps() function in test_posix (giampaolo#1341)
  fix giampaolo#1343: document Process.as_dict() attrs values
  giampaolo#1332 - update HISTORY
  make psutil_debug() aware of PSUTIL_DEBUG (giampaolo#1332)
  also include PYPY (or try to :P)
  travis: add python 3.7 build
  add download badge
  remove failing test assertions
  remove failing test
  make test more robust
  pre release
  pre release
  set version to 5.4.7
  OSX / SMC / sensors: revert giampaolo#1284 (giampaolo#1325)
  setup.py: add py 3.7
  fix giampaolo#1323: [Linux] sensors_temperatures() may fail with ValueError
  fix failing linux tests
  giampaolo#1321 add unit tests
  giampaolo#1321: refactoring
  make disk_io_counters more robust (giampaolo#1324)
  fix typo
  Fix DeprecationWarning: invalid escape sequence (giampaolo#1318)
  remove old test
  update is_storage_device() docstring
  fix giampaolo#1305 / disk_io_counters() / Linux: assume SECTOR_SIZE is a fixed 512
  giampaolo#1313 remove test which no longer makes sense
  disk_io_counters() - linux: mimic iostat behavior (giampaolo#1313)
  fix wrong reference link in doc
  disambiguate TESTFN for parallel testing
  fix giampaolo#1309: add STATUS_PARKED constant and fix STATUS_IDLE (both on linux)
  give CREDITS to @sylvainduchesne for giampaolo#1294
  retain GIL when querying connections table (giampaolo#1306)
  Update index.rst (giampaolo#1308)
  fix giampaolo#1279: catch and skip ENODEV in net_if_stat()
  appveyor: retire 3.5, add 3.7
  revert file renaming of macos files; get them back to 'osx' prefix
  winmake: add upload-wheels cmd
  Rename OSX to macOS (giampaolo#1298)
  apveyor: reset py 3.4 and remove 3.7 (not available yet)
  try to fix occasional children() failure on Win: https://ci.appveyor.com/project/giampaolo/psutil/build/job/je3qyldbb86ff66h
  appveyor: remove py 3.4 and add 3.7
  giampaolo#1284: give credits to @amanusk + some minor adjustments
  little refactoring
  Osx temps (giampaolo#1284)
  ...
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this issue Oct 3, 2019
psutil has a bug on arm systems where it will return None for physical_cores:
giampaolo/psutil#1359

This causes us to generate invalid telemetry data which raises an error. Fix
this by simply omitting the field in this case.

Differential Revision: https://phabricator.services.mozilla.com/D14969

UltraBlame original commit: be66f8877e465637de546fd3a94a55009e74f973
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this issue Oct 3, 2019
psutil has a bug on arm systems where it will return None for physical_cores:
giampaolo/psutil#1359

This causes us to generate invalid telemetry data which raises an error. Fix
this by simply omitting the field in this case.

Differential Revision: https://phabricator.services.mozilla.com/D14969

UltraBlame original commit: be66f8877e465637de546fd3a94a55009e74f973
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this issue Oct 3, 2019
psutil has a bug on arm systems where it will return None for physical_cores:
giampaolo/psutil#1359

This causes us to generate invalid telemetry data which raises an error. Fix
this by simply omitting the field in this case.

Differential Revision: https://phabricator.services.mozilla.com/D14969

UltraBlame original commit: be66f8877e465637de546fd3a94a55009e74f973
@ddelange
Copy link

ddelange commented Apr 9, 2022

FYI, I cannot reproduce this error on the Amazon Graviton2 processor and a psutil aarch64 wheel built from source:

Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from packaging.markers import default_environment
>>> default_environment()
{'implementation_name': 'cpython', 'implementation_version': '3.8.10', 'os_name': 'posix', 'platform_machine': 'aarch64', 'platform_release': '5.13.0-1017-aws', 'platform_system': 'Linux', 'platform_version': '#19~20.04.1-Ubuntu SMP Mon Mar 7 12:55:31 UTC 2022', 'python_full_version': '3.8.10', 'platform_python_implementation': 'CPython', 'python_version': '3.8', 'sys_platform': 'linux'}
>>> import psutil
>>> (psutil.cpu_count(logical=False), psutil.cpu_count(logical=True))
(4, 4)
CPU info

# cat /proc/cpuinfo
processor       : 0
BogoMIPS        : 243.75
Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
CPU implementer : 0x41
CPU architecture: 8
CPU variant     : 0x3
CPU part        : 0xd0c
CPU revision    : 1

processor       : 1
BogoMIPS        : 243.75
Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
CPU implementer : 0x41
CPU architecture: 8
CPU variant     : 0x3
CPU part        : 0xd0c
CPU revision    : 1

processor       : 2
BogoMIPS        : 243.75
Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
CPU implementer : 0x41
CPU architecture: 8
CPU variant     : 0x3
CPU part        : 0xd0c
CPU revision    : 1

processor       : 3
BogoMIPS        : 243.75
Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
CPU implementer : 0x41
CPU architecture: 8
CPU variant     : 0x3
CPU part        : 0xd0c
CPU revision    : 1
# lscpu
Architecture:                    aarch64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
CPU(s):                          4
On-line CPU(s) list:             0-3
Thread(s) per core:              1
Core(s) per socket:              4
Socket(s):                       1
NUMA node(s):                    1
Vendor ID:                       ARM
Model:                           1
Model name:                      Neoverse-N1
Stepping:                        r3p1
BogoMIPS:                        243.75
L1d cache:                       256 KiB
L1i cache:                       256 KiB
L2 cache:                        4 MiB
L3 cache:                        32 MiB
NUMA node0 CPU(s):               0-3
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:        Mitigation; __user pointer sanitization
Vulnerability Spectre v2:        Mitigation; CSV2, BHB
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants