From 92b369eaf13684fa2191f370b1401878edce2598 Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 14:32:08 -0600 Subject: [PATCH 01/15] initial commit to fork --- partitioned-communication/Makefile | 367 ++++++++++++++++++ partitioned-communication/README.md | 84 ++++ partitioned-communication/runtests.py | 331 ++++++++++++++++ partitioned-communication/test_cancel0.c | 98 +++++ partitioned-communication/test_common.h | 24 ++ partitioned-communication/test_datatype0.c | 95 +++++ partitioned-communication/test_datatype1.c | 95 +++++ partitioned-communication/test_datatype2.c | 96 +++++ partitioned-communication/test_datatype3.c | 108 ++++++ partitioned-communication/test_datatype4.c | 77 ++++ partitioned-communication/test_datatype5.c | 78 ++++ partitioned-communication/test_example1a.c | 78 ++++ partitioned-communication/test_example1b.c | 75 ++++ partitioned-communication/test_example2.c | 100 +++++ partitioned-communication/test_example3a.c | 116 ++++++ partitioned-communication/test_example3b.c | 110 ++++++ partitioned-communication/test_example3c.c | 115 ++++++ partitioned-communication/test_free0.c | 90 +++++ partitioned-communication/test_init0.c | 98 +++++ partitioned-communication/test_init1.c | 86 ++++ partitioned-communication/test_init2.c | 88 +++++ partitioned-communication/test_local0.c | 86 ++++ partitioned-communication/test_local1.c | 85 ++++ partitioned-communication/test_numparts0.c | 82 ++++ partitioned-communication/test_numparts1.c | 82 ++++ partitioned-communication/test_order0.c | 116 ++++++ partitioned-communication/test_parrived0.c | 92 +++++ partitioned-communication/test_parrived1.c | 57 +++ partitioned-communication/test_parrived2.c | 74 ++++ partitioned-communication/test_partitions0.c | 80 ++++ partitioned-communication/test_partitions1.c | 80 ++++ partitioned-communication/test_partitions2.c | 78 ++++ partitioned-communication/test_partitions3.c | 83 ++++ partitioned-communication/test_pready0.c | 82 ++++ partitioned-communication/test_pready1.c | 82 ++++ partitioned-communication/test_pready2.c | 82 ++++ partitioned-communication/test_pready3.c | 82 ++++ partitioned-communication/test_pready4.c | 61 +++ partitioned-communication/test_pready_list0.c | 82 ++++ partitioned-communication/test_pready_list1.c | 86 ++++ .../test_pready_range0.c | 81 ++++ partitioned-communication/test_startall0.c | 160 ++++++++ partitioned-communication/test_state0.c | 151 +++++++ partitioned-communication/test_wildcard0.c | 79 ++++ partitioned-communication/test_wildcard1.c | 79 ++++ partitioned-communication/test_zerocount0.c | 79 ++++ partitioned-communication/test_zerocount1.c | 79 ++++ 47 files changed, 4669 insertions(+) create mode 100644 partitioned-communication/Makefile create mode 100644 partitioned-communication/README.md create mode 100644 partitioned-communication/runtests.py create mode 100644 partitioned-communication/test_cancel0.c create mode 100644 partitioned-communication/test_common.h create mode 100644 partitioned-communication/test_datatype0.c create mode 100644 partitioned-communication/test_datatype1.c create mode 100644 partitioned-communication/test_datatype2.c create mode 100644 partitioned-communication/test_datatype3.c create mode 100644 partitioned-communication/test_datatype4.c create mode 100644 partitioned-communication/test_datatype5.c create mode 100644 partitioned-communication/test_example1a.c create mode 100644 partitioned-communication/test_example1b.c create mode 100644 partitioned-communication/test_example2.c create mode 100644 partitioned-communication/test_example3a.c create mode 100644 partitioned-communication/test_example3b.c create mode 100644 partitioned-communication/test_example3c.c create mode 100644 partitioned-communication/test_free0.c create mode 100644 partitioned-communication/test_init0.c create mode 100644 partitioned-communication/test_init1.c create mode 100644 partitioned-communication/test_init2.c create mode 100644 partitioned-communication/test_local0.c create mode 100644 partitioned-communication/test_local1.c create mode 100644 partitioned-communication/test_numparts0.c create mode 100644 partitioned-communication/test_numparts1.c create mode 100644 partitioned-communication/test_order0.c create mode 100644 partitioned-communication/test_parrived0.c create mode 100644 partitioned-communication/test_parrived1.c create mode 100644 partitioned-communication/test_parrived2.c create mode 100644 partitioned-communication/test_partitions0.c create mode 100644 partitioned-communication/test_partitions1.c create mode 100644 partitioned-communication/test_partitions2.c create mode 100644 partitioned-communication/test_partitions3.c create mode 100644 partitioned-communication/test_pready0.c create mode 100644 partitioned-communication/test_pready1.c create mode 100644 partitioned-communication/test_pready2.c create mode 100644 partitioned-communication/test_pready3.c create mode 100644 partitioned-communication/test_pready4.c create mode 100644 partitioned-communication/test_pready_list0.c create mode 100644 partitioned-communication/test_pready_list1.c create mode 100644 partitioned-communication/test_pready_range0.c create mode 100644 partitioned-communication/test_startall0.c create mode 100644 partitioned-communication/test_state0.c create mode 100644 partitioned-communication/test_wildcard0.c create mode 100644 partitioned-communication/test_wildcard1.c create mode 100644 partitioned-communication/test_zerocount0.c create mode 100644 partitioned-communication/test_zerocount1.c diff --git a/partitioned-communication/Makefile b/partitioned-communication/Makefile new file mode 100644 index 0000000..70b98af --- /dev/null +++ b/partitioned-communication/Makefile @@ -0,0 +1,367 @@ +BIN=./bin/ +OBJ=./obj/ + +# C compiler +CC=gcc + +# MPI +# if required, add paths to mpi.h and any other necessary headers (e.g., UCX) +CFLAGS= +# if required, add paths to ompi libraries and any other necessary libraries +LDFLAGS= + +.PHONY: clean + +all: test_cancel0.x test_datatype0.x test_datatype1.x test_datatype2.x test_datatype3.x test_datatype4.x test_datatype5.x test_example1a.x test_example1b.x test_example2.x test_example3a.x test_example3b.x test_example3c.x test_free0.x test_init0.x test_init1.x test_init2.x test_local0.x test_local1.x test_numparts0.x test_numparts1.x test_order0.x test_parrived0.x test_parrived1.x test_parrived2.x test_pready0.x test_pready1.x test_pready2.x test_pready3.x test_pready4.x test_pready_list0.x test_pready_list1.x test_pready_range0.x test_partitions0.x test_partitions1.x test_partitions2.x test_partitions3.x test_startall0.x test_state0.x test_wildcard0.x test_wildcard1.x test_zerocount0.x test_zerocount1.x + +test_cancel0.x: test_cancel0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_cancel0.o: test_cancel0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype0.x: test_datatype0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype0.o: test_datatype0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype1.x: test_datatype1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype1.o: test_datatype1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype2.x: test_datatype2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype2.o: test_datatype2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype3.x: test_datatype3.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype3.o: test_datatype3.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype4.x: test_datatype4.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype4.o: test_datatype4.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype5.x: test_datatype5.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype5.o: test_datatype5.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_example1a.x: test_example1a.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_example1a.o: test_example1a.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_example1b.x: test_example1b.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_example1b.o: test_example1b.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_example2.x: test_example2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) -fopenmp + +test_example2.o: test_example2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) -fopenmp + +test_example3a.x: test_example3a.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) -fopenmp + +test_example3a.o: test_example3a.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) -fopenmp + +test_example3b.x: test_example3b.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) -fopenmp + +test_example3b.o: test_example3b.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) -fopenmp + +test_example3c.x: test_example3c.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) -fopenmp + +test_example3c.o: test_example3c.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) -fopenmp + +test_free0.x: test_free0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_free0.o: test_free0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_init0.x: test_init0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_init0.o: test_init0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_init1.x: test_init1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_init1.o: test_init1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_init2.x: test_init2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_init2.o: test_init2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_local0.x: test_local0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_local0.o: test_local0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_local1.x: test_local1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_local1.o: test_local1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_numparts1.x: test_numparts1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_numparts1.o: test_numparts1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_numparts0.x: test_numparts0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_numparts0.o: test_numparts0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_order0.x: test_order0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_order0.o: test_order0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_parrived0.x: test_parrived0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_parrived0.o: test_parrived0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_parrived1.x: test_parrived1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_parrived1.o: test_parrived1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_parrived2.x: test_parrived2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_parrived2.o: test_parrived2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_partitions0.x: test_partitions0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_partitions0.o: test_partitions0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_partitions1.x: test_partitions1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_partitions1.o: test_partitions1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_partitions2.x: test_partitions2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_partitions2.o: test_partitions2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_partitions3.x: test_partitions3.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_partitions3.o: test_partitions3.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready0.x: test_pready0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready0.o: test_pready0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready1.x: test_pready1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready1.o: test_pready1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready2.x: test_pready2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready2.o: test_pready2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready3.x: test_pready3.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready3.o: test_pready3.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready4.x: test_pready4.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready4.o: test_pready4.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready_list0.x: test_pready_list0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready_list0.o: test_pready_list0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready_list1.x: test_pready_list1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready_list1.o: test_pready_list1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready_range0.x: test_pready_range0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready_range0.o: test_pready_range0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_startall0.x: test_startall0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_startall0.o: test_startall0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_state0.x: test_state0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_state0.o: test_state0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_wildcard0.x: test_wildcard0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_wildcard0.o: test_wildcard0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_wildcard1.x: test_wildcard1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_wildcard1.o: test_wildcard1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_zerocount0.x: test_zerocount0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_zerocount0.o: test_zerocount0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_zerocount1.x: test_zerocount1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_zerocount1.o: test_zerocount1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +clean: + rm -f *.o + rm -f *.x + rm -f ${OBJ}*.o + rm -f ${BIN}*.x + rm -r obj + rm -r bin diff --git a/partitioned-communication/README.md b/partitioned-communication/README.md new file mode 100644 index 0000000..8ce245b --- /dev/null +++ b/partitioned-communication/README.md @@ -0,0 +1,84 @@ +## A collection of tests for the MPI 4.1 partitioned communication API + +These tests target partitioned communication as it appears in Chapter 4 of +the [MPI Specification v. 4.1](https://www.mpi-forum.org/docs/). + +The repository contains the following: +- `test_*.c` : the tests (see below) +- `runtests.py` : a simple python 3 script for executing tests and generating a report +- other misc files : skeleton makefile, license, etc. + +### runtests.py script + +The script executes each test and looks for an expected output string in its +`stderr` output. Tests pass if the expected string is found somewhere in the +output, or (optionally) on a specific line of the output. Alternatively a test +may be designed to elicit a timeout, in which case it passes if a timeout occurs. + +A report is generated in a subdirectory along with the stderr output of each test. + +Run with `-v` flag to generate progress information on `stdout`; otherwise the tests +run silently. + +See comments in script for more information. + +### Tests + +A summary of tests is given below. For each, see the comments in the source for +motivation for the test, including (when available) references to specific pages and lines in the +v4.1 MPI specification. + +Some tests are designed to elicit errors from the MPI implementation, and if no +error is produced, the test fails. In some cases the assumption that the implementation +will produce an error message may be unfounded, e.g., because performing such a check is +difficult, impacts performance, or it is really up to the user to avoid the situation. +These tests may warrant additional discussion or exclusion. + +| Test | Description | +| ---- | ---- | +| `test_cancel01.c` | Calling MPI_Cancel on an active request should cause an error; PASS = some sort of error; FAIL = unexpected timeout or incorrect/missing error. | +| `test_datatypeX.c` | Examples in chapter 4 of the specification use different combinations of sender and receiver contiguous datatypes as well as OpenMP pragmas. The datatype tests eschew the OpenMP and check just the combination of datatypes. | +| `test_datatype0.c` | Checks case where the same datatype is used on both sender and reciever, and the same number of partitions. PASS = run to completion. | +| `test_datatype1.c` | Based on example 4.3 in specification. This test has the sender and receiver use the same number of partitions. The sender uses a datatype (one per partition) while the receiver uses MPI_INT * PARTSIZE. PASS = run to completion. See also `test_datatype4.c` | +| `test_datatype2.c` | Based on example 4.3 in specification, this test has the sender use multiple partitions and the receiver use a single partition. The sender uses contiguous datatypes (one per partition) and the reciever MESSAGE_LENGTH. PASS = run to completion. See also `test_datatype4.c` | +| `test_datatype3.c` | Same as test_datatype2.c, except receiver uses a single contiguous datatype of size MESSAGE_LENGTH. See also `test_datatype5.c`, which does the same using Isend/Irecv. PASS = run to completion. | +| `test_datatype4.c` | A sanity check confirming the combination of sender-side contiguous datatype and receiver-side non-derived datatype (MPI_INT) works outside of partcomm with Isend/Irecv. PASS = run to completion | +| `test_datatype5.c` | A sanity check confirming the combination of multiple sender-side contiguous datatypes to a single receiver-side contiguous datatype works with Isend/Irecv. PASS = run to completion. | +| `test_example1a.c` | Example 1 from the 4.1 specification. PASS = run to completion | +| `test_example1b.c` | Example 1 from the 4.1 spec, except uses MPI_WAIT instead of MPI_TEST. PASS = run to completion | +| `test_example2.c` | Example 2 from the 4.1 specification. PASS = run to completion | +| `test_example3a.c` | Example 3 from the 4.1 specification, modified to not use any contiguous datatypes, use MPI_INT, and make the number of partitions the same on both sender and receiver. PASS = run to completion. | +| `test_example3b.c` | Example 3 from the 4.1 specification, modified to use MPI_INT and not use any contiguous datatypes. Uses multiple partitions on sender and one on receiver. | +| `test_example3c.c` | Example 3 from the 4.1 specification, modified to use MPI_INT. PASS = run to completion. See also `test_datatype[2,3].c` | +| `test_free0.c` | Calling MPI_Free on an active request should cause an error; PASS = some sort of error (TBD); FAIL = unexpected timeout or incorrect/missing error | +| `test_init0.c` | Tries to match a PSEND_INIT with an IRECV. PASS = expected timeout. | +| `test_init1.c` | Tries to match an ISEND with a PRECV_INIT. PASS = expected timeout. | +| `test_init2.c` | Tries to match a persistent send init (MPI_SEND_INIT) with a partcomm recv init (PRECV_INIT). PASS = expected timeout. | +| `test_local0.c` | Confirms partcomm calls are local, so the sender can get to test/wait before the receiver even calls PRECV_INIT PASS = runs to completion. | +| `test_local1.c` | Confirms partcomm calls are local, so the receiver can get to test/wait before the sender even calls PSEND_INIT. PASS = runs to completion | +| `test_numparts0.c` | Confirms a sender can have more partitions than a receiver. PASS = runs to completion. | +| `test_numparts1.c` | Confirms a receiver can have more partitions than a sender. PASS = runs to completion. | +| `test_order0.c` | Confirms the order in which partcomm init calls are made is the order they are matched (and hence filled). PASS = runs to completion; FAIL = likely fails check of received message contents | +| `test_parrived0.c` | Confirms PARRIVED works. Also (likely) calls PARRIVED more than once on the same partition. PASS = run to completion | +| `test_parrived1.c` | Confirms PARRIVED works on a request that has never been used (an inactive request). PASS = run to completion | +| `test_parrived2.c` | Tries to call PARRIVED on a request that does not correspond to a partitioned receive operation. PASS = some sort of error | +| `test_partitions0.c` | Tries to use PSEND_INIT with zero partitions. PASS = some sort of error | +| `test_partitions1.c` | Tries to use PSEND_INIT with negative partitions. PASS = some sort of error | +| `test_partitions2.c` | Tries to use PRECV_INIT with zero partitions. PASS = some sort of error | +| `test_partitions3.c` | Tries to use PRECV_INIT with negative partitions. PASS = some sort of error | +| `test_pready0.c` | Tries to call PREADY on a partition whose index is greater than the largest valid index. PASS = some sort of error | +| `test_pready1.c` | Tries to call PREADY on a partition whose index is equal to the number of partitions (so is 1 beyond the last valid index). PASS = some sort of error | +| `test_pready2.c` | Tries to call PREADY on a partition whose index is negative. PASS = some sort of error | +| `test_pready3.c` | Tries to call PREADY on a partition that has already been marked ready by PREADY. PASS = some sort of error | +| `test_pready4.c` | Tries to call PREADY on a request object that does not correspond to a partitioned send operation. PASS = some sort of error | +| `test_pready_range0.c` | Uses PREADY_RANGE in a standard way; PASS = successfully runs to completion | +| `test_pready_list0.c` | Uses PREADY_LIST in a standard way; PASS = runs to completion | +| `test_pready_list1.c` | Uses PREADY_LIST with the same partition appearing more than once. See also test_pready3.c. PASS = some sort of error | +| `test_startall0.c` | Sets up multiple PSEND_INIT + PRECV_INIT pairs using different tags and does partcomm for each. PASS = runs to completion. | +| `test_state0.c` | Confirms that the request status is reset when multiple rounds of START/PREADY/TEST are used. See also [OMPI Issue #12328](https://github.com/open-mpi/ompi/issues/12328) PASS = runs to completion. | +| `test_wildcard0.c` | Tries to use MPI_ANY_SOURCE with PRECV_INIT. PASS = an error of some sort | +| `test_wildcard0.c` | Tries to use MPI_ANY_SOURCE with PRECV_INIT. PASS = an error of some sort | +| `test_zerocount0.c` | Confirms PSEND_INIT and PRECV_INIT can use 0 partitions with a greater-than-zero count. PASS = runs to completion | +| `test_zerocount1.c` | Confirms PSEND_INIT and PRECV_INIT can use greater-than-zero partitions with a zero count. PASS = runs to completion | + + diff --git a/partitioned-communication/runtests.py b/partitioned-communication/runtests.py new file mode 100644 index 0000000..9b8413d --- /dev/null +++ b/partitioned-communication/runtests.py @@ -0,0 +1,331 @@ +# Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +# (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +# Government retains certain rights in this software. + +# A simple python script for running unit tests and checking their outputs +# +# The `tests` dict (below) specifies which tests are to be run and how the +# stderr output of each test is to be evaluated. Tests can pass because +# (i) an expected string was found in the output (or, optionally, on a specific +# line of the output), or (ii) the test was expected to timeout and it did. +# +# Some tests are written to elicit an error message from the MPI implementation. Because it may not +# be known a priori what this message is, the text variable TBD_ERROR is used +# as the matching string, with the expectation it will be replaced with the +# actual error message when it is available. Below, tests that contain TBD_ERROR +# are tests that fail because no error is reported by OMPI. +# +# All tests are written to use stderr, and assume OMPI error messages will appear on stderr; stdout is ignored. +# +# The script assumes if a segmentation fault occurs in the MPI implementation, it is an error. +# Segmentation faults can generate stderr outputs that are not readable by Python in text mode (only +# in binary mode). Therefore, the script tests if the output is readable in text mode; if it is not, it +# reports the test as failing and notes the file was not readable. +# +# + +import argparse +import os +import subprocess +import sys +import threading +import time + +# Use the following as placeholder text for tests designed to elicit an error message. +# When the specific error message is known, replace. +TBD_ERROR = "UNKNOWN ERROR MESSAGE EXPECTED" + +# For tests designed to elicit a timeout, use the following matching text: +TIMEOUT_EXPECTED = "__TIMEOUT_EXPECTED__" + +# The following variables are default text for generating the report +TIMEOUT_EXPECTED_AND_FOUND = "Timeout expected and did occur" +TIMEOUT_EXPECTED_AND_NOT_FOUND = "A timeout was expected but the test terminated for some other reason." +TIMEOUT_UNEXPECTED_AND_FOUND = "No timeout was expected but test terminated due to timeout" +TIMEOUT_UNEXPECTED_AND_NOT_FOUND = "This outcome should not arise" + +# subdirectory where tests are located relative to this script +BIN = "./bin/" + +# Dict of tests to run along with the string that, if found in the ouput, means the test passes. +# +# The tuple is the string to be matched, followed by the line on which it is expected. Use "*" to allow the +# matching string to appear on any line. +# +# TBD_ERROR is used as the expected string when a test is supposed to elicit an error but we do not +# have a proper output string to test for (e.g., if the test fails to error). +# +# If a timeout is the expected outcome, then use the TIMEOUT_EXPECTED variable for the match string. +# +tests = { + "test_cancel0.x": (TBD_ERROR,"*"), + "test_datatype0.x": ("END", "1"), + "test_datatype1.x": ("END", "1"), + "test_datatype2.x": ("END", "1"), + "test_datatype3.x": ("END", "1"), + "test_datatype4.x": ("END", "1"), + "test_datatype5.x": ("END", "1"), + "test_example1a.x": ("END", "1"), + "test_example1b.x": ("END", "1"), + "test_example2.x": ("END", "1"), + "test_example3a.x": ("END", "1"), + "test_example3b.x": ("END", "1"), + "test_example3c.x": ("END", "1"), + "test_free0.x": (TBD_ERROR, "*"), + "test_init0.x": (TIMEOUT_EXPECTED, "*"), + "test_init1.x": (TIMEOUT_EXPECTED, "*"), + "test_init2.x": (TIMEOUT_EXPECTED, "*"), + "test_local0.x" : ("END", "1"), + "test_local1.x" : ("END", "1"), + "test_numparts0.x" : ("END", "1"), + "test_numparts1.x" : ("END", "1"), + "test_order0.x" : ("END", "1"), + "test_parrived0.x" : ("END", "*"), + "test_parrived1.x" : ("END", "*"), + "test_parrived2.x" : ("*** An error occurred in MPI_Parrived", "*"), + "test_partitions0.x" : (TBD_ERROR, "*"), + "test_partitions1.x" : (TBD_ERROR, "*"), + "test_partitions2.x" : (TBD_ERROR, "*"), + "test_partitions3.x" : (TBD_ERROR, "*"), + "test_pready0.x" : (TBD_ERROR, "*"), + "test_pready1.x" : (TBD_ERROR, "*"), + "test_pready2.x" : (TBD_ERROR, "*"), + "test_pready3.x" : (TBD_ERROR, "*"), + "test_pready4.x" : ("MPI_ERR_REQUEST: invalid request", "*"), + "test_pready_list0.x": ("END", "1"), + "test_pready_list1.x": (TBD_ERROR, "*"), + "test_pready_range0.x": ("END", "1"), + "test_startall0.x" : ("END", "*"), + "test_state0.x" : (TBD_ERROR, "*"), + "test_wildcard0.x" : (TBD_ERROR, "*"), + "test_wildcard1.x" : (TBD_ERROR, "*"), + "test_zerocount0.x" : ("END", "*"), + "test_zerocount1.x" : ("END", "*") + } + +# for colored verbose output +class txt_colors: + PASS = '\033[92m' + FAIL = '\033[91m' + ENDC = '\033[0m' + +# test output is directed here +out_stderr = ".stderr" +out_stdout = ".stdout" + +# prefix of output directory (date/time will be appended) +outdir = "results_" + +# name of report file +reportfn = "report.txt" + +# for timeout +timeout_thread_abort = False +timeout_occurred = False +DEFAULT_TIMEOUT_SECONDS = 25 + +# for stats +passed = 0 +failed = 0 + +def error(msg): + print("ERROR: {0}".format(msg), file=sys.stderr) + exit(1) + +# if the test passed +def report_success(outfile, test, msg=""): + global passed + passed += 1 + print("{0} : passed : {1}".format(test, msg), file=outfile) + +# if the test failed +def report_failure(outfile, test, msg=""): + global failed + failed += 1 + print("{0} : FAILED : {1}".format(test, msg), file=outfile) + +def get_process_id(name): + child = subprocess.Popen(['pgrep', '-f', name], stdout=subprocess.PIPE, shell=False) + response = child.communicate()[0] + return [int(pid) for pid in response.split()] + +# function for timeout thread +def timeout_function(seconds, t): + global timeout_occurred + timeout_occurred = False + count = 0 + pid = get_process_id(t) + while (not pid) and (count < 5): + pid = get_process_id(t) + t_start = int(time.time()) + while ((int(time.time()) - t_start) < seconds): + if timeout_thread_abort: + return + timeout_occurred = True + subprocess.run("kill -9 {0}".format(pid[0]), stderr=outfile_stderr, stdout=subprocess.DEVNULL, shell=True) + return + +# check if output file to be checked has only text +# When a segfault occurs, it can generate outout that cannot be decoded to text +def file_is_readable(infn): + try: + infile = open(infn, "r") + except: + error("Could not open file {0}".format(infn)) + try: + for line in infile: + print("", end='') + except: + return False + return True + +# helper to avoid duplicating code +def verbose_pass_fail(test_passed): + if test_passed: + print(f"{txt_colors.PASS}PASSED{txt_colors.ENDC}", file=sys.stdout) + else: + print(f"{txt_colors.FAIL}FAILED{txt_colors.ENDC}", file=sys.stdout) + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", help="Verbose mode") + + args = parser.parse_args() + verbose = args.verbose + + tstr = time.strftime("%Y%m%d-%H%M%S") + outdir = outdir + tstr + os.mkdir(outdir) + outdir = "./" + outdir + + reportfn = outdir + "/" + reportfn + try: + reportfile = open(reportfn, "w") + except: + error("Could not open file {0} for writing A".format(reportfn)) + + total_tests = len(tests) + cur_test = 0 + + # add some info to the report + print("", file=reportfile) + print("---- Tests start: {0} ----".format(tstr), file=reportfile) + print("Tests (num = {0}):".format(total_tests), file=reportfile) + for t in tests: + print(" {0}".format(t), file=reportfile) + print(file=reportfile) + + tt_start = time.time() + + for t in tests: + cur_test += 1 + if verbose: + print("{0} / {1} : Running test: {2} --> ".format(cur_test, total_tests, t),end='', file=sys.stdout, flush=True) + command = "mpirun -np 2 --npernode 1 " + BIN + t + tmp_out_stderr = outdir + "/" + t + out_stderr + try: + outfile_stderr = open(tmp_out_stderr, 'w') + except: + error("Could not open file {0} for writing B".format(tmp_out_stderr)) + + timeout_thread_abort = False + timeout_thread = threading.Thread(target=timeout_function, args=(DEFAULT_TIMEOUT_SECONDS,t,)) + + timeout_thread.start() + subprocess.run(command, stderr=outfile_stderr, stdout=subprocess.DEVNULL, shell=True) + if not timeout_occurred: + timeout_thread_abort = True + outfile_stderr.close() + + match_string = tests[t][0] + testline = tests[t][1] + + test_passed = False + + # Confirm the file can be read as text + # If a segmentation fault occurs in the MPI implementation, it can generate contents that are + # only readable in binary mode, which this code cannot test. So if it is not readable, its an + # error. + is_readable = file_is_readable(tmp_out_stderr) + if not is_readable: + report_failure(reportfile, t, "Output is not readable as text. Check .stderr output") + if verbose: + verbose_pass_fail(test_passed) + continue + + testfile = open(tmp_out_stderr,'r') + + curline = 0 + foundline = False + # timeout occurred but not expected + if timeout_occurred and (match_string != TIMEOUT_EXPECTED): + report_failure(reportfile, t, TIMEOUT_UNEXPECTED_AND_FOUND) + foundline = True # to avoid another failure message + # timeout occured and expected + elif timeout_occurred and (match_string == TIMEOUT_EXPECTED): + report_success(reportfile, t, TIMEOUT_EXPECTED_AND_FOUND) + foundline = True # to avoid another failure message + test_passed = True + # timeout did not occur but was expected + elif (not timeout_occurred) and (match_string == TIMEOUT_EXPECTED): + report_failure(reportfile, t, TIMEOUT_EXPECTED_AND_NOT_FOUND) + foundline = True # to avoid another failure message + elif testline == "*": + for line in testfile: + curline += 1 + line = line.rstrip() + if match_string in line: + foundline = True + report_success(reportfile, t, "Match found on line {0}".format(curline)) + test_passed = True + break + else: # look only at specified line + try: + testline = int(testline) + except: + error("Line specified for test {0} is neither an int nor *") + for line in testfile: + curline += 1 + line = line.rstrip() + if curline == testline: + foundline = True + if match_string in line: + report_success(reportfile, t, "Match found on line {0}".format(curline)) + test_passed = True + else: + report_failure(reportfile, t, "On line {0}: Expected: {1} Found: {2}".format(testline, match_string, line)) + break + + # If no match found, provide more information + if not foundline: + if testline == "*": + report_failure(reportfile, t, "Expected text not found on any line. ({0})".format(match_string)) + else: + report_failure(reportfile, t, "Expected to test on line {0}, but stderr output file has only {1} lines.".format(testline, curline)) + + if verbose: + verbose_pass_fail(test_passed) + + time.sleep(7) + + tt_end = time.time() + + print("", file=reportfile) + print("", file=reportfile) + if (total_tests != (passed + failed)): + print("Note: total_tests (= {0}) did not equal passed + failed (= {1})".format(total_tests, passed, failed), file=reportfile) + passed_total = float(passed)/float(total_tests) + failed_total = float(failed)/float(total_tests) + print("{0} of {1} tests passed ({2:.2f}%)".format(passed, total_tests, passed_total*100), file=reportfile) + print("{0} of {1} tests failed ({2:.2f}%)".format(failed, total_tests, failed_total*100), file=reportfile) + print("", file=reportfile) + print("---- Tests end: {0} ----".format(time.strftime("%Y%m%d-%H%M%S")), file=reportfile) + print("---- Total time required to run tests: {0:.2f} seconds".format(tt_end - tt_start), file=reportfile) + reportfile.close() + + if verbose: + print("{0} of {1} tests passed ({2:.2f}%)".format(passed, total_tests, passed_total*100), file=sys.stdout) + print("{0} of {1} tests failed ({2:.2f}%)".format(failed, total_tests, failed_total*100), file=sys.stdout) + diff --git a/partitioned-communication/test_cancel0.c b/partitioned-communication/test_cancel0.c new file mode 100644 index 0000000..4a84e82 --- /dev/null +++ b/partitioned-communication/test_cancel0.c @@ -0,0 +1,98 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 116, line 11: Freeing or canceling a partitioned communication request that is active (i.e., initialized and started) and not completed is erroneous. + * + * Expected outcome: Error message due to calling MPI_Cancel on a request that is active + * If test times out, then the error was not caught by the MPI library + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + fprintf(stderr, "Rank 0 initializing and starting Psend\n"); + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + MPI_Start(&request); + + /* This should cause an error. See 4.1 p. 102 for info on cancel */ + fprintf(stderr, "Rank 0 canceling request (erroneous)\n"); + CHECK_RETVAL(MPI_Cancel(&request)); + + /* Cancel is followed by wait, which should be local. If cancel ignored, then may hang here because nothing has been marked ready */ + fprintf(stderr, "Rank 0 waiting on cancelled request\n"); + CHECK_RETVAL(MPI_Wait(&request, MPI_STATUS_IGNORE)); + + /* Now we the request is inactive and we can use it again or free it */ + MPI_Request_free(&request); + + /* Rest of code is the standard Psend/Precv example. If the MPI_Request_free is ignored and no error reported, + * then the remainder of the code may hang because the first Psend is never completed, and the destination is testing on it + */ + + fprintf(stderr, "Rank 0 starting second Psend\n"); + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (myrank == 0) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_common.h b/partitioned-communication/test_common.h new file mode 100644 index 0000000..b5d7cd3 --- /dev/null +++ b/partitioned-communication/test_common.h @@ -0,0 +1,24 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +#ifndef TEST_COMMON_H +#define TEST_COMMON_H + +#include +#include +#include "mpi.h" + +#define CHECK_RETVAL(x) do { \ + int retval = (x); \ + if (retval != MPI_SUCCESS) { \ + fprintf(stderr, "Error: %s returned %d (expected %d)\n", #x, retval, MPI_SUCCESS); \ + MPI_Abort(MPI_COMM_WORLD, 999); \ + } \ + } while (0) + +#define TEST_RAN_TO_COMPLETION() do { \ + fprintf(stderr, "END\n"); \ + } while (0) + +#endif diff --git a/partitioned-communication/test_datatype0.c b/partitioned-communication/test_datatype0.c new file mode 100644 index 0000000..63296f5 --- /dev/null +++ b/partitioned-communication/test_datatype0.c @@ -0,0 +1,95 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * This test uses the same datatype on sender and receiver, and the same + * number of partitions. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 64 +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int partitions = PARTITIONS; + int partlength = PARTLENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype xfer_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender and receiver both use the same transfer datatype */ + MPI_Type_contiguous(partlength, MPI_INT, &xfer_type); + MPI_Type_commit(&xfer_type); + + if (0 == myrank) { + + for (i = 0; i < partitions * partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, partitions, count, xfer_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < partlength; ++j) { + message[j + (i * partlength)] = j + (i * partlength); + } + MPI_Pready(i, request); + } + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < partitions * partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, partitions, count, xfer_type, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + + if (myrank == 0) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_datatype1.c b/partitioned-communication/test_datatype1.c new file mode 100644 index 0000000..dd4bc46 --- /dev/null +++ b/partitioned-communication/test_datatype1.c @@ -0,0 +1,95 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * Example 4.3 uses a contiguous send datatype (one per partition) to a receiver using a single partition of + * MPI_DOUBLEs. This test simplifies by removing OpenMP code and makes the number of partitions + * the same. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 64 +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int partitions = PARTITIONS; + int partlength = PARTLENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < partitions * partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < partlength; ++j) { + message[j + (i * partlength)] = j + (i * partlength); + } + MPI_Pready(i, request); + } + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); } + + else if (1 == myrank) { + for (i = 0; i < partitions * partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, partitions, partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_datatype2.c b/partitioned-communication/test_datatype2.c new file mode 100644 index 0000000..cf1023c --- /dev/null +++ b/partitioned-communication/test_datatype2.c @@ -0,0 +1,96 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * Example 4.3 uses a contiguous send datatype (one per partition) to a receiver using a single partition of + * MPI_DOUBLEs. This test simplifies by using MPI_INT and removing OpenMP + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 64 +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < send_partlength; ++j) { + message[j + (i * send_partlength)] = j + (i * send_partlength); + } + MPI_Pready(i, request); + } + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_datatype3.c b/partitioned-communication/test_datatype3.c new file mode 100644 index 0000000..f6747be --- /dev/null +++ b/partitioned-communication/test_datatype3.c @@ -0,0 +1,108 @@ +// Copyright 2022 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * This test has the sender use a datatype multiple times (one per partition) and + * the receiver receive into a single partition with a single datatype. + * + * Compare with test_datatype5.c, which does the same thing with Isend/Irecv insteaad of partcomm + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 64 +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + // If the test seg faults, it may be a memory alignment issue + //int *message = NULL; + //if (posix_memalign((void *)&message, 32, sizeof(int) * MESSAGE_LENGTH)) { + // fprintf(stderr, "Error using posix_memalign\n"); + // exit(-1); + //} + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int send_count = 1, recv_count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type, recv_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* sender uses PARTITIONS partitions each comprising one instance of a PARTLENTH contiguous datatype */ + MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + /* receier uses 1 partition comprising one instance of a MESSAGE_LENGTH contiguous datatype */ + MPI_Type_contiguous(recv_partlength, MPI_INT, &recv_type); + MPI_Type_commit(&recv_type); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, send_count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < send_partlength; ++j) { + message[j + (i * send_partlength)] = j + (i * send_partlength); + } + MPI_Pready(i, request); + } + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_count, recv_type, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_datatype4.c b/partitioned-communication/test_datatype4.c new file mode 100644 index 0000000..1bfd696 --- /dev/null +++ b/partitioned-communication/test_datatype4.c @@ -0,0 +1,77 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * This test is simply a sanity check to make sure the combination of sender-side + * contiguous datatype and receiver-side non-derived datatype works with basic non-blocking send/recv. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define MESSAGE_LENGTH 256 +#define DATATYPE_LENGTH 128 + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + + int count = 2, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(DATATYPE_LENGTH, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < MESSAGE_LENGTH; ++i) message[i] = i; + + MPI_Isend(message, count, send_type, dest, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + } else if (1 == myrank) { + + for (i = 0; i < MESSAGE_LENGTH; ++i) message[i] = 101; + + MPI_Irecv(message, MESSAGE_LENGTH, MPI_INT, source, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_datatype5.c b/partitioned-communication/test_datatype5.c new file mode 100644 index 0000000..f7191aa --- /dev/null +++ b/partitioned-communication/test_datatype5.c @@ -0,0 +1,78 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * This is a sanity check to determine that a multipe counts of a sender-side + * contiguous datatype can be send to a receiver with a single contiguous datatype + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define MESSAGE_LENGTH 256 +#define SEND_DATATYPE_LENGTH 64 + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + + int send_count = 4, recv_count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type, recv_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + MPI_Type_contiguous(SEND_DATATYPE_LENGTH, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + MPI_Type_contiguous(MESSAGE_LENGTH, MPI_INT, &recv_type); + MPI_Type_commit(&recv_type); + + if (0 == myrank) { + + for (i = 0; i < MESSAGE_LENGTH; ++i) message[i] = i; + + MPI_Isend(message, send_count, send_type, dest, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + } else if (1 == myrank) { + + for (i = 0; i < MESSAGE_LENGTH; ++i) message[i] = 101; + + MPI_Irecv(message, recv_count, recv_type, source, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_example1a.c b/partitioned-communication/test_example1a.c new file mode 100644 index 0000000..1d94db2 --- /dev/null +++ b/partitioned-communication/test_example1a.c @@ -0,0 +1,78 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This is example 4.1, p. 114-115, MPI Standard v. 4.1 + * Extended to (1) fill buffer, (2) test that correct results are received. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_example1b.c b/partitioned-communication/test_example1b.c new file mode 100644 index 0000000..8603518 --- /dev/null +++ b/partitioned-communication/test_example1b.c @@ -0,0 +1,75 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This is example 4.1, p. 114-115, MPI Standard v. 4.1 + * Extended to (1) fill buffer, (2) test that correct results are received. + * + * This version uses MPI_Wait instead of MPI_Test, to confirm WAIT works (P. 120, line 16) + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + CHECK_RETVAL(MPI_Wait(&request, MPI_STATUS_IGNORE)); + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + CHECK_RETVAL(MPI_Wait(&request, MPI_STATUS_IGNORE)); + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_example2.c b/partitioned-communication/test_example2.c new file mode 100644 index 0000000..c34dbff --- /dev/null +++ b/partitioned-communication/test_example2.c @@ -0,0 +1,100 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This is a variation on example 4.2, p. 122-123, MPI Standard v. 4.1 + * + * Note that this example (like the original) uses the same congituous datatype on both + * sender and receiver. See test_example3x.c for other variations. + * + * Expected outcome: PASS + * + */ + +#include +#include "test_common.h" + +#define NUM_THREADS 8 +#define PARTITIONS 8 +#define PARTLENGTH 16 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*PARTLENGTH]; + int partitions = PARTITIONS; + int partlength = PARTLENGTH; + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int my_thread_id; + int myrank; + int provided; + + omp_set_dynamic(0); // Disable dynamic teams + omp_set_num_threads(NUM_THREADS); + + for (i = 0; i < partitions * partlength; ++i) message[i] = 0; + + MPI_Request request; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype xfer_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + MPI_Type_contiguous(partlength , MPI_INT, &xfer_type); + MPI_Type_commit(&xfer_type); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, count, xfer_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel for shared(request,message) private(j, my_thread_id) num_threads(NUM_THREADS) + for (i=0; i +#include "test_common.h" + +#define NUM_THREADS 8 +#define NUM_TASKS 64 +#define PARTITIONS NUM_TASKS +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int partitions = PARTITIONS; + int partlength = PARTLENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + for (i = 0; i < partitions * partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, partitions, partlength, MPI_INT, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) + { +#pragma omp single + { + /* single thread creates 64 tasks to be executed by 8 threads */ + for (int task_num=0; task_num < NUM_TASKS; task_num++) { +#pragma omp task firstprivate(task_num) + { + my_thread_id = omp_get_thread_num(); + for (i=0; i < partlength; ++i) { + message[i + (task_num * partlength)] = i + (task_num * partlength); + } + MPI_Pready(task_num, request); + } /* end task */ + } /* end for */ + } /* end single */ + } /* end parallel */ + + // fprintf(stderr, "Sent: "); + // for (i = 0; i < MESSAGE_LENGTH; ++i) fprintf(stderr, "%d ", message[i]); + // fprintf(stderr, "\n"); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < partitions * partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, partitions, partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + // fprintf(stderr, "Received: "); + // for (i = 0; i < MESSAGE_LENGTH; ++i) fprintf(stderr, "%d ", message[i]); + // fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_example3b.c b/partitioned-communication/test_example3b.c new file mode 100644 index 0000000..f1fecad --- /dev/null +++ b/partitioned-communication/test_example3b.c @@ -0,0 +1,110 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Variation on Example 4.3, pp. 123-124 + * + * Original example: + * - Uses MPI_DOUBLE + * - Uses derived contiguous datatype on send side and MPI_DOUBLE on recv side + * - Has multiple partitions on send side and a single partition on recv side + * + * This version: + * - Uses MPI_INT + * - Does not use contiguous datatype on either side + * - Does have multiple partitions on send side and a single partition on recv side + * + * Expected outcome: PASS + * + */ + +#include +#include "test_common.h" + +#define NUM_THREADS 8 +#define NUM_TASKS 64 +#define PARTITIONS NUM_TASKS +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, send_partlength, MPI_INT, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) + { +#pragma omp single + { + /* single thread creates 64 tasks to be executed by 8 threads */ + for (int task_num=0; task_num < NUM_TASKS; task_num++) { +#pragma omp task firstprivate(task_num) + { + my_thread_id = omp_get_thread_num(); + for (i=0; i < send_partlength; ++i) { + message[i + (task_num * send_partlength)] = i + (task_num * send_partlength); + } + MPI_Pready(task_num, request); + } /* end task */ + } /* end for */ + } /* end single */ + } /* end parallel */ + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_example3c.c b/partitioned-communication/test_example3c.c new file mode 100644 index 0000000..cccc63b --- /dev/null +++ b/partitioned-communication/test_example3c.c @@ -0,0 +1,115 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Variation on Example 4.3, pp. 123-124 + * + * Original example: + * - Uses MPI_DOUBLE + * - Uses derived contiguous datatype on send side and MPI_DOUBLE on recv side + * - Has multiple partitions on send side and a single partition on recv side + * + * This version: + * - Uses MPI_INT + * + * See also test_datatypeX.c + * + * Expected outcome: PASS + * + */ + +#include +#include "test_common.h" + +#define NUM_THREADS 8 +#define NUM_TASKS 64 +#define PARTITIONS NUM_TASKS +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Datatype send_type; + MPI_Info info = MPI_INFO_NULL; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (myrank == 0) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + #pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) + { + #pragma omp single + { + /* single thread creates 64 tasks to be executed by 8 threads */ + for (int task_num=0; task_num < NUM_TASKS; task_num++) { + #pragma omp task firstprivate(task_num) + { + my_thread_id = omp_get_thread_num(); + for (i=0; i < send_partlength; ++i) { + message[i + (task_num * send_partlength)] = i + (task_num * send_partlength); + } + MPI_Pready(task_num, request); + } /* end task */ + } /* end for */ + } /* end single */ + } /* end parallel */ + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (myrank == 1) { + for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (myrank == 0) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + return 0; + +} diff --git a/partitioned-communication/test_free0.c b/partitioned-communication/test_free0.c new file mode 100644 index 0000000..56973af --- /dev/null +++ b/partitioned-communication/test_free0.c @@ -0,0 +1,90 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 116, line 11: Freeing or canceling a partitioned communication request that is active (i.e., initialized and started) and not completed is erroneous. + * + * Expected outcome: Error message + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + fprintf(stderr, "Rank 0 initializing and starting Psend\n"); + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* This should cause an error */ + fprintf(stderr, "Rank 0 freeing request (erroneous)\n"); + CHECK_RETVAL(MPI_Request_free(&request)); + + + /* Rest of code is the standard Psend/Precv example. If the MPI_Request_free is ignored and no error reported, + * then the remainder of the code may hang because the first Psend is never completed, and the destination is testing on it + */ + + fprintf(stderr, "Rank 0 starting second Psend\n"); + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_init0.c b/partitioned-communication/test_init0.c new file mode 100644 index 0000000..3b35435 --- /dev/null +++ b/partitioned-communication/test_init0.c @@ -0,0 +1,98 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * P. 117, line 13: PSEND_INIT can only match with partitioned communication initialization operations, therefore it is required to be matched with a corresponding MPI_PRECV_INIT. + * + * This test tries to match a PSEND_INIT with an IRECV. Because the PSEND_INIT should not match the + * IRECV, the code should timeout waiting + * + * Expected outcome: TIMEOUT + * + */ + +#include "test_common.h" + +#define PARTITIONS 1 +#define COUNT 64 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + fprintf(stderr, "Sending message: \n"); + for (i=0; i < partitions * COUNT; ++i) { + fprintf(stderr, "%d, ", message[i]); + } + fprintf(stderr, "\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + + fprintf(stderr, "Received message: \n"); + for (i=0; i < partitions * COUNT; ++i) { + fprintf(stderr, "%d, ", message[i]); + } + fprintf(stderr, "\n"); + + /* This should not work. Test should time out */ + fprintf(stderr, "Rank 1 posting Irecv\n"); + CHECK_RETVAL(MPI_Irecv(message, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, &request)); + fprintf(stderr, "Rank 1 waiting\n"); + CHECK_RETVAL(MPI_Wait(&request, MPI_STATUS_IGNORE)); /* should time out here */ + + fprintf(stderr, "Received message: \n"); + for (i=0; i < partitions * COUNT; ++i) { + fprintf(stderr, "%d, ", message[i]); + } + fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + fprintf(stderr, "Rank 1: Contents verfied\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_init1.c b/partitioned-communication/test_init1.c new file mode 100644 index 0000000..08d0a55 --- /dev/null +++ b/partitioned-communication/test_init1.c @@ -0,0 +1,86 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * P. 118, line 20: PRECV_INIT can only match with partitioned communication initialization operations, therefore + * the MPI library is required to match MPI_PRECV_INIT calls only with a corresponding MPI_PSEND_INIT call. + * + * This test uses PRECV_INIT with an Isend; the latter should fail to match and the test timeout + * + * Expected outcome: TIMEOUT + * + */ + +#include "test_common.h" + +#define PARTITIONS 1 +#define COUNT 64 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + /* Fill message to be sent */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + } + + fprintf(stderr, "Rank 0 issuing Isend to Rank 1's corresponding MPI_Precv_init\n"); + MPI_Isend(message, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD, &request); + + fprintf(stderr, "Rank 0 waiting\n"); + MPI_Wait(&request, MPI_STATUS_IGNORE); + + fprintf(stderr, "Rank 0 done\n"); + + } + else if (1 == myrank) { + + fprintf(stderr, "Rank 1 initializing and starting Precv\n"); + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, MPI_INFO_NULL, &request)); + CHECK_RETVAL(MPI_Start(&request)); + + fprintf(stderr, "Rank 1 testing for completion ... should timeout here if Precv did not match Isend\n"); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + fprintf(stderr, "Rank 1 received message\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + fprintf(stderr, "Rank 1: Contents verfied\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_init2.c b/partitioned-communication/test_init2.c new file mode 100644 index 0000000..9d86c7c --- /dev/null +++ b/partitioned-communication/test_init2.c @@ -0,0 +1,88 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * P. 118, line 20: PRECV_INIT can only match with partitioned communication initialization operations, therefore + * the MPI library is required to match MPI_PRECV_INIT calls only with a corresponding MPI_PSEND_INIT call. + * + * This version use persistent send + * + * Expected outcome: TIMEOUT + * + */ + +#include "test_common.h" + +#define PARTITIONS 1 +#define COUNT 64 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + fprintf(stderr, "Rank 0 initializing persistent send\n"); + MPI_Send_init(message, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD, &request); + + /* Fill message to be sent */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + } + + fprintf(stderr, "Rank 0 starting persistent send\n"); + MPI_Start(&request); + + fprintf(stderr, "Rank 0 waiting\n"); + MPI_Wait(&request, MPI_STATUS_IGNORE); + + fprintf(stderr, "Rank 0 done\n"); + + } + else if (1 == myrank) { + + fprintf(stderr, "Rank 1 initializing and starting Precv\n"); + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, MPI_INFO_NULL, &request); + MPI_Start(&request); + + fprintf(stderr, "Rank 1 testing for completion ... should timeout here if Precv did not match persistent send\n"); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + fprintf(stderr, "Rank 1 received message\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + fprintf(stderr, "Rank 1: Contents verfied\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_local0.c b/partitioned-communication/test_local0.c new file mode 100644 index 0000000..416af73 --- /dev/null +++ b/partitioned-communication/test_local0.c @@ -0,0 +1,86 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 114, line 11: Part comm initialization functions are local. + * P. 117, line 14-15: Partitioned communication initialization calls are local. + * + * Therefore, the sender should be able to get to test/wait before the receiver calls PRECV_INIT, and + * the receiver should be able to get to test/wait before the sender calls PSEND_INIT + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + /* receiver does not call PRECV_INIT until after this barrier */ + /* putting barrier after test causes deadlock */ + MPI_Barrier(MPI_COMM_WORLD); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Barrier(MPI_COMM_WORLD); + + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (1 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_local1.c b/partitioned-communication/test_local1.c new file mode 100644 index 0000000..07a3530 --- /dev/null +++ b/partitioned-communication/test_local1.c @@ -0,0 +1,85 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 114, line 11: Part comm initialization functions are local. + * P. 117, line 14-15: Partitioned communication initialization calls are local. + * + * Therefore, the sender should be able to get to test/wait before the receiver calls PRECV_INIT, and + * the receiver should be able to get to test/wait before the sender calls PSEND_INIT + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Barrier(MPI_COMM_WORLD); + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + + + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + MPI_Barrier(MPI_COMM_WORLD); /* barrier after test causes deadlock */ + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_numparts0.c b/partitioned-communication/test_numparts0.c new file mode 100644 index 0000000..8dc2188 --- /dev/null +++ b/partitioned-communication/test_numparts0.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * Test 4: P. 114, line 12-13: The number of user-visible partitions on the send and receiver side may differ. + * + * This test has twice as many send partitions as recv partitions + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 8 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = PARTITIONS * 2; + MPI_Count send_count = (int)COUNT/2; + MPI_Count recv_partitions = PARTITIONS; + MPI_Count recv_count = COUNT; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, send_partitions, send_count, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < send_count; ++j) message[j+(send_count*i)] = j+(send_count*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, recv_partitions, recv_count, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < recv_partitions*recv_count; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_numparts1.c b/partitioned-communication/test_numparts1.c new file mode 100644 index 0000000..9638589 --- /dev/null +++ b/partitioned-communication/test_numparts1.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * Test 4: P. 114, line 12-13: The number of user-visible partitions on the send and receiver side may differ. + * + * This test has twice as many recv partitions as send partitions + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 8 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = PARTITIONS; + MPI_Count send_count = COUNT; + MPI_Count recv_partitions = PARTITIONS * 2; + MPI_Count recv_count = (int)COUNT/2; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, send_partitions, send_count, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < send_count; ++j) message[j+(send_count*i)] = j+(send_count*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, recv_partitions, recv_count, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < recv_partitions*recv_count; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_order0.c b/partitioned-communication/test_order0.c new file mode 100644 index 0000000..fd11997 --- /dev/null +++ b/partitioned-communication/test_order0.c @@ -0,0 +1,116 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 113, line 15: Part comm operations are matched based on the order in which the local initialization calls are performed. + * P. 117, line 10: In the event that the communicator, tag, and source do not uniquely identify a message, the order + * in which partitioned communication initialization calls are made is the order in which they will eventually match. + * P. 118, line 24: If communicator, tag, and source are not enough to match, order is used. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message0[PARTITIONS*COUNT]; + int message1[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag0 = 0, flag1 = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message0[i] = 0; + for (i = 0; i < PARTITIONS * COUNT; ++i) message1[i] = 0; + + MPI_Request request0, request1; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + /* init in order 0, 1 */ + MPI_Psend_init(message0, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request0); + MPI_Psend_init(message1, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request1); + + /* start both */ + MPI_Start(&request0); + MPI_Start(&request1); + + /* fill 0; should fill 1 on receiver */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message0[j+(COUNT*i)] = 10*(j+(COUNT*i)); + MPI_Pready(i, request0); + } + + while (!flag0) { + MPI_Test(&request0, &flag0, MPI_STATUS_IGNORE); + } + + /* fill 1; should fill 0 on receiver */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message1[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request1); + } + + while (!flag1) { + MPI_Test(&request1, &flag1, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request0); + MPI_Request_free(&request1); + + } + else if (1 == myrank) { + /* init in order 1, 0 */ + MPI_Precv_init(message1, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request1); + MPI_Precv_init(message0, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request0); + + MPI_Start(&request0); + MPI_Start(&request1); + + while (!flag0 && !flag1) { + MPI_Test(&request0, &flag0, MPI_STATUS_IGNORE); + MPI_Test(&request1, &flag1, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request0); + MPI_Request_free(&request1); + + /* all partitions received; check contents */ + //fprintf(stderr, "Message 0: "); + for (i = 0; i < PARTITIONS*COUNT; ++i) { + //fprintf(stderr, "%d, ", message0[i]); + if (message0[i] != i) { + fprintf(stderr, "ERROR: Contents received in message buffer 0 do not match contents sent (expected %d, found %d).\n",i,message0[i]); + MPI_Abort(MPI_COMM_WORLD, 0); + } + } + //fprintf(stderr, "\n"); + //fprintf(stderr, "Message 1: "); + for (i = 0; i < PARTITIONS*COUNT; ++i) { + //fprintf(stderr, "%d, ", message1[i]); + if (message1[i] != i*10) { + fprintf(stderr, "ERROR: Contents received in message buffer 1 do not match contents sent (expected %d, found %d).\n",i,message1[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + //fprintf(stderr, "\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_parrived0.c b/partitioned-communication/test_parrived0.c new file mode 100644 index 0000000..bac2903 --- /dev/null +++ b/partitioned-communication/test_parrived0.c @@ -0,0 +1,92 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 120: definition of PARRIVED + * + * This test simply uses PARRIVED and confirms the data in the partition is as expected + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + int part_of_interest = 3; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* loop until the partition of interest has arrived */ + int try = 0; + while (!flag) { + CHECK_RETVAL(MPI_Parrived(request, part_of_interest, &flag)); + ++try; + } + + /* acess the partition data */ + fprintf(stderr, "Number of PARRIVED calls: %d\n", try); + for (i=0; i < COUNT; ++i) { + fprintf(stderr,"%d\n", message[(part_of_interest*COUNT)+i]); + } + + /* continue as usual */ + MPI_Wait(&request, MPI_STATUS_IGNORE); + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_parrived1.c b/partitioned-communication/test_parrived1.c new file mode 100644 index 0000000..8e9f73f --- /dev/null +++ b/partitioned-communication/test_parrived1.c @@ -0,0 +1,57 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 121, line 10: PARRIVED can be called on a null or inactive request; in this case, flag = true + * + * Expected outcome: PASS + * + */ + +#include +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + int part_of_interest = 3; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + sleep(10); + + } + else if (1 == myrank) { + + /* request never used; confirm parrived sets flag to true */ + if (!flag) fprintf(stderr, "Flag is false\n"); + while (!flag) { + CHECK_RETVAL(MPI_Parrived(request, 0, &flag)); + } + fprintf(stderr, "Flag is true\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_parrived2.c b/partitioned-communication/test_parrived2.c new file mode 100644 index 0000000..409e20e --- /dev/null +++ b/partitioned-communication/test_parrived2.c @@ -0,0 +1,74 @@ +/* + * P. 121, line 11: Calling MPI_PARRIVED on a request that does not correspond to a partitioned receive operation + * is erroneous. + * + * This test uses PARRIVED on a request corresponding to an Irecv + * + * Expected outcome: some sort of error + * + */ + +#include "test_common.h" + +#define COUNT 32 + +int main(int argc, char *argv[]) { + + int message[COUNT]; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + for (i = 0; i < COUNT; ++i) message[i] = i; + + MPI_Isend(message, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD, &request); + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + //MPI_Request_free(&request); + + } + else if (1 == myrank) { + + MPI_Irecv(message, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, &request); + + /* this is erroneous */ + MPI_Parrived(request, 0, &flag); + + /* continue as usual */ + MPI_Wait(&request, MPI_STATUS_IGNORE); + + for (i=0; i < COUNT; ++i) { + fprintf(stderr,"%d ", message[i]); + } + fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_partitions0.c b/partitioned-communication/test_partitions0.c new file mode 100644 index 0000000..b33dc1c --- /dev/null +++ b/partitioned-communication/test_partitions0.c @@ -0,0 +1,80 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Initializes using an invalid number of partitions: Psend_init with 0 partitions. + * + * P. 114, line 13-14: Valid partitioned communication operations must have one or more partitions specified. + * P. 117, line 15-16: It is erroneous to provide a partitions value <= 0. + * P. 118, line 28: It is erroneous to provide a partitions value <= 0. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = 0; /* Bad number of send partitions */ + MPI_Count recv_partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + /* Error should occur with this call */ + CHECK_RETVAL(MPI_Psend_init(message, send_partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, recv_partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_partitions1.c b/partitioned-communication/test_partitions1.c new file mode 100644 index 0000000..2f5a152 --- /dev/null +++ b/partitioned-communication/test_partitions1.c @@ -0,0 +1,80 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Initializes using an invalid number of partitions: Psend_init with negative partitions. + * + * P. 114, line 13-14: Valid partitioned communication operations must have one or more partitions specified. + * P. 117, line 15-16: It is erroneous to provide a partitions value <= 0. + * P. 118, line 28: It is erroneous to provide a partitions value <= 0. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = -8; /* Bad number of partitions; MPI_Count is a signed int */ + MPI_Count recv_partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + /* Error should occur with this call */ + CHECK_RETVAL(MPI_Psend_init(message, send_partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, recv_partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_partitions2.c b/partitioned-communication/test_partitions2.c new file mode 100644 index 0000000..920b1c7 --- /dev/null +++ b/partitioned-communication/test_partitions2.c @@ -0,0 +1,78 @@ +/* + * Initializes using an invalid number of partitions: Precv_init with 0 partitions. + * + * P. 114, line 13-14: Valid partitioned communication operations must have one or more partitions specified. + * P. 117, line 15-16: It is erroneous to provide a partitions value <= 0. + * P. 118, line 28: It is erroneous to provide a partitions value <= 0. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = PARTITIONS; + MPI_Count recv_partitions = 0; /* bad number of partitions */ + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, send_partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + fprintf(stderr, "Rank 1 initializing recv partitions to %d\n", recv_partitions); + /* Error should occur with this call */ + CHECK_RETVAL(MPI_Precv_init(message, recv_partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + + CHECK_RETVAL( MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_partitions3.c b/partitioned-communication/test_partitions3.c new file mode 100644 index 0000000..8f03a94 --- /dev/null +++ b/partitioned-communication/test_partitions3.c @@ -0,0 +1,83 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Initializes using an invalid number of partitions: Precv_init with negative partitions. + * + * P. 114, line 13-14: Valid partitioned communication operations must have one or more partitions specified. + * P. 117, line 15-16: It is erroneous to provide a partitions value <= 0. + * P. 118, line 28: It is erroneous to provide a partitions value <= 0. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = PARTITIONS; + MPI_Count recv_partitions = -3; /* Bad number of partitions */ + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, send_partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + + MPI_Start(&request); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + fprintf(stderr, "Rank 1 initializing recv partitions to %d\n", recv_partitions); + /* Error should occur with this call */ + CHECK_RETVAL(MPI_Precv_init(message, recv_partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_pready0.c b/partitioned-communication/test_pready0.c new file mode 100644 index 0000000..8d4c57b --- /dev/null +++ b/partitioned-communication/test_pready0.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls pready on a partition whose index is greater than the upper bound. + * + * P. 119, line 7-9: "Partition numbering ranges from 0 to 1 less than number of partitions declared in the MPI_PSEND_INIT call, and specifying a partition number that is equal to or larger is erroneous." + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + MPI_Count bad_partition = PARTITIONS + 5; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Call Pready on a nonexistant partition; an error should occur */ + fprintf(stderr, "Marking invalid partition ready...\n"); + CHECK_RETVAL(MPI_Pready(bad_partition, request)); + fprintf(stderr, "Invalid partition marked ready...\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_pready1.c b/partitioned-communication/test_pready1.c new file mode 100644 index 0000000..f02903b --- /dev/null +++ b/partitioned-communication/test_pready1.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls pready on a partition whose index is equal to the number of partitions. + * + * P. 119, line 7-9: "Partition numbering ranges from 0 to 1 less than number of partitions declared in the MPI_PSEND_INIT call, and specifying a partition number that is equal to or larger is erroneous." + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + MPI_Count bad_partition = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Call Pready on a nonexistant partition; an error should occur */ + fprintf(stderr, "Marking invalid partition ready...\n"); + CHECK_RETVAL(MPI_Pready(bad_partition, request)); + fprintf(stderr, "Invalid partition marked ready...\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_pready2.c b/partitioned-communication/test_pready2.c new file mode 100644 index 0000000..134fc98 --- /dev/null +++ b/partitioned-communication/test_pready2.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls pready on a partition whose index is negative. + * + * P. 119, line 7-9: "Partition numbering ranges from 0 to 1 less than number of partitions declared in the MPI_PSEND_INIT call, and specifying a partition number that is equal to or larger is erroneous." + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + MPI_Count bad_partition = -5; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Call Pready on a nonexistant partition; an error should occur */ + fprintf(stderr, "Marking invalid partition ready...\n"); + CHECK_RETVAL(MPI_Pready(bad_partition, request)); + fprintf(stderr, "Invalid partition marked ready...\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_pready3.c b/partitioned-communication/test_pready3.c new file mode 100644 index 0000000..e4ecae2 --- /dev/null +++ b/partitioned-communication/test_pready3.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls pready on a partition that is active, i.e., has already been marked as ready. + * + * P. 119, line 11-12: Calling MPI_PREADY on an active partition is erroneous. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + MPI_Count active_partition = 2; // assumes at least 3 partitions + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Call Pready on a partition already marked as ready; an error should occur */ + fprintf(stderr, "Marking previously marked partition ready...\n"); + CHECK_RETVAL(MPI_Pready(active_partition, request)); + fprintf(stderr, "Previously marked partition marked again...\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_pready4.c b/partitioned-communication/test_pready4.c new file mode 100644 index 0000000..d4437bf --- /dev/null +++ b/partitioned-communication/test_pready4.c @@ -0,0 +1,61 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls PREADY on a request object that corresponds to an Isend. + * + * P. 119, line 6: "It is erroneous to use MPI_PREADY on any request object that does not correspond to a partitioned send operation." + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Request isend_request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Isend(message, PARTITIONS*COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD, &isend_request)); + + + // This call is erroneous + CHECK_RETVAL(MPI_Pready(0, isend_request)); + + CHECK_RETVAL(MPI_Wait(&isend_request, MPI_STATUS_IGNORE)); + + } + else if (1 == myrank) { + + MPI_Irecv(message, PARTITIONS*COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_pready_list0.c b/partitioned-communication/test_pready_list0.c new file mode 100644 index 0000000..ce9e2f2 --- /dev/null +++ b/partitioned-communication/test_pready_list0.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 119-120: PREADY_LIST defined here. + * + * This test just uses PREADY_LIST instead of PREADY + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + int partitions_list[PARTITIONS]; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + partitions_list[i] = i; + } + + /* Basic Pready list use case */ + CHECK_RETVAL(MPI_Pready_list(partitions, partitions_list, request)); + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_pready_list1.c b/partitioned-communication/test_pready_list1.c new file mode 100644 index 0000000..6790fca --- /dev/null +++ b/partitioned-communication/test_pready_list1.c @@ -0,0 +1,86 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 119-120: PREADY_LIST defined here. + * The discussion of PREADY (P. 119, line 11-12) implies the same partition cannot occur more than once in a list, so that is checked here + * + * Expected outcome: Some sort of error + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + int partitions_list[PARTITIONS]; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + partitions_list[i] = i; + } + + /* make is so the same partition appears more than once in the list */ + partitions_list[0] = PARTITIONS-1; + + /* this is erroneous */ + CHECK_RETVAL(MPI_Pready_list(partitions, partitions_list, request)); + /* this will keeping the test from hanging if an error did not occur */ + MPI_Pready(0, request); + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_pready_range0.c b/partitioned-communication/test_pready_range0.c new file mode 100644 index 0000000..5f5bde3 --- /dev/null +++ b/partitioned-communication/test_pready_range0.c @@ -0,0 +1,81 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 110: Definition of MPI_PREADY_RANGE. It is inclusive (line 36) + * + * This test just uses PREADY_RANGE instead of PREADY + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions*/ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + // CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Basic Pready range use case */ + CHECK_RETVAL(MPI_Pready_range(0,partitions-1,request)); + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_startall0.c b/partitioned-communication/test_startall0.c new file mode 100644 index 0000000..d73975f --- /dev/null +++ b/partitioned-communication/test_startall0.c @@ -0,0 +1,160 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * STARTALL should start multiple channels, since it is a generalization of MPI_START. (Section 3.9, pp. 109-110). + * + * This test simply confirms this. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 +#define CHANNELS 3 + +int main(int argc, char *argv[]) { + + int messageA[PARTITIONS*COUNT]; + int messageB[PARTITIONS*COUNT]; + int messageC[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tagA = 1, tagB = 2, tagC = 3, flagA = 0, flagB = 0, flagC = 0, sflag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) { + messageA[i] = 0; + messageB[i] = 0; + messageC[i] = 0; + } + + MPI_Request requests[CHANNELS]; + MPI_Status status; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(messageA, partitions, COUNT, MPI_INT, dest, tagA, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[0])); + CHECK_RETVAL(MPI_Psend_init(messageB, partitions, COUNT, MPI_INT, dest, tagB, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[1])); + CHECK_RETVAL(MPI_Psend_init(messageC, partitions, COUNT, MPI_INT, dest, tagC, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[2])); + + sflag = 0; + MPI_Request_get_status(requests[0], &sflag, &status); + fprintf(stderr, "After send init: request 0: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[1], &sflag, &status); + fprintf(stderr, "After send init: request 1: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[2], &sflag, &status); + fprintf(stderr, "After send init: request 2: %d\n", sflag); + + CHECK_RETVAL(MPI_Startall(CHANNELS, requests)); + + sflag = 0; + MPI_Request_get_status(requests[0], &sflag, &status); + fprintf(stderr, "After startall: request 0: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[1], &sflag, &status); + fprintf(stderr, "After startall: request 1: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[2], &sflag, &status); + fprintf(stderr, "After startall: request 2: %d\n", sflag); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) messageA[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, requests[0])); + for (j = 0; j < COUNT; ++j) messageB[j+(COUNT*i)] = (j+(COUNT*i)) * 10; + CHECK_RETVAL(MPI_Pready(i, requests[1])); + for (j = 0; j < COUNT; ++j) messageC[j+(COUNT*i)] = (j+(COUNT*i)) * 100; + CHECK_RETVAL(MPI_Pready(i, requests[2])); + } + + sflag = 0; + MPI_Request_get_status(requests[0], &sflag, &status); + fprintf(stderr, "After pready: request 0: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[1], &sflag, &status); + fprintf(stderr, "After pready: request 1: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[2], &sflag, &status); + fprintf(stderr, "After pready: request 2: %d\n", sflag); + + + fprintf(stderr, "Rank 0: testing\n"); + + while ( !(flagA && flagB && flagC) ) { + CHECK_RETVAL(MPI_Test(&requests[0], &flagA, MPI_STATUS_IGNORE)); + CHECK_RETVAL(MPI_Test(&requests[1], &flagB, MPI_STATUS_IGNORE)); + CHECK_RETVAL(MPI_Test(&requests[2], &flagC, MPI_STATUS_IGNORE)); + } + + fprintf(stderr, "Rank 1: all flags True\n"); + + MPI_Request_free(&requests[0]); + MPI_Request_free(&requests[1]); + MPI_Request_free(&requests[2]); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(messageA, partitions, COUNT, MPI_INT, source, tagA, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[0])); + CHECK_RETVAL(MPI_Precv_init(messageB, partitions, COUNT, MPI_INT, source, tagB, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[1])); + CHECK_RETVAL(MPI_Precv_init(messageC, partitions, COUNT, MPI_INT, source, tagC, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[2])); + + CHECK_RETVAL(MPI_Startall(CHANNELS, requests)); + + fprintf(stderr, "Rank 1: testing\n"); + while ( !(flagA && flagB && flagC) ) { + CHECK_RETVAL(MPI_Test(&requests[0], &flagA, MPI_STATUS_IGNORE)); + CHECK_RETVAL(MPI_Test(&requests[1], &flagB, MPI_STATUS_IGNORE)); + CHECK_RETVAL(MPI_Test(&requests[2], &flagC, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&requests[0]); + MPI_Request_free(&requests[1]); + MPI_Request_free(&requests[2]); + + fprintf(stderr, "Message A: "); + for (i=0; i< PARTITIONS*COUNT; ++i) fprintf(stderr, "%d ", messageA[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "Message B: "); + for (i=0; i< PARTITIONS*COUNT; ++i) fprintf(stderr, "%d ", messageB[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "Message C: "); + for (i=0; i< PARTITIONS*COUNT; ++i) fprintf(stderr, "%d ", messageC[i]); + fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (messageA[i] != i) { + fprintf(stderr, "ERROR: Contents of buffer messageA do not match contents sent (expected %d, found %d).\n",i,messageA[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + if (messageB[i] != i*10) { + fprintf(stderr, "ERROR: Contents of buffer messageB do not match contents sent (expected %d, found %d).\n",i*10,messageB[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + if (messageC[i] != i*100) { + fprintf(stderr, "ERROR: Contents of buffer messageC do not match contents sent (expected %d, found %d).\n",i*100,messageC[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_state0.c b/partitioned-communication/test_state0.c new file mode 100644 index 0000000..f359d82 --- /dev/null +++ b/partitioned-communication/test_state0.c @@ -0,0 +1,151 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This test is motivated by https://github.com/open-mpi/ompi/issues/12328 + * + * The test confirms that the request status is reset in subsequent rounds using the same Send/Recv channel. + * + * On the sender side, if the request status does not reset with the second call to START, marking partitions + * with PREADY will do nothing, and the TEST/WAIT will automatically succeed with no data having been sent. + * + * On the reciever side, if the request status does not reset with the second call to START, the receiver will + * immediately succeed on TEST/WAIT and then the test will fail when validating the buffer contents (because the + * receiver did not get round 2 data). If the request status is reset, then the test will hang waiting for + * completion. + * + * The test is passed if it runs to completion successfully. + * + */ + +#include "test_common.h" + +#define PARTITIONS 4 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Status status; + + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 1: After PSEND_INIT, request status is: %d\n", flag); + + /* Round 1 */ + MPI_Start(&request); + + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 1: After START, request status is: %d\n", flag); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 1: After PREADY #%d, request status is: %d\n", i, flag); + } + + fprintf(stderr, "Sent in round 1: "); + for (i=0; i < COUNT * PARTITIONS; ++i) fprintf(stderr, " %d", message[i]); + fprintf(stderr, "\n"); + + flag = 0; + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 1: After TEST, request status is: %d\n", flag); + + /* Round 2 */ + MPI_Start(&request); + + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 2: After START, request status is: %d\n", flag); + + /* Fill the sending partitions and mark as ready as each is filled; note data is different than first round */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = 10*(j+(COUNT*i)); + MPI_Pready(i, request); + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 2: After PREADY #%d, request status is: %d\n", i, flag); + } + + fprintf(stderr, "Sent in round 2: "); + for (i=0; i < COUNT * PARTITIONS; ++i) fprintf(stderr, " %d", message[i]); + fprintf(stderr, "\n"); + + flag = 0; + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 2: After TEST, request status is: %d\n", flag); + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + /* Round 1 */ + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + fprintf(stderr, "Received in round 1: "); + for (i=0; i < COUNT * PARTITIONS; ++i) fprintf(stderr, " %d", message[i]); + fprintf(stderr, "\n"); + + /* Round 2 */ + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + fprintf(stderr, "Received in round 2: "); + for (i=0; i < COUNT * PARTITIONS; ++i) fprintf(stderr, " %d", message[i]); + fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != 10*i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",10*i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_wildcard0.c b/partitioned-communication/test_wildcard0.c new file mode 100644 index 0000000..fbf0b67 --- /dev/null +++ b/partitioned-communication/test_wildcard0.c @@ -0,0 +1,79 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This test attempts to use MPI_ANY_SOURCE + * + * P. 118, line 28: Wildcards for source and tag are not allowed. + * + * Expected outcome: Error message + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + /* This call should cause error because of MPI_ANY_SOURCE */ + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_wildcard1.c b/partitioned-communication/test_wildcard1.c new file mode 100644 index 0000000..e6e247e --- /dev/null +++ b/partitioned-communication/test_wildcard1.c @@ -0,0 +1,79 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This test attempts to use MPI_ANY_TAG + * + * P. 118, line 28: Wildcards for source and tag are not allowed. + * + * Expected outcome: Error message + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + /* This call should cause error because of MPI_ANY_TAG */ + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, MPI_ANY_TAG, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_zerocount0.c b/partitioned-communication/test_zerocount0.c new file mode 100644 index 0000000..3b9c232 --- /dev/null +++ b/partitioned-communication/test_zerocount0.c @@ -0,0 +1,79 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * In PSEND_INIT and PRECV_INIT, partitions and count can be zero. + * P. 116, line 19: In PSEND_INIT, partitions is defined as “number of partitions (non-negative integer)” + * P. 116, line 20: In PSEND_INIT, count is defined as “number of elements per partition (non-negative integer)”. + * Same for PRECV_INIT (p. 117, line 27 and p. 117, line 29) + * + * This test confirms nothing goes wrong when both PSEND_INIT and PRECV_INIT use 0 partitions with a > 0 count. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + MPI_Count comm_partitions = 0; // use 0 partitions for init + MPI_Count comm_count = COUNT; // use COUNT partitions for init + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, comm_partitions, comm_count, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + /* Because there are 0 partitions, Pready never gets called */ + for (i = 0; i < comm_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, comm_partitions, comm_count, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_zerocount1.c b/partitioned-communication/test_zerocount1.c new file mode 100644 index 0000000..637200e --- /dev/null +++ b/partitioned-communication/test_zerocount1.c @@ -0,0 +1,79 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * In PSEND_INIT and PRECV_INIT, partitions and count can be zero. + * P. 116, line 19: In PSEND_INIT, partitions is defined as “number of partitions (non-negative integer)” + * P. 116, line 20: In PSEND_INIT, count is defined as “number of elements per partition (non-negative integer)”. + * Same for PRECV_INIT (p. 117, line 27 and p. 117, line 29) + * + * This test confirms nothing goes wrong when both PSEND_INIT and PRECV_INIT use > 0 partitions each with 0 count. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + MPI_Count comm_partitions = PARTITIONS; // use PARTITIONS partitions for init + MPI_Count comm_count = 0; // use 0 partitions for init + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, comm_partitions, comm_count, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + /* There are non-zero partitions, so the message buffer will get filled; however, the message generated by or after PREADY will have a 0 count payload */ + for (i = 0; i < comm_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, comm_partitions, comm_count, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + From c001fd2f24ed686454c25feecbde1d46e4867fc8 Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 14:34:59 -0600 Subject: [PATCH 02/15] fixed conditional expression --- partitioned-communication/test_cancel0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/partitioned-communication/test_cancel0.c b/partitioned-communication/test_cancel0.c index 4a84e82..264c0e5 100644 --- a/partitioned-communication/test_cancel0.c +++ b/partitioned-communication/test_cancel0.c @@ -89,7 +89,7 @@ int main(int argc, char *argv[]) { } MPI_Barrier(MPI_COMM_WORLD); - if (myrank == 0) {TEST_RAN_TO_COMPLETION();} + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} MPI_Finalize (); From 110096a223af5f9603179f8c26f675fcd8896199 Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 14:50:06 -0600 Subject: [PATCH 03/15] removing extra space and fixing tab space size --- partitioned-communication/test_cancel0.c | 2 +- partitioned-communication/test_datatype0.c | 2 +- partitioned-communication/test_datatype1.c | 2 +- partitioned-communication/test_datatype2.c | 2 +- partitioned-communication/test_datatype3.c | 2 +- partitioned-communication/test_datatype4.c | 2 +- partitioned-communication/test_datatype5.c | 2 +- partitioned-communication/test_example1a.c | 2 +- partitioned-communication/test_example1b.c | 2 +- partitioned-communication/test_example2.c | 2 +- partitioned-communication/test_example3a.c | 2 +- partitioned-communication/test_example3b.c | 2 +- partitioned-communication/test_example3c.c | 155 +++++++++--------- partitioned-communication/test_free0.c | 2 +- partitioned-communication/test_init0.c | 2 +- partitioned-communication/test_init1.c | 2 +- partitioned-communication/test_local0.c | 2 +- partitioned-communication/test_local1.c | 2 +- partitioned-communication/test_numparts0.c | 2 +- partitioned-communication/test_numparts1.c | 2 +- partitioned-communication/test_order0.c | 2 +- partitioned-communication/test_parrived0.c | 2 +- partitioned-communication/test_parrived1.c | 2 +- partitioned-communication/test_parrived2.c | 2 +- partitioned-communication/test_partitions0.c | 2 +- partitioned-communication/test_partitions1.c | 2 +- partitioned-communication/test_partitions2.c | 2 +- partitioned-communication/test_partitions3.c | 2 +- partitioned-communication/test_pready0.c | 2 +- partitioned-communication/test_pready1.c | 2 +- partitioned-communication/test_pready2.c | 2 +- partitioned-communication/test_pready3.c | 2 +- partitioned-communication/test_pready4.c | 2 +- partitioned-communication/test_pready_list0.c | 2 +- partitioned-communication/test_pready_list1.c | 2 +- .../test_pready_range0.c | 2 +- partitioned-communication/test_startall0.c | 2 +- partitioned-communication/test_wildcard0.c | 2 +- partitioned-communication/test_wildcard1.c | 2 +- partitioned-communication/test_zerocount0.c | 2 +- partitioned-communication/test_zerocount1.c | 2 +- 41 files changed, 117 insertions(+), 118 deletions(-) diff --git a/partitioned-communication/test_cancel0.c b/partitioned-communication/test_cancel0.c index 264c0e5..2c31fa9 100644 --- a/partitioned-communication/test_cancel0.c +++ b/partitioned-communication/test_cancel0.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype0.c b/partitioned-communication/test_datatype0.c index 63296f5..1c932ff 100644 --- a/partitioned-communication/test_datatype0.c +++ b/partitioned-communication/test_datatype0.c @@ -89,7 +89,7 @@ int main(int argc, char *argv[]) { if (myrank == 0) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype1.c b/partitioned-communication/test_datatype1.c index dd4bc46..03e7578 100644 --- a/partitioned-communication/test_datatype1.c +++ b/partitioned-communication/test_datatype1.c @@ -89,7 +89,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype2.c b/partitioned-communication/test_datatype2.c index cf1023c..ee6b9c2 100644 --- a/partitioned-communication/test_datatype2.c +++ b/partitioned-communication/test_datatype2.c @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype3.c b/partitioned-communication/test_datatype3.c index f6747be..d40a14c 100644 --- a/partitioned-communication/test_datatype3.c +++ b/partitioned-communication/test_datatype3.c @@ -102,7 +102,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype4.c b/partitioned-communication/test_datatype4.c index 1bfd696..ff77c85 100644 --- a/partitioned-communication/test_datatype4.c +++ b/partitioned-communication/test_datatype4.c @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype5.c b/partitioned-communication/test_datatype5.c index f7191aa..5aef3a4 100644 --- a/partitioned-communication/test_datatype5.c +++ b/partitioned-communication/test_datatype5.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example1a.c b/partitioned-communication/test_example1a.c index 1d94db2..740bcb9 100644 --- a/partitioned-communication/test_example1a.c +++ b/partitioned-communication/test_example1a.c @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example1b.c b/partitioned-communication/test_example1b.c index 8603518..1827221 100644 --- a/partitioned-communication/test_example1b.c +++ b/partitioned-communication/test_example1b.c @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example2.c b/partitioned-communication/test_example2.c index c34dbff..fd706f0 100644 --- a/partitioned-communication/test_example2.c +++ b/partitioned-communication/test_example2.c @@ -95,6 +95,6 @@ int main(int argc, char *argv[]) { if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example3a.c b/partitioned-communication/test_example3a.c index 03cb801..270770b 100644 --- a/partitioned-communication/test_example3a.c +++ b/partitioned-communication/test_example3a.c @@ -110,7 +110,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example3b.c b/partitioned-communication/test_example3b.c index f1fecad..7432081 100644 --- a/partitioned-communication/test_example3b.c +++ b/partitioned-communication/test_example3b.c @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example3c.c b/partitioned-communication/test_example3c.c index cccc63b..640e48e 100644 --- a/partitioned-communication/test_example3c.c +++ b/partitioned-communication/test_example3c.c @@ -30,86 +30,85 @@ int main(int argc, char *argv[]) { - int message[MESSAGE_LENGTH]; - int send_partitions = PARTITIONS; - int send_partlength = PARTLENGTH; - int recv_partitions = 1; - int recv_partlength = MESSAGE_LENGTH; - - int count = 1, source = 0, dest = 1, tag = 1, flag = 0; - int i, j; - int myrank; - int provided; - int my_thread_id; - - MPI_Request request; - MPI_Status status; - MPI_Datatype send_type; - MPI_Info info = MPI_INFO_NULL; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); - if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); - MPI_Comm_rank(MPI_COMM_WORLD , &myrank); - - /* Sender uses this datatype */ - MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); - MPI_Type_commit(&send_type); - - if (myrank == 0) { - - for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; - - MPI_Psend_init(message, send_partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); - MPI_Start(&request); - - #pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) - { - #pragma omp single - { - /* single thread creates 64 tasks to be executed by 8 threads */ - for (int task_num=0; task_num < NUM_TASKS; task_num++) { - #pragma omp task firstprivate(task_num) - { - my_thread_id = omp_get_thread_num(); - for (i=0; i < send_partlength; ++i) { - message[i + (task_num * send_partlength)] = i + (task_num * send_partlength); + int message[MESSAGE_LENGTH]; + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Datatype send_type; + MPI_Info info = MPI_INFO_NULL; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) + { +#pragma omp single + { + /* single thread creates 64 tasks to be executed by 8 threads */ + for (int task_num=0; task_num < NUM_TASKS; task_num++) { +#pragma omp task firstprivate(task_num) + { + my_thread_id = omp_get_thread_num(); + for (i=0; i < send_partlength; ++i) { + message[i + (task_num * send_partlength)] = i + (task_num * send_partlength); + } + MPI_Pready(task_num, request); + } /* end task */ + } /* end for */ + } /* end single */ + } /* end parallel */ + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); } - MPI_Pready(task_num, request); - } /* end task */ - } /* end for */ - } /* end single */ - } /* end parallel */ - - while(!flag) { - MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } } - MPI_Request_free(&request); + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - } else if (myrank == 1) { - for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; - - MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); - MPI_Start(&request); - - while(!flag) { - MPI_Test(&request, &flag, MPI_STATUS_IGNORE); - } - - MPI_Request_free(&request); - - /* all partitions received; check contents */ - for (i = 0; i < MESSAGE_LENGTH; ++i) { - if (message[i] != i) { - fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); - MPI_Abort(MPI_COMM_WORLD, 1); - } - } - } - - MPI_Barrier(MPI_COMM_WORLD); - if (myrank == 0) {TEST_RAN_TO_COMPLETION();} - - MPI_Finalize (); - return 0; - + MPI_Finalize(); + return 0; } diff --git a/partitioned-communication/test_free0.c b/partitioned-communication/test_free0.c index 56973af..9b06de3 100644 --- a/partitioned-communication/test_free0.c +++ b/partitioned-communication/test_free0.c @@ -83,7 +83,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_init0.c b/partitioned-communication/test_init0.c index 3b35435..c0b3d45 100644 --- a/partitioned-communication/test_init0.c +++ b/partitioned-communication/test_init0.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_init1.c b/partitioned-communication/test_init1.c index 08d0a55..2cf3401 100644 --- a/partitioned-communication/test_init1.c +++ b/partitioned-communication/test_init1.c @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_local0.c b/partitioned-communication/test_local0.c index 416af73..644caa6 100644 --- a/partitioned-communication/test_local0.c +++ b/partitioned-communication/test_local0.c @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (1 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_local1.c b/partitioned-communication/test_local1.c index 07a3530..9dc5c28 100644 --- a/partitioned-communication/test_local1.c +++ b/partitioned-communication/test_local1.c @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_numparts0.c b/partitioned-communication/test_numparts0.c index 8dc2188..55dc524 100644 --- a/partitioned-communication/test_numparts0.c +++ b/partitioned-communication/test_numparts0.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_numparts1.c b/partitioned-communication/test_numparts1.c index 9638589..605cf38 100644 --- a/partitioned-communication/test_numparts1.c +++ b/partitioned-communication/test_numparts1.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_order0.c b/partitioned-communication/test_order0.c index fd11997..d140e09 100644 --- a/partitioned-communication/test_order0.c +++ b/partitioned-communication/test_order0.c @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_parrived0.c b/partitioned-communication/test_parrived0.c index bac2903..664e267 100644 --- a/partitioned-communication/test_parrived0.c +++ b/partitioned-communication/test_parrived0.c @@ -85,7 +85,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_parrived1.c b/partitioned-communication/test_parrived1.c index 8e9f73f..300618a 100644 --- a/partitioned-communication/test_parrived1.c +++ b/partitioned-communication/test_parrived1.c @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_parrived2.c b/partitioned-communication/test_parrived2.c index 409e20e..0b2ff46 100644 --- a/partitioned-communication/test_parrived2.c +++ b/partitioned-communication/test_parrived2.c @@ -67,7 +67,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_partitions0.c b/partitioned-communication/test_partitions0.c index b33dc1c..fc7457d 100644 --- a/partitioned-communication/test_partitions0.c +++ b/partitioned-communication/test_partitions0.c @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_partitions1.c b/partitioned-communication/test_partitions1.c index 2f5a152..ef66120 100644 --- a/partitioned-communication/test_partitions1.c +++ b/partitioned-communication/test_partitions1.c @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_partitions2.c b/partitioned-communication/test_partitions2.c index 920b1c7..053ae32 100644 --- a/partitioned-communication/test_partitions2.c +++ b/partitioned-communication/test_partitions2.c @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_partitions3.c b/partitioned-communication/test_partitions3.c index 8f03a94..dea2ba8 100644 --- a/partitioned-communication/test_partitions3.c +++ b/partitioned-communication/test_partitions3.c @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready0.c b/partitioned-communication/test_pready0.c index 8d4c57b..ec2bbf0 100644 --- a/partitioned-communication/test_pready0.c +++ b/partitioned-communication/test_pready0.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready1.c b/partitioned-communication/test_pready1.c index f02903b..8d657f2 100644 --- a/partitioned-communication/test_pready1.c +++ b/partitioned-communication/test_pready1.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready2.c b/partitioned-communication/test_pready2.c index 134fc98..913bec9 100644 --- a/partitioned-communication/test_pready2.c +++ b/partitioned-communication/test_pready2.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready3.c b/partitioned-communication/test_pready3.c index e4ecae2..7b24394 100644 --- a/partitioned-communication/test_pready3.c +++ b/partitioned-communication/test_pready3.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready4.c b/partitioned-communication/test_pready4.c index d4437bf..309cdca 100644 --- a/partitioned-communication/test_pready4.c +++ b/partitioned-communication/test_pready4.c @@ -54,7 +54,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready_list0.c b/partitioned-communication/test_pready_list0.c index ce9e2f2..6bed784 100644 --- a/partitioned-communication/test_pready_list0.c +++ b/partitioned-communication/test_pready_list0.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready_list1.c b/partitioned-communication/test_pready_list1.c index 6790fca..0750b8f 100644 --- a/partitioned-communication/test_pready_list1.c +++ b/partitioned-communication/test_pready_list1.c @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready_range0.c b/partitioned-communication/test_pready_range0.c index 5f5bde3..61ead3b 100644 --- a/partitioned-communication/test_pready_range0.c +++ b/partitioned-communication/test_pready_range0.c @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_startall0.c b/partitioned-communication/test_startall0.c index d73975f..41a0ad7 100644 --- a/partitioned-communication/test_startall0.c +++ b/partitioned-communication/test_startall0.c @@ -153,7 +153,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_wildcard0.c b/partitioned-communication/test_wildcard0.c index fbf0b67..6853dbc 100644 --- a/partitioned-communication/test_wildcard0.c +++ b/partitioned-communication/test_wildcard0.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_wildcard1.c b/partitioned-communication/test_wildcard1.c index e6e247e..52bbd58 100644 --- a/partitioned-communication/test_wildcard1.c +++ b/partitioned-communication/test_wildcard1.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_zerocount0.c b/partitioned-communication/test_zerocount0.c index 3b9c232..9e6dfcf 100644 --- a/partitioned-communication/test_zerocount0.c +++ b/partitioned-communication/test_zerocount0.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_zerocount1.c b/partitioned-communication/test_zerocount1.c index 637200e..aff5327 100644 --- a/partitioned-communication/test_zerocount1.c +++ b/partitioned-communication/test_zerocount1.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } From e274c00cfdab378d805dba893e88495bfe0a2ae5 Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 15:06:09 -0600 Subject: [PATCH 04/15] Empty commit to add signoff Signed-off-by: Whit Schonbein From 758fb69a43cc105cff279a9ecf50815a596d0a30 Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 15:06:09 -0600 Subject: [PATCH 05/15] Empty commit to add signoff Signed-off-by: Whit Schonbein From 650470b9ceb6f00dcf96a049d363cad34d7a45e1 Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 14:34:59 -0600 Subject: [PATCH 06/15] fixed conditional expression Signed-off-by: Whit Schonbein --- partitioned-communication/test_cancel0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/partitioned-communication/test_cancel0.c b/partitioned-communication/test_cancel0.c index 4a84e82..264c0e5 100644 --- a/partitioned-communication/test_cancel0.c +++ b/partitioned-communication/test_cancel0.c @@ -89,7 +89,7 @@ int main(int argc, char *argv[]) { } MPI_Barrier(MPI_COMM_WORLD); - if (myrank == 0) {TEST_RAN_TO_COMPLETION();} + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} MPI_Finalize (); From 9e33104c5c94e2e809f8eda03ed289f1e113f8be Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 14:50:06 -0600 Subject: [PATCH 07/15] removing extra space and fixing tab space size Signed-off-by: Whit Schonbein --- partitioned-communication/test_cancel0.c | 2 +- partitioned-communication/test_datatype0.c | 2 +- partitioned-communication/test_datatype1.c | 2 +- partitioned-communication/test_datatype2.c | 2 +- partitioned-communication/test_datatype3.c | 2 +- partitioned-communication/test_datatype4.c | 2 +- partitioned-communication/test_datatype5.c | 2 +- partitioned-communication/test_example1a.c | 2 +- partitioned-communication/test_example1b.c | 2 +- partitioned-communication/test_example2.c | 2 +- partitioned-communication/test_example3a.c | 2 +- partitioned-communication/test_example3b.c | 2 +- partitioned-communication/test_example3c.c | 155 +++++++++--------- partitioned-communication/test_free0.c | 2 +- partitioned-communication/test_init0.c | 2 +- partitioned-communication/test_init1.c | 2 +- partitioned-communication/test_local0.c | 2 +- partitioned-communication/test_local1.c | 2 +- partitioned-communication/test_numparts0.c | 2 +- partitioned-communication/test_numparts1.c | 2 +- partitioned-communication/test_order0.c | 2 +- partitioned-communication/test_parrived0.c | 2 +- partitioned-communication/test_parrived1.c | 2 +- partitioned-communication/test_parrived2.c | 2 +- partitioned-communication/test_partitions0.c | 2 +- partitioned-communication/test_partitions1.c | 2 +- partitioned-communication/test_partitions2.c | 2 +- partitioned-communication/test_partitions3.c | 2 +- partitioned-communication/test_pready0.c | 2 +- partitioned-communication/test_pready1.c | 2 +- partitioned-communication/test_pready2.c | 2 +- partitioned-communication/test_pready3.c | 2 +- partitioned-communication/test_pready4.c | 2 +- partitioned-communication/test_pready_list0.c | 2 +- partitioned-communication/test_pready_list1.c | 2 +- .../test_pready_range0.c | 2 +- partitioned-communication/test_startall0.c | 2 +- partitioned-communication/test_wildcard0.c | 2 +- partitioned-communication/test_wildcard1.c | 2 +- partitioned-communication/test_zerocount0.c | 2 +- partitioned-communication/test_zerocount1.c | 2 +- 41 files changed, 117 insertions(+), 118 deletions(-) diff --git a/partitioned-communication/test_cancel0.c b/partitioned-communication/test_cancel0.c index 264c0e5..2c31fa9 100644 --- a/partitioned-communication/test_cancel0.c +++ b/partitioned-communication/test_cancel0.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype0.c b/partitioned-communication/test_datatype0.c index 63296f5..1c932ff 100644 --- a/partitioned-communication/test_datatype0.c +++ b/partitioned-communication/test_datatype0.c @@ -89,7 +89,7 @@ int main(int argc, char *argv[]) { if (myrank == 0) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype1.c b/partitioned-communication/test_datatype1.c index dd4bc46..03e7578 100644 --- a/partitioned-communication/test_datatype1.c +++ b/partitioned-communication/test_datatype1.c @@ -89,7 +89,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype2.c b/partitioned-communication/test_datatype2.c index cf1023c..ee6b9c2 100644 --- a/partitioned-communication/test_datatype2.c +++ b/partitioned-communication/test_datatype2.c @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype3.c b/partitioned-communication/test_datatype3.c index f6747be..d40a14c 100644 --- a/partitioned-communication/test_datatype3.c +++ b/partitioned-communication/test_datatype3.c @@ -102,7 +102,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype4.c b/partitioned-communication/test_datatype4.c index 1bfd696..ff77c85 100644 --- a/partitioned-communication/test_datatype4.c +++ b/partitioned-communication/test_datatype4.c @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_datatype5.c b/partitioned-communication/test_datatype5.c index f7191aa..5aef3a4 100644 --- a/partitioned-communication/test_datatype5.c +++ b/partitioned-communication/test_datatype5.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example1a.c b/partitioned-communication/test_example1a.c index 1d94db2..740bcb9 100644 --- a/partitioned-communication/test_example1a.c +++ b/partitioned-communication/test_example1a.c @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example1b.c b/partitioned-communication/test_example1b.c index 8603518..1827221 100644 --- a/partitioned-communication/test_example1b.c +++ b/partitioned-communication/test_example1b.c @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example2.c b/partitioned-communication/test_example2.c index c34dbff..fd706f0 100644 --- a/partitioned-communication/test_example2.c +++ b/partitioned-communication/test_example2.c @@ -95,6 +95,6 @@ int main(int argc, char *argv[]) { if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example3a.c b/partitioned-communication/test_example3a.c index 03cb801..270770b 100644 --- a/partitioned-communication/test_example3a.c +++ b/partitioned-communication/test_example3a.c @@ -110,7 +110,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example3b.c b/partitioned-communication/test_example3b.c index f1fecad..7432081 100644 --- a/partitioned-communication/test_example3b.c +++ b/partitioned-communication/test_example3b.c @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_example3c.c b/partitioned-communication/test_example3c.c index cccc63b..640e48e 100644 --- a/partitioned-communication/test_example3c.c +++ b/partitioned-communication/test_example3c.c @@ -30,86 +30,85 @@ int main(int argc, char *argv[]) { - int message[MESSAGE_LENGTH]; - int send_partitions = PARTITIONS; - int send_partlength = PARTLENGTH; - int recv_partitions = 1; - int recv_partlength = MESSAGE_LENGTH; - - int count = 1, source = 0, dest = 1, tag = 1, flag = 0; - int i, j; - int myrank; - int provided; - int my_thread_id; - - MPI_Request request; - MPI_Status status; - MPI_Datatype send_type; - MPI_Info info = MPI_INFO_NULL; - MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); - if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); - MPI_Comm_rank(MPI_COMM_WORLD , &myrank); - - /* Sender uses this datatype */ - MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); - MPI_Type_commit(&send_type); - - if (myrank == 0) { - - for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; - - MPI_Psend_init(message, send_partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); - MPI_Start(&request); - - #pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) - { - #pragma omp single - { - /* single thread creates 64 tasks to be executed by 8 threads */ - for (int task_num=0; task_num < NUM_TASKS; task_num++) { - #pragma omp task firstprivate(task_num) - { - my_thread_id = omp_get_thread_num(); - for (i=0; i < send_partlength; ++i) { - message[i + (task_num * send_partlength)] = i + (task_num * send_partlength); + int message[MESSAGE_LENGTH]; + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Datatype send_type; + MPI_Info info = MPI_INFO_NULL; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) + { +#pragma omp single + { + /* single thread creates 64 tasks to be executed by 8 threads */ + for (int task_num=0; task_num < NUM_TASKS; task_num++) { +#pragma omp task firstprivate(task_num) + { + my_thread_id = omp_get_thread_num(); + for (i=0; i < send_partlength; ++i) { + message[i + (task_num * send_partlength)] = i + (task_num * send_partlength); + } + MPI_Pready(task_num, request); + } /* end task */ + } /* end for */ + } /* end single */ + } /* end parallel */ + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); } - MPI_Pready(task_num, request); - } /* end task */ - } /* end for */ - } /* end single */ - } /* end parallel */ - - while(!flag) { - MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } } - MPI_Request_free(&request); + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - } else if (myrank == 1) { - for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; - - MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); - MPI_Start(&request); - - while(!flag) { - MPI_Test(&request, &flag, MPI_STATUS_IGNORE); - } - - MPI_Request_free(&request); - - /* all partitions received; check contents */ - for (i = 0; i < MESSAGE_LENGTH; ++i) { - if (message[i] != i) { - fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); - MPI_Abort(MPI_COMM_WORLD, 1); - } - } - } - - MPI_Barrier(MPI_COMM_WORLD); - if (myrank == 0) {TEST_RAN_TO_COMPLETION();} - - MPI_Finalize (); - return 0; - + MPI_Finalize(); + return 0; } diff --git a/partitioned-communication/test_free0.c b/partitioned-communication/test_free0.c index 56973af..9b06de3 100644 --- a/partitioned-communication/test_free0.c +++ b/partitioned-communication/test_free0.c @@ -83,7 +83,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_init0.c b/partitioned-communication/test_init0.c index 3b35435..c0b3d45 100644 --- a/partitioned-communication/test_init0.c +++ b/partitioned-communication/test_init0.c @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_init1.c b/partitioned-communication/test_init1.c index 08d0a55..2cf3401 100644 --- a/partitioned-communication/test_init1.c +++ b/partitioned-communication/test_init1.c @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_local0.c b/partitioned-communication/test_local0.c index 416af73..644caa6 100644 --- a/partitioned-communication/test_local0.c +++ b/partitioned-communication/test_local0.c @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (1 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_local1.c b/partitioned-communication/test_local1.c index 07a3530..9dc5c28 100644 --- a/partitioned-communication/test_local1.c +++ b/partitioned-communication/test_local1.c @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_numparts0.c b/partitioned-communication/test_numparts0.c index 8dc2188..55dc524 100644 --- a/partitioned-communication/test_numparts0.c +++ b/partitioned-communication/test_numparts0.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_numparts1.c b/partitioned-communication/test_numparts1.c index 9638589..605cf38 100644 --- a/partitioned-communication/test_numparts1.c +++ b/partitioned-communication/test_numparts1.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_order0.c b/partitioned-communication/test_order0.c index fd11997..d140e09 100644 --- a/partitioned-communication/test_order0.c +++ b/partitioned-communication/test_order0.c @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_parrived0.c b/partitioned-communication/test_parrived0.c index bac2903..664e267 100644 --- a/partitioned-communication/test_parrived0.c +++ b/partitioned-communication/test_parrived0.c @@ -85,7 +85,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_parrived1.c b/partitioned-communication/test_parrived1.c index 8e9f73f..300618a 100644 --- a/partitioned-communication/test_parrived1.c +++ b/partitioned-communication/test_parrived1.c @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_parrived2.c b/partitioned-communication/test_parrived2.c index 409e20e..0b2ff46 100644 --- a/partitioned-communication/test_parrived2.c +++ b/partitioned-communication/test_parrived2.c @@ -67,7 +67,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_partitions0.c b/partitioned-communication/test_partitions0.c index b33dc1c..fc7457d 100644 --- a/partitioned-communication/test_partitions0.c +++ b/partitioned-communication/test_partitions0.c @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_partitions1.c b/partitioned-communication/test_partitions1.c index 2f5a152..ef66120 100644 --- a/partitioned-communication/test_partitions1.c +++ b/partitioned-communication/test_partitions1.c @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_partitions2.c b/partitioned-communication/test_partitions2.c index 920b1c7..053ae32 100644 --- a/partitioned-communication/test_partitions2.c +++ b/partitioned-communication/test_partitions2.c @@ -71,7 +71,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_partitions3.c b/partitioned-communication/test_partitions3.c index 8f03a94..dea2ba8 100644 --- a/partitioned-communication/test_partitions3.c +++ b/partitioned-communication/test_partitions3.c @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready0.c b/partitioned-communication/test_pready0.c index 8d4c57b..ec2bbf0 100644 --- a/partitioned-communication/test_pready0.c +++ b/partitioned-communication/test_pready0.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready1.c b/partitioned-communication/test_pready1.c index f02903b..8d657f2 100644 --- a/partitioned-communication/test_pready1.c +++ b/partitioned-communication/test_pready1.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready2.c b/partitioned-communication/test_pready2.c index 134fc98..913bec9 100644 --- a/partitioned-communication/test_pready2.c +++ b/partitioned-communication/test_pready2.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready3.c b/partitioned-communication/test_pready3.c index e4ecae2..7b24394 100644 --- a/partitioned-communication/test_pready3.c +++ b/partitioned-communication/test_pready3.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready4.c b/partitioned-communication/test_pready4.c index d4437bf..309cdca 100644 --- a/partitioned-communication/test_pready4.c +++ b/partitioned-communication/test_pready4.c @@ -54,7 +54,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready_list0.c b/partitioned-communication/test_pready_list0.c index ce9e2f2..6bed784 100644 --- a/partitioned-communication/test_pready_list0.c +++ b/partitioned-communication/test_pready_list0.c @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready_list1.c b/partitioned-communication/test_pready_list1.c index 6790fca..0750b8f 100644 --- a/partitioned-communication/test_pready_list1.c +++ b/partitioned-communication/test_pready_list1.c @@ -79,7 +79,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_pready_range0.c b/partitioned-communication/test_pready_range0.c index 5f5bde3..61ead3b 100644 --- a/partitioned-communication/test_pready_range0.c +++ b/partitioned-communication/test_pready_range0.c @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_startall0.c b/partitioned-communication/test_startall0.c index d73975f..41a0ad7 100644 --- a/partitioned-communication/test_startall0.c +++ b/partitioned-communication/test_startall0.c @@ -153,7 +153,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_wildcard0.c b/partitioned-communication/test_wildcard0.c index fbf0b67..6853dbc 100644 --- a/partitioned-communication/test_wildcard0.c +++ b/partitioned-communication/test_wildcard0.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_wildcard1.c b/partitioned-communication/test_wildcard1.c index e6e247e..52bbd58 100644 --- a/partitioned-communication/test_wildcard1.c +++ b/partitioned-communication/test_wildcard1.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_zerocount0.c b/partitioned-communication/test_zerocount0.c index 3b9c232..9e6dfcf 100644 --- a/partitioned-communication/test_zerocount0.c +++ b/partitioned-communication/test_zerocount0.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } diff --git a/partitioned-communication/test_zerocount1.c b/partitioned-communication/test_zerocount1.c index 637200e..aff5327 100644 --- a/partitioned-communication/test_zerocount1.c +++ b/partitioned-communication/test_zerocount1.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { MPI_Barrier(MPI_COMM_WORLD); if (0 == myrank) {TEST_RAN_TO_COMPLETION();} - MPI_Finalize (); + MPI_Finalize(); return 0; } From 79a1abfaf492309a7f5ed14cfa615bc8091b5707 Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 15:06:09 -0600 Subject: [PATCH 08/15] Empty commit to add signoff Signed-off-by: Whit Schonbein From c5e01dcec5eb7d49da36fd9ef8ad8b7cbdfc6c7e Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 15:06:09 -0600 Subject: [PATCH 09/15] Empty commit to add signoff Signed-off-by: Whit Schonbein From 415704269eab0ff6e9aab4e788902d5667b442eb Mon Sep 17 00:00:00 2001 From: Joshua Hursey Date: Mon, 22 Aug 2022 18:01:26 -0400 Subject: [PATCH 10/15] Extend MPI_COMM_TYPE_HW_GUIDED test to include MPI_UNDEFINED Signed-off-by: Joshua Hursey --- comm_split_type/cmsplit_type.c | 56 ++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/comm_split_type/cmsplit_type.c b/comm_split_type/cmsplit_type.c index e1426aa..19f6a8d 100644 --- a/comm_split_type/cmsplit_type.c +++ b/comm_split_type/cmsplit_type.c @@ -51,6 +51,8 @@ int main(int argc, char *argv[]) MPI_Comm comm; MPI_Info info; int ret; + int value = 0; + int expected_value = 3; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &mcw_rank); @@ -181,6 +183,60 @@ int main(int argc, char *argv[]) sync_hr(); + /* + * Test MPI_COMM_TYPE_HW_GUIDED: + * - Test with "mpi_hw_resource_type" = "mpi_shared_memory" + * - Mix in some MPI_UNDEFINED values to make sure those are handled properly + */ + expected_value = 3; + if (expected_value > mcw_size) { + expected_value = mcw_size; + } + MPI_Info_create(&info); + MPI_Info_set(info, "mpi_hw_resource_type", "mpi_shared_memory"); + if (mcw_rank == 0 && verbose) { + printf("MPI_COMM_TYPE_HW_GUIDED: Trying MPI Standard value %s with some MPI_UNDEFINED\n", "mpi_shared_memory"); + } + if (mcw_rank < expected_value) { + ret = MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_HW_GUIDED, 0, info, &comm); + } else { + ret = MPI_Comm_split_type(MPI_COMM_WORLD, MPI_UNDEFINED, 0, info, &comm); + } + if (ret != MPI_SUCCESS) { + printf("MPI_COMM_TYPE_HW_GUIDED (%s) failed\n", split_topo[i]); + errs++; + } else if (comm != MPI_COMM_NULL) { + MPI_Comm_rank(comm, &rank); + MPI_Comm_size(comm, &size); + value = 1; + if (rank == 0 && verbose) { + printf("MPI_COMM_TYPE_HW_GUIDED (%s): %d/%d Created shared subcommunicator of size %d\n", + "mpi_shared_memory", mcw_rank, mcw_size, size); + } + MPI_Comm_free(&comm); + } else if (verbose) { + value = 0; + printf("MPI_COMM_TYPE_HW_GUIDED (%s): %d/%d Returned MPI_COMM_NULL\n", + "mpi_shared_memory", mcw_rank, mcw_size); + } + MPI_Info_free(&info); + + if (mcw_rank == 0) { + MPI_Reduce(MPI_IN_PLACE, &value, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); + if (expected_value != value) { + printf("MPI_COMM_TYPE_HW_GUIDED (%s): Failed: Verify expected %d == actual %d\n", + "mpi_shared_memory", expected_value, value); + } else if (verbose) { + printf("MPI_COMM_TYPE_HW_GUIDED (%s): Passed: Verify expected %d == actual %d\n", + "mpi_shared_memory", expected_value, value); + } + } else { + MPI_Reduce(&value, NULL, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); + } + MPI_Barrier(MPI_COMM_WORLD); + + sync_hr(); + /* * Test MPI_COMM_TYPE_HW_GUIDED: * - info with correct key, but different values a different ranks, it must throw an error From 884779d0763f3a00abdc1b460b492ccdee32eae3 Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Fri, 30 Sep 2022 08:07:50 -0400 Subject: [PATCH 11/15] Add Github Action for checking PR git commits Signed-off-by: Jeff Squyres --- .github/workflows/pr-checks.yaml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/pr-checks.yaml diff --git a/.github/workflows/pr-checks.yaml b/.github/workflows/pr-checks.yaml new file mode 100644 index 0000000..4dbe4fb --- /dev/null +++ b/.github/workflows/pr-checks.yaml @@ -0,0 +1,28 @@ +name: GitHub Action CI + +# We're using pull_request_target here instead of just pull_request so that the +# action runs in the context of the base of the pull request, rather than in the +# context of the merge commit. For more detail about the differences, see: +# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target +on: + pull_request_target: + # We don't need this to be run on all types of PR behavior + # See https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request + types: + - opened + - synchronize + - edited + +permissions: {} # none + +jobs: + check: + permissions: + pull-requests: write + name: Check Commits + runs-on: ubuntu-latest + steps: + - name: Pull Request Commit Checker + uses: open-mpi/pr-git-commit-checker@v1.0.0 + with: + token: "${{ secrets.GITHUB_TOKEN}}" From 6f767517681041f14b79c89c683186dcd77dcd6f Mon Sep 17 00:00:00 2001 From: David Wootton Date: Mon, 19 Sep 2022 14:28:55 -0400 Subject: [PATCH 12/15] Update cmsplit_type.c to add tests for communicator unguided split case Remove stray #if 0 Signed-off-by: David Wootton --- comm_split_type/cmsplit_type.c | 137 ++++++++++++++++++++++++++++++--- 1 file changed, 127 insertions(+), 10 deletions(-) diff --git a/comm_split_type/cmsplit_type.c b/comm_split_type/cmsplit_type.c index 19f6a8d..02a8693 100644 --- a/comm_split_type/cmsplit_type.c +++ b/comm_split_type/cmsplit_type.c @@ -11,6 +11,8 @@ #include #include +#define MAX_NUM_LEVELS 32 + static const char *split_topo[] = { "mpi_shared_memory", "hwthread", @@ -53,6 +55,12 @@ int main(int argc, char *argv[]) int ret; int value = 0; int expected_value = 3; + MPI_Comm hwcomm[MAX_NUM_LEVELS]; + int level_num = 0; + char resource_type[100] = ""; + int has_key = 0; + int old_size; + int new_size, new_rank; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &mcw_rank); @@ -236,7 +244,7 @@ int main(int argc, char *argv[]) MPI_Barrier(MPI_COMM_WORLD); sync_hr(); - + /* * Test MPI_COMM_TYPE_HW_GUIDED: * - info with correct key, but different values a different ranks, it must throw an error @@ -293,34 +301,143 @@ int main(int argc, char *argv[]) #endif /* Test MPI_COMM_TYPE_HW_UNGUIDED: - * - TODO + * - Simple single iteration */ -#if 0 - if (mcw_rank == 0 && verbose) + if (mcw_rank == 0 && verbose) { printf("MPI_COMM_TYPE_HW_UNGUIDED: Trying basic\n"); + } MPI_Info_create(&info); MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_HW_UNGUIDED, 0, info, &comm); if (comm != MPI_COMM_NULL) { - int newsize; - MPI_Comm_size(comm, &newsize); - if (!(newsize < mcw_size)) { + resource_type[0] = '\0'; + has_key = 0; + + MPI_Comm_size(comm, &new_size); + MPI_Comm_rank(comm, &new_rank); + if (!(new_size < mcw_size)) { printf("MPI_COMM_TYPE_HW_UNGUIDED: Expected comm to be a proper sub communicator\n"); errs++; } - char resource_type[100] = ""; - int has_key = 0; MPI_Info_get(info, "mpi_hw_resource_type", 100, resource_type, &has_key); if (!has_key || strlen(resource_type) == 0) { printf("MPI_COMM_TYPE_HW_UNGUIDED: info for mpi_hw_resource_type not returned\n"); errs++; } + if (new_rank == 0 && verbose) { + printf("MPI_COMM_TYPE_HW_UNGUIDED (%s): %d/%d -> %d/%d Created shared subcommunicator\n", + resource_type, mcw_rank, mcw_size, new_rank, new_size); + } + MPI_Comm_free(&comm); } else if (mcw_rank == 0 && verbose) { printf("MPI_COMM_TYPE_HW_UNGUIDED: Returned MPI_COMM_NULL\n"); } -#endif + MPI_Barrier(MPI_COMM_WORLD); + + sync_hr(); + + /* Test MPI_COMM_TYPE_HW_UNGUIDED: + * - Loop until all are NULL + * Example 7.4 from MPI 4.0 standard + */ + hwcomm[level_num] = MPI_COMM_WORLD; + + while((hwcomm[level_num] != MPI_COMM_NULL) && (level_num < MAX_NUM_LEVELS-1)) { + MPI_Comm_rank(hwcomm[level_num], &rank); + if (rank == 0 && verbose) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: (iter = %d) %d/%d Trying loop\n", level_num, mcw_rank, mcw_size); + } + MPI_Info_create(&info); + MPI_Comm_split_type(hwcomm[level_num], + MPI_COMM_TYPE_HW_UNGUIDED, + rank, info, &hwcomm[level_num+1]); + if (hwcomm[level_num+1] == MPI_COMM_NULL) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: (iter = %d) %d/%d Returned MPI_COMM_NULL\n", level_num, mcw_rank, mcw_size); + } else if (hwcomm[level_num+1] == MPI_COMM_SELF) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: (iter = %d) %d/%d Returned MPI_COMM_SELF\n", level_num, mcw_rank, mcw_size); + } else { + MPI_Comm_rank(hwcomm[level_num+1], &rank); + MPI_Comm_size(hwcomm[level_num], &old_size); + MPI_Comm_size(hwcomm[level_num+1], &size); + if (!(size < old_size)) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: Expected comm to be a proper sub communicator\n"); + errs++; + } + resource_type[0] = '\0'; + has_key = 0; + MPI_Info_get(info, "mpi_hw_resource_type", 100, resource_type, &has_key); + if (!has_key || strlen(resource_type) == 0) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: info for mpi_hw_resource_type not returned\n"); + errs++; + } + + if (rank == 0 && verbose) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: (iter = %d) %d/%d -> %d/%d Returned subcommunicator of (%s)\n", + level_num, + mcw_rank, mcw_size, rank, size, + resource_type); + } + } + level_num++; + } + MPI_Barrier(MPI_COMM_WORLD); + + sync_hr(); + + /* + * Test MPI_COMM_TYPE_HW_UNGUIDED: + * - Single step + * - Mix in some MPI_UNDEFINED values to make sure those are handled properly + */ + expected_value = 3; + if (expected_value > mcw_size) { + expected_value = mcw_size; + } + MPI_Info_create(&info); + if (mcw_rank == 0 && verbose) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: Trying MPI Standard value %s with some MPI_UNDEFINED\n", "mpi_shared_memory"); + } + if (mcw_rank < expected_value) { + ret = MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_HW_UNGUIDED, 0, info, &comm); + } else { + ret = MPI_Comm_split_type(MPI_COMM_WORLD, MPI_UNDEFINED, 0, info, &comm); + } + if (ret != MPI_SUCCESS) { + printf("MPI_COMM_TYPE_HW_UNGUIDED (%s) failed\n", split_topo[i]); + errs++; + } else if (comm != MPI_COMM_NULL) { + resource_type[0] = '\0'; + has_key = 0; + + MPI_Comm_rank(comm, &rank); + MPI_Comm_size(comm, &new_size); + if (!(new_size < mcw_size)) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: Expected comm to be a proper sub communicator\n"); + errs++; + } + MPI_Info_get(info, "mpi_hw_resource_type", 100, resource_type, &has_key); + if (!has_key || strlen(resource_type) == 0) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: info for mpi_hw_resource_type not returned\n"); + errs++; + } + if (rank == 0 && verbose) { + printf("MPI_COMM_TYPE_HW_UNGUIDED: %d/%d -> %d/%d Created shared subcommunicator of (%s)\n", + mcw_rank, mcw_size, rank, new_size, resource_type); + } + MPI_Comm_free(&comm); + value = 1; + } else if (verbose) { + value = 0; + printf("MPI_COMM_TYPE_HW_UNGUIDED: %d/%d Returned MPI_COMM_NULL\n", + mcw_rank, mcw_size); + } + MPI_Info_free(&info); + + MPI_Barrier(MPI_COMM_WORLD); + + sync_hr(); /* * All done - figure out if we passed From 71942cbf6dda4eb88438d07234a787cc63557277 Mon Sep 17 00:00:00 2001 From: Joshua Hursey Date: Mon, 20 Feb 2023 14:15:30 -0600 Subject: [PATCH 13/15] Runtime Testing harness Signed-off-by: Joshua Hursey --- runtime/.ci-configure | 15 ++++++ runtime/.ci-tests | 2 + runtime/README.md | 41 ++++++++++++++ runtime/bin/cleanup-scrub-local.sh | 30 +++++++++++ runtime/bin/cleanup.sh | 62 +++++++++++++++++++++ runtime/hello_world/build.sh | 19 +++++++ runtime/hello_world/run.sh | 87 ++++++++++++++++++++++++++++++ 7 files changed, 256 insertions(+) create mode 100644 runtime/.ci-configure create mode 100644 runtime/.ci-tests create mode 100644 runtime/README.md create mode 100755 runtime/bin/cleanup-scrub-local.sh create mode 100755 runtime/bin/cleanup.sh create mode 100755 runtime/hello_world/build.sh create mode 100755 runtime/hello_world/run.sh diff --git a/runtime/.ci-configure b/runtime/.ci-configure new file mode 100644 index 0000000..41f3b20 --- /dev/null +++ b/runtime/.ci-configure @@ -0,0 +1,15 @@ +# +# Open MPI is built with the following options: +# ./configure --prefix=/opt/ci/support/exports/ompi --disable-cuda --disable-nvml --with-cuda=no --without-hcoll +# +# Additional options can be added by listing them. +# Options can be listed as either: +# - One option per line +# - Multiple options per line +# Note: Line continutions are not supported +# +# Enable Debug +--enable-debug +# With Python Bindings +# Need to install Cython on the CI machine +#--enable-python-bindings diff --git a/runtime/.ci-tests b/runtime/.ci-tests new file mode 100644 index 0000000..70822a6 --- /dev/null +++ b/runtime/.ci-tests @@ -0,0 +1,2 @@ +# Start with the basics +hello_world diff --git a/runtime/README.md b/runtime/README.md new file mode 100644 index 0000000..5cf648e --- /dev/null +++ b/runtime/README.md @@ -0,0 +1,41 @@ +# Test suite for Open MPI runtime + +This test suite is meant to be able to be run stand-alone or under CI. + +All of the tests that are intended for CI must be listed in the `.ci-tests` file. + +If the Open MPI build needs additional `configure` options those can be added to the `.ci-configure` file. + +## Running tests stand alone + + 1. Make sure that Open MPI and other required libraries are in your `PATH`/`LD_LIBRARY_PATH` + 2. Drop into a directory: + - Use the `build.sh` script to build any test articles + - Use the `run.sh` script to run the test program + + +## CI Environment Variables + +The CI infrastructure defines the following environment variables to be used in the test programs. These are defined during the `run.sh` phase and not the `build.sh` phase. + + * `CI_HOSTFILE` : Absolute path to the hostfile for this run. + * `CI_NUM_NODES` : Number of nodes in this cluster. + * `CI_OMPI_SRC` : top level directory of the Open MPI repository checkout. + * `CI_OMPI_TESTS_PUBLIC_DIR` : Top level directory of the [Open MPI Public Test](https://github.com/open-mpi/ompi-tests-public) repository checkout + * `OMPI_ROOT` : Open MPI install directory. + + +### Adding a new test for CI + + 1. Create a directory with your test. + - **Note**: Please make your test scripts such that they can be easily run with or without the CI environment variables. + 2. Create a build script named `build.sh` + - CI will call this exactly one time (with a timeout in case it hangs). + - If the script returns `0` then it is considered successful. Otherwise it is considered failed. + 3. Create a run script named `run.sh` + - The script is responsible for running your test including any runtime setup/shutdown and test result inspection. + - CI will call this exactly one time (with a timeout in case it hangs). + - If the script returns `0` then it is considered successful. Otherwise it is considered failed. + 4. Add your directory name to the `.ci-tests` file in this directory in the order that they should be executed. + - Note that adding the directory is not sufficient to have CI run the test, it must be in the file. + - Comments (starting with `#`) are allowed. diff --git a/runtime/bin/cleanup-scrub-local.sh b/runtime/bin/cleanup-scrub-local.sh new file mode 100755 index 0000000..533a3e2 --- /dev/null +++ b/runtime/bin/cleanup-scrub-local.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +PROGS="prte prted prun mpirun timeout" + +clean_files() +{ + FILES=("pmix-*" "core*" "openmpi-sessions-*" "pmix_dstor_*" "ompi.*" "prrte.*" ) + + for fn in ${FILES[@]}; do + find /tmp/ -maxdepth 1 \ + -user $USER -a \ + -name $fn \ + -exec rm -rf {} \; + + if [ -n "$TMPDIR" ] ; then + find $TMPDIR -maxdepth 1 \ + -user $USER -a \ + -name $fn \ + -exec rm -rf {} \; + fi + done +} + +killall -q ${PROGS} > /dev/null +clean_files +killall -q -9 ${PROGS} > /dev/null + +exit 0 + + diff --git a/runtime/bin/cleanup.sh b/runtime/bin/cleanup.sh new file mode 100755 index 0000000..d5d634c --- /dev/null +++ b/runtime/bin/cleanup.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +clean_server() +{ + SERVER=$1 + ITER=$2 + MAX=$3 + QUIET=$4 + + SCRIPTDIR=$PWD/`dirname $0`/ + + if [[ $QUIET == 0 ]] ; then + echo "Cleaning server ($ITER / $MAX): $SERVER" + fi + ssh -oBatchMode=yes ${SERVER} ${SCRIPTDIR}/cleanup-scrub-local.sh +} + +if [[ "x" != "x$CI_HOSTFILE" && -f "$CI_HOSTFILE" ]] ; then + ALLHOSTS=(`cat $CI_HOSTFILE | sort | uniq`) +else + ALLHOSTS=(`hostname`) +fi +LEN=${#ALLHOSTS[@]} + +# Use a background mode if running at scale +USE_BG=0 +if [ $LEN -gt 10 ] ; then + USE_BG=1 +fi + +for (( i=0; i<${LEN}; i++ )); +do + if [ $USE_BG == 1 ] ; then + if [ $(($i % 100)) == 0 ] ; then + echo "| $i" + else + if [ $(($i % 10)) == 0 ] ; then + echo -n "|" + else + echo -n "." + fi + fi + fi + + if [ $USE_BG == 1 ] ; then + clean_server ${ALLHOSTS[$i]} $i $LEN $USE_BG & + sleep 0.25 + else + clean_server ${ALLHOSTS[$i]} $i $LEN $USE_BG + echo "-------------------------" + fi +done + +if [ $USE_BG == 1 ] ; then + echo "" + echo "------------------------- Waiting" + wait +fi + +echo "------------------------- Done" + +exit 0 diff --git a/runtime/hello_world/build.sh b/runtime/hello_world/build.sh new file mode 100755 index 0000000..a9faece --- /dev/null +++ b/runtime/hello_world/build.sh @@ -0,0 +1,19 @@ +#!/bin/bash -e + +# Wrapper compiler +_MPICC=mpicc +echo "==========================" +echo "Wrapper compiler: $_MPICC" +echo "==========================" +${_MPICC} --showme + +echo "==========================" +echo "Building MPI Hello World" +echo "==========================" +cp ${CI_OMPI_SRC}/examples/hello_c.c . +${_MPICC} hello_c.c -o hello + +echo "==========================" +echo "Success" +echo "==========================" +exit 0 diff --git a/runtime/hello_world/run.sh b/runtime/hello_world/run.sh new file mode 100755 index 0000000..678b55a --- /dev/null +++ b/runtime/hello_world/run.sh @@ -0,0 +1,87 @@ +#!/bin/bash -xe + +# Final return value +FINAL_RTN=0 + +# Number of nodes - for accounting/verification purposes +# Default: 1 +NUM_NODES=${CI_NUM_NODES:-1} + +if [ "x" != "x${CI_HOSTFILE}" ] ; then + ARG_HOSTFILE="--hostfile ${CI_HOSTFILE}" +else + ARG_HOSTFILE="" +fi + +_shutdown() +{ + # --------------------------------------- + # Cleanup + # --------------------------------------- + + exit $FINAL_RTN +} + +# --------------------------------------- +# Run the test - Hostname +# --------------------------------------- +echo "==========================" +echo "Test: hostname" +echo "==========================" +mpirun ${ARG_HOSTFILE} --map-by ppr:5:node hostname 2>&1 | tee output-hn.txt + +# --------------------------------------- +# Verify the results +# --------------------------------------- +ERRORS=`grep ERROR output-hn.txt | wc -l` +if [[ $ERRORS -ne 0 ]] ; then + echo "ERROR: Error string detected in the output" + FINAL_RTN=1 + _shutdown +fi + +LINES=`wc -l output-hn.txt | awk '{print $1}'` +if [[ $LINES -ne $(( 5 * $NUM_NODES )) ]] ; then + echo "ERROR: Incorrect number of lines of output" + FINAL_RTN=2 + _shutdown +fi + +if [ $FINAL_RTN == 0 ] ; then + echo "Success - hostname" +fi + + +# --------------------------------------- +# Run the test - Hello World +# --------------------------------------- +echo "==========================" +echo "Test: Hello World" +echo "==========================" +mpirun ${ARG_HOSTFILE} --map-by ppr:5:node ./hello 2>&1 | tee output.txt + +# --------------------------------------- +# Verify the results +# --------------------------------------- +ERRORS=`grep ERROR output.txt | wc -l` +if [[ $ERRORS -ne 0 ]] ; then + echo "ERROR: Error string detected in the output" + FINAL_RTN=1 + _shutdown +fi + +LINES=`wc -l output.txt | awk '{print $1}'` +if [[ $LINES -ne $(( 5 * $NUM_NODES )) ]] ; then + echo "ERROR: Incorrect number of lines of output" + FINAL_RTN=2 + _shutdown +fi + +if [ $FINAL_RTN == 0 ] ; then + echo "Success - hello world" +fi + +echo "==========================" +echo "Success" +echo "==========================" +_shutdown From 77ca9b51519e5c9670dc564a11e1855854004c73 Mon Sep 17 00:00:00 2001 From: Joshua Hursey Date: Wed, 22 Feb 2023 12:27:54 -0500 Subject: [PATCH 14/15] Runtime CI: Add a tool to display the hwloc binding without relying on MPI or PMIx interfaces Signed-off-by: Joshua Hursey --- .gitignore | 2 + runtime/README.md | 2 +- runtime/bin/pretty-print-hwloc/.gitignore | 72 ++++ runtime/bin/pretty-print-hwloc/Makefile.am | 9 + runtime/bin/pretty-print-hwloc/README.md | 66 ++++ runtime/bin/pretty-print-hwloc/autogen.sh | 3 + runtime/bin/pretty-print-hwloc/configure.ac | 146 ++++++++ .../bin/pretty-print-hwloc/src/Makefile.am | 25 ++ .../pretty-print-hwloc/src/get-pretty-cpu.c | 163 +++++++++ .../autogen/hwloc_tools_config_bottom.h | 8 + .../include/autogen/hwloc_tools_config_top.h | 5 + .../pretty-print-hwloc/src/include/utils.h | 43 +++ runtime/bin/pretty-print-hwloc/src/support.c | 333 ++++++++++++++++++ 13 files changed, 876 insertions(+), 1 deletion(-) create mode 100644 runtime/bin/pretty-print-hwloc/.gitignore create mode 100644 runtime/bin/pretty-print-hwloc/Makefile.am create mode 100644 runtime/bin/pretty-print-hwloc/README.md create mode 100755 runtime/bin/pretty-print-hwloc/autogen.sh create mode 100644 runtime/bin/pretty-print-hwloc/configure.ac create mode 100644 runtime/bin/pretty-print-hwloc/src/Makefile.am create mode 100644 runtime/bin/pretty-print-hwloc/src/get-pretty-cpu.c create mode 100644 runtime/bin/pretty-print-hwloc/src/include/autogen/hwloc_tools_config_bottom.h create mode 100644 runtime/bin/pretty-print-hwloc/src/include/autogen/hwloc_tools_config_top.h create mode 100644 runtime/bin/pretty-print-hwloc/src/include/utils.h create mode 100644 runtime/bin/pretty-print-hwloc/src/support.c diff --git a/.gitignore b/.gitignore index 7fe1d18..a07f70b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ comm_split_type/cmsplit_type singleton/hello_c singleton/simple_spawn singleton/simple_spawn_multiple + +.vscode diff --git a/runtime/README.md b/runtime/README.md index 5cf648e..c5c69ec 100644 --- a/runtime/README.md +++ b/runtime/README.md @@ -37,5 +37,5 @@ The CI infrastructure defines the following environment variables to be used in - CI will call this exactly one time (with a timeout in case it hangs). - If the script returns `0` then it is considered successful. Otherwise it is considered failed. 4. Add your directory name to the `.ci-tests` file in this directory in the order that they should be executed. - - Note that adding the directory is not sufficient to have CI run the test, it must be in the file. + - Note that adding the directory is not sufficient to have CI run the test, it must be in the `.ci-tests` file. - Comments (starting with `#`) are allowed. diff --git a/runtime/bin/pretty-print-hwloc/.gitignore b/runtime/bin/pretty-print-hwloc/.gitignore new file mode 100644 index 0000000..5c000d7 --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/.gitignore @@ -0,0 +1,72 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# Autoconf/Automake leftovers +autom4te.cache/ +compile +depcomp +aclocal.m4 +config.log +config.status +configure +install-sh +missing +.deps +.libs +*.in +Makefile +src/include/autogen/config.h* +src/include/autogen/stamp-h1 + +# Binary leftovers +src/get-pretty-cpu diff --git a/runtime/bin/pretty-print-hwloc/Makefile.am b/runtime/bin/pretty-print-hwloc/Makefile.am new file mode 100644 index 0000000..04e56a6 --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/Makefile.am @@ -0,0 +1,9 @@ +# +# High level Makefile +# +headers = +sources = +nodist_headers = +EXTRA_DIST = + +SUBDIRS = . src diff --git a/runtime/bin/pretty-print-hwloc/README.md b/runtime/bin/pretty-print-hwloc/README.md new file mode 100644 index 0000000..6cf65d7 --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/README.md @@ -0,0 +1,66 @@ +# Pretty Print HWLOC Process Binding + +## Building + +```shell +./autogen.sh +./configure --prefix=${YOUR_INSTALL_DIR} --with-hwloc=${HWLOC_INSTALL_PATH} +make +make install +```` + +## Running + +### Default: Print HWLOC bitmap + +```shell +shell$ get-pretty-cpu + 0/ 0 on c660f5n18) Process Bound : 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +``` + +```shell +shell$ hwloc-bind core:2 get-pretty-cpu + 0/ 0 on c660f5n18) Process Bound : 0x00ff0000 +``` + +```shell +shell$ mpirun -np 2 get-pretty-cpu + 0/ 2 on c660f5n18) Process Bound : 0x000000ff + 1/ 2 on c660f5n18) Process Bound : 0x0000ff00 +``` + +### Full descriptive output + +```shell +shell$ get-pretty-cpu -b -f + 0/ 0 on c660f5n18) Process Bound : socket 0[core 0[hwt 0-7]],socket 0[core 1[hwt 0-7]],socket 0[core 2[hwt 0-7]],socket 0[core 3[hwt 0-7]],socket 0[core 4[hwt 0-7]],socket 0[core 5[hwt 0-7]],socket 0[core 6[hwt 0-7]],socket 0[core 7[hwt 0-7]],socket 0[core 8[hwt 0-7]],socket 0[core 9[hwt 0-7]],socket 1[core 10[hwt 0-7]],socket 1[core 11[hwt 0-7]],socket 1[core 12[hwt 0-7]],socket 1[core 13[hwt 0-7]],socket 1[core 14[hwt 0-7]],socket 1[core 15[hwt 0-7]],socket 1[core 16[hwt 0-7]],socket 1[core 17[hwt 0-7]],socket 1[core 18[hwt 0-7]],socket 1[core 19[hwt 0-7]] +``` + +```shell +shell$ hwloc-bind core:2 get-pretty-cpu -b -f + 0/ 0 on c660f5n18) Process Bound : socket 0[core 2[hwt 0-7]] +``` + +```shell +shell$ mpirun -np 2 get-pretty-cpu -b -f + 1/ 2 on c660f5n18) Process Bound : socket 0[core 1[hwt 0-7]] + 0/ 2 on c660f5n18) Process Bound : socket 0[core 0[hwt 0-7]] +``` + +### Full descriptive bracketed output + +```shell +shell$ get-pretty-cpu -b -m + 0/ 0 on c660f5n18) Process Bound : [BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB][BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB/BBBBBBBB] +``` + +```shell +shell$ hwloc-bind core:2 get-pretty-cpu -b -m + 0/ 0 on c660f5n18) Process Bound : [......../......../BBBBBBBB/......../......../......../......../......../......../........][......../......../......../......../......../......../......../......../......../........] +``` + +```shell +shell$ mpirun -np 2 get-pretty-cpu -b -m + 1/ 2 on c660f5n18) Process Bound : [......../BBBBBBBB/......../......../......../......../......../......../......../........][......../......../......../......../......../......../......../......../......../........] + 0/ 2 on c660f5n18) Process Bound : [BBBBBBBB/......../......../......../......../......../......../......../......../........][......../......../......../......../......../......../......../......../......../........] +``` diff --git a/runtime/bin/pretty-print-hwloc/autogen.sh b/runtime/bin/pretty-print-hwloc/autogen.sh new file mode 100755 index 0000000..089f597 --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/bash -e + +autoreconf -ivf diff --git a/runtime/bin/pretty-print-hwloc/configure.ac b/runtime/bin/pretty-print-hwloc/configure.ac new file mode 100644 index 0000000..e24391a --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/configure.ac @@ -0,0 +1,146 @@ +# +# +# + +###################### +# Project Information +###################### +AC_INIT([HWLOC Tools], + [0.1]) +AC_PREREQ(2.63) + + +###################### +# Utilities +###################### +_show_title() { + cat < + +]) +AH_BOTTOM([ + +#include +#endif /* HWLOC_TOOLS_CONFIG_H */ +]) + +AC_CONFIG_HEADERS([src/include/autogen/config.h]) + + +###################### +# Make automake clean emacs ~ files for "make clean" +###################### +CLEANFILES="*~ .\#*" +AC_SUBST(CLEANFILES) + + +###################### +# C Compiler +###################### +_show_title "Setup C Compiler" + +CFLAGS_save="$CFLAGS" +AC_PROG_CC +CFLAGS="$CFLAGS_save" + +AC_SUBST(CFLAGS) +AC_SUBST(CXXFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(LIBS) + + +###################### +# HWLOC Install +###################### +_show_title "Setup HWLOC" + +# +# --with-hwloc=DIR +# --with-hwloc-libdir=DIR +# +AC_ARG_WITH([hwloc], + [AC_HELP_STRING([--with-hwloc=DIR], + [Search for hwloc headers and libraries in DIR ])]) + +AC_ARG_WITH([hwloc-libdir], + [AC_HELP_STRING([--with-hwloc-libdir=DIR], + [Search for hwloc libraries in DIR ])]) +# HWLOC is required +AS_IF([test "$with_hwloc" = "no"], + [AC_MSG_WARN([HWLOC is required. --without-hwloc is not supported.]) + AC_MSG_ERROR([Cannot continue])]) +AS_IF([test -z "$with_hwloc" || test "$with_hwloc" == "yes"], + [AC_MSG_WARN([HWLOC is required. Default search functionality not supported.]) + AC_MSG_ERROR([Cannot continue])]) + +AC_MSG_CHECKING([HWLOC Location]) +AC_MSG_RESULT([$with_hwloc]) + +CFLAGS="-I$with_hwloc/include $CFLAGS" + +# Do we really need '-ludev'? +#LDFLAGS="-ludev $LDFLAGS" + +AC_MSG_CHECKING([If static HWLOC library is available]) +AS_IF([test -f "$with_hwloc/lib/libhwloc.a" ], + [AC_MSG_RESULT([yes]) + LIBS="$with_hwloc/lib/libhwloc.a $LIBS"], + [LDFLAGS="-L$with_hwloc/lib $LDFLAGS" + LIBS="-lhwloc $LIBS"]) + +AC_MSG_CHECKING([Final CFLAGS]) +AC_MSG_RESULT([$CFLAGS]) + +AC_MSG_CHECKING([Final LDFLAGS]) +AC_MSG_RESULT([$LDFLAGS]) + +AC_MSG_CHECKING([Final LIBS]) +AC_MSG_RESULT([$LIBS]) + +###################### +# Makefile +###################### +AC_CONFIG_FILES([Makefile src/Makefile]) + +###################### +# Done +###################### +_show_title "All Done" +AC_OUTPUT + diff --git a/runtime/bin/pretty-print-hwloc/src/Makefile.am b/runtime/bin/pretty-print-hwloc/src/Makefile.am new file mode 100644 index 0000000..5ba6718 --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/src/Makefile.am @@ -0,0 +1,25 @@ +# +# +# + +headers = +sources = +nodist_headers = +EXTRA_DIST = + +AM_CPPFLAGS = -I./include/ +AM_LDFLAGS = -lm + +# Headers +headers += include/utils.h + +# Source +sources += \ + get-pretty-cpu.c \ + support.c + +bin_PROGRAMS = get-pretty-cpu + +get_pretty_cpu_SOURCES = $(sources) $(headers) +#get_pretty_cpu_CFLAGS = $(CFLAGS_HWLOC) +#get_pretty_cpu_LDADD = $(LIBS_HWLOC) diff --git a/runtime/bin/pretty-print-hwloc/src/get-pretty-cpu.c b/runtime/bin/pretty-print-hwloc/src/get-pretty-cpu.c new file mode 100644 index 0000000..212fc9a --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/src/get-pretty-cpu.c @@ -0,0 +1,163 @@ +#include +#include +#include + +#include + +#include "include/utils.h" + +static hwloc_topology_t topology; +static int global_rank, global_size; +static int local_rank, local_size; +static char hostname[HOST_NAME_MAX] = { '\0' }; + +static void display_message(char * fmt, ...); + +bool is_verbose = false; +bool is_quiet = false; +bool report_smallest = false; +bool report_full = false; +bool report_full_map = false; +bool report_hwloc_bind = true; + +int main(int argc, char **argv) +{ + hwloc_topology_t topology; + hwloc_bitmap_t bound_set; + hwloc_obj_t obj; + char type[64]; + int i; + char pretty_str[PRETTY_LEN]; + char *buffer_str = NULL; + char whoami_str[PRETTY_LEN]; + + + /* + * Simple arg parsing + */ + if( argc > 0 ) { + for( i = 1; i < argc; ++i ) { + if( 0 == strcmp(argv[i], "-v") || + 0 == strcmp(argv[i], "--v") || + 0 == strcmp(argv[i], "-verbose") || + 0 == strcmp(argv[i], "--verbose") ) { + is_verbose = true; + } + else if( 0 == strcmp(argv[i], "-q") || + 0 == strcmp(argv[i], "--q") || + 0 == strcmp(argv[i], "-quiet") || + 0 == strcmp(argv[i], "--quiet") ) { + is_quiet = true; + } + else if( 0 == strcmp(argv[i], "-s") || + 0 == strcmp(argv[i], "--s") || + 0 == strcmp(argv[i], "-smallest") || + 0 == strcmp(argv[i], "--smallest") ) { + report_smallest = true; + } + else if( 0 == strcmp(argv[i], "-f") || + 0 == strcmp(argv[i], "--f") || + 0 == strcmp(argv[i], "-full") || + 0 == strcmp(argv[i], "--full") ) { + report_full = true; + } + else if( 0 == strcmp(argv[i], "-m") || + 0 == strcmp(argv[i], "--m") || + 0 == strcmp(argv[i], "-map") || + 0 == strcmp(argv[i], "--map") ) { + report_full_map = true; + } + else if( 0 == strcmp(argv[i], "-b") || + 0 == strcmp(argv[i], "--b") || + 0 == strcmp(argv[i], "-no-bind") || + 0 == strcmp(argv[i], "--no-bind") ) { + report_hwloc_bind = false; + } + } + } + + gethostname(hostname, HOST_NAME_MAX); + + /* Get rank/size information from the launching environment */ + get_rank_size_info(&global_rank, &global_size, + &local_rank, &local_size); + sprintf(whoami_str, "%3d/%3d on %s) ", global_rank, global_size, hostname); + + /* Allocate and initialize topology object. */ + hwloc_topology_init(&topology); + + /* Perform the topology detection. */ + hwloc_topology_load(topology); + + /* retrieve the CPU binding of the current entire process */ + bound_set = hwloc_bitmap_alloc(); + + hwloc_get_cpubind(topology, bound_set, HWLOC_CPUBIND_PROCESS); + + /* print the smallest object covering the current process binding */ + if( report_smallest ) { + obj = hwloc_get_obj_covering_cpuset(topology, bound_set); + if( NULL == obj ) { + display_message("Not bound\n"); + } else { + hwloc_obj_type_snprintf(type, sizeof(type), obj, 0); + display_message("Bound to \"%s\" logical index %u (physical index %u)\n", + type, obj->logical_index, obj->os_index); + } + } + + /* print the full descriptive output */ + if( report_full ) { + opal_hwloc_base_cset2str(pretty_str, PRETTY_LEN, topology, bound_set, true ); + if( is_verbose ) { + printf("%s Process Bound :\n%s\n", whoami_str, pretty_str); + } else { + printf("%s Process Bound : %s\n", whoami_str, pretty_str); + } + } + + /* print the full bracketed map output */ + if( report_full_map ) { + opal_hwloc_base_cset2mapstr(pretty_str, PRETTY_LEN, topology, bound_set); + if( is_verbose ) { + printf("%s Process Bound :\n%s\n", whoami_str, pretty_str); + } else { + printf("%s Process Bound : %s\n", whoami_str, pretty_str); + } + } + + /* print the hwloc binding bitmap */ + if( report_hwloc_bind ) { + hwloc_bitmap_asprintf(&buffer_str, bound_set); + if( is_verbose ) { + printf("%s Process Bound :\n%s\n", whoami_str, buffer_str); + } else { + printf("%s Process Bound : %s\n", whoami_str, buffer_str); + } + free(buffer_str); + } + + /* Destroy topology object. */ + hwloc_topology_destroy(topology); + + return 0; +} + + +static void display_message(char *fmt, ...) +{ + va_list args; + + printf("%3d/%3d on %s (%3d/%3d): ", + global_rank, global_size, + hostname, + local_rank, local_size); + va_start(args, fmt); + + vprintf(fmt, args); + if( '\n' != fmt[strlen(fmt)-1] ) { + printf("\n"); + } + + va_end(args); +} diff --git a/runtime/bin/pretty-print-hwloc/src/include/autogen/hwloc_tools_config_bottom.h b/runtime/bin/pretty-print-hwloc/src/include/autogen/hwloc_tools_config_bottom.h new file mode 100644 index 0000000..9bcd03a --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/src/include/autogen/hwloc_tools_config_bottom.h @@ -0,0 +1,8 @@ +/* + * + */ + +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif diff --git a/runtime/bin/pretty-print-hwloc/src/include/autogen/hwloc_tools_config_top.h b/runtime/bin/pretty-print-hwloc/src/include/autogen/hwloc_tools_config_top.h new file mode 100644 index 0000000..d27c99c --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/src/include/autogen/hwloc_tools_config_top.h @@ -0,0 +1,5 @@ +/* + * + */ + +// Empty diff --git a/runtime/bin/pretty-print-hwloc/src/include/utils.h b/runtime/bin/pretty-print-hwloc/src/include/utils.h new file mode 100644 index 0000000..8d97193 --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/src/include/utils.h @@ -0,0 +1,43 @@ +/* + * + */ +#ifndef _UTILS_H +#define _UTILS_H + +#include +#include + +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 64 +#endif + +#define PRETTY_LEN 1024 + +// Configure header +#include "include/autogen/config.h" + +/* + * Access the global/local rank/size from environment variables set by the launcher + */ +int get_rank_size_info(int *global_rank, int *global_size, + int *local_rank, int *local_size); + +/* + * Create a string representation of the binding + * 0/2 on node18) Process Bound : socket 0[core 1[hwt 0-7]],socket 1[core 10[hwt 0-7]] + */ +int opal_hwloc_base_cset2str(char *str, int len, + hwloc_topology_t topo, + hwloc_cpuset_t cpuset, + bool is_full); + +/* + * Create a string representation of the binding using a bracketed notion + * 0/2 on node18) Process Bound : [......../BBBBBBBB/......../......../......../......../......../......../......../........][BBBBBBBB/......../......../......../......../......../......../......../......../........] + */ +int opal_hwloc_base_cset2mapstr(char *str, int len, + hwloc_topology_t topo, + hwloc_cpuset_t cpuset); + +#endif /* _UTILS_H */ + diff --git a/runtime/bin/pretty-print-hwloc/src/support.c b/runtime/bin/pretty-print-hwloc/src/support.c new file mode 100644 index 0000000..0ff0fd7 --- /dev/null +++ b/runtime/bin/pretty-print-hwloc/src/support.c @@ -0,0 +1,333 @@ +/* + * + */ +#include +#include +#include + +#include "include/utils.h" + +static int build_map(int *num_sockets_arg, int *num_cores_arg, + hwloc_cpuset_t cpuset, int ***map, hwloc_topology_t topo); +static char *bitmap2rangestr(int bitmap); + + +int get_rank_size_info(int *global_rank, int *global_size, + int *local_rank, int *local_size) +{ + char *envar = NULL; + + *global_rank = 0; + *global_size = 0; + *local_rank = 0; + *local_size = 0; + + // JSM + if( NULL != getenv("JSM_NAMESPACE_SIZE") ) { + envar = getenv("JSM_NAMESPACE_RANK"); + *global_rank = atoi(envar); + envar = getenv("JSM_NAMESPACE_SIZE"); + *global_size = atoi(envar); + + envar = getenv("JSM_NAMESPACE_LOCAL_RANK"); + *local_rank = atoi(envar); + envar = getenv("JSM_NAMESPACE_LOCAL_SIZE"); + *local_size = atoi(envar); + } + // ORTE/PRRTE + else if( NULL != getenv("OMPI_COMM_WORLD_SIZE") ) { + envar = getenv("OMPI_COMM_WORLD_RANK"); + *global_rank = atoi(envar); + envar = getenv("OMPI_COMM_WORLD_SIZE"); + *global_size = atoi(envar); + + envar = getenv("OMPI_COMM_WORLD_LOCAL_RANK"); + *local_rank = atoi(envar); + envar = getenv("OMPI_COMM_WORLD_LOCAL_SIZE"); + *local_size = atoi(envar); + } + // MVAPICH2 + else if( NULL != getenv("MV2_COMM_WORLD_SIZE") ) { + envar = getenv("MV2_COMM_WORLD_RANK"); + *global_rank = atoi(envar); + envar = getenv("MV2_COMM_WORLD_SIZE"); + *global_size = atoi(envar); + + envar = getenv("MV2_COMM_WORLD_LOCAL_RANK"); + *local_rank = atoi(envar); + envar = getenv("MV2_COMM_WORLD_LOCAL_SIZE"); + *local_size = atoi(envar); + } + + return 0; +} + +int opal_hwloc_base_cset2str(char *str, int len, + hwloc_topology_t topo, + hwloc_cpuset_t cpuset, + bool is_full) +{ + bool first; + int num_sockets, num_cores; + int ret, socket_index, core_index; + char tmp[BUFSIZ]; + const int stmp = sizeof(tmp) - 1; + int **map=NULL; + //hwloc_obj_t root; + //opal_hwloc_topo_data_t *sum; + + str[0] = tmp[stmp] = '\0'; + + /* if the cpuset is all zero, then not bound */ + if (hwloc_bitmap_iszero(cpuset)) { + return -1; + } + + if (0 != (ret = build_map(&num_sockets, &num_cores, cpuset, &map, topo))) { + return ret; + } + /* Iterate over the data matrix and build up the string */ + first = true; + for (socket_index = 0; socket_index < num_sockets; ++socket_index) { + for (core_index = 0; core_index < num_cores; ++core_index) { + if (map[socket_index][core_index] > 0) { + if (!first) { + if( is_full ) { + //strncat(str, ",\n", len - strlen(str)); + strncat(str, ",", len - strlen(str)); + } else { + strncat(str, ",", len - strlen(str)); + } + } + first = false; + + if( is_full ) { + snprintf(tmp, stmp, "socket %d[core %2d[hwt %s]]", + socket_index, core_index, + bitmap2rangestr(map[socket_index][core_index])); + } else { + snprintf(tmp, stmp, "%2d", core_index); + } + strncat(str, tmp, len - strlen(str)); + } + } + } + if (NULL != map) { + if (NULL != map[0]) { + free(map[0]); + } + free(map); + } + + return 0; +} + +int opal_hwloc_base_cset2mapstr(char *str, int len, + hwloc_topology_t topo, + hwloc_cpuset_t cpuset) +{ + char tmp[BUFSIZ]; + int core_index, pu_index; + const int stmp = sizeof(tmp) - 1; + hwloc_obj_t socket, core, pu; + //hwloc_obj_t root; + //opal_hwloc_topo_data_t *sum; + + str[0] = tmp[stmp] = '\0'; + + /* if the cpuset is all zero, then not bound */ + if (hwloc_bitmap_iszero(cpuset)) { + return -1; //OPAL_ERR_NOT_BOUND; + } + + /* Iterate over all existing sockets */ + for (socket = hwloc_get_obj_by_type(topo, HWLOC_OBJ_SOCKET, 0); + NULL != socket; + socket = socket->next_cousin) { + strncat(str, "[", len - strlen(str)); + + /* Iterate over all existing cores in this socket */ + core_index = 0; + for (core = hwloc_get_obj_inside_cpuset_by_type(topo, + socket->cpuset, + HWLOC_OBJ_CORE, core_index); + NULL != core; + core = hwloc_get_obj_inside_cpuset_by_type(topo, + socket->cpuset, + HWLOC_OBJ_CORE, ++core_index)) { + if (core_index > 0) { + strncat(str, "/", len - strlen(str)); + } + + /* Iterate over all existing PUs in this core */ + pu_index = 0; + for (pu = hwloc_get_obj_inside_cpuset_by_type(topo, + core->cpuset, + HWLOC_OBJ_PU, pu_index); + NULL != pu; + pu = hwloc_get_obj_inside_cpuset_by_type(topo, + core->cpuset, + HWLOC_OBJ_PU, ++pu_index)) { + + /* Is this PU in the cpuset? */ + if (hwloc_bitmap_isset(cpuset, pu->os_index)) { + strncat(str, "B", len - strlen(str)); + } else { + strncat(str, ".", len - strlen(str)); + } + } + } + strncat(str, "]", len - strlen(str)); + } + + return 0; +} + +/* + * Make a map of socket/core/hwthread tuples + */ +static int build_map(int *num_sockets_arg, int *num_cores_arg, + hwloc_cpuset_t cpuset, int ***map, hwloc_topology_t topo) +{ + int num_sockets, num_cores; + int socket_index, core_index, pu_index; + hwloc_obj_t socket, core, pu; + int **data; + + /* Find out how many sockets we have */ + num_sockets = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_SOCKET); + /* some systems (like the iMac) only have one + * socket and so don't report a socket + */ + if (0 == num_sockets) { + num_sockets = 1; + } + /* Lazy: take the total number of cores that we have in the + topology; that'll be more than the max number of cores + under any given socket */ + num_cores = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_CORE); + *num_sockets_arg = num_sockets; + *num_cores_arg = num_cores; + + /* Alloc a 2D array: sockets x cores. */ + data = malloc(num_sockets * sizeof(int *)); + if (NULL == data) { + return -1; //OPAL_ERR_OUT_OF_RESOURCE; + } + data[0] = calloc(num_sockets * num_cores, sizeof(int)); + if (NULL == data[0]) { + free(data); + return -1; //OPAL_ERR_OUT_OF_RESOURCE; + } + for (socket_index = 1; socket_index < num_sockets; ++socket_index) { + data[socket_index] = data[socket_index - 1] + num_cores; + } + + /* Iterate the PUs in this cpuset; fill in the data[][] array with + the socket/core/pu triples */ + for (pu_index = 0, + pu = hwloc_get_obj_inside_cpuset_by_type(topo, + cpuset, HWLOC_OBJ_PU, + pu_index); + NULL != pu; + pu = hwloc_get_obj_inside_cpuset_by_type(topo, + cpuset, HWLOC_OBJ_PU, + ++pu_index)) { + /* Go upward and find the core this PU belongs to */ + core = pu; + while (NULL != core && core->type != HWLOC_OBJ_CORE) { + core = core->parent; + } + core_index = 0; + if (NULL != core) { + core_index = core->logical_index; + } + + /* Go upward and find the socket this PU belongs to */ + socket = pu; + while (NULL != socket && socket->type != HWLOC_OBJ_SOCKET) { + socket = socket->parent; + } + socket_index = 0; + if (NULL != socket) { + socket_index = socket->logical_index; + } + + /* Save this socket/core/pu combo. LAZY: Assuming that we + won't have more PU's per core than (sizeof(int)*8). */ + data[socket_index][core_index] |= (1 << pu->sibling_rank); + } + + *map = data; + return 0; +} + +/* + * Turn an int bitmap to a "a-b,c" range kind of string + */ +static char *bitmap2rangestr(int bitmap) +{ + size_t i; + int range_start, range_end; + bool first, isset; + char tmp[BUFSIZ]; + const int stmp = sizeof(tmp) - 1; + static char ret[BUFSIZ]; + + memset(ret, 0, sizeof(ret)); + + first = true; + range_start = -999; + for (i = 0; i < sizeof(int) * 8; ++i) { + isset = (bitmap & (1 << i)); + + /* Do we have a running range? */ + if (range_start >= 0) { + if (isset) { + continue; + } else { + /* A range just ended; output it */ + if (!first) { + strncat(ret, ",", sizeof(ret) - strlen(ret) - 1); + } else { + first = false; + } + + range_end = i - 1; + if (range_start == range_end) { + snprintf(tmp, stmp, "%d", range_start); + } else { + snprintf(tmp, stmp, "%d-%d", range_start, range_end); + } + strncat(ret, tmp, sizeof(ret) - strlen(ret) - 1); + + range_start = -999; + } + } + + /* No running range */ + else { + if (isset) { + range_start = i; + } + } + } + + /* If we ended the bitmap with a range open, output it */ + if (range_start >= 0) { + if (!first) { + strncat(ret, ",", sizeof(ret) - strlen(ret) - 1); + first = false; + } + + range_end = i - 1; + if (range_start == range_end) { + snprintf(tmp, stmp, "%d", range_start); + } else { + snprintf(tmp, stmp, "%d-%d", range_start, range_end); + } + strncat(ret, tmp, sizeof(ret) - strlen(ret) - 1); + } + + return ret; +} From e680def701368e4cb14b37d07254847f461c5cf7 Mon Sep 17 00:00:00 2001 From: Whit Schonbein Date: Thu, 2 May 2024 14:32:08 -0600 Subject: [PATCH 15/15] initial commit to fork fixed conditional expression Signed-off-by: Whit Schonbein removing extra space and fixing tab space size Signed-off-by: Whit Schonbein Empty commit to add signoff Signed-off-by: Whit Schonbein Empty commit to add signoff Signed-off-by: Whit Schonbein fixed conditional expression removing extra space and fixing tab space size Empty commit to add signoff Signed-off-by: Whit Schonbein Empty commit to add signoff Signed-off-by: Whit Schonbein --- partitioned-communication/Makefile | 367 ++++++++++++++++++ partitioned-communication/README.md | 84 ++++ partitioned-communication/runtests.py | 331 ++++++++++++++++ partitioned-communication/test_cancel0.c | 98 +++++ partitioned-communication/test_common.h | 24 ++ partitioned-communication/test_datatype0.c | 95 +++++ partitioned-communication/test_datatype1.c | 95 +++++ partitioned-communication/test_datatype2.c | 96 +++++ partitioned-communication/test_datatype3.c | 108 ++++++ partitioned-communication/test_datatype4.c | 77 ++++ partitioned-communication/test_datatype5.c | 78 ++++ partitioned-communication/test_example1a.c | 78 ++++ partitioned-communication/test_example1b.c | 75 ++++ partitioned-communication/test_example2.c | 100 +++++ partitioned-communication/test_example3a.c | 116 ++++++ partitioned-communication/test_example3b.c | 110 ++++++ partitioned-communication/test_example3c.c | 114 ++++++ partitioned-communication/test_free0.c | 90 +++++ partitioned-communication/test_init0.c | 98 +++++ partitioned-communication/test_init1.c | 86 ++++ partitioned-communication/test_init2.c | 88 +++++ partitioned-communication/test_local0.c | 86 ++++ partitioned-communication/test_local1.c | 85 ++++ partitioned-communication/test_numparts0.c | 82 ++++ partitioned-communication/test_numparts1.c | 82 ++++ partitioned-communication/test_order0.c | 116 ++++++ partitioned-communication/test_parrived0.c | 92 +++++ partitioned-communication/test_parrived1.c | 57 +++ partitioned-communication/test_parrived2.c | 74 ++++ partitioned-communication/test_partitions0.c | 80 ++++ partitioned-communication/test_partitions1.c | 80 ++++ partitioned-communication/test_partitions2.c | 78 ++++ partitioned-communication/test_partitions3.c | 83 ++++ partitioned-communication/test_pready0.c | 82 ++++ partitioned-communication/test_pready1.c | 82 ++++ partitioned-communication/test_pready2.c | 82 ++++ partitioned-communication/test_pready3.c | 82 ++++ partitioned-communication/test_pready4.c | 61 +++ partitioned-communication/test_pready_list0.c | 82 ++++ partitioned-communication/test_pready_list1.c | 86 ++++ .../test_pready_range0.c | 81 ++++ partitioned-communication/test_startall0.c | 160 ++++++++ partitioned-communication/test_state0.c | 151 +++++++ partitioned-communication/test_wildcard0.c | 79 ++++ partitioned-communication/test_wildcard1.c | 79 ++++ partitioned-communication/test_zerocount0.c | 79 ++++ partitioned-communication/test_zerocount1.c | 79 ++++ 47 files changed, 4668 insertions(+) create mode 100644 partitioned-communication/Makefile create mode 100644 partitioned-communication/README.md create mode 100644 partitioned-communication/runtests.py create mode 100644 partitioned-communication/test_cancel0.c create mode 100644 partitioned-communication/test_common.h create mode 100644 partitioned-communication/test_datatype0.c create mode 100644 partitioned-communication/test_datatype1.c create mode 100644 partitioned-communication/test_datatype2.c create mode 100644 partitioned-communication/test_datatype3.c create mode 100644 partitioned-communication/test_datatype4.c create mode 100644 partitioned-communication/test_datatype5.c create mode 100644 partitioned-communication/test_example1a.c create mode 100644 partitioned-communication/test_example1b.c create mode 100644 partitioned-communication/test_example2.c create mode 100644 partitioned-communication/test_example3a.c create mode 100644 partitioned-communication/test_example3b.c create mode 100644 partitioned-communication/test_example3c.c create mode 100644 partitioned-communication/test_free0.c create mode 100644 partitioned-communication/test_init0.c create mode 100644 partitioned-communication/test_init1.c create mode 100644 partitioned-communication/test_init2.c create mode 100644 partitioned-communication/test_local0.c create mode 100644 partitioned-communication/test_local1.c create mode 100644 partitioned-communication/test_numparts0.c create mode 100644 partitioned-communication/test_numparts1.c create mode 100644 partitioned-communication/test_order0.c create mode 100644 partitioned-communication/test_parrived0.c create mode 100644 partitioned-communication/test_parrived1.c create mode 100644 partitioned-communication/test_parrived2.c create mode 100644 partitioned-communication/test_partitions0.c create mode 100644 partitioned-communication/test_partitions1.c create mode 100644 partitioned-communication/test_partitions2.c create mode 100644 partitioned-communication/test_partitions3.c create mode 100644 partitioned-communication/test_pready0.c create mode 100644 partitioned-communication/test_pready1.c create mode 100644 partitioned-communication/test_pready2.c create mode 100644 partitioned-communication/test_pready3.c create mode 100644 partitioned-communication/test_pready4.c create mode 100644 partitioned-communication/test_pready_list0.c create mode 100644 partitioned-communication/test_pready_list1.c create mode 100644 partitioned-communication/test_pready_range0.c create mode 100644 partitioned-communication/test_startall0.c create mode 100644 partitioned-communication/test_state0.c create mode 100644 partitioned-communication/test_wildcard0.c create mode 100644 partitioned-communication/test_wildcard1.c create mode 100644 partitioned-communication/test_zerocount0.c create mode 100644 partitioned-communication/test_zerocount1.c diff --git a/partitioned-communication/Makefile b/partitioned-communication/Makefile new file mode 100644 index 0000000..70b98af --- /dev/null +++ b/partitioned-communication/Makefile @@ -0,0 +1,367 @@ +BIN=./bin/ +OBJ=./obj/ + +# C compiler +CC=gcc + +# MPI +# if required, add paths to mpi.h and any other necessary headers (e.g., UCX) +CFLAGS= +# if required, add paths to ompi libraries and any other necessary libraries +LDFLAGS= + +.PHONY: clean + +all: test_cancel0.x test_datatype0.x test_datatype1.x test_datatype2.x test_datatype3.x test_datatype4.x test_datatype5.x test_example1a.x test_example1b.x test_example2.x test_example3a.x test_example3b.x test_example3c.x test_free0.x test_init0.x test_init1.x test_init2.x test_local0.x test_local1.x test_numparts0.x test_numparts1.x test_order0.x test_parrived0.x test_parrived1.x test_parrived2.x test_pready0.x test_pready1.x test_pready2.x test_pready3.x test_pready4.x test_pready_list0.x test_pready_list1.x test_pready_range0.x test_partitions0.x test_partitions1.x test_partitions2.x test_partitions3.x test_startall0.x test_state0.x test_wildcard0.x test_wildcard1.x test_zerocount0.x test_zerocount1.x + +test_cancel0.x: test_cancel0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_cancel0.o: test_cancel0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype0.x: test_datatype0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype0.o: test_datatype0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype1.x: test_datatype1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype1.o: test_datatype1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype2.x: test_datatype2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype2.o: test_datatype2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype3.x: test_datatype3.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype3.o: test_datatype3.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype4.x: test_datatype4.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype4.o: test_datatype4.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_datatype5.x: test_datatype5.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_datatype5.o: test_datatype5.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_example1a.x: test_example1a.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_example1a.o: test_example1a.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_example1b.x: test_example1b.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_example1b.o: test_example1b.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_example2.x: test_example2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) -fopenmp + +test_example2.o: test_example2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) -fopenmp + +test_example3a.x: test_example3a.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) -fopenmp + +test_example3a.o: test_example3a.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) -fopenmp + +test_example3b.x: test_example3b.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) -fopenmp + +test_example3b.o: test_example3b.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) -fopenmp + +test_example3c.x: test_example3c.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) -fopenmp + +test_example3c.o: test_example3c.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) -fopenmp + +test_free0.x: test_free0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_free0.o: test_free0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_init0.x: test_init0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_init0.o: test_init0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_init1.x: test_init1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_init1.o: test_init1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_init2.x: test_init2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_init2.o: test_init2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_local0.x: test_local0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_local0.o: test_local0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_local1.x: test_local1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_local1.o: test_local1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_numparts1.x: test_numparts1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_numparts1.o: test_numparts1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_numparts0.x: test_numparts0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_numparts0.o: test_numparts0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_order0.x: test_order0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_order0.o: test_order0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_parrived0.x: test_parrived0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_parrived0.o: test_parrived0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_parrived1.x: test_parrived1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_parrived1.o: test_parrived1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_parrived2.x: test_parrived2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_parrived2.o: test_parrived2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_partitions0.x: test_partitions0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_partitions0.o: test_partitions0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_partitions1.x: test_partitions1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_partitions1.o: test_partitions1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_partitions2.x: test_partitions2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_partitions2.o: test_partitions2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_partitions3.x: test_partitions3.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_partitions3.o: test_partitions3.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready0.x: test_pready0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready0.o: test_pready0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready1.x: test_pready1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready1.o: test_pready1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready2.x: test_pready2.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready2.o: test_pready2.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready3.x: test_pready3.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready3.o: test_pready3.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready4.x: test_pready4.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready4.o: test_pready4.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready_list0.x: test_pready_list0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready_list0.o: test_pready_list0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready_list1.x: test_pready_list1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready_list1.o: test_pready_list1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_pready_range0.x: test_pready_range0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_pready_range0.o: test_pready_range0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_startall0.x: test_startall0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_startall0.o: test_startall0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_state0.x: test_state0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_state0.o: test_state0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_wildcard0.x: test_wildcard0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_wildcard0.o: test_wildcard0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_wildcard1.x: test_wildcard1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_wildcard1.o: test_wildcard1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_zerocount0.x: test_zerocount0.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_zerocount0.o: test_zerocount0.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +test_zerocount1.x: test_zerocount1.o + mkdir -p ${BIN} + $(CC) -o ${BIN}$@ -L${OBJ} $(LDFLAGS) $(addprefix ${OBJ}, $^) + +test_zerocount1.o: test_zerocount1.c + mkdir -p ${OBJ} + $(CC) -c $< -o ${OBJ}$@ $(CFLAGS) + +clean: + rm -f *.o + rm -f *.x + rm -f ${OBJ}*.o + rm -f ${BIN}*.x + rm -r obj + rm -r bin diff --git a/partitioned-communication/README.md b/partitioned-communication/README.md new file mode 100644 index 0000000..8ce245b --- /dev/null +++ b/partitioned-communication/README.md @@ -0,0 +1,84 @@ +## A collection of tests for the MPI 4.1 partitioned communication API + +These tests target partitioned communication as it appears in Chapter 4 of +the [MPI Specification v. 4.1](https://www.mpi-forum.org/docs/). + +The repository contains the following: +- `test_*.c` : the tests (see below) +- `runtests.py` : a simple python 3 script for executing tests and generating a report +- other misc files : skeleton makefile, license, etc. + +### runtests.py script + +The script executes each test and looks for an expected output string in its +`stderr` output. Tests pass if the expected string is found somewhere in the +output, or (optionally) on a specific line of the output. Alternatively a test +may be designed to elicit a timeout, in which case it passes if a timeout occurs. + +A report is generated in a subdirectory along with the stderr output of each test. + +Run with `-v` flag to generate progress information on `stdout`; otherwise the tests +run silently. + +See comments in script for more information. + +### Tests + +A summary of tests is given below. For each, see the comments in the source for +motivation for the test, including (when available) references to specific pages and lines in the +v4.1 MPI specification. + +Some tests are designed to elicit errors from the MPI implementation, and if no +error is produced, the test fails. In some cases the assumption that the implementation +will produce an error message may be unfounded, e.g., because performing such a check is +difficult, impacts performance, or it is really up to the user to avoid the situation. +These tests may warrant additional discussion or exclusion. + +| Test | Description | +| ---- | ---- | +| `test_cancel01.c` | Calling MPI_Cancel on an active request should cause an error; PASS = some sort of error; FAIL = unexpected timeout or incorrect/missing error. | +| `test_datatypeX.c` | Examples in chapter 4 of the specification use different combinations of sender and receiver contiguous datatypes as well as OpenMP pragmas. The datatype tests eschew the OpenMP and check just the combination of datatypes. | +| `test_datatype0.c` | Checks case where the same datatype is used on both sender and reciever, and the same number of partitions. PASS = run to completion. | +| `test_datatype1.c` | Based on example 4.3 in specification. This test has the sender and receiver use the same number of partitions. The sender uses a datatype (one per partition) while the receiver uses MPI_INT * PARTSIZE. PASS = run to completion. See also `test_datatype4.c` | +| `test_datatype2.c` | Based on example 4.3 in specification, this test has the sender use multiple partitions and the receiver use a single partition. The sender uses contiguous datatypes (one per partition) and the reciever MESSAGE_LENGTH. PASS = run to completion. See also `test_datatype4.c` | +| `test_datatype3.c` | Same as test_datatype2.c, except receiver uses a single contiguous datatype of size MESSAGE_LENGTH. See also `test_datatype5.c`, which does the same using Isend/Irecv. PASS = run to completion. | +| `test_datatype4.c` | A sanity check confirming the combination of sender-side contiguous datatype and receiver-side non-derived datatype (MPI_INT) works outside of partcomm with Isend/Irecv. PASS = run to completion | +| `test_datatype5.c` | A sanity check confirming the combination of multiple sender-side contiguous datatypes to a single receiver-side contiguous datatype works with Isend/Irecv. PASS = run to completion. | +| `test_example1a.c` | Example 1 from the 4.1 specification. PASS = run to completion | +| `test_example1b.c` | Example 1 from the 4.1 spec, except uses MPI_WAIT instead of MPI_TEST. PASS = run to completion | +| `test_example2.c` | Example 2 from the 4.1 specification. PASS = run to completion | +| `test_example3a.c` | Example 3 from the 4.1 specification, modified to not use any contiguous datatypes, use MPI_INT, and make the number of partitions the same on both sender and receiver. PASS = run to completion. | +| `test_example3b.c` | Example 3 from the 4.1 specification, modified to use MPI_INT and not use any contiguous datatypes. Uses multiple partitions on sender and one on receiver. | +| `test_example3c.c` | Example 3 from the 4.1 specification, modified to use MPI_INT. PASS = run to completion. See also `test_datatype[2,3].c` | +| `test_free0.c` | Calling MPI_Free on an active request should cause an error; PASS = some sort of error (TBD); FAIL = unexpected timeout or incorrect/missing error | +| `test_init0.c` | Tries to match a PSEND_INIT with an IRECV. PASS = expected timeout. | +| `test_init1.c` | Tries to match an ISEND with a PRECV_INIT. PASS = expected timeout. | +| `test_init2.c` | Tries to match a persistent send init (MPI_SEND_INIT) with a partcomm recv init (PRECV_INIT). PASS = expected timeout. | +| `test_local0.c` | Confirms partcomm calls are local, so the sender can get to test/wait before the receiver even calls PRECV_INIT PASS = runs to completion. | +| `test_local1.c` | Confirms partcomm calls are local, so the receiver can get to test/wait before the sender even calls PSEND_INIT. PASS = runs to completion | +| `test_numparts0.c` | Confirms a sender can have more partitions than a receiver. PASS = runs to completion. | +| `test_numparts1.c` | Confirms a receiver can have more partitions than a sender. PASS = runs to completion. | +| `test_order0.c` | Confirms the order in which partcomm init calls are made is the order they are matched (and hence filled). PASS = runs to completion; FAIL = likely fails check of received message contents | +| `test_parrived0.c` | Confirms PARRIVED works. Also (likely) calls PARRIVED more than once on the same partition. PASS = run to completion | +| `test_parrived1.c` | Confirms PARRIVED works on a request that has never been used (an inactive request). PASS = run to completion | +| `test_parrived2.c` | Tries to call PARRIVED on a request that does not correspond to a partitioned receive operation. PASS = some sort of error | +| `test_partitions0.c` | Tries to use PSEND_INIT with zero partitions. PASS = some sort of error | +| `test_partitions1.c` | Tries to use PSEND_INIT with negative partitions. PASS = some sort of error | +| `test_partitions2.c` | Tries to use PRECV_INIT with zero partitions. PASS = some sort of error | +| `test_partitions3.c` | Tries to use PRECV_INIT with negative partitions. PASS = some sort of error | +| `test_pready0.c` | Tries to call PREADY on a partition whose index is greater than the largest valid index. PASS = some sort of error | +| `test_pready1.c` | Tries to call PREADY on a partition whose index is equal to the number of partitions (so is 1 beyond the last valid index). PASS = some sort of error | +| `test_pready2.c` | Tries to call PREADY on a partition whose index is negative. PASS = some sort of error | +| `test_pready3.c` | Tries to call PREADY on a partition that has already been marked ready by PREADY. PASS = some sort of error | +| `test_pready4.c` | Tries to call PREADY on a request object that does not correspond to a partitioned send operation. PASS = some sort of error | +| `test_pready_range0.c` | Uses PREADY_RANGE in a standard way; PASS = successfully runs to completion | +| `test_pready_list0.c` | Uses PREADY_LIST in a standard way; PASS = runs to completion | +| `test_pready_list1.c` | Uses PREADY_LIST with the same partition appearing more than once. See also test_pready3.c. PASS = some sort of error | +| `test_startall0.c` | Sets up multiple PSEND_INIT + PRECV_INIT pairs using different tags and does partcomm for each. PASS = runs to completion. | +| `test_state0.c` | Confirms that the request status is reset when multiple rounds of START/PREADY/TEST are used. See also [OMPI Issue #12328](https://github.com/open-mpi/ompi/issues/12328) PASS = runs to completion. | +| `test_wildcard0.c` | Tries to use MPI_ANY_SOURCE with PRECV_INIT. PASS = an error of some sort | +| `test_wildcard0.c` | Tries to use MPI_ANY_SOURCE with PRECV_INIT. PASS = an error of some sort | +| `test_zerocount0.c` | Confirms PSEND_INIT and PRECV_INIT can use 0 partitions with a greater-than-zero count. PASS = runs to completion | +| `test_zerocount1.c` | Confirms PSEND_INIT and PRECV_INIT can use greater-than-zero partitions with a zero count. PASS = runs to completion | + + diff --git a/partitioned-communication/runtests.py b/partitioned-communication/runtests.py new file mode 100644 index 0000000..9b8413d --- /dev/null +++ b/partitioned-communication/runtests.py @@ -0,0 +1,331 @@ +# Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +# (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +# Government retains certain rights in this software. + +# A simple python script for running unit tests and checking their outputs +# +# The `tests` dict (below) specifies which tests are to be run and how the +# stderr output of each test is to be evaluated. Tests can pass because +# (i) an expected string was found in the output (or, optionally, on a specific +# line of the output), or (ii) the test was expected to timeout and it did. +# +# Some tests are written to elicit an error message from the MPI implementation. Because it may not +# be known a priori what this message is, the text variable TBD_ERROR is used +# as the matching string, with the expectation it will be replaced with the +# actual error message when it is available. Below, tests that contain TBD_ERROR +# are tests that fail because no error is reported by OMPI. +# +# All tests are written to use stderr, and assume OMPI error messages will appear on stderr; stdout is ignored. +# +# The script assumes if a segmentation fault occurs in the MPI implementation, it is an error. +# Segmentation faults can generate stderr outputs that are not readable by Python in text mode (only +# in binary mode). Therefore, the script tests if the output is readable in text mode; if it is not, it +# reports the test as failing and notes the file was not readable. +# +# + +import argparse +import os +import subprocess +import sys +import threading +import time + +# Use the following as placeholder text for tests designed to elicit an error message. +# When the specific error message is known, replace. +TBD_ERROR = "UNKNOWN ERROR MESSAGE EXPECTED" + +# For tests designed to elicit a timeout, use the following matching text: +TIMEOUT_EXPECTED = "__TIMEOUT_EXPECTED__" + +# The following variables are default text for generating the report +TIMEOUT_EXPECTED_AND_FOUND = "Timeout expected and did occur" +TIMEOUT_EXPECTED_AND_NOT_FOUND = "A timeout was expected but the test terminated for some other reason." +TIMEOUT_UNEXPECTED_AND_FOUND = "No timeout was expected but test terminated due to timeout" +TIMEOUT_UNEXPECTED_AND_NOT_FOUND = "This outcome should not arise" + +# subdirectory where tests are located relative to this script +BIN = "./bin/" + +# Dict of tests to run along with the string that, if found in the ouput, means the test passes. +# +# The tuple is the string to be matched, followed by the line on which it is expected. Use "*" to allow the +# matching string to appear on any line. +# +# TBD_ERROR is used as the expected string when a test is supposed to elicit an error but we do not +# have a proper output string to test for (e.g., if the test fails to error). +# +# If a timeout is the expected outcome, then use the TIMEOUT_EXPECTED variable for the match string. +# +tests = { + "test_cancel0.x": (TBD_ERROR,"*"), + "test_datatype0.x": ("END", "1"), + "test_datatype1.x": ("END", "1"), + "test_datatype2.x": ("END", "1"), + "test_datatype3.x": ("END", "1"), + "test_datatype4.x": ("END", "1"), + "test_datatype5.x": ("END", "1"), + "test_example1a.x": ("END", "1"), + "test_example1b.x": ("END", "1"), + "test_example2.x": ("END", "1"), + "test_example3a.x": ("END", "1"), + "test_example3b.x": ("END", "1"), + "test_example3c.x": ("END", "1"), + "test_free0.x": (TBD_ERROR, "*"), + "test_init0.x": (TIMEOUT_EXPECTED, "*"), + "test_init1.x": (TIMEOUT_EXPECTED, "*"), + "test_init2.x": (TIMEOUT_EXPECTED, "*"), + "test_local0.x" : ("END", "1"), + "test_local1.x" : ("END", "1"), + "test_numparts0.x" : ("END", "1"), + "test_numparts1.x" : ("END", "1"), + "test_order0.x" : ("END", "1"), + "test_parrived0.x" : ("END", "*"), + "test_parrived1.x" : ("END", "*"), + "test_parrived2.x" : ("*** An error occurred in MPI_Parrived", "*"), + "test_partitions0.x" : (TBD_ERROR, "*"), + "test_partitions1.x" : (TBD_ERROR, "*"), + "test_partitions2.x" : (TBD_ERROR, "*"), + "test_partitions3.x" : (TBD_ERROR, "*"), + "test_pready0.x" : (TBD_ERROR, "*"), + "test_pready1.x" : (TBD_ERROR, "*"), + "test_pready2.x" : (TBD_ERROR, "*"), + "test_pready3.x" : (TBD_ERROR, "*"), + "test_pready4.x" : ("MPI_ERR_REQUEST: invalid request", "*"), + "test_pready_list0.x": ("END", "1"), + "test_pready_list1.x": (TBD_ERROR, "*"), + "test_pready_range0.x": ("END", "1"), + "test_startall0.x" : ("END", "*"), + "test_state0.x" : (TBD_ERROR, "*"), + "test_wildcard0.x" : (TBD_ERROR, "*"), + "test_wildcard1.x" : (TBD_ERROR, "*"), + "test_zerocount0.x" : ("END", "*"), + "test_zerocount1.x" : ("END", "*") + } + +# for colored verbose output +class txt_colors: + PASS = '\033[92m' + FAIL = '\033[91m' + ENDC = '\033[0m' + +# test output is directed here +out_stderr = ".stderr" +out_stdout = ".stdout" + +# prefix of output directory (date/time will be appended) +outdir = "results_" + +# name of report file +reportfn = "report.txt" + +# for timeout +timeout_thread_abort = False +timeout_occurred = False +DEFAULT_TIMEOUT_SECONDS = 25 + +# for stats +passed = 0 +failed = 0 + +def error(msg): + print("ERROR: {0}".format(msg), file=sys.stderr) + exit(1) + +# if the test passed +def report_success(outfile, test, msg=""): + global passed + passed += 1 + print("{0} : passed : {1}".format(test, msg), file=outfile) + +# if the test failed +def report_failure(outfile, test, msg=""): + global failed + failed += 1 + print("{0} : FAILED : {1}".format(test, msg), file=outfile) + +def get_process_id(name): + child = subprocess.Popen(['pgrep', '-f', name], stdout=subprocess.PIPE, shell=False) + response = child.communicate()[0] + return [int(pid) for pid in response.split()] + +# function for timeout thread +def timeout_function(seconds, t): + global timeout_occurred + timeout_occurred = False + count = 0 + pid = get_process_id(t) + while (not pid) and (count < 5): + pid = get_process_id(t) + t_start = int(time.time()) + while ((int(time.time()) - t_start) < seconds): + if timeout_thread_abort: + return + timeout_occurred = True + subprocess.run("kill -9 {0}".format(pid[0]), stderr=outfile_stderr, stdout=subprocess.DEVNULL, shell=True) + return + +# check if output file to be checked has only text +# When a segfault occurs, it can generate outout that cannot be decoded to text +def file_is_readable(infn): + try: + infile = open(infn, "r") + except: + error("Could not open file {0}".format(infn)) + try: + for line in infile: + print("", end='') + except: + return False + return True + +# helper to avoid duplicating code +def verbose_pass_fail(test_passed): + if test_passed: + print(f"{txt_colors.PASS}PASSED{txt_colors.ENDC}", file=sys.stdout) + else: + print(f"{txt_colors.FAIL}FAILED{txt_colors.ENDC}", file=sys.stdout) + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", help="Verbose mode") + + args = parser.parse_args() + verbose = args.verbose + + tstr = time.strftime("%Y%m%d-%H%M%S") + outdir = outdir + tstr + os.mkdir(outdir) + outdir = "./" + outdir + + reportfn = outdir + "/" + reportfn + try: + reportfile = open(reportfn, "w") + except: + error("Could not open file {0} for writing A".format(reportfn)) + + total_tests = len(tests) + cur_test = 0 + + # add some info to the report + print("", file=reportfile) + print("---- Tests start: {0} ----".format(tstr), file=reportfile) + print("Tests (num = {0}):".format(total_tests), file=reportfile) + for t in tests: + print(" {0}".format(t), file=reportfile) + print(file=reportfile) + + tt_start = time.time() + + for t in tests: + cur_test += 1 + if verbose: + print("{0} / {1} : Running test: {2} --> ".format(cur_test, total_tests, t),end='', file=sys.stdout, flush=True) + command = "mpirun -np 2 --npernode 1 " + BIN + t + tmp_out_stderr = outdir + "/" + t + out_stderr + try: + outfile_stderr = open(tmp_out_stderr, 'w') + except: + error("Could not open file {0} for writing B".format(tmp_out_stderr)) + + timeout_thread_abort = False + timeout_thread = threading.Thread(target=timeout_function, args=(DEFAULT_TIMEOUT_SECONDS,t,)) + + timeout_thread.start() + subprocess.run(command, stderr=outfile_stderr, stdout=subprocess.DEVNULL, shell=True) + if not timeout_occurred: + timeout_thread_abort = True + outfile_stderr.close() + + match_string = tests[t][0] + testline = tests[t][1] + + test_passed = False + + # Confirm the file can be read as text + # If a segmentation fault occurs in the MPI implementation, it can generate contents that are + # only readable in binary mode, which this code cannot test. So if it is not readable, its an + # error. + is_readable = file_is_readable(tmp_out_stderr) + if not is_readable: + report_failure(reportfile, t, "Output is not readable as text. Check .stderr output") + if verbose: + verbose_pass_fail(test_passed) + continue + + testfile = open(tmp_out_stderr,'r') + + curline = 0 + foundline = False + # timeout occurred but not expected + if timeout_occurred and (match_string != TIMEOUT_EXPECTED): + report_failure(reportfile, t, TIMEOUT_UNEXPECTED_AND_FOUND) + foundline = True # to avoid another failure message + # timeout occured and expected + elif timeout_occurred and (match_string == TIMEOUT_EXPECTED): + report_success(reportfile, t, TIMEOUT_EXPECTED_AND_FOUND) + foundline = True # to avoid another failure message + test_passed = True + # timeout did not occur but was expected + elif (not timeout_occurred) and (match_string == TIMEOUT_EXPECTED): + report_failure(reportfile, t, TIMEOUT_EXPECTED_AND_NOT_FOUND) + foundline = True # to avoid another failure message + elif testline == "*": + for line in testfile: + curline += 1 + line = line.rstrip() + if match_string in line: + foundline = True + report_success(reportfile, t, "Match found on line {0}".format(curline)) + test_passed = True + break + else: # look only at specified line + try: + testline = int(testline) + except: + error("Line specified for test {0} is neither an int nor *") + for line in testfile: + curline += 1 + line = line.rstrip() + if curline == testline: + foundline = True + if match_string in line: + report_success(reportfile, t, "Match found on line {0}".format(curline)) + test_passed = True + else: + report_failure(reportfile, t, "On line {0}: Expected: {1} Found: {2}".format(testline, match_string, line)) + break + + # If no match found, provide more information + if not foundline: + if testline == "*": + report_failure(reportfile, t, "Expected text not found on any line. ({0})".format(match_string)) + else: + report_failure(reportfile, t, "Expected to test on line {0}, but stderr output file has only {1} lines.".format(testline, curline)) + + if verbose: + verbose_pass_fail(test_passed) + + time.sleep(7) + + tt_end = time.time() + + print("", file=reportfile) + print("", file=reportfile) + if (total_tests != (passed + failed)): + print("Note: total_tests (= {0}) did not equal passed + failed (= {1})".format(total_tests, passed, failed), file=reportfile) + passed_total = float(passed)/float(total_tests) + failed_total = float(failed)/float(total_tests) + print("{0} of {1} tests passed ({2:.2f}%)".format(passed, total_tests, passed_total*100), file=reportfile) + print("{0} of {1} tests failed ({2:.2f}%)".format(failed, total_tests, failed_total*100), file=reportfile) + print("", file=reportfile) + print("---- Tests end: {0} ----".format(time.strftime("%Y%m%d-%H%M%S")), file=reportfile) + print("---- Total time required to run tests: {0:.2f} seconds".format(tt_end - tt_start), file=reportfile) + reportfile.close() + + if verbose: + print("{0} of {1} tests passed ({2:.2f}%)".format(passed, total_tests, passed_total*100), file=sys.stdout) + print("{0} of {1} tests failed ({2:.2f}%)".format(failed, total_tests, failed_total*100), file=sys.stdout) + diff --git a/partitioned-communication/test_cancel0.c b/partitioned-communication/test_cancel0.c new file mode 100644 index 0000000..2c31fa9 --- /dev/null +++ b/partitioned-communication/test_cancel0.c @@ -0,0 +1,98 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 116, line 11: Freeing or canceling a partitioned communication request that is active (i.e., initialized and started) and not completed is erroneous. + * + * Expected outcome: Error message due to calling MPI_Cancel on a request that is active + * If test times out, then the error was not caught by the MPI library + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + fprintf(stderr, "Rank 0 initializing and starting Psend\n"); + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + MPI_Start(&request); + + /* This should cause an error. See 4.1 p. 102 for info on cancel */ + fprintf(stderr, "Rank 0 canceling request (erroneous)\n"); + CHECK_RETVAL(MPI_Cancel(&request)); + + /* Cancel is followed by wait, which should be local. If cancel ignored, then may hang here because nothing has been marked ready */ + fprintf(stderr, "Rank 0 waiting on cancelled request\n"); + CHECK_RETVAL(MPI_Wait(&request, MPI_STATUS_IGNORE)); + + /* Now we the request is inactive and we can use it again or free it */ + MPI_Request_free(&request); + + /* Rest of code is the standard Psend/Precv example. If the MPI_Request_free is ignored and no error reported, + * then the remainder of the code may hang because the first Psend is never completed, and the destination is testing on it + */ + + fprintf(stderr, "Rank 0 starting second Psend\n"); + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_common.h b/partitioned-communication/test_common.h new file mode 100644 index 0000000..b5d7cd3 --- /dev/null +++ b/partitioned-communication/test_common.h @@ -0,0 +1,24 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +#ifndef TEST_COMMON_H +#define TEST_COMMON_H + +#include +#include +#include "mpi.h" + +#define CHECK_RETVAL(x) do { \ + int retval = (x); \ + if (retval != MPI_SUCCESS) { \ + fprintf(stderr, "Error: %s returned %d (expected %d)\n", #x, retval, MPI_SUCCESS); \ + MPI_Abort(MPI_COMM_WORLD, 999); \ + } \ + } while (0) + +#define TEST_RAN_TO_COMPLETION() do { \ + fprintf(stderr, "END\n"); \ + } while (0) + +#endif diff --git a/partitioned-communication/test_datatype0.c b/partitioned-communication/test_datatype0.c new file mode 100644 index 0000000..1c932ff --- /dev/null +++ b/partitioned-communication/test_datatype0.c @@ -0,0 +1,95 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * This test uses the same datatype on sender and receiver, and the same + * number of partitions. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 64 +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int partitions = PARTITIONS; + int partlength = PARTLENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype xfer_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender and receiver both use the same transfer datatype */ + MPI_Type_contiguous(partlength, MPI_INT, &xfer_type); + MPI_Type_commit(&xfer_type); + + if (0 == myrank) { + + for (i = 0; i < partitions * partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, partitions, count, xfer_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < partlength; ++j) { + message[j + (i * partlength)] = j + (i * partlength); + } + MPI_Pready(i, request); + } + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < partitions * partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, partitions, count, xfer_type, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + + if (myrank == 0) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; + +} diff --git a/partitioned-communication/test_datatype1.c b/partitioned-communication/test_datatype1.c new file mode 100644 index 0000000..03e7578 --- /dev/null +++ b/partitioned-communication/test_datatype1.c @@ -0,0 +1,95 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * Example 4.3 uses a contiguous send datatype (one per partition) to a receiver using a single partition of + * MPI_DOUBLEs. This test simplifies by removing OpenMP code and makes the number of partitions + * the same. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 64 +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int partitions = PARTITIONS; + int partlength = PARTLENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < partitions * partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < partlength; ++j) { + message[j + (i * partlength)] = j + (i * partlength); + } + MPI_Pready(i, request); + } + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); } + + else if (1 == myrank) { + for (i = 0; i < partitions * partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, partitions, partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; + +} diff --git a/partitioned-communication/test_datatype2.c b/partitioned-communication/test_datatype2.c new file mode 100644 index 0000000..ee6b9c2 --- /dev/null +++ b/partitioned-communication/test_datatype2.c @@ -0,0 +1,96 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * Example 4.3 uses a contiguous send datatype (one per partition) to a receiver using a single partition of + * MPI_DOUBLEs. This test simplifies by using MPI_INT and removing OpenMP + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 64 +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < send_partlength; ++j) { + message[j + (i * send_partlength)] = j + (i * send_partlength); + } + MPI_Pready(i, request); + } + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; + +} diff --git a/partitioned-communication/test_datatype3.c b/partitioned-communication/test_datatype3.c new file mode 100644 index 0000000..d40a14c --- /dev/null +++ b/partitioned-communication/test_datatype3.c @@ -0,0 +1,108 @@ +// Copyright 2022 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * This test has the sender use a datatype multiple times (one per partition) and + * the receiver receive into a single partition with a single datatype. + * + * Compare with test_datatype5.c, which does the same thing with Isend/Irecv insteaad of partcomm + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 64 +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + // If the test seg faults, it may be a memory alignment issue + //int *message = NULL; + //if (posix_memalign((void *)&message, 32, sizeof(int) * MESSAGE_LENGTH)) { + // fprintf(stderr, "Error using posix_memalign\n"); + // exit(-1); + //} + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int send_count = 1, recv_count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type, recv_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* sender uses PARTITIONS partitions each comprising one instance of a PARTLENTH contiguous datatype */ + MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + /* receier uses 1 partition comprising one instance of a MESSAGE_LENGTH contiguous datatype */ + MPI_Type_contiguous(recv_partlength, MPI_INT, &recv_type); + MPI_Type_commit(&recv_type); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, send_count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < send_partlength; ++j) { + message[j + (i * send_partlength)] = j + (i * send_partlength); + } + MPI_Pready(i, request); + } + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_count, recv_type, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; + +} diff --git a/partitioned-communication/test_datatype4.c b/partitioned-communication/test_datatype4.c new file mode 100644 index 0000000..ff77c85 --- /dev/null +++ b/partitioned-communication/test_datatype4.c @@ -0,0 +1,77 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * This test is simply a sanity check to make sure the combination of sender-side + * contiguous datatype and receiver-side non-derived datatype works with basic non-blocking send/recv. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define MESSAGE_LENGTH 256 +#define DATATYPE_LENGTH 128 + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + + int count = 2, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(DATATYPE_LENGTH, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < MESSAGE_LENGTH; ++i) message[i] = i; + + MPI_Isend(message, count, send_type, dest, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + } else if (1 == myrank) { + + for (i = 0; i < MESSAGE_LENGTH; ++i) message[i] = 101; + + MPI_Irecv(message, MESSAGE_LENGTH, MPI_INT, source, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; + +} diff --git a/partitioned-communication/test_datatype5.c b/partitioned-communication/test_datatype5.c new file mode 100644 index 0000000..5aef3a4 --- /dev/null +++ b/partitioned-communication/test_datatype5.c @@ -0,0 +1,78 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * The examples in chapter 4 of the specification use different combinations of + * sender and receiver contiguous datatypes that for testing purposes should be + * considered outside the use of OpenMP pragmas. + * + * This is a sanity check to determine that a multipe counts of a sender-side + * contiguous datatype can be send to a receiver with a single contiguous datatype + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define MESSAGE_LENGTH 256 +#define SEND_DATATYPE_LENGTH 64 + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + + int send_count = 4, recv_count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype send_type, recv_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + MPI_Type_contiguous(SEND_DATATYPE_LENGTH, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + MPI_Type_contiguous(MESSAGE_LENGTH, MPI_INT, &recv_type); + MPI_Type_commit(&recv_type); + + if (0 == myrank) { + + for (i = 0; i < MESSAGE_LENGTH; ++i) message[i] = i; + + MPI_Isend(message, send_count, send_type, dest, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + } else if (1 == myrank) { + + for (i = 0; i < MESSAGE_LENGTH; ++i) message[i] = 101; + + MPI_Irecv(message, recv_count, recv_type, source, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; + +} diff --git a/partitioned-communication/test_example1a.c b/partitioned-communication/test_example1a.c new file mode 100644 index 0000000..740bcb9 --- /dev/null +++ b/partitioned-communication/test_example1a.c @@ -0,0 +1,78 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This is example 4.1, p. 114-115, MPI Standard v. 4.1 + * Extended to (1) fill buffer, (2) test that correct results are received. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_example1b.c b/partitioned-communication/test_example1b.c new file mode 100644 index 0000000..1827221 --- /dev/null +++ b/partitioned-communication/test_example1b.c @@ -0,0 +1,75 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This is example 4.1, p. 114-115, MPI Standard v. 4.1 + * Extended to (1) fill buffer, (2) test that correct results are received. + * + * This version uses MPI_Wait instead of MPI_Test, to confirm WAIT works (P. 120, line 16) + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + CHECK_RETVAL(MPI_Wait(&request, MPI_STATUS_IGNORE)); + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + CHECK_RETVAL(MPI_Wait(&request, MPI_STATUS_IGNORE)); + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_example2.c b/partitioned-communication/test_example2.c new file mode 100644 index 0000000..fd706f0 --- /dev/null +++ b/partitioned-communication/test_example2.c @@ -0,0 +1,100 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This is a variation on example 4.2, p. 122-123, MPI Standard v. 4.1 + * + * Note that this example (like the original) uses the same congituous datatype on both + * sender and receiver. See test_example3x.c for other variations. + * + * Expected outcome: PASS + * + */ + +#include +#include "test_common.h" + +#define NUM_THREADS 8 +#define PARTITIONS 8 +#define PARTLENGTH 16 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*PARTLENGTH]; + int partitions = PARTITIONS; + int partlength = PARTLENGTH; + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int my_thread_id; + int myrank; + int provided; + + omp_set_dynamic(0); // Disable dynamic teams + omp_set_num_threads(NUM_THREADS); + + for (i = 0; i < partitions * partlength; ++i) message[i] = 0; + + MPI_Request request; + MPI_Info info = MPI_INFO_NULL; + MPI_Datatype xfer_type; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + MPI_Type_contiguous(partlength , MPI_INT, &xfer_type); + MPI_Type_commit(&xfer_type); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, count, xfer_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel for shared(request,message) private(j, my_thread_id) num_threads(NUM_THREADS) + for (i=0; i +#include "test_common.h" + +#define NUM_THREADS 8 +#define NUM_TASKS 64 +#define PARTITIONS NUM_TASKS +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int partitions = PARTITIONS; + int partlength = PARTLENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + for (i = 0; i < partitions * partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, partitions, partlength, MPI_INT, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) + { +#pragma omp single + { + /* single thread creates 64 tasks to be executed by 8 threads */ + for (int task_num=0; task_num < NUM_TASKS; task_num++) { +#pragma omp task firstprivate(task_num) + { + my_thread_id = omp_get_thread_num(); + for (i=0; i < partlength; ++i) { + message[i + (task_num * partlength)] = i + (task_num * partlength); + } + MPI_Pready(task_num, request); + } /* end task */ + } /* end for */ + } /* end single */ + } /* end parallel */ + + // fprintf(stderr, "Sent: "); + // for (i = 0; i < MESSAGE_LENGTH; ++i) fprintf(stderr, "%d ", message[i]); + // fprintf(stderr, "\n"); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < partitions * partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, partitions, partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + // fprintf(stderr, "Received: "); + // for (i = 0; i < MESSAGE_LENGTH; ++i) fprintf(stderr, "%d ", message[i]); + // fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; + +} diff --git a/partitioned-communication/test_example3b.c b/partitioned-communication/test_example3b.c new file mode 100644 index 0000000..7432081 --- /dev/null +++ b/partitioned-communication/test_example3b.c @@ -0,0 +1,110 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Variation on Example 4.3, pp. 123-124 + * + * Original example: + * - Uses MPI_DOUBLE + * - Uses derived contiguous datatype on send side and MPI_DOUBLE on recv side + * - Has multiple partitions on send side and a single partition on recv side + * + * This version: + * - Uses MPI_INT + * - Does not use contiguous datatype on either side + * - Does have multiple partitions on send side and a single partition on recv side + * + * Expected outcome: PASS + * + */ + +#include +#include "test_common.h" + +#define NUM_THREADS 8 +#define NUM_TASKS 64 +#define PARTITIONS NUM_TASKS +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Info info = MPI_INFO_NULL; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, send_partlength, MPI_INT, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) + { +#pragma omp single + { + /* single thread creates 64 tasks to be executed by 8 threads */ + for (int task_num=0; task_num < NUM_TASKS; task_num++) { +#pragma omp task firstprivate(task_num) + { + my_thread_id = omp_get_thread_num(); + for (i=0; i < send_partlength; ++i) { + message[i + (task_num * send_partlength)] = i + (task_num * send_partlength); + } + MPI_Pready(task_num, request); + } /* end task */ + } /* end for */ + } /* end single */ + } /* end parallel */ + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; + +} diff --git a/partitioned-communication/test_example3c.c b/partitioned-communication/test_example3c.c new file mode 100644 index 0000000..640e48e --- /dev/null +++ b/partitioned-communication/test_example3c.c @@ -0,0 +1,114 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Variation on Example 4.3, pp. 123-124 + * + * Original example: + * - Uses MPI_DOUBLE + * - Uses derived contiguous datatype on send side and MPI_DOUBLE on recv side + * - Has multiple partitions on send side and a single partition on recv side + * + * This version: + * - Uses MPI_INT + * + * See also test_datatypeX.c + * + * Expected outcome: PASS + * + */ + +#include +#include "test_common.h" + +#define NUM_THREADS 8 +#define NUM_TASKS 64 +#define PARTITIONS NUM_TASKS +#define PARTLENGTH 16 +#define MESSAGE_LENGTH PARTITIONS*PARTLENGTH + +int main(int argc, char *argv[]) { + + int message[MESSAGE_LENGTH]; + int send_partitions = PARTITIONS; + int send_partlength = PARTLENGTH; + int recv_partitions = 1; + int recv_partlength = MESSAGE_LENGTH; + + int count = 1, source = 0, dest = 1, tag = 1, flag = 0; + int i, j; + int myrank; + int provided; + int my_thread_id; + + MPI_Request request; + MPI_Status status; + MPI_Datatype send_type; + MPI_Info info = MPI_INFO_NULL; + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided); + if (provided < MPI_THREAD_MULTIPLE) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + /* Sender uses this datatype */ + MPI_Type_contiguous(send_partlength, MPI_INT, &send_type); + MPI_Type_commit(&send_type); + + if (0 == myrank) { + + for (i = 0; i < send_partitions * send_partlength; ++i) message[i] = 100; + + MPI_Psend_init(message, send_partitions, count, send_type, dest, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + +#pragma omp parallel shared(request,message) private(i, my_thread_id) num_threads(NUM_THREADS) + { +#pragma omp single + { + /* single thread creates 64 tasks to be executed by 8 threads */ + for (int task_num=0; task_num < NUM_TASKS; task_num++) { +#pragma omp task firstprivate(task_num) + { + my_thread_id = omp_get_thread_num(); + for (i=0; i < send_partlength; ++i) { + message[i + (task_num * send_partlength)] = i + (task_num * send_partlength); + } + MPI_Pready(task_num, request); + } /* end task */ + } /* end for */ + } /* end single */ + } /* end parallel */ + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } else if (1 == myrank) { + for (i = 0; i < recv_partitions * recv_partlength; ++i) message[i] = 101; + + MPI_Precv_init(message, recv_partitions, recv_partlength, MPI_INT, source, tag, MPI_COMM_WORLD, info, &request); + MPI_Start(&request); + + while(!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < MESSAGE_LENGTH; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + return 0; +} diff --git a/partitioned-communication/test_free0.c b/partitioned-communication/test_free0.c new file mode 100644 index 0000000..9b06de3 --- /dev/null +++ b/partitioned-communication/test_free0.c @@ -0,0 +1,90 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 116, line 11: Freeing or canceling a partitioned communication request that is active (i.e., initialized and started) and not completed is erroneous. + * + * Expected outcome: Error message + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + fprintf(stderr, "Rank 0 initializing and starting Psend\n"); + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* This should cause an error */ + fprintf(stderr, "Rank 0 freeing request (erroneous)\n"); + CHECK_RETVAL(MPI_Request_free(&request)); + + + /* Rest of code is the standard Psend/Precv example. If the MPI_Request_free is ignored and no error reported, + * then the remainder of the code may hang because the first Psend is never completed, and the destination is testing on it + */ + + fprintf(stderr, "Rank 0 starting second Psend\n"); + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_init0.c b/partitioned-communication/test_init0.c new file mode 100644 index 0000000..c0b3d45 --- /dev/null +++ b/partitioned-communication/test_init0.c @@ -0,0 +1,98 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * P. 117, line 13: PSEND_INIT can only match with partitioned communication initialization operations, therefore it is required to be matched with a corresponding MPI_PRECV_INIT. + * + * This test tries to match a PSEND_INIT with an IRECV. Because the PSEND_INIT should not match the + * IRECV, the code should timeout waiting + * + * Expected outcome: TIMEOUT + * + */ + +#include "test_common.h" + +#define PARTITIONS 1 +#define COUNT 64 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + fprintf(stderr, "Sending message: \n"); + for (i=0; i < partitions * COUNT; ++i) { + fprintf(stderr, "%d, ", message[i]); + } + fprintf(stderr, "\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + + fprintf(stderr, "Received message: \n"); + for (i=0; i < partitions * COUNT; ++i) { + fprintf(stderr, "%d, ", message[i]); + } + fprintf(stderr, "\n"); + + /* This should not work. Test should time out */ + fprintf(stderr, "Rank 1 posting Irecv\n"); + CHECK_RETVAL(MPI_Irecv(message, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, &request)); + fprintf(stderr, "Rank 1 waiting\n"); + CHECK_RETVAL(MPI_Wait(&request, MPI_STATUS_IGNORE)); /* should time out here */ + + fprintf(stderr, "Received message: \n"); + for (i=0; i < partitions * COUNT; ++i) { + fprintf(stderr, "%d, ", message[i]); + } + fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + fprintf(stderr, "Rank 1: Contents verfied\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_init1.c b/partitioned-communication/test_init1.c new file mode 100644 index 0000000..2cf3401 --- /dev/null +++ b/partitioned-communication/test_init1.c @@ -0,0 +1,86 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * P. 118, line 20: PRECV_INIT can only match with partitioned communication initialization operations, therefore + * the MPI library is required to match MPI_PRECV_INIT calls only with a corresponding MPI_PSEND_INIT call. + * + * This test uses PRECV_INIT with an Isend; the latter should fail to match and the test timeout + * + * Expected outcome: TIMEOUT + * + */ + +#include "test_common.h" + +#define PARTITIONS 1 +#define COUNT 64 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + /* Fill message to be sent */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + } + + fprintf(stderr, "Rank 0 issuing Isend to Rank 1's corresponding MPI_Precv_init\n"); + MPI_Isend(message, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD, &request); + + fprintf(stderr, "Rank 0 waiting\n"); + MPI_Wait(&request, MPI_STATUS_IGNORE); + + fprintf(stderr, "Rank 0 done\n"); + + } + else if (1 == myrank) { + + fprintf(stderr, "Rank 1 initializing and starting Precv\n"); + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, MPI_INFO_NULL, &request)); + CHECK_RETVAL(MPI_Start(&request)); + + fprintf(stderr, "Rank 1 testing for completion ... should timeout here if Precv did not match Isend\n"); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + fprintf(stderr, "Rank 1 received message\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + fprintf(stderr, "Rank 1: Contents verfied\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_init2.c b/partitioned-communication/test_init2.c new file mode 100644 index 0000000..9d86c7c --- /dev/null +++ b/partitioned-communication/test_init2.c @@ -0,0 +1,88 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * P. 118, line 20: PRECV_INIT can only match with partitioned communication initialization operations, therefore + * the MPI library is required to match MPI_PRECV_INIT calls only with a corresponding MPI_PSEND_INIT call. + * + * This version use persistent send + * + * Expected outcome: TIMEOUT + * + */ + +#include "test_common.h" + +#define PARTITIONS 1 +#define COUNT 64 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + fprintf(stderr, "Rank 0 initializing persistent send\n"); + MPI_Send_init(message, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD, &request); + + /* Fill message to be sent */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + } + + fprintf(stderr, "Rank 0 starting persistent send\n"); + MPI_Start(&request); + + fprintf(stderr, "Rank 0 waiting\n"); + MPI_Wait(&request, MPI_STATUS_IGNORE); + + fprintf(stderr, "Rank 0 done\n"); + + } + else if (1 == myrank) { + + fprintf(stderr, "Rank 1 initializing and starting Precv\n"); + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, MPI_INFO_NULL, &request); + MPI_Start(&request); + + fprintf(stderr, "Rank 1 testing for completion ... should timeout here if Precv did not match persistent send\n"); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + fprintf(stderr, "Rank 1 received message\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + fprintf(stderr, "Rank 1: Contents verfied\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_local0.c b/partitioned-communication/test_local0.c new file mode 100644 index 0000000..644caa6 --- /dev/null +++ b/partitioned-communication/test_local0.c @@ -0,0 +1,86 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 114, line 11: Part comm initialization functions are local. + * P. 117, line 14-15: Partitioned communication initialization calls are local. + * + * Therefore, the sender should be able to get to test/wait before the receiver calls PRECV_INIT, and + * the receiver should be able to get to test/wait before the sender calls PSEND_INIT + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + /* receiver does not call PRECV_INIT until after this barrier */ + /* putting barrier after test causes deadlock */ + MPI_Barrier(MPI_COMM_WORLD); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Barrier(MPI_COMM_WORLD); + + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (1 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_local1.c b/partitioned-communication/test_local1.c new file mode 100644 index 0000000..9dc5c28 --- /dev/null +++ b/partitioned-communication/test_local1.c @@ -0,0 +1,85 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 114, line 11: Part comm initialization functions are local. + * P. 117, line 14-15: Partitioned communication initialization calls are local. + * + * Therefore, the sender should be able to get to test/wait before the receiver calls PRECV_INIT, and + * the receiver should be able to get to test/wait before the sender calls PSEND_INIT + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Barrier(MPI_COMM_WORLD); + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + + + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + MPI_Barrier(MPI_COMM_WORLD); /* barrier after test causes deadlock */ + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_numparts0.c b/partitioned-communication/test_numparts0.c new file mode 100644 index 0000000..55dc524 --- /dev/null +++ b/partitioned-communication/test_numparts0.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * Test 4: P. 114, line 12-13: The number of user-visible partitions on the send and receiver side may differ. + * + * This test has twice as many send partitions as recv partitions + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 8 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = PARTITIONS * 2; + MPI_Count send_count = (int)COUNT/2; + MPI_Count recv_partitions = PARTITIONS; + MPI_Count recv_count = COUNT; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, send_partitions, send_count, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < send_count; ++j) message[j+(send_count*i)] = j+(send_count*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, recv_partitions, recv_count, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < recv_partitions*recv_count; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_numparts1.c b/partitioned-communication/test_numparts1.c new file mode 100644 index 0000000..605cf38 --- /dev/null +++ b/partitioned-communication/test_numparts1.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * + * Test 4: P. 114, line 12-13: The number of user-visible partitions on the send and receiver side may differ. + * + * This test has twice as many recv partitions as send partitions + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 8 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = PARTITIONS; + MPI_Count send_count = COUNT; + MPI_Count recv_partitions = PARTITIONS * 2; + MPI_Count recv_count = (int)COUNT/2; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, send_partitions, send_count, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < send_count; ++j) message[j+(send_count*i)] = j+(send_count*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, recv_partitions, recv_count, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < recv_partitions*recv_count; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_order0.c b/partitioned-communication/test_order0.c new file mode 100644 index 0000000..d140e09 --- /dev/null +++ b/partitioned-communication/test_order0.c @@ -0,0 +1,116 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 113, line 15: Part comm operations are matched based on the order in which the local initialization calls are performed. + * P. 117, line 10: In the event that the communicator, tag, and source do not uniquely identify a message, the order + * in which partitioned communication initialization calls are made is the order in which they will eventually match. + * P. 118, line 24: If communicator, tag, and source are not enough to match, order is used. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message0[PARTITIONS*COUNT]; + int message1[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag0 = 0, flag1 = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message0[i] = 0; + for (i = 0; i < PARTITIONS * COUNT; ++i) message1[i] = 0; + + MPI_Request request0, request1; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + /* init in order 0, 1 */ + MPI_Psend_init(message0, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request0); + MPI_Psend_init(message1, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request1); + + /* start both */ + MPI_Start(&request0); + MPI_Start(&request1); + + /* fill 0; should fill 1 on receiver */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message0[j+(COUNT*i)] = 10*(j+(COUNT*i)); + MPI_Pready(i, request0); + } + + while (!flag0) { + MPI_Test(&request0, &flag0, MPI_STATUS_IGNORE); + } + + /* fill 1; should fill 0 on receiver */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message1[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request1); + } + + while (!flag1) { + MPI_Test(&request1, &flag1, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request0); + MPI_Request_free(&request1); + + } + else if (1 == myrank) { + /* init in order 1, 0 */ + MPI_Precv_init(message1, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request1); + MPI_Precv_init(message0, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request0); + + MPI_Start(&request0); + MPI_Start(&request1); + + while (!flag0 && !flag1) { + MPI_Test(&request0, &flag0, MPI_STATUS_IGNORE); + MPI_Test(&request1, &flag1, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request0); + MPI_Request_free(&request1); + + /* all partitions received; check contents */ + //fprintf(stderr, "Message 0: "); + for (i = 0; i < PARTITIONS*COUNT; ++i) { + //fprintf(stderr, "%d, ", message0[i]); + if (message0[i] != i) { + fprintf(stderr, "ERROR: Contents received in message buffer 0 do not match contents sent (expected %d, found %d).\n",i,message0[i]); + MPI_Abort(MPI_COMM_WORLD, 0); + } + } + //fprintf(stderr, "\n"); + //fprintf(stderr, "Message 1: "); + for (i = 0; i < PARTITIONS*COUNT; ++i) { + //fprintf(stderr, "%d, ", message1[i]); + if (message1[i] != i*10) { + fprintf(stderr, "ERROR: Contents received in message buffer 1 do not match contents sent (expected %d, found %d).\n",i,message1[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + //fprintf(stderr, "\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_parrived0.c b/partitioned-communication/test_parrived0.c new file mode 100644 index 0000000..664e267 --- /dev/null +++ b/partitioned-communication/test_parrived0.c @@ -0,0 +1,92 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 120: definition of PARRIVED + * + * This test simply uses PARRIVED and confirms the data in the partition is as expected + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + int part_of_interest = 3; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* loop until the partition of interest has arrived */ + int try = 0; + while (!flag) { + CHECK_RETVAL(MPI_Parrived(request, part_of_interest, &flag)); + ++try; + } + + /* acess the partition data */ + fprintf(stderr, "Number of PARRIVED calls: %d\n", try); + for (i=0; i < COUNT; ++i) { + fprintf(stderr,"%d\n", message[(part_of_interest*COUNT)+i]); + } + + /* continue as usual */ + MPI_Wait(&request, MPI_STATUS_IGNORE); + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_parrived1.c b/partitioned-communication/test_parrived1.c new file mode 100644 index 0000000..300618a --- /dev/null +++ b/partitioned-communication/test_parrived1.c @@ -0,0 +1,57 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 121, line 10: PARRIVED can be called on a null or inactive request; in this case, flag = true + * + * Expected outcome: PASS + * + */ + +#include +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + int part_of_interest = 3; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + sleep(10); + + } + else if (1 == myrank) { + + /* request never used; confirm parrived sets flag to true */ + if (!flag) fprintf(stderr, "Flag is false\n"); + while (!flag) { + CHECK_RETVAL(MPI_Parrived(request, 0, &flag)); + } + fprintf(stderr, "Flag is true\n"); + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_parrived2.c b/partitioned-communication/test_parrived2.c new file mode 100644 index 0000000..0b2ff46 --- /dev/null +++ b/partitioned-communication/test_parrived2.c @@ -0,0 +1,74 @@ +/* + * P. 121, line 11: Calling MPI_PARRIVED on a request that does not correspond to a partitioned receive operation + * is erroneous. + * + * This test uses PARRIVED on a request corresponding to an Irecv + * + * Expected outcome: some sort of error + * + */ + +#include "test_common.h" + +#define COUNT 32 + +int main(int argc, char *argv[]) { + + int message[COUNT]; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + for (i = 0; i < COUNT; ++i) message[i] = i; + + MPI_Isend(message, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD, &request); + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + //MPI_Request_free(&request); + + } + else if (1 == myrank) { + + MPI_Irecv(message, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, &request); + + /* this is erroneous */ + MPI_Parrived(request, 0, &flag); + + /* continue as usual */ + MPI_Wait(&request, MPI_STATUS_IGNORE); + + for (i=0; i < COUNT; ++i) { + fprintf(stderr,"%d ", message[i]); + } + fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_partitions0.c b/partitioned-communication/test_partitions0.c new file mode 100644 index 0000000..fc7457d --- /dev/null +++ b/partitioned-communication/test_partitions0.c @@ -0,0 +1,80 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Initializes using an invalid number of partitions: Psend_init with 0 partitions. + * + * P. 114, line 13-14: Valid partitioned communication operations must have one or more partitions specified. + * P. 117, line 15-16: It is erroneous to provide a partitions value <= 0. + * P. 118, line 28: It is erroneous to provide a partitions value <= 0. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = 0; /* Bad number of send partitions */ + MPI_Count recv_partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + /* Error should occur with this call */ + CHECK_RETVAL(MPI_Psend_init(message, send_partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, recv_partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_partitions1.c b/partitioned-communication/test_partitions1.c new file mode 100644 index 0000000..ef66120 --- /dev/null +++ b/partitioned-communication/test_partitions1.c @@ -0,0 +1,80 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Initializes using an invalid number of partitions: Psend_init with negative partitions. + * + * P. 114, line 13-14: Valid partitioned communication operations must have one or more partitions specified. + * P. 117, line 15-16: It is erroneous to provide a partitions value <= 0. + * P. 118, line 28: It is erroneous to provide a partitions value <= 0. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = -8; /* Bad number of partitions; MPI_Count is a signed int */ + MPI_Count recv_partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + /* Error should occur with this call */ + CHECK_RETVAL(MPI_Psend_init(message, send_partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, recv_partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_partitions2.c b/partitioned-communication/test_partitions2.c new file mode 100644 index 0000000..053ae32 --- /dev/null +++ b/partitioned-communication/test_partitions2.c @@ -0,0 +1,78 @@ +/* + * Initializes using an invalid number of partitions: Precv_init with 0 partitions. + * + * P. 114, line 13-14: Valid partitioned communication operations must have one or more partitions specified. + * P. 117, line 15-16: It is erroneous to provide a partitions value <= 0. + * P. 118, line 28: It is erroneous to provide a partitions value <= 0. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = PARTITIONS; + MPI_Count recv_partitions = 0; /* bad number of partitions */ + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, send_partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + fprintf(stderr, "Rank 1 initializing recv partitions to %d\n", recv_partitions); + /* Error should occur with this call */ + CHECK_RETVAL(MPI_Precv_init(message, recv_partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + + CHECK_RETVAL( MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_partitions3.c b/partitioned-communication/test_partitions3.c new file mode 100644 index 0000000..dea2ba8 --- /dev/null +++ b/partitioned-communication/test_partitions3.c @@ -0,0 +1,83 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Initializes using an invalid number of partitions: Precv_init with negative partitions. + * + * P. 114, line 13-14: Valid partitioned communication operations must have one or more partitions specified. + * P. 117, line 15-16: It is erroneous to provide a partitions value <= 0. + * P. 118, line 28: It is erroneous to provide a partitions value <= 0. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count send_partitions = PARTITIONS; + MPI_Count recv_partitions = -3; /* Bad number of partitions */ + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, send_partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + + MPI_Start(&request); + + for (i = 0; i < send_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + fprintf(stderr, "Rank 1 initializing recv partitions to %d\n", recv_partitions); + /* Error should occur with this call */ + CHECK_RETVAL(MPI_Precv_init(message, recv_partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_pready0.c b/partitioned-communication/test_pready0.c new file mode 100644 index 0000000..ec2bbf0 --- /dev/null +++ b/partitioned-communication/test_pready0.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls pready on a partition whose index is greater than the upper bound. + * + * P. 119, line 7-9: "Partition numbering ranges from 0 to 1 less than number of partitions declared in the MPI_PSEND_INIT call, and specifying a partition number that is equal to or larger is erroneous." + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + MPI_Count bad_partition = PARTITIONS + 5; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Call Pready on a nonexistant partition; an error should occur */ + fprintf(stderr, "Marking invalid partition ready...\n"); + CHECK_RETVAL(MPI_Pready(bad_partition, request)); + fprintf(stderr, "Invalid partition marked ready...\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_pready1.c b/partitioned-communication/test_pready1.c new file mode 100644 index 0000000..8d657f2 --- /dev/null +++ b/partitioned-communication/test_pready1.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls pready on a partition whose index is equal to the number of partitions. + * + * P. 119, line 7-9: "Partition numbering ranges from 0 to 1 less than number of partitions declared in the MPI_PSEND_INIT call, and specifying a partition number that is equal to or larger is erroneous." + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + MPI_Count bad_partition = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Call Pready on a nonexistant partition; an error should occur */ + fprintf(stderr, "Marking invalid partition ready...\n"); + CHECK_RETVAL(MPI_Pready(bad_partition, request)); + fprintf(stderr, "Invalid partition marked ready...\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_pready2.c b/partitioned-communication/test_pready2.c new file mode 100644 index 0000000..913bec9 --- /dev/null +++ b/partitioned-communication/test_pready2.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls pready on a partition whose index is negative. + * + * P. 119, line 7-9: "Partition numbering ranges from 0 to 1 less than number of partitions declared in the MPI_PSEND_INIT call, and specifying a partition number that is equal to or larger is erroneous." + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + MPI_Count bad_partition = -5; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Call Pready on a nonexistant partition; an error should occur */ + fprintf(stderr, "Marking invalid partition ready...\n"); + CHECK_RETVAL(MPI_Pready(bad_partition, request)); + fprintf(stderr, "Invalid partition marked ready...\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_pready3.c b/partitioned-communication/test_pready3.c new file mode 100644 index 0000000..7b24394 --- /dev/null +++ b/partitioned-communication/test_pready3.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls pready on a partition that is active, i.e., has already been marked as ready. + * + * P. 119, line 11-12: Calling MPI_PREADY on an active partition is erroneous. + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + MPI_Count active_partition = 2; // assumes at least 3 partitions + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Call Pready on a partition already marked as ready; an error should occur */ + fprintf(stderr, "Marking previously marked partition ready...\n"); + CHECK_RETVAL(MPI_Pready(active_partition, request)); + fprintf(stderr, "Previously marked partition marked again...\n"); + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_pready4.c b/partitioned-communication/test_pready4.c new file mode 100644 index 0000000..309cdca --- /dev/null +++ b/partitioned-communication/test_pready4.c @@ -0,0 +1,61 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * Calls PREADY on a request object that corresponds to an Isend. + * + * P. 119, line 6: "It is erroneous to use MPI_PREADY on any request object that does not correspond to a partitioned send operation." + * + * Expected outcome: Error message + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Request isend_request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Isend(message, PARTITIONS*COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD, &isend_request)); + + + // This call is erroneous + CHECK_RETVAL(MPI_Pready(0, isend_request)); + + CHECK_RETVAL(MPI_Wait(&isend_request, MPI_STATUS_IGNORE)); + + } + else if (1 == myrank) { + + MPI_Irecv(message, PARTITIONS*COUNT, MPI_INT, source, tag, MPI_COMM_WORLD, &request); + + MPI_Wait(&request, MPI_STATUS_IGNORE); + + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_pready_list0.c b/partitioned-communication/test_pready_list0.c new file mode 100644 index 0000000..6bed784 --- /dev/null +++ b/partitioned-communication/test_pready_list0.c @@ -0,0 +1,82 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 119-120: PREADY_LIST defined here. + * + * This test just uses PREADY_LIST instead of PREADY + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + int partitions_list[PARTITIONS]; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + partitions_list[i] = i; + } + + /* Basic Pready list use case */ + CHECK_RETVAL(MPI_Pready_list(partitions, partitions_list, request)); + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_pready_list1.c b/partitioned-communication/test_pready_list1.c new file mode 100644 index 0000000..0750b8f --- /dev/null +++ b/partitioned-communication/test_pready_list1.c @@ -0,0 +1,86 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 119-120: PREADY_LIST defined here. + * The discussion of PREADY (P. 119, line 11-12) implies the same partition cannot occur more than once in a list, so that is checked here + * + * Expected outcome: Some sort of error + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + int partitions_list[PARTITIONS]; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + partitions_list[i] = i; + } + + /* make is so the same partition appears more than once in the list */ + partitions_list[0] = PARTITIONS-1; + + /* this is erroneous */ + CHECK_RETVAL(MPI_Pready_list(partitions, partitions_list, request)); + /* this will keeping the test from hanging if an error did not occur */ + MPI_Pready(0, request); + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_pready_range0.c b/partitioned-communication/test_pready_range0.c new file mode 100644 index 0000000..61ead3b --- /dev/null +++ b/partitioned-communication/test_pready_range0.c @@ -0,0 +1,81 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * P. 110: Definition of MPI_PREADY_RANGE. It is inclusive (line 36) + * + * This test just uses PREADY_RANGE instead of PREADY + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions*/ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + // CHECK_RETVAL(MPI_Pready(i, request)); + } + + /* Basic Pready range use case */ + CHECK_RETVAL(MPI_Pready_range(0,partitions-1,request)); + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_startall0.c b/partitioned-communication/test_startall0.c new file mode 100644 index 0000000..41a0ad7 --- /dev/null +++ b/partitioned-communication/test_startall0.c @@ -0,0 +1,160 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * STARTALL should start multiple channels, since it is a generalization of MPI_START. (Section 3.9, pp. 109-110). + * + * This test simply confirms this. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 +#define CHANNELS 3 + +int main(int argc, char *argv[]) { + + int messageA[PARTITIONS*COUNT]; + int messageB[PARTITIONS*COUNT]; + int messageC[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tagA = 1, tagB = 2, tagC = 3, flagA = 0, flagB = 0, flagC = 0, sflag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) { + messageA[i] = 0; + messageB[i] = 0; + messageC[i] = 0; + } + + MPI_Request requests[CHANNELS]; + MPI_Status status; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(messageA, partitions, COUNT, MPI_INT, dest, tagA, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[0])); + CHECK_RETVAL(MPI_Psend_init(messageB, partitions, COUNT, MPI_INT, dest, tagB, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[1])); + CHECK_RETVAL(MPI_Psend_init(messageC, partitions, COUNT, MPI_INT, dest, tagC, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[2])); + + sflag = 0; + MPI_Request_get_status(requests[0], &sflag, &status); + fprintf(stderr, "After send init: request 0: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[1], &sflag, &status); + fprintf(stderr, "After send init: request 1: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[2], &sflag, &status); + fprintf(stderr, "After send init: request 2: %d\n", sflag); + + CHECK_RETVAL(MPI_Startall(CHANNELS, requests)); + + sflag = 0; + MPI_Request_get_status(requests[0], &sflag, &status); + fprintf(stderr, "After startall: request 0: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[1], &sflag, &status); + fprintf(stderr, "After startall: request 1: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[2], &sflag, &status); + fprintf(stderr, "After startall: request 2: %d\n", sflag); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) messageA[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, requests[0])); + for (j = 0; j < COUNT; ++j) messageB[j+(COUNT*i)] = (j+(COUNT*i)) * 10; + CHECK_RETVAL(MPI_Pready(i, requests[1])); + for (j = 0; j < COUNT; ++j) messageC[j+(COUNT*i)] = (j+(COUNT*i)) * 100; + CHECK_RETVAL(MPI_Pready(i, requests[2])); + } + + sflag = 0; + MPI_Request_get_status(requests[0], &sflag, &status); + fprintf(stderr, "After pready: request 0: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[1], &sflag, &status); + fprintf(stderr, "After pready: request 1: %d\n", sflag); + sflag = 0; + MPI_Request_get_status(requests[2], &sflag, &status); + fprintf(stderr, "After pready: request 2: %d\n", sflag); + + + fprintf(stderr, "Rank 0: testing\n"); + + while ( !(flagA && flagB && flagC) ) { + CHECK_RETVAL(MPI_Test(&requests[0], &flagA, MPI_STATUS_IGNORE)); + CHECK_RETVAL(MPI_Test(&requests[1], &flagB, MPI_STATUS_IGNORE)); + CHECK_RETVAL(MPI_Test(&requests[2], &flagC, MPI_STATUS_IGNORE)); + } + + fprintf(stderr, "Rank 1: all flags True\n"); + + MPI_Request_free(&requests[0]); + MPI_Request_free(&requests[1]); + MPI_Request_free(&requests[2]); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(messageA, partitions, COUNT, MPI_INT, source, tagA, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[0])); + CHECK_RETVAL(MPI_Precv_init(messageB, partitions, COUNT, MPI_INT, source, tagB, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[1])); + CHECK_RETVAL(MPI_Precv_init(messageC, partitions, COUNT, MPI_INT, source, tagC, MPI_COMM_WORLD, MPI_INFO_NULL, &requests[2])); + + CHECK_RETVAL(MPI_Startall(CHANNELS, requests)); + + fprintf(stderr, "Rank 1: testing\n"); + while ( !(flagA && flagB && flagC) ) { + CHECK_RETVAL(MPI_Test(&requests[0], &flagA, MPI_STATUS_IGNORE)); + CHECK_RETVAL(MPI_Test(&requests[1], &flagB, MPI_STATUS_IGNORE)); + CHECK_RETVAL(MPI_Test(&requests[2], &flagC, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&requests[0]); + MPI_Request_free(&requests[1]); + MPI_Request_free(&requests[2]); + + fprintf(stderr, "Message A: "); + for (i=0; i< PARTITIONS*COUNT; ++i) fprintf(stderr, "%d ", messageA[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "Message B: "); + for (i=0; i< PARTITIONS*COUNT; ++i) fprintf(stderr, "%d ", messageB[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "Message C: "); + for (i=0; i< PARTITIONS*COUNT; ++i) fprintf(stderr, "%d ", messageC[i]); + fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (messageA[i] != i) { + fprintf(stderr, "ERROR: Contents of buffer messageA do not match contents sent (expected %d, found %d).\n",i,messageA[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + if (messageB[i] != i*10) { + fprintf(stderr, "ERROR: Contents of buffer messageB do not match contents sent (expected %d, found %d).\n",i*10,messageB[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + if (messageC[i] != i*100) { + fprintf(stderr, "ERROR: Contents of buffer messageC do not match contents sent (expected %d, found %d).\n",i*100,messageC[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_state0.c b/partitioned-communication/test_state0.c new file mode 100644 index 0000000..f359d82 --- /dev/null +++ b/partitioned-communication/test_state0.c @@ -0,0 +1,151 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This test is motivated by https://github.com/open-mpi/ompi/issues/12328 + * + * The test confirms that the request status is reset in subsequent rounds using the same Send/Recv channel. + * + * On the sender side, if the request status does not reset with the second call to START, marking partitions + * with PREADY will do nothing, and the TEST/WAIT will automatically succeed with no data having been sent. + * + * On the reciever side, if the request status does not reset with the second call to START, the receiver will + * immediately succeed on TEST/WAIT and then the test will fail when validating the buffer contents (because the + * receiver did not get round 2 data). If the request status is reset, then the test will hang waiting for + * completion. + * + * The test is passed if it runs to completion successfully. + * + */ + +#include "test_common.h" + +#define PARTITIONS 4 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Status status; + + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 1: After PSEND_INIT, request status is: %d\n", flag); + + /* Round 1 */ + MPI_Start(&request); + + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 1: After START, request status is: %d\n", flag); + + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 1: After PREADY #%d, request status is: %d\n", i, flag); + } + + fprintf(stderr, "Sent in round 1: "); + for (i=0; i < COUNT * PARTITIONS; ++i) fprintf(stderr, " %d", message[i]); + fprintf(stderr, "\n"); + + flag = 0; + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 1: After TEST, request status is: %d\n", flag); + + /* Round 2 */ + MPI_Start(&request); + + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 2: After START, request status is: %d\n", flag); + + /* Fill the sending partitions and mark as ready as each is filled; note data is different than first round */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = 10*(j+(COUNT*i)); + MPI_Pready(i, request); + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 2: After PREADY #%d, request status is: %d\n", i, flag); + } + + fprintf(stderr, "Sent in round 2: "); + for (i=0; i < COUNT * PARTITIONS; ++i) fprintf(stderr, " %d", message[i]); + fprintf(stderr, "\n"); + + flag = 0; + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + flag = 0; + MPI_Request_get_status(request, &flag, &status); + fprintf(stderr, "Rank 0: Communication Round 2: After TEST, request status is: %d\n", flag); + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + /* Round 1 */ + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + fprintf(stderr, "Received in round 1: "); + for (i=0; i < COUNT * PARTITIONS; ++i) fprintf(stderr, " %d", message[i]); + fprintf(stderr, "\n"); + + /* Round 2 */ + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + fprintf(stderr, "Received in round 2: "); + for (i=0; i < COUNT * PARTITIONS; ++i) fprintf(stderr, " %d", message[i]); + fprintf(stderr, "\n"); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != 10*i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",10*i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize (); + + return 0; +} + diff --git a/partitioned-communication/test_wildcard0.c b/partitioned-communication/test_wildcard0.c new file mode 100644 index 0000000..6853dbc --- /dev/null +++ b/partitioned-communication/test_wildcard0.c @@ -0,0 +1,79 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This test attempts to use MPI_ANY_SOURCE + * + * P. 118, line 28: Wildcards for source and tag are not allowed. + * + * Expected outcome: Error message + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + /* This call should cause error because of MPI_ANY_SOURCE */ + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_wildcard1.c b/partitioned-communication/test_wildcard1.c new file mode 100644 index 0000000..52bbd58 --- /dev/null +++ b/partitioned-communication/test_wildcard1.c @@ -0,0 +1,79 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * This test attempts to use MPI_ANY_TAG + * + * P. 118, line 28: Wildcards for source and tag are not allowed. + * + * Expected outcome: Error message + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + MPI_Psend_init(message, partitions, COUNT, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request); + MPI_Start(&request); + + /* Fill the sending partitions and mark as ready as each is filled */ + for (i = 0; i < partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + MPI_Pready(i, request); + } + + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + /* This call should cause error because of MPI_ANY_TAG */ + CHECK_RETVAL(MPI_Precv_init(message, partitions, COUNT, MPI_INT, source, MPI_ANY_TAG, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + MPI_Test(&request, &flag, MPI_STATUS_IGNORE); + } + + MPI_Request_free(&request); + + /* all partitions received; check contents */ + for (i = 0; i < PARTITIONS*COUNT; ++i) { + if (message[i] != i) { + fprintf(stderr, "ERROR: Contents received do not match contents sent (expected %d, found %d).\n",i,message[i]); + MPI_Abort(MPI_COMM_WORLD, 1); + } + } + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_zerocount0.c b/partitioned-communication/test_zerocount0.c new file mode 100644 index 0000000..9e6dfcf --- /dev/null +++ b/partitioned-communication/test_zerocount0.c @@ -0,0 +1,79 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * In PSEND_INIT and PRECV_INIT, partitions and count can be zero. + * P. 116, line 19: In PSEND_INIT, partitions is defined as “number of partitions (non-negative integer)” + * P. 116, line 20: In PSEND_INIT, count is defined as “number of elements per partition (non-negative integer)”. + * Same for PRECV_INIT (p. 117, line 27 and p. 117, line 29) + * + * This test confirms nothing goes wrong when both PSEND_INIT and PRECV_INIT use 0 partitions with a > 0 count. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + MPI_Count comm_partitions = 0; // use 0 partitions for init + MPI_Count comm_count = COUNT; // use COUNT partitions for init + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, comm_partitions, comm_count, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + /* Because there are 0 partitions, Pready never gets called */ + for (i = 0; i < comm_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, comm_partitions, comm_count, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} + diff --git a/partitioned-communication/test_zerocount1.c b/partitioned-communication/test_zerocount1.c new file mode 100644 index 0000000..aff5327 --- /dev/null +++ b/partitioned-communication/test_zerocount1.c @@ -0,0 +1,79 @@ +// Copyright 2024 National Technology & Engineering Solutions of Sandia, LLC +// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. + +/* + * In PSEND_INIT and PRECV_INIT, partitions and count can be zero. + * P. 116, line 19: In PSEND_INIT, partitions is defined as “number of partitions (non-negative integer)” + * P. 116, line 20: In PSEND_INIT, count is defined as “number of elements per partition (non-negative integer)”. + * Same for PRECV_INIT (p. 117, line 27 and p. 117, line 29) + * + * This test confirms nothing goes wrong when both PSEND_INIT and PRECV_INIT use > 0 partitions each with 0 count. + * + * Expected outcome: PASS + * + */ + +#include "test_common.h" + +#define PARTITIONS 8 +#define COUNT 5 + +int main(int argc, char *argv[]) { + + int message[PARTITIONS*COUNT]; + + MPI_Count partitions = PARTITIONS; + + MPI_Count comm_partitions = PARTITIONS; // use PARTITIONS partitions for init + MPI_Count comm_count = 0; // use 0 partitions for init + + int source = 0, dest = 1, tag = 1, flag = 0; + int myrank, i, j; + int provided; + + for (i = 0; i < PARTITIONS * COUNT; ++i) message[i] = 0; + + MPI_Request request; + MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided); + if (provided < MPI_THREAD_SERIALIZED) MPI_Abort(MPI_COMM_WORLD , EXIT_FAILURE); + MPI_Comm_rank(MPI_COMM_WORLD , &myrank); + + if (0 == myrank) { + + CHECK_RETVAL(MPI_Psend_init(message, comm_partitions, comm_count, MPI_INT, dest, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + + /* Fill the sending partitions and mark as ready as each is filled */ + /* There are non-zero partitions, so the message buffer will get filled; however, the message generated by or after PREADY will have a 0 count payload */ + for (i = 0; i < comm_partitions; ++i) { + for (j = 0; j < COUNT; ++j) message[j+(COUNT*i)] = j+(COUNT*i); + CHECK_RETVAL(MPI_Pready(i, request)); + } + + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + else if (1 == myrank) { + CHECK_RETVAL(MPI_Precv_init(message, comm_partitions, comm_count, MPI_INT, source, tag, MPI_COMM_WORLD , MPI_INFO_NULL , &request)); + CHECK_RETVAL(MPI_Start(&request)); + while (!flag) { + CHECK_RETVAL(MPI_Test(&request, &flag, MPI_STATUS_IGNORE)); + } + + MPI_Request_free(&request); + + } + + MPI_Barrier(MPI_COMM_WORLD); + if (0 == myrank) {TEST_RAN_TO_COMPLETION();} + + MPI_Finalize(); + + return 0; +} +