Repository navigation
Native Windows support (MinGW-w64, ch3:sock, single node) - #8007
yorickreum wants to merge 10 commits into
Conversation
Linux impact reviewPR 8007 is low-risk for Linux builds. The branch builds cleanly on Linux and the tests I ran pass. One correction to the description: Linux is not completely unaffected. One behavior change and one header change reach Linux, and both look fine. What I checked
Changes that reach Linux
|
|
@yorickreum is it feasible to set up github action for the windows testing? |
Add MPL_sock_{read,write,close,poll,accept,set_nonblock,set_cloexec,pair}
and MPL_sock_init. On POSIX they are thin inline wrappers. On Windows they
use Winsock and translate WSAGetLastError() into errno, so callers can keep
testing errno against EAGAIN, EINPROGRESS etc. MPL_sock_poll ignores
negative fds like poll() does (WSAPoll reports them as POLLNVAL), and
MPL_sock_pair replaces pipe() with a connected loopback socket pair.
mpl_sockaddr uses GetAdaptersAddresses instead of getifaddrs on Windows,
and MPL_large_readv/writev use WSARecv/WSASend. mpl_iov.h provides
struct iovec where <sys/uio.h> does not exist.
The NT shm backend no longer compiled against the current MPL_shm interface. Rewrite it with named file mappings. Unlike POSIX, a mapping disappears with its last handle, so the local handle is kept open until the shm handle is finalized. Select it automatically when neither mmap nor SysV shm is available but windows.h is, and only use mmap in the memory tracer when it exists.
Use strerror_s and _putenv_s where strerror_r and setenv do not exist, only include dlfcn.h when dlopen is available, use MPL_MAX instead of the non-standard MAX macro, and skip SIGUSR1 where it is not defined.
Use the MPL_sock_* functions instead of read/write/close/fcntl/poll/pipe on sockets in ch3:sock, the PMI client and the spawn/join code, so they also work with Winsock. The wakeup pipe of the sock channel becomes a socket pair, which WSAPoll can wait on.
- PMI singleton init (fork/exec of mpiexec) is not available on Windows. - Finalize PMI right away on Windows: an atexit handler registered from a DLL runs at DLL detach, when Winsock may already be gone, so the deferred PMI_Finalize could not reach the process manager.
Link Winsock and the IP helper library and pass -no-undefined so libtool builds DLLs. Disable weak symbols: depending on the binutils version the "#pragma weak" checks may pass, but weak aliases are not exported from a DLL, so the MPI_* entry points would be missing; build the separate libpmpi instead. ch3:sock gets poll() from WSAPoll, and the socklen_t and gethostname probes include the Winsock headers. The MPII_Bsend_data_t size probe passes the include directory with -I, since a native compiler cannot open the absolute MSYS path that was used in the #include.
When MPICH_INTERFACE_HOSTNAME is 127.0.0.1 or localhost, other processes can only reach us through loopback anyway, so do not listen on all interfaces. Besides not exposing the port, this avoids a firewall prompt on Windows for every new program.
mpiexec starts the ranks with CreateProcess, serves PMI-1 over a loopback port (PMI_PORT/PMI_ID), and places the ranks in a job object so they are killed together. Like hydra, it forwards the output of the ranks line by line and connects stdin to rank 0 only. It honors MPIEXEC_TIMEOUT, defaults the ranks to loopback communication, and adds <prefix>\Library\bin to their PATH when installed in a Python environment. It is the default process manager on MinGW (--with-pm=winexec).
mpif.h and "use mpi" define MPI_BOTTOM, MPI_IN_PLACE etc. as common blocks, which libmpifort recognizes by address. A DLL and the program using it each get their own copy of a common block, so these constants were not recognized (e.g. MPI_Allreduce with MPI_IN_PLACE gave wrong results). Link the thin Fortran layer statically, as it is done for a similar reason on Darwin with -flat_namespace; libmpi stays a DLL. As a consequence, intercepting MPI routines from Fortran by defining them in the program (test/mpi/f*/profile) results in duplicate symbols.
Build MPICH natively on Windows with MSYS2 (UCRT64), ch3:sock and the winexec process manager on a GitHub-hosted runner, and run a subset of test/mpi (basic, init, group, pt2pt, comm, coll). The job fails if any test fails, since runtests itself exits with 0 in that case.
6ebe710 to
0e03ccd
Compare
Added a workflow. MSYS2/UCRT64 on a hosted Windows runner, ch3:sock + winexec, and the basic/init/group/pt2pt/comm/coll subset of test/mpi (352 tests). It fails if any test fails. Total run time is about 45 minutes, mostly the build. I am happy to reduce run time in a follow-up commit by just adding ccache. |
Follow-up to #7280. This makes MPICH build and run natively on Windows with MSYS2/MinGW-w64 (UCRT64) and the existing autotools build, using ch3:sock:
Native Windows builds (no Cygwin) produce
libmpi-0.dll/libpmpi-0.dll. Programs built with MSVC can link to them through the C ABI.What changes:
MPL_sock_*(read/write/close/poll/accept/set_nonblock/pair/get_error) are inline wrappers on POSIX. On Windows they use Winsock and translateWSAGetLastError()intoerrno, so the callers' error handling stays the same.MPL_sock_pollignores negative fds likepoll()(WSAPoll reports them asPOLLNVAL).MPL_sock_pairis a loopback socket pair that verifies its peer.-no-undefined, weak symbols off since weak aliases are not exported from DLLs, Winsock-aware probes).mpiexec(CreateProcess, PMI-1 over a loopback port, job object, line-wise output forwarding like hydra,MPIEXEC_TIMEOUT). It is the default process manager on MinGW.libmpifortis static on MinGW, becausempif.hcommon blocks (MPI_BOTTOM,MPI_IN_PLACE) cannot be shared between a DLL and the program.Linux builds are unaffected: everything is behind
_WIN32or MinGW-only configure branches.Limitations / open questions
MPI_Comm_spawn, name publishing and singleton init are not supported by winexec (it replies with an error).src/pm/util/pmiserv.c, which depends onfork. Is reusing it preferred?libmpifort): 269 of 274 tests pass. The profiling tests fail (overriding MPI routines collides with the static archive), and so doesallocmemf, which the test makefiles do not build by default.Testing
test/mpidirectories basic, init, group, pt2pt, comm, coll, attr, datatype, errhan, info, rma, topo, mpi_t, threads, session: 789 of 790 pass with the default 180 s time limit (typenameneeds Fortran). Some RMA tests are slow over loopback TCP, e.g.rma/large_acc_flush_localtakes about 70 s.typename, built without Fortran), ch4:ofi with Fortran 1092 of 1092.Author Checklist