|
| 1 | +# Alltoallv Validation of complex datatypes |
| 2 | + |
| 3 | +This test creates a variety of configurations for testing data validation of |
| 4 | +the alltoallv collective using non-standard datatypes. |
| 5 | + |
| 6 | +The approach is the following sequence: |
| 7 | + - Create some datatype |
| 8 | + - Determine the packed size, and allocate both packed and unpacked buffers to |
| 9 | + hold the send data. |
| 10 | + - Fill the packed buffer with a test pattern, then sendrecv it to the unpacked |
| 11 | + send buffer by sending from a MPI_BYTES buffer to the test datatype. |
| 12 | + - Perform the alltoallv collective |
| 13 | + - Transfer the received data back into a packed format. |
| 14 | + - Verify the contents of the packed format using knowledge of what data was |
| 15 | + being sent. |
| 16 | + - Verify that no buffer under-runs or over-runs occured in the buffers by |
| 17 | + checking some guard bytes. |
| 18 | + |
| 19 | +Validation is the only purpose of this test. It should not be used for |
| 20 | +performance timing, as many extra memory copies and assignments are performed. |
| 21 | +No timing is printed. |
| 22 | + |
| 23 | +The code is written in C++ only to access a predictable random number generator. |
| 24 | +All MPI calls are done via C interface. |
| 25 | + |
| 26 | +## Test Overview |
| 27 | + |
| 28 | +Tests are broken into complexity levels. |
| 29 | + |
| 30 | +### Level 1 |
| 31 | + |
| 32 | +Level 1 types are composed of basic MPI types like `MPI_CHAR`, `MPI_REAL`, |
| 33 | +`MPI_INT64_T` and so forth. The data types are not exhaustive, only 9 are used. |
| 34 | +Executing only the level 1 tests will perform only 9 tests: both sending and |
| 35 | +receiving the same datatype. |
| 36 | + |
| 37 | +### Level 2 |
| 38 | + |
| 39 | +Level 2 types are collections of Level 1 types. There are 7 Level 1 types in |
| 40 | +various configurations including: |
| 41 | + |
| 42 | + - increasing the count, using the same type |
| 43 | + - contiguous and non-contiguous vectors |
| 44 | + - contiguous and non-contiguous vectors with negative stride |
| 45 | + |
| 46 | +Level 2 tests all exchange compatible types, therefore all combinations of the |
| 47 | +above are used as send and receive types. With 7 types, Level 2 executes 49 |
| 48 | +tests. |
| 49 | + |
| 50 | +All level 2 tests are performed with the same basic datatype (MPI_INT). |
| 51 | + |
| 52 | +Note that each "one" of these types is a vector, so setting `--item-count` to 10 |
| 53 | +really means you are sending 10 vectors each with some number (happens to be 12) |
| 54 | +of basic types. |
| 55 | + |
| 56 | +### Level 3 |
| 57 | + |
| 58 | +Level 3 tests collections of two different Level 1 types. We test MPI_INT and |
| 59 | +MPI_CHAR together. These tests create the type using MPI_Type_create_struct in |
| 60 | +various orders and configurations including: |
| 61 | + - contiguous and non-contiguous in-order elements |
| 62 | + - contiguous and non-contiguous reverse-order elements |
| 63 | + - Negative lower bounds |
| 64 | + - Padding in extents |
| 65 | + |
| 66 | +There are 6 Level 3 tests, and like Level 2 tests they are all compatible types, |
| 67 | +so 36 total tests are executed. |
| 68 | + |
| 69 | +### Level 4 |
| 70 | + |
| 71 | +There are two hand-made Level 4 tests. These are composed of several layers of |
| 72 | +level 2 and level 3 types in combination with each other to make collections of |
| 73 | +different kinds of types in vectors with various paddings and spacings. Best to |
| 74 | +read the code for these. They are not cross-compatible, so only 2 tests are |
| 75 | +executed. |
| 76 | + |
| 77 | +Again note that these constructed tytes are somewhat large themselves (hundreds |
| 78 | +of bytes), so setting a high `--item-count` could result in longer runtimes. |
| 79 | + |
| 80 | +### Total |
| 81 | + |
| 82 | +As of the initial version of this program, there were 96 tests. The |
| 83 | +configuration where all ranks send and receive 1 count for only 1 iteration |
| 84 | +results in each rank sending and receiving approximately 2.7KBytes of data per |
| 85 | +rank during the full test battery. |
| 86 | + |
| 87 | +However there is not so much data that the execution time is unreasonable. Test |
| 88 | +execution of 32 ranks on a single host using all default options takes less than |
| 89 | +5 seconds, and most ranks send about 630 KBytes. |
| 90 | + |
| 91 | +# Compile |
| 92 | +``` |
| 93 | +$ ./autogen.sh && ./configure && make |
| 94 | +
|
| 95 | +$ mpirun -n 13 src/alltoallv_ddt |
| 96 | +Rank 0 sent 254104 bytes, and received 265152 bytes. |
| 97 | +[OK] All tests passsed. Executed 96 tests with seed 0 with 13 total ranks). |
| 98 | +
|
| 99 | +``` |
| 100 | + |
| 101 | +# Usage |
| 102 | +``` |
| 103 | +Test alltoallv using various ddt's and validate results. |
| 104 | +This test uses pseudo-random sequences from C++'s mt19937 generator. |
| 105 | +The test (but not necessarily the implementation) is deterministic |
| 106 | +when the options and number of ranks remain the same. |
| 107 | +Options: |
| 108 | + [-s|--seed <seed>] Change the seed to shuffle which datapoints are exchanged |
| 109 | + [-c|--item-count <citems>] Each rank will create <citems> to consider for exchange (default=10). |
| 110 | + [-i|--prob-item <prob>] Probability that rank r will send item k to rank q. (0.50) |
| 111 | + [-r|--prob-rank <prob>] Probability that rank r will send anything to rank q. (0.90) |
| 112 | + [-w|--prob-world <prob>] Probability that rank r will do anything at all. (0.95) |
| 113 | + [-t|--iters <iters>] The number of iterations to test each dtype. |
| 114 | + [-o|--only <high,low>] Only execute a specific test signified by the pair high,low. |
| 115 | + [-v|--verbose=level ] Set verbosity during execution (0=quiet (default). 1,2,3: loud). |
| 116 | + [-h|--help] Print this help and exit. |
| 117 | + [-z|--verbose-rank] Only the provided rank will print. Default=0. ALL = -1. |
| 118 | +``` |
| 119 | + |
| 120 | +Some recommended test cases: |
| 121 | +``` |
| 122 | +# no ranks exchange any data |
| 123 | +alltoallv_ddt -w 0 |
| 124 | +
|
| 125 | +# same as alltoall: all ranks exchange same amount of data |
| 126 | +alltoallv_ddt -w 1 -r 1 -i 1 |
| 127 | +
|
| 128 | +# perform a different test each time you run, or repeat the same test: |
| 129 | +alltoallv_ddt -s $RANDOM |
| 130 | +alltoallv_ddt -s 1234 |
| 131 | +``` |
| 132 | + |
| 133 | +Note since alltoall is a hefty collective, and we go to the trouble of |
| 134 | +validating every single message, caution should be used when exercising large |
| 135 | +numbers of ranks, large numbers of counts, or large numbers of iterations. |
| 136 | + |
| 137 | +# Debugging |
| 138 | + |
| 139 | +In the case of data validation failure: re-run the test harness on only the |
| 140 | +failing test (using `--only` and increase the verbosity up to 3. You may also |
| 141 | +need to set the verbosity of a particular rank with `-z`). |
| 142 | + |
| 143 | +For example at verbosity 0, we only know that validation failed on rank 1, but |
| 144 | +not which test. |
| 145 | + |
| 146 | +``` |
| 147 | +mpirun -n 2 src/alltoallv_ddt -z 1 -v 3 -w 1 |
| 148 | +Rank 1 failed to validate data! |
| 149 | +ERROR: Validation failed on rank 1! |
| 150 | +``` |
| 151 | + |
| 152 | +Setting the rank-specific verbosity to that rank (or to all ranks) and the |
| 153 | +verbosity up to 2 reveals some additional details including which test, and what |
| 154 | +part of the buffer: |
| 155 | + |
| 156 | +``` |
| 157 | +$ mpirun -n 2 src/alltoallv_ddt -z 1 -v 3 -w 1 |
| 158 | +--- Starting test 2,1. Crossing 0 x 0 |
| 159 | +Rank 1 failed to validate data! |
| 160 | +0010: 42-42 99-43 44-44 45-45 46-46 47-47 48-48 49-49 50-50 51-51 -- CORRUPT |
| 161 | +0020: 52-52 53-53 54-54 55-55 56-56 57-57 58-58 59-59 60-60 61-61 -- VALID |
| 162 | +ERROR: Validation failed on rank 1! |
| 163 | +``` |
| 164 | + |
| 165 | +Buffer addresses are provided. These are base-10 addresses relative to the |
| 166 | +packed representation of the datatype. The first number is what was received, |
| 167 | +the second number is what was expected. To avoid too much print-outs, |
| 168 | +subsequent CORRUPT lines are skipped and only the next valid line is printed, so |
| 169 | +output will allways appear to alternate between CORRUPT and VALID. |
0 commit comments