diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 6bcf873..3954c43 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,7 +1,6 @@
{
- "image": "ghcr.io/uliegecsm/hwloc-xml-parser/hwloc_xml_parser:latest",
+ "image": "ghcr.io/uliegecsm/hwloc-xml-parser",
"extensions" : [
- "ms-vscode.cmake-tools",
"eamodio.gitlens",
"mhutchie.git-graph",
"ms-azuretools.vscode-docker"
diff --git a/.github/workflows/build.image.yml b/.github/workflows/build.image.yml
index e5a5e88..9653e1e 100644
--- a/.github/workflows/build.image.yml
+++ b/.github/workflows/build.image.yml
@@ -6,19 +6,21 @@ on:
- main
paths:
- 'requirements/*'
+ - 'docker/dockerfile'
pull_request:
branches:
- main
paths:
- 'requirements/*'
+ - 'docker/dockerfile'
jobs:
- set_vars:
+ set-vars:
uses: ./.github/workflows/set-vars.yml
build-image:
- needs: [set_vars]
+ needs: [set-vars]
runs-on: [ubuntu-latest]
container:
image: docker:latest
@@ -37,7 +39,7 @@ jobs:
- name: Login to GitHub Container Registry.
uses: docker/login-action@v3
with:
- registry: ${{ needs.set_vars.outputs.CI_REGISTRY }}
+ registry: ${{ needs.set-vars.outputs.CI_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
@@ -45,10 +47,10 @@ jobs:
uses: docker/build-push-action@v5
with:
context: .
- platforms: linux/amd64,linux/arm64
- push: true #${{ github.ref == 'refs/heads/main' }}
- file: docker/dockerfile
- tags: '${{ needs.set_vars.outputs.CI_IMAGE }}:latest'
- cache-from: type=registry,ref='${{ needs.set_vars.outputs.CI_IMAGE }}:latest'
- cache-to: type=inline
- labels: "org.opencontainers.image.source=${{ github.repositoryUrl }}"
+ platforms: linux/amd64,linux/arm64
+ push: ${{ github.ref == 'refs/heads/main' }}
+ file: docker/dockerfile
+ tags: ${{ needs.set-vars.outputs.CI_IMAGE }}
+ cache-from: type=registry,ref=${{ needs.set-vars.outputs.CI_IMAGE }}
+ cache-to: type=inline
+ labels: "org.opencontainers.image.source=${{ github.repositoryUrl }}"
diff --git a/.github/workflows/set-vars.yml b/.github/workflows/set-vars.yml
index fd4a7c6..bd930b3 100644
--- a/.github/workflows/set-vars.yml
+++ b/.github/workflows/set-vars.yml
@@ -2,16 +2,16 @@ on:
workflow_call:
outputs:
CI_IMAGE:
- value: ${{ jobs.set_vars.outputs.CI_IMAGE }}
+ value: ${{ jobs.set-vars.outputs.CI_IMAGE }}
CI_REGISTRY:
- value: ${{ jobs.set_vars.outputs.CI_REGISTRY }}
+ value: ${{ jobs.set-vars.outputs.CI_REGISTRY }}
env:
REGISTRY: ghcr.io
jobs:
- set_vars:
+ set-vars:
runs-on: [ubuntu-latest]
outputs:
CI_IMAGE : ${{ steps.common.outputs.CI_IMAGE }}
@@ -20,5 +20,5 @@ jobs:
- name: Export common variables.
id : common
run : |
- echo "CI_IMAGE=${{ env.REGISTRY }}/${{ github.repository }}/hwloc_xml_parser" >> $GITHUB_OUTPUT
- echo "CI_REGISTRY=${{ env.REGISTRY }}" >> $GITHUB_OUTPUT
+ echo "CI_IMAGE=${{ env.REGISTRY }}/${{ github.repository }}" >> $GITHUB_OUTPUT
+ echo "CI_REGISTRY=${{ env.REGISTRY }}" >> $GITHUB_OUTPUT
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 8d2e138..8f2ccea 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -9,14 +9,14 @@ on:
- main
jobs:
- set_vars:
+ set-vars:
uses: ./.github/workflows/set-vars.yml
test:
- needs: [set_vars]
+ needs: [set-vars]
runs-on: [ubuntu-latest]
container:
- image: '${{ needs.set_vars.outputs.CI_IMAGE }}:latest'
+ image: ${{ needs.set-vars.outputs.CI_IMAGE }}
steps:
- name: Checkout code.
uses: actions/checkout@v4
@@ -26,10 +26,10 @@ jobs:
python -m pytest tests/test_topology.py
install-as-package-and-test:
- needs: [set_vars]
+ needs: [set-vars]
runs-on: [ubuntu-latest]
container:
- image: '${{ needs.set_vars.outputs.CI_IMAGE }}:latest'
+ image: ${{ needs.set-vars.outputs.CI_IMAGE }}
steps:
- name: Install as package.
run : |
diff --git a/hwloc_xml_parser/topology.py b/hwloc_xml_parser/topology.py
index 70af08c..ad19d1b 100644
--- a/hwloc_xml_parser/topology.py
+++ b/hwloc_xml_parser/topology.py
@@ -90,7 +90,7 @@ def get_num_pus(self) -> int:
@typeguard.typechecked
def all_equal_num_pus_per_core(self) -> bool:
"""
- Returns True if all cores have the same number of processing units.
+ Returns `True` if all cores have the same number of processing units.
"""
return all([core.get_num_pus() == self.cores[0].get_num_pus() for core in self.cores])
@@ -226,6 +226,6 @@ def get_num_pus(self) -> int:
@typeguard.typechecked
def all_equal_num_pus_per_core(self) -> bool:
"""
- Returns True if all cores have the same number of processing units.
+ Returns `True` if all cores have the same number of processing units.
"""
return all([package.all_equal_num_pus_per_core() for package in self.packages])
diff --git a/tests/data/single-apple-m2.xml b/tests/data/single-apple-m2.xml
new file mode 100644
index 0000000..051df53
--- /dev/null
+++ b/tests/data/single-apple-m2.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
diff --git a/tests/data/single-nvidia-jetson-xavier-agx.xml b/tests/data/single-nvidia-jetson-xavier-agx.xml
new file mode 100644
index 0000000..253f61e
--- /dev/null
+++ b/tests/data/single-nvidia-jetson-xavier-agx.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/test_topology.py b/tests/test_topology.py
index 9301a33..e656d93 100644
--- a/tests/test_topology.py
+++ b/tests/test_topology.py
@@ -12,7 +12,7 @@ class TestSystemTopology:
def test_parse_single_intel_core_i7_4790(self):
"""
The test reads an `xml` file with the output of `lstopo-no-graphics`
- for a single Intel Core i7 4790 machine with the following topology:
+ for a single `Intel Core i7 4790` machine with the following topology:
.. code-block:: python
@@ -69,41 +69,49 @@ def test_parse_single_intel_core_i7_4790(self):
assert st.get_num_packages() == 1
# The package has 4 cores.
- assert len(st.packages[0].cores) == 4
- assert st.packages[0].get_num_cores() == 4
+ package = st.packages[0]
+
+ assert len(package.cores) == 4
+ assert package.get_num_cores() == 4
# The first core of the package has 2 PUs.
- assert len(st.packages[0].cores[0].pus) == 2
- assert st.packages[0].cores[0].get_num_pus() == 2
+ assert len(package.cores[0].pus) == 2
+ assert package.cores[0].get_num_pus() == 2
# The first PU of the second core of the package has OS index 1 and logical index 2.
- assert st.packages[0].cores[1].pus[0].os_index == 1
- assert st.packages[0].cores[1].pus[0].logical_index == 2
+ assert package.cores[1].pus[0].os_index == 1
+ assert package.cores[1].pus[0].logical_index == 2
+ # Repeat the last assertions, but using this time the generator returned by the
+ # method :py:meth:`hwloc_xml_parser.topology.SystemTopology.recurse_cores`.
gen_cores = st.recurse_cores()
_ = next(gen_cores)
second_core = next(gen_cores)
+ assert second_core.pus[0].os_index == 1
assert second_core.pus[0].logical_index == 2
+ # Repeat the last assertions, but using this time the generator returned by the
+ # method :py:meth:`hwloc_xml_parser.topology.SystemTopology.recurse_pus`.
gen_pus = st.recurse_pus()
_ = next(gen_pus)
_ = next(gen_pus)
third_pu = next(gen_pus)
+ assert third_pu.os_index == 1
assert third_pu.logical_index == 2
# The second PU of the second core of the package has OS index 5 and logical index 3.
- assert st.packages[0].cores[1].pus[1].os_index == 5
- assert st.packages[0].cores[1].pus[1].logical_index == 3
+ assert package.cores[1].pus[1].os_index == 5
+ assert package.cores[1].pus[1].logical_index == 3
# All cores of the package have 2 PUs.
- assert st.packages[0].all_equal_num_pus_per_core()
+ assert package.all_equal_num_pus_per_core()
# The machine has 8 PUs in total.
assert st.get_num_cores() == 4
# The machine has 8 PUs in total.
assert st.get_num_pus() == 8
- assert st.packages[0].get_num_pus() == 8
+ assert package.get_num_pus() == 8
# All cores of the machine have the same number of PUs.
assert st.all_equal_num_pus_per_core()
@@ -111,7 +119,7 @@ def test_parse_single_intel_core_i7_4790(self):
def test_parse_dual_intel_xeon_gold_6126(self):
"""
The test reads an `xml` file with the output of `lstopo-no-graphics`
- for a dual Intel Xeon Gold 6126 machine with the following topology:
+ for a dual `Intel Xeon Gold 6126` machine with the following topology:
.. code-block:: python
@@ -232,15 +240,17 @@ def test_parse_dual_intel_xeon_gold_6126(self):
assert st.get_num_packages() == 2
# The first package has 12 cores.
- assert len(st.packages[0].cores) == 12
- assert st.packages[0].get_num_cores() == 12
+ first_package = st.packages[0]
+
+ assert len(first_package.cores) == 12
+ assert first_package.get_num_cores() == 12
# The first core of the first package has 2 PUs.
- assert len(st.packages[0].cores[0].pus) == 2
- assert st.packages[0].cores[0].get_num_pus() == 2
+ assert len(first_package.cores[0].pus) == 2
+ assert first_package.cores[0].get_num_pus() == 2
# All cores of the first package have 2 PUs.
- assert st.packages[0].all_equal_num_pus_per_core()
+ assert first_package.all_equal_num_pus_per_core()
# The machine has 24 cores in total.
assert st.get_num_cores() == 24
@@ -250,3 +260,67 @@ def test_parse_dual_intel_xeon_gold_6126(self):
# All cores of the machine have the same number of PUs.
assert st.all_equal_num_pus_per_core()
+
+ def test_parse_single_nvidia_jetson_xavier_agx(self):
+ """
+ The test reads an `xml` file with the output of `lstopo-no-graphics`
+ for a single `Nvidia Jetson Xavier AGX` machine.
+ """
+ hwloc_calc_values = [
+ b'0,1,2,3',
+ b'0,1,2,3,4,5,6,7',
+ b'0,1,2,3,4,5,6,7'
+ ]
+
+ with unittest.mock.patch(
+ target = 'subprocess.check_output',
+ side_effect = hwloc_calc_values,
+ ):
+ st = SystemTopology(load = False)
+ st._parse(filename = 'tests/data/single-nvidia-jetson-xavier-agx.xml')
+
+ # There are 4 packages.
+ # This is how `hwloc` reports it. Physically, there is a single package, with 4 clusters of 2 cores each.
+ #
+ # See also:
+ # - https://www.anandtech.com/show/13584/nvidia-xavier-agx-hands-on-carmel-and-more
+ assert st.get_num_packages() == 4
+
+ # The machine has 8 cores in total.
+ assert st.get_num_cores() == 8
+
+ # The machine has 8 PUs in total.
+ assert st.get_num_pus() == 8
+
+ # All cores of the machine have the same number of PUs.
+ assert st.all_equal_num_pus_per_core()
+
+ def test_parse_single_apple_m2(self):
+ """
+ The test reads an `xml` file with the output of `lstopo-no-graphics`
+ for a single `Apple M2` machine.
+ """
+ hwloc_calc_values = [
+ b'0',
+ b'0,1,2,3,4,5,6,7',
+ b'0,1,2,3,4,5,6,7'
+ ]
+
+ with unittest.mock.patch(
+ target = 'subprocess.check_output',
+ side_effect = hwloc_calc_values,
+ ):
+ st = SystemTopology(load = False)
+ st._parse(filename = 'tests/data/single-apple-m2.xml')
+
+ # The machine has 1 package.
+ assert st.get_num_packages() == 1
+
+ # The machine has 8 cores in total.
+ assert st.get_num_cores() == 8
+
+ # The machine has 8 PUs in total.
+ assert st.get_num_pus() == 8
+
+ # All cores of the machine have the same number of PUs.
+ assert st.all_equal_num_pus_per_core()