Skip to content

Commit

Permalink
Add aarch64 manylinux wheels (#2425)
Browse files Browse the repository at this point in the history
  • Loading branch information
mayeut committed Jun 18, 2024
1 parent 1d092e7 commit 5b30ef4
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 24 deletions.
29 changes: 15 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,20 @@ concurrency:
jobs:
# Linux + macOS + Windows Python 3
py3:
name: py3-${{ matrix.os }}-${{ startsWith(matrix.os, 'ubuntu') && 'all' || matrix.archs }}
name: "py3-${{ matrix.os }}-${{ matrix.arch }}"
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
archs: "x86_64 i686"
- os: macos-12
archs: "x86_64"
- os: macos-14
archs: "arm64"
- os: windows-2019
archs: "AMD64"
- os: windows-2019
archs: "x86"
- {os: ubuntu-latest, arch: x86_64}
- {os: ubuntu-latest, arch: i686}
- {os: ubuntu-latest, arch: aarch64}
- {os: macos-12, arch: x86_64}
- {os: macos-14, arch: arm64}
- {os: windows-2019, arch: AMD64}
- {os: windows-2019, arch: x86}
steps:
- uses: actions/checkout@v4

Expand All @@ -51,16 +48,20 @@ jobs:
with:
python-version: 3.11

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
if: matrix.arch == 'aarch64'

- name: Create wheels + run tests
uses: pypa/cibuildwheel@v2.18.0
uses: pypa/cibuildwheel@v2.19.1
env:
CIBW_ARCHS: "${{ matrix.archs }}"
CIBW_ARCHS: "${{ matrix.arch }}"
CIBW_PRERELEASE_PYTHONS: True

- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-py3-${{ matrix.os }}-${{ startsWith(matrix.os, 'ubuntu') && 'all' || matrix.archs }}
name: wheels-py3-${{ matrix.os }}-${{ matrix.arch }}
path: wheelhouse

- name: Generate .tar.gz
Expand Down
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- 2407_: `Process.connections()`_ was renamed to `Process.net_connections()`_.
The old name is still available, but it's deprecated (triggers a
``DeprecationWarning``) and will be removed in the future.
- 2425_: [Linux]: provide aarch64 wheels. (patch by Matthieu Darbois / Ben Raz)

**Bug fixes**

Expand Down
8 changes: 7 additions & 1 deletion psutil/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"HAS_IONICE", "HAS_MEMORY_MAPS", "HAS_PROC_CPU_NUM", "HAS_RLIMIT",
"HAS_SENSORS_BATTERY", "HAS_BATTERY", "HAS_SENSORS_FANS",
"HAS_SENSORS_TEMPERATURES", "HAS_NET_CONNECTIONS_UNIX", "MACOS_11PLUS",
"MACOS_12PLUS", "COVERAGE",
"MACOS_12PLUS", "COVERAGE", 'AARCH64', "QEMU_USER",
# subprocesses
'pyrun', 'terminate', 'reap_children', 'spawn_testproc', 'spawn_zombie',
'spawn_children_pair',
Expand Down Expand Up @@ -128,8 +128,14 @@
GITHUB_ACTIONS = 'GITHUB_ACTIONS' in os.environ or 'CIBUILDWHEEL' in os.environ
CI_TESTING = APPVEYOR or GITHUB_ACTIONS
COVERAGE = 'COVERAGE_RUN' in os.environ
if LINUX and GITHUB_ACTIONS:
with open('/proc/1/cmdline') as f:
QEMU_USER = "/bin/qemu-" in f.read()
else:
QEMU_USER = False
# are we a 64 bit process?
IS_64BIT = sys.maxsize > 2**32
AARCH64 = platform.machine() == "aarch64"


@memoize
Expand Down
2 changes: 2 additions & 0 deletions psutil/tests/test_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from psutil.tests import HAS_SENSORS_FANS
from psutil.tests import HAS_SENSORS_TEMPERATURES
from psutil.tests import PYPY
from psutil.tests import QEMU_USER
from psutil.tests import SKIP_SYSCONS
from psutil.tests import PsutilTestCase
from psutil.tests import create_sockets
Expand Down Expand Up @@ -277,6 +278,7 @@ def test_net_if_addrs(self):
self.assertIsInstance(addr.netmask, (str, type(None)))
self.assertIsInstance(addr.broadcast, (str, type(None)))

@unittest.skipIf(QEMU_USER, 'QEMU user not supported')
def test_net_if_stats(self):
# Duplicate of test_system.py. Keep it anyway.
for ifname, info in psutil.net_if_stats().items():
Expand Down
23 changes: 20 additions & 3 deletions psutil/tests/test_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
from psutil._compat import PY3
from psutil._compat import FileNotFoundError
from psutil._compat import basestring
from psutil.tests import AARCH64
from psutil.tests import GITHUB_ACTIONS
from psutil.tests import GLOBAL_TIMEOUT
from psutil.tests import HAS_BATTERY
from psutil.tests import HAS_CPU_FREQ
from psutil.tests import HAS_GETLOADAVG
from psutil.tests import HAS_RLIMIT
from psutil.tests import PYPY
from psutil.tests import QEMU_USER
from psutil.tests import TOLERANCE_DISK_USAGE
from psutil.tests import TOLERANCE_SYS_MEM
from psutil.tests import PsutilTestCase
Expand Down Expand Up @@ -277,8 +279,14 @@ def test_used(self):
# This got changed in:
# https://gitlab.com/procps-ng/procps/commit/
# 05d751c4f076a2f0118b914c5e51cfbb4762ad8e
# Newer versions of procps are using yet another way to compute used
# memory.
# https://gitlab.com/procps-ng/procps/commit/
# 2184e90d2e7cdb582f9a5b706b47015e56707e4d
if get_free_version_info() < (3, 3, 12):
raise unittest.SkipTest("old free version")
raise unittest.SkipTest("free version too old")
if get_free_version_info() >= (4, 0, 0):
raise unittest.SkipTest("free version too recent")
cli_value = free_physmem().used
psutil_value = psutil.virtual_memory().used
self.assertAlmostEqual(
Expand Down Expand Up @@ -341,8 +349,14 @@ def test_used(self):
# This got changed in:
# https://gitlab.com/procps-ng/procps/commit/
# 05d751c4f076a2f0118b914c5e51cfbb4762ad8e
# Newer versions of procps are using yet another way to compute used
# memory.
# https://gitlab.com/procps-ng/procps/commit/
# 2184e90d2e7cdb582f9a5b706b47015e56707e4d
if get_free_version_info() < (3, 3, 12):
raise unittest.SkipTest("old free version")
raise unittest.SkipTest("free version too old")
if get_free_version_info() >= (4, 0, 0):
raise unittest.SkipTest("free version too recent")
vmstat_value = vmstat('used memory') * 1024
psutil_value = psutil.virtual_memory().used
self.assertAlmostEqual(
Expand Down Expand Up @@ -830,6 +844,7 @@ def path_exists_mock(path):
assert psutil.cpu_freq()

@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
@unittest.skipIf(AARCH64, "aarch64 does not report mhz in /proc/cpuinfo")
def test_emulate_use_cpuinfo(self):
# Emulate a case where /sys/devices/system/cpu/cpufreq* does not
# exist and /proc/cpuinfo is used instead.
Expand Down Expand Up @@ -1037,6 +1052,7 @@ def test_ips(self):


@unittest.skipIf(not LINUX, "LINUX only")
@unittest.skipIf(QEMU_USER, "QEMU user not supported")
class TestSystemNetIfStats(PsutilTestCase):
@unittest.skipIf(not which("ifconfig"), "ifconfig utility not available")
def test_against_ifconfig(self):
Expand Down Expand Up @@ -1596,7 +1612,7 @@ def test_issue_687(self):
with ThreadTask():
p = psutil.Process()
threads = p.threads()
self.assertEqual(len(threads), 2)
self.assertEqual(len(threads), 3 if QEMU_USER else 2)
tid = sorted(threads, key=lambda x: x.id)[1].id
self.assertNotEqual(p.pid, tid)
pt = psutil.Process(tid)
Expand Down Expand Up @@ -2276,6 +2292,7 @@ def test_name(self):
value = self.read_status_file("Name:")
self.assertEqual(self.proc.name(), value)

@unittest.skipIf(QEMU_USER, "QEMU user not supported")
def test_status(self):
value = self.read_status_file("State:")
value = value[value.find('(') + 1 : value.rfind(')')]
Expand Down
9 changes: 9 additions & 0 deletions psutil/tests/test_memleaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import functools
import os
import platform
import sys
import unittest

import psutil
Expand All @@ -43,6 +44,7 @@
from psutil.tests import HAS_SENSORS_BATTERY
from psutil.tests import HAS_SENSORS_FANS
from psutil.tests import HAS_SENSORS_TEMPERATURES
from psutil.tests import QEMU_USER
from psutil.tests import TestMemoryLeak
from psutil.tests import create_sockets
from psutil.tests import get_testfn
Expand Down Expand Up @@ -398,6 +400,7 @@ def test_disk_usage(self):
times = FEW_TIMES if POSIX else self.times
self.execute(lambda: psutil.disk_usage('.'), times=times)

@unittest.skipIf(QEMU_USER, "QEMU user not supported")
def test_disk_partitions(self):
self.execute(psutil.disk_partitions)

Expand Down Expand Up @@ -435,6 +438,7 @@ def test_net_if_addrs(self):
tolerance = 80 * 1024 if WINDOWS else self.tolerance
self.execute(psutil.net_if_addrs, tolerance=tolerance)

@unittest.skipIf(QEMU_USER, "QEMU user not supported")
def test_net_if_stats(self):
self.execute(psutil.net_if_stats)

Expand Down Expand Up @@ -491,6 +495,11 @@ def test_win_service_get_description(self):


if __name__ == '__main__':
from psutil.tests.runner import cprint
from psutil.tests.runner import run_from_name

if QEMU_USER:
cprint("skipping %s tests under QEMU_USER" % __file__, "brown")
sys.exit(0)

run_from_name(__file__)
5 changes: 5 additions & 0 deletions psutil/tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from psutil.tests import HAS_SENSORS_TEMPERATURES
from psutil.tests import PYTHON_EXE
from psutil.tests import PYTHON_EXE_ENV
from psutil.tests import QEMU_USER
from psutil.tests import SCRIPTS_DIR
from psutil.tests import PsutilTestCase
from psutil.tests import mock
Expand Down Expand Up @@ -288,6 +289,9 @@ def check(ret):
for fun, name in ns.iter(ns.getters):
if name in {"win_service_iter", "win_service_get"}:
continue
if QEMU_USER and name == "net_if_stats":
# OSError: [Errno 38] ioctl(SIOCETHTOOL) not implemented
continue
with self.subTest(name=name):
try:
ret = fun()
Expand Down Expand Up @@ -1008,6 +1012,7 @@ def test_pstree(self):
def test_netstat(self):
self.assert_stdout('netstat.py')

@unittest.skipIf(QEMU_USER, 'QEMU user not supported')
def test_ifconfig(self):
self.assert_stdout('ifconfig.py')

Expand Down
7 changes: 6 additions & 1 deletion psutil/tests/test_posix.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from psutil import SUNOS
from psutil.tests import HAS_NET_IO_COUNTERS
from psutil.tests import PYTHON_EXE
from psutil.tests import QEMU_USER
from psutil.tests import PsutilTestCase
from psutil.tests import mock
from psutil.tests import retry_on_failure
Expand Down Expand Up @@ -102,7 +103,11 @@ def ps_name(pid):
field = "command"
if SUNOS:
field = "comm"
return ps(field, pid).split()[0]
command = ps(field, pid).split()
if QEMU_USER:
assert "/bin/qemu-" in command[0]
return command[1]
return command[0]


def ps_args(pid):
Expand Down
24 changes: 19 additions & 5 deletions psutil/tests/test_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from psutil.tests import PYPY
from psutil.tests import PYTHON_EXE
from psutil.tests import PYTHON_EXE_ENV
from psutil.tests import QEMU_USER
from psutil.tests import PsutilTestCase
from psutil.tests import ThreadTask
from psutil.tests import call_until
Expand Down Expand Up @@ -253,6 +254,7 @@ def test_cpu_percent_numcpus_none(self):
psutil.Process().cpu_percent()
assert m.called

@unittest.skipIf(QEMU_USER, "QEMU user not supported")
def test_cpu_times(self):
times = psutil.Process().cpu_times()
assert times.user >= 0.0, times
Expand All @@ -265,6 +267,7 @@ def test_cpu_times(self):
for name in times._fields:
time.strftime("%H:%M:%S", time.localtime(getattr(times, name)))

@unittest.skipIf(QEMU_USER, "QEMU user not supported")
def test_cpu_times_2(self):
user_time, kernel_time = psutil.Process().cpu_times()[:2]
utime, ktime = os.times()[:2]
Expand Down Expand Up @@ -633,6 +636,8 @@ def test_memory_maps(self):

for nt in maps:
if not nt.path.startswith('['):
if QEMU_USER and "/bin/qemu-" in nt.path:
continue
assert os.path.isabs(nt.path), nt.path
if POSIX:
try:
Expand Down Expand Up @@ -698,6 +703,7 @@ def test_is_running(self):
assert not p.is_running()
assert not p.is_running()

@unittest.skipIf(QEMU_USER, "QEMU user not supported")
def test_exe(self):
p = self.spawn_psproc()
exe = p.exe()
Expand Down Expand Up @@ -754,6 +760,9 @@ def test_cmdline(self):
' '.join(p.cmdline()[1:]), ' '.join(cmdline[1:])
)
return
if QEMU_USER:
self.assertEqual(' '.join(p.cmdline()[2:]), ' '.join(cmdline))
return
self.assertEqual(' '.join(p.cmdline()), ' '.join(cmdline))

@unittest.skipIf(PYPY, "broken on PYPY")
Expand All @@ -771,21 +780,23 @@ def test_long_cmdline(self):
self.assertEqual(p.cmdline(), cmdline)
except psutil.ZombieProcess:
raise unittest.SkipTest("OPENBSD: process turned into zombie")
elif NETBSD:
elif QEMU_USER:
self.assertEqual(p.cmdline()[2:], cmdline)
else:
ret = p.cmdline()
if ret == []:
if NETBSD and ret == []:
# https://github.com/giampaolo/psutil/issues/2250
raise unittest.SkipTest("OPENBSD: returned EBUSY")

self.assertEqual(p.cmdline(), cmdline)
self.assertEqual(ret, cmdline)

def test_name(self):
p = self.spawn_psproc()
name = p.name().lower()
pyexe = os.path.basename(os.path.realpath(sys.executable)).lower()
assert pyexe.startswith(name), (pyexe, name)

@unittest.skipIf(PYPY, "unreliable on PYPY")
@unittest.skipIf(PYPY or QEMU_USER, "unreliable on PYPY")
@unittest.skipIf(QEMU_USER, "unreliable on QEMU user")
def test_long_name(self):
pyexe = create_py_exe(self.get_testfn(suffix="0123456789" * 2))
cmdline = [
Expand Down Expand Up @@ -816,6 +827,7 @@ def test_long_name(self):
@unittest.skipIf(SUNOS, "broken on SUNOS")
@unittest.skipIf(AIX, "broken on AIX")
@unittest.skipIf(PYPY, "broken on PYPY")
@unittest.skipIf(QEMU_USER, "broken on QEMU user")
def test_prog_w_funky_name(self):
# Test that name(), exe() and cmdline() correctly handle programs
# with funky chars such as spaces and ")", see:
Expand Down Expand Up @@ -922,6 +934,7 @@ def cleanup(init):
except psutil.AccessDenied:
pass

@unittest.skipIf(QEMU_USER, "QEMU user not supported")
def test_status(self):
p = psutil.Process()
self.assertEqual(p.status(), psutil.STATUS_RUNNING)
Expand Down Expand Up @@ -1149,6 +1162,7 @@ def test_parent_multi(self):
self.assertEqual(grandchild.parent(), child)
self.assertEqual(child.parent(), parent)

@unittest.skipIf(QEMU_USER, "QEMU user not supported")
@retry_on_failure()
def test_parents(self):
parent = psutil.Process()
Expand Down
4 changes: 4 additions & 0 deletions psutil/tests/test_process_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from psutil._compat import long
from psutil._compat import unicode
from psutil.tests import CI_TESTING
from psutil.tests import QEMU_USER
from psutil.tests import VALID_PROC_STATUSES
from psutil.tests import PsutilTestCase
from psutil.tests import check_connection_ntuple
Expand Down Expand Up @@ -235,6 +236,9 @@ def username(self, ret, info):
def status(self, ret, info):
self.assertIsInstance(ret, str)
assert ret, ret
if QEMU_USER:
# status does not work under qemu user
return
self.assertNotEqual(ret, '?') # XXX
self.assertIn(ret, VALID_PROC_STATUSES)

Expand Down
Loading

0 comments on commit 5b30ef4

Please sign in to comment.