Skip to content

Commit

Permalink
Improvements in use of python SharedMemory (#26)
Browse files Browse the repository at this point in the history
* Improvements in use of python SharedMemory:

- Remove previous patch and instead ship a backport of the changes
  which are in python 3.13.  This allows the "track=False" option
  when creating SharedMemory segments.

- In order to better handle cleanup, keep a registry of all memory
  segments allocated on every process.  Register a cleanup handler
  for python atexit and also register a cleanup handler for signals
  such as SIGTERM.

- Expand unit tests

- Convert build to pyproject.toml with minimal setup.py backend.

- Improve test and deployment workflows.

* Fix test.yml branch

* Remove some typing info in backport, for compatibility with 3.9

* Use mpich for running CI tests

* Remove stale scripts

* Add multinode test script for perlmutter.

* Remove stale scripts and fix typo in readme
  • Loading branch information
tskisner authored Jan 6, 2025
1 parent 02cd641 commit 48b946c
Show file tree
Hide file tree
Showing 20 changed files with 544 additions and 2,711 deletions.
24 changes: 9 additions & 15 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,26 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python 3.10
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"

- name: Install Dependencies
run: ./test_scripts/install_deps_github_ubuntu.sh && pip install twine
run: python3 -m pip install build twine numpy

- name: Install Package
run: pip install .
run: python3 -m pip install .

- name: Run Serial Test
run: MPI_DISABLE=1 python3 -c 'import pshmem.test; pshmem.test.run()'

- name: Run MPI Test on 1 Process
run: mpirun -np 1 python3 -c 'import pshmem.test; pshmem.test.run()'

- name: Run MPI Test on 2 Processes
run: mpirun -np 2 python3 -c 'import pshmem.test; pshmem.test.run()'
- name: Run Simple Test
run: python3 -c 'import pshmem.test; pshmem.test.run()'

- name: Build source package
run: rm -rf dist && python setup.py sdist
run: rm -rf dist && python3 -m build --sdist

- name: Build wheels
run: mkdir -p wheelhouse && pip wheel -w wheelhouse .
run: python3 -m build --wheel

- name: Upload to PyPI
run: |
python -m twine upload dist/*.tar.gz && python -m twine upload wheelhouse/pshmem*.whl
python -m twine upload dist/*.tar.gz && python -m twine upload dist/pshmem*.whl
149 changes: 91 additions & 58 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,72 +1,105 @@
# Use pre-built docker containers to run our unit tests on different python versions.
# In general, we try to run on:
# - The oldest supported python
# - The latest stable python that is the common default on most systems and conda
# - (During transitions) The newly released bleeding edge python

name: Tests
name: Run Test Suite

on:
push:
branches: [ master ]
branches:
- master
pull_request:
branches: [ master ]
branches:
- master

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
linux:
runs-on: ubuntu-latest
test:
name: Tests on ${{ matrix.arch }} with Conda Python-${{ matrix.python }}
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash -l {0}
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.10", "3.11", "3.12"]
include:
- os: ubuntu-latest
python: "3.9"
arch: Linux-x86_64
- os: ubuntu-latest
python: "3.11"
arch: Linux-x86_64
- os: ubuntu-latest
python: "3.13"
arch: Linux-x86_64
- os: macos-latest
python: "3.10"
arch: MacOSX-x86_64
- os: macos-latest
python: "3.13"
arch: MacOSX-x86_64
- os: macos-latest
python: "3.10"
arch: MacOSX-arm64
- os: macos-latest
python: "3.13"
arch: MacOSX-arm64
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Dependencies
run: ./test_scripts/install_deps_github_ubuntu.sh

- name: Install Package
run: pip3 install .

- name: Run Serial Test
run: MPI_DISABLE=1 python3 -c 'import pshmem.test; pshmem.test.run()'

- name: Run MPI Test on 1 Process
run: mpirun -np 1 python3 -c 'import pshmem.test; pshmem.test.run()'

- name: Run MPI Test on 2 Processes
run: mpirun -np 2 python3 -c 'import pshmem.test; pshmem.test.run()'

macos:
runs-on: macos-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Dependencies
run: ./test_scripts/install_deps_github_macos.sh

- name: Install Package
run: pip3 install .

- name: Run Serial Test
run: MPI_DISABLE=1 python3 -c 'import pshmem.test; pshmem.test.run()'

- name: Run MPI Test on 1 Process
run: mpirun -np 1 python3 -c 'import pshmem.test; pshmem.test.run()'

- name: Run MPI Test on 2 Processes
run: mpirun -np 2 python3 -c 'import pshmem.test; pshmem.test.run()'
- name: Checkout
uses: actions/checkout@v4

- name: Setup Conda Base
run: |
sudo rm -rf /usr/share/miniconda \
&& sudo rm -rf /usr/local/miniconda \
&& curl -SL -o miniforge.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-${{ matrix.arch }}.sh \
&& bash miniforge.sh -b -f -p ~/conda \
&& source ~/conda/etc/profile.d/conda.sh \
&& conda activate base \
&& conda update -n base --yes conda
- name: Check Conda Config
run: |
source ~/conda/etc/profile.d/conda.sh \
&& conda activate base \
&& conda info \
&& conda list \
&& conda config --show-sources \
&& conda config --show
- name: Install Dependencies
run: |
source ~/conda/etc/profile.d/conda.sh \
&& conda create --yes -n test python==${{ matrix.python }} \
&& conda activate test \
&& conda install --yes numpy mpich mpi4py
- name: Install
run: |
source ~/conda/etc/profile.d/conda.sh \
&& conda activate test \
&& pip install .
- name: Run Serial Tests
run: |
source ~/conda/etc/profile.d/conda.sh \
&& conda activate test \
&& mkdir -p test \
&& pushd test >/dev/null 2>&1 \
&& MPI_DISABLE=1 python3 -c 'import pshmem.test; pshmem.test.run()' \
&& popd >/dev/null 2>&1
- name: Run MPI Tests
run: |
source ~/conda/etc/profile.d/conda.sh \
&& conda activate test \
&& mkdir -p test \
&& pushd test >/dev/null 2>&1 \
&& mpirun -np 1 python3 -c 'import pshmem.test; pshmem.test.run()' \
&& mpirun -np 2 python3 -c 'import pshmem.test; pshmem.test.run()' \
&& popd >/dev/null 2>&1
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,24 @@ shared memory constructs.
This package needs a recent version of the `mpi4py` package in order to be useful.
However, the classes also accept a value of `None` for the communicator, in which case a
trivial local implementation is used. The code uses other widely available packages
(like numpy) and requires a recent Python3 installation. You can install the code from
a git checkout with:
(like numpy) and requires a recent Python3 installation.

pip install .
### Binary Packages

Wheels are available on PyPI:

pip install pshmem

Or you can install packages from conda-forge:

Or:
conda install -c conda-forge pshmem

python3 setup.py install
### Installing from Source

You can install the code from a git checkout with:

pip install .

Or directly from github.

## MPIShared Class

Expand Down
2 changes: 1 addition & 1 deletion pshmem/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
##
# Copyright (c) 2017-2020, all rights reserved. Use of this source code
# Copyright (c) 2017-2025, all rights reserved. Use of this source code
# is governed by a BSD license that can be found in the top-level
# LICENSE file.
##
Expand Down
2 changes: 1 addition & 1 deletion pshmem/locking.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
##
# Copyright (c) 2017-2024, all rights reserved. Use of this source code
# Copyright (c) 2017-2025, all rights reserved. Use of this source code
# is governed by a BSD license that can be found in the top-level
# LICENSE file.
##
Expand Down
60 changes: 60 additions & 0 deletions pshmem/registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
##
# Copyright (c) 2017-2025, all rights reserved. Use of this source code
# is governed by a BSD license that can be found in the top-level
# LICENSE file.
##

import sys
import atexit
import signal


class MPISharedRegistry:
"""Registry of shared memory buffers.
This tracks all MPIShared memory buffers on the current process and
ensures they are cleaned up when the process is terminated.
"""
def __init__(self):
self.reg = dict()

def register(self, name, buffer, noderank):
self.reg[name] = (buffer, noderank)

def unregister(self, name):
del self.reg[name]

def cleanup(self):
for name, (buf, noderank) in self.reg.items():
buf.close()
if noderank == 0:
buf.unlink()
self.reg.clear()


"""Single instance of the registry"""
registry = MPISharedRegistry()


def _signal_handler(sig, frame):
global registry
registry.cleanup()
sys.exit(0)


@atexit.register
def _atexit_handler():
global registry
registry.cleanup()


def _register_signals():
signal.signal(signal.SIGINT, _signal_handler)
signal.signal(signal.SIGTERM, _signal_handler)
signal.signal(signal.SIGQUIT, _signal_handler)
signal.signal(signal.SIGHUP, _signal_handler)


# Register signal handlers on import
_register_signals()
Loading

0 comments on commit 48b946c

Please sign in to comment.