Skip to content

Commit a285986

Browse files
committed
Support for OFI and UCX
* MPICH: Configure --with-device=ch4:ofi,ucx * Open MPI: Configure --with-ofi --with-ucx * Reproducible builds * Strip binaries to reduce size * Remove unneeded binaries
1 parent eaf7bc2 commit a285986

File tree

10 files changed

+620
-110
lines changed

10 files changed

+620
-110
lines changed

.github/workflows/cd-wheel.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ jobs:
7676
shell: python
7777
name: 'setup build matrix'
7878
run: |
79+
# setup build matrix # "
7980
keys = ("os", "arch", "runner")
8081
rows = [
8182
("Linux", "aarch64", "ubuntu-22.04"),
@@ -93,6 +94,7 @@ jobs:
9394
import os, json
9495
with open(os.getenv("GITHUB_OUTPUT"), "w") as out:
9596
print(f"matrix={json.dumps(matrix)}", file=out)
97+
# "
9698
9799
build:
98100
needs: setup
@@ -117,12 +119,12 @@ jobs:
117119
cd $(brew --prefix)/bin
118120
gfortran=$(ls gfortran-* | sort | head -n 1)
119121
sudo ln -s $gfortran gfortran
122+
# unlink libevent
123+
brew unlink libevent || true
120124
# install autotools
121125
brew install autoconf
122126
brew install automake
123127
brew install libtool
124-
# unlink libevent
125-
brew unlink libevent || true
126128
# install uv
127129
brew install uv
128130
@@ -142,9 +144,13 @@ jobs:
142144

143145
- id: source-date-epoch
144146
run: |
145-
SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
147+
read -r SOURCE_DATE_EPOCH < source-date-epoch || true
148+
SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH:-$(git log -1 --pretty=%ct)}
146149
echo SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH >> $GITHUB_ENV
147-
echo $(git log -1 --pretty=%ci) [timestamp=$SOURCE_DATE_EPOCH]
150+
echo [SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH] $(
151+
date -u -d @$SOURCE_DATE_EPOCH 2>/dev/null ||
152+
date -u -r $SOURCE_DATE_EPOCH 2>/dev/null )
153+
working-directory: package/source
148154

149155
- id: build
150156
uses: pypa/[email protected]
@@ -174,7 +180,7 @@ jobs:
174180
CIBW_REPAIR_WHEEL_COMMAND_MACOS: >
175181
delocate-wheel
176182
--ignore-missing-dependencies
177-
--exclude libmpi --exclude libpmpi
183+
--exclude libmpi --exclude libpmpi --exclude libfabric
178184
--require-archs {delocate_archs}
179185
-w {dest_dir} -v {wheel}
180186

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
/venv/
66
*.egg-info/
77
*.tar.gz
8+
*.tar.bz2
89
*~

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ lint:
1010
yamllint .github/
1111

1212
clean:
13+
$(RM) -r package/METADATA
14+
$(RM) -r package/LICENSE*
1315
$(RM) -r package/build
14-
$(RM) -r package/LICENSE
15-
$(RM) -r package/install
1616
$(RM) -r package/source
1717
$(RM) -r package/workdir
18+
$(RM) -r package/install
1819
$(RM) -r package/*.egg-info
1920
$(RM) -r .*_cache

bootstrap.sh

Lines changed: 121 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ case "$mpiname" in
88
esac
99
version=${VERSION:-$version}
1010

11+
ucxversion=1.15.0
12+
ofiversion=1.21.1
13+
ucxversion=${UCXVERSION:-$ucxversion}
14+
ofiversion=${OFIVERSION:-$ofiversion}
15+
1116
PROJECT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
1217
PACKAGE=$PROJECT/package
1318
SOURCE=$PACKAGE/source
@@ -27,21 +32,49 @@ fi
2732
if test ! -d "$SOURCE"; then
2833
if test ! -f "$tarball"; then
2934
echo downloading "$urlbase"/"$tarball"...
30-
curl -fsO "$urlbase"/"$tarball"
35+
curl -fsSLO "$urlbase"/"$tarball"
3136
else
3237
echo reusing "$tarball"...
3338
fi
34-
echo extracting "$tarball" to "$SOURCE"...
39+
echo extracting "$tarball"...
3540
tar xf "$tarball"
3641
mv "$mpiname-$version" "$SOURCE"
3742
patch="$PROJECT/patches/$mpiname-$version"
3843
if test -f "$patch"; then
3944
patch -p1 -i "$patch" -d "$SOURCE"
4045
fi
41-
if test "$mpiname-$(uname)" = "openmpi-Darwin"; then
42-
if test -d "$SOURCE"/3rd-party; then
43-
cd "$SOURCE"/3rd-party
44-
tar xf libevent-*.tar.gz && cd libevent-*
46+
if test "$mpiname" = "mpich"; then
47+
if test "${version}" \> "4.2.2" && test "$(uname)" = "Linux"; then
48+
conf_args='s/\(ofi_subdir_args\)=\("--enable-embedded"\)/\1=""/'
49+
configure="$SOURCE"/configure
50+
sed -i.orig "$conf_args" "$configure"
51+
fi
52+
if test "${version}" \< "4.2.0"; then
53+
disable_doc='s/^\(install-data-local:\s\+\)\$/\1#\$/'
54+
Makefile="$SOURCE"/Makefile.in
55+
sed -i.orig "$disable_doc" "$Makefile"
56+
fi
57+
fi
58+
if test "$mpiname" = "openmpi"; then
59+
for deptarball in "$SOURCE"/3rd-party/*.tar.*; do
60+
test -f "$deptarball" || continue
61+
echo extracting "$(basename "$deptarball")"
62+
tar xf "$deptarball" -C "$(dirname "$deptarball")"
63+
done
64+
makefiles=(
65+
"$SOURCE"/3rd-party/openpmix/src/util/keyval/Makefile.in
66+
"$SOURCE"/3rd-party/prrte/src/mca/rmaps/rank_file/Makefile.in
67+
"$SOURCE"/3rd-party/prrte/src/util/hostfile/Makefile.in
68+
)
69+
for makefile in "${makefiles[@]}"; do
70+
test -f "$makefile" || continue
71+
echo "PMIX_CFLAGS_BEFORE_PICKY = @CFLAGS@" >> "$makefile"
72+
echo "PRTE_CFLAGS_BEFORE_PICKY = @CFLAGS@" >> "$makefile"
73+
done
74+
fi
75+
if test "$mpiname" = "openmpi" && test "${version}" \< "5.0.5"; then
76+
if test "$(uname)" = "Darwin"; then
77+
cd "$SOURCE"/3rd-party/libevent-*
4578
echo running autogen.sh on "$(basename "$(pwd)")"
4679
./autogen.sh
4780
cd "$PROJECT"
@@ -50,5 +83,86 @@ if test ! -d "$SOURCE"; then
5083
else
5184
echo reusing directory "$SOURCE"...
5285
fi
53-
echo copying license file...
86+
87+
if test "$(uname)" = "Linux"; then
88+
if test "$mpiname" = "mpich"; then
89+
ofidestdir="$SOURCE"/modules/libfabric
90+
ucxdestdir="$SOURCE"/modules/ucx
91+
fi
92+
if test "$mpiname" = "openmpi"; then
93+
ofigithub="https://github.com/ofiwg/libfabric"
94+
ofiurlbase="$ofigithub/releases/download/v$ofiversion"
95+
ofitarball="libfabric-$ofiversion.tar.bz2"
96+
ofidestdir="$SOURCE"/3rd-party/"${ofitarball%%.tar.bz2}"
97+
if test ! -d "$ofidestdir"; then
98+
if test ! -f "$ofitarball"; then
99+
echo downloading "$ofiurlbase"/"$ofitarball"...
100+
curl -fsSLO "$ofiurlbase"/"$ofitarball"
101+
else
102+
echo reusing "$ofitarball"...
103+
fi
104+
echo extracting "$ofitarball"...
105+
tar xf "$ofitarball"
106+
mkdir -p "$(dirname "$ofidestdir")"
107+
mv "$(basename "$ofidestdir")" "$ofidestdir"
108+
else
109+
echo reusing directory "$ofidestdir"...
110+
fi
111+
ucxgithub="https://github.com/openucx/ucx"
112+
ucxurlbase="$ucxgithub/releases/download/v$ucxversion"
113+
ucxtarball="ucx-$ucxversion.tar.gz"
114+
ucxdestdir="$SOURCE"/3rd-party/"${ucxtarball%%.tar.gz}"
115+
if test ! -d "$ucxdestdir"; then
116+
if test ! -f "$ucxtarball"; then
117+
echo downloading "$ucxurlbase"/"$ucxtarball"...
118+
curl -fsSLO "$ucxurlbase"/"$ucxtarball"
119+
else
120+
echo reusing "$ucxtarball"...
121+
fi
122+
echo extracting "$ucxtarball"...
123+
tar xf "$ucxtarball"
124+
mkdir -p "$(dirname "$ucxdestdir")"
125+
mv "$(basename "$ucxdestdir")" "$ucxdestdir"
126+
else
127+
echo reusing directory "$ucxdestdir"...
128+
fi
129+
fi
130+
fi
131+
132+
if test "$mpiname" = "mpich"; then
133+
mpidate=$(sed -nE "s/MPICH_RELEASE_DATE=\"(.*)\"/\1/p" "$SOURCE/configure")
134+
fi
135+
if test "$mpiname" = "openmpi"; then
136+
mpidate=$(sed -nE "s/date=\"(.*)\"/\1/p" "$SOURCE/VERSION")
137+
fi
138+
if test -n "${mpidate+x}"; then
139+
case "$(uname)" in
140+
Linux)
141+
timestamp=$(date -d "$mpidate" "+%s")
142+
;;
143+
Darwin)
144+
datefmt="%b %d, %Y %T%z"
145+
if test "$mpiname" = "mpich"; then
146+
mpidate=$(awk '{$3=$3",";print $2,$3,$NF}' <<< "$mpidate")
147+
fi
148+
timestamp=$(date -j -f "$datefmt" "$mpidate 12:00:00+0000" "+%s")
149+
;;
150+
esac
151+
echo writing source-date-epoch ...
152+
echo "$timestamp" > "$SOURCE/source-date-epoch"
153+
fi
154+
155+
echo writing package metadata ...
156+
echo "Name: $mpiname" > "$PACKAGE/METADATA"
157+
echo "Version: $version" >> "$PACKAGE/METADATA"
158+
159+
echo copying MPI license file...
54160
cp "$SOURCE"/"$license" "$PACKAGE/LICENSE"
161+
if test -n "${ofidestdir+x}"; then
162+
echo copying OFI license file...
163+
cp "$ofidestdir/COPYING" "$PACKAGE/LICENSE.ofi"
164+
fi
165+
if test -n "${ucxdestdir+x}"; then
166+
echo copying UCX license file...
167+
cp "$ucxdestdir/LICENSE" "$PACKAGE/LICENSE.ucx"
168+
fi

build-wheel.sh

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@ WORKDIR=package/workdir
66
DESTDIR=package/install
77
ARCHLIST=${ARCHLIST:-$(uname -m)}
88

9+
read -r SOURCE_DATE_EPOCH < "$SOURCE"/source-date-epoch
10+
export SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH
11+
912
export CIBW_BUILD_FRONTEND='build'
1013
export CIBW_BUILD='cp313-*'
1114
export CIBW_SKIP='*musllinux*'
1215
export CIBW_ARCHS=$ARCHLIST
1316
export CIBW_BEFORE_ALL='bash {project}/cibw-build-mpi.sh'
1417
export CIBW_TEST_COMMAND='bash {project}/cibw-check-mpi.sh'
1518
export CIBW_ENVIRONMENT_PASS='MPINAME RELEASE SOURCE WORKDIR DESTDIR'
16-
export CIBW_REPAIR_WHEEL_COMMAND_MACOS='delocate-wheel --ignore-missing-dependencies --exclude libmpi --exclude libpmpi --require-archs {delocate_archs -w {dest_dir} -v {wheel}'
19+
export CIBW_REPAIR_WHEEL_COMMAND_MACOS='delocate-wheel --ignore-missing-dependencies --exclude libmpi --exclude libpmpi --exclude libfabric --require-archs {delocate_archs -w {dest_dir} -v {wheel}'
1720

1821
if test "$(uname)" = Linux; then
1922
containerengine=$(basename "$(command -v podman || command -v docker)")
2023
export CIBW_CONTAINER_ENGINE=$containerengine
2124
export SOURCE="/project/$SOURCE"
22-
export WORKDIR="/host/$PWD/$WORKDIR"
23-
export DESTDIR="/host/$PWD/$DESTDIR"
25+
export WORKDIR="/host$PWD/$WORKDIR"
26+
export DESTDIR="/host$PWD/$DESTDIR"
2427
platform=linux
2528
fi
2629
if test "$(uname)" = Darwin; then

check-wheel.sh

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ unzip -qq "$wheelfile" -d "$workdir"
1616
cd "$workdir"
1717

1818
whlname=$(basename "$wheelfile")
19-
pkgname=${whlname%%-*}
19+
whlinfo=${whlname%%-py*}
20+
pkgname=${whlinfo%%-*}
21+
version=${whlinfo##*-}
2022
mpiname=${pkgname}
2123

2224
data=$(ls -d "$pkgname"-*.data/data)
@@ -29,9 +31,12 @@ if test "$(uname)" = Linux; then
2931
libsdir=.libs
3032
print-runpath() { patchelf --print-rpath "$1"; }
3133
print-needed() { patchelf --print-needed "$1"; }
32-
if test -f "$data"/lib/libucp.so; then
34+
if test -f "$data"/lib/*/libucp.so.*; then
3335
runlibs=$runlibs'|libuc(m|p|s|t)'$soregex
3436
fi
37+
if test -f "$data"/lib/*/libfabric.so.*; then
38+
runlibs=$runlibs'|libfabric'$soregex
39+
fi
3540
fi
3641
if test "$(uname)" = Darwin; then
3742
runpath='@executable_path/../lib/|@loader_path/'
@@ -41,9 +46,12 @@ if test "$(uname)" = Darwin; then
4146
libsdir=.dylibs
4247
print-runpath() { otool -l "$1" | sed -n '/RPATH/{n;n;p;}'; }
4348
print-needed() { otool -L "$1" | sed 1,1d; }
44-
if test -f "$data"/lib/libucp.dylib; then
49+
if test -f "$data"/lib/libucp.*.dylib; then
4550
runlibs=$runlibs'|libuc(m|p|s|t)'$soregex
4651
fi
52+
if test -f "$data"/lib/libfabric.*.dylib; then
53+
runlibs=$runlibs'|libfabric'$soregex
54+
fi
4755
fi
4856

4957
if test "$mpiname" = "mpich"; then
@@ -65,12 +73,17 @@ if test "$mpiname" = "mpich"; then
6573
"$data"/bin/hydra_*
6674
)
6775
libraries=(
68-
"$data"/lib/libmpi.*
76+
"$data"/lib/lib*mpi.*
6977
)
70-
if test -d "$data"/lib/ucx; then
78+
if ls "$data"/lib/*/libfabric.* > /dev/null 2>&1; then
79+
libraries+=(
80+
"$data"/lib/*/libfabric.*
81+
)
82+
fi
83+
if ls "$data"/lib/*/libucp.* > /dev/null 2>&1; then
7184
libraries+=(
72-
"$data"/lib/libuc[mpst]*.*
73-
"$data"/lib/ucx/libuc*.*
85+
"$data"/lib/*/libuc[mpst]*.*
86+
"$data"/lib/*/ucx/libuc[mpst]*.*
7487
)
7588
fi
7689
fi
@@ -96,33 +109,53 @@ if test "$mpiname" = "openmpi"; then
96109
"$data"/lib/libmpi.*
97110
"$data"/lib/libopen-*.*
98111
)
112+
if test "${version%%.*}" -ge 5; then
113+
libraries+=(
114+
"$data"/lib/libevent*.*
115+
"$data"/lib/libhwloc.*
116+
"$data"/lib/libpmix.*
117+
"$data"/lib/libprrte.*
118+
)
119+
fi
120+
if ls "$data"/lib/*/libucp.* > /dev/null 2>&1; then
121+
libraries+=(
122+
"$data"/lib/*/libuc[mpst]*.*
123+
"$data"/lib/*/ucx/libuc[mpst]*.*
124+
)
125+
fi
126+
if ls "$data"/lib/*/libfabric.* > /dev/null 2>&1; then
127+
libraries+=(
128+
"$data"/lib/*/libfabric.*
129+
)
130+
fi
99131
runlibs+='|lib(z|util|event.*|hwloc)'$soregex
100132
runlibs+='|lib(open-(pal|rte)|pmix|prrte)'$soregex
101133
fi
102134

103135
check-binary() {
104136
local dso=$1 out1="" out2=""
105137
echo checking "$dso"...
106-
test -f "$dso" || printf "ERROR: file not found\n"
138+
test -f "$dso" || (printf "ERROR: file not found\n"; exit 1)
107139
out1="$(print-runpath "$dso" | grep -vE "$runpath" || true)"
108140
test -z "$out1" || printf "ERROR: RUNPATH\n%s\n" "$out1"
109141
out2="$(print-needed "$dso" | grep -vE "$runlibs" || true)"
110142
test -z "$out2" || printf "ERROR: NEEDED\n%s\n" "$out2"
111-
test -z "$out1" -a -z "$out2"
143+
test -z "$out1"
144+
test -z "$out2"
112145
}
113146

114147
for header in "${headers[@]-}"; do
115148
test -n "$header" || break
116149
echo checking "$header"...
117-
test -f "$header"
150+
test -f "$header" || (printf "ERROR: file not found\n"; exit 1)
118151
out=$(grep -E '^#include\s+"mpicxx\.h"' "$header" || true)
119152
test -z "$out" || printf "ERROR: include\n%s\n" "$out"
120153
test -z "$out"
121154
done
122155
for script in "${scripts[@]-}"; do
123156
test -n "$script" || break
124157
echo checking "$script"...
125-
test -f "$script"
158+
test -f "$script" || (printf "ERROR: file not found\n"; exit 1)
126159
out=$(grep -E "/opt/$mpiname" "$script" || true)
127160
test -z "$out" || printf "ERROR: prefix\n%s\n" "$out"
128161
test -z "$out"

0 commit comments

Comments
 (0)