Actual source code: ex63.c
1: static char help[] = "Tests `GarbageKeyAllReduceIntersect_Private()` in parallel\n\n";
3: #include <petsc/private/garbagecollector.h>
5: /* This program tests `GarbageKeyAllReduceIntersect_Private()`.
6: To test this routine in parallel, the sieve of Eratosthenes is
7: implemented.
8: */
10: /* Populate an array with Prime numbers <= n.
11: Primes are generated using trial division
12: */
13: PetscErrorCode Prime(PetscInt64 **set, PetscInt64 n)
14: {
15: size_t overestimate;
16: PetscBool is_prime;
17: PetscInt64 ii, jj, count = 0;
18: PetscInt64 *prime;
20: PetscFunctionBeginUser;
21: /* There will be fewer than ceil(1.26 * n/log(n)) primes <= n */
22: overestimate = (size_t)PetscCeilReal(((PetscReal)n) * 1.26 / PetscLogReal((PetscReal)n));
23: PetscCall(PetscMalloc1(overestimate, &prime));
24: for (ii = 2; ii < n + 1; ii++) {
25: is_prime = PETSC_TRUE;
26: for (jj = 2; jj <= PetscFloorReal(PetscSqrtReal(ii)); jj++) {
27: if (ii % jj == 0) {
28: is_prime = PETSC_FALSE;
29: break;
30: }
31: }
32: if (is_prime) {
33: prime[count] = ii;
34: count++;
35: }
36: }
38: PetscCall(PetscMalloc1((size_t)count + 1, set));
39: (*set)[0] = count;
40: for (ii = 1; ii < count + 1; ii++) (*set)[ii] = prime[ii - 1];
41: PetscCall(PetscFree(prime));
42: PetscFunctionReturn(PETSC_SUCCESS);
43: }
45: /* Print out the contents of a set */
46: PetscErrorCode PrintSet(MPI_Comm comm, PetscInt64 *set)
47: {
48: char text[64];
49: PetscInt ii;
51: PetscFunctionBeginUser;
52: PetscCall(PetscSynchronizedPrintf(comm, "["));
53: for (ii = 1; ii <= (PetscInt)set[0]; ii++) {
54: PetscCall(PetscFormatConvert(" %" PetscInt64_FMT ",", text));
55: PetscCall(PetscSynchronizedPrintf(comm, text, set[ii]));
56: }
57: PetscCall(PetscSynchronizedPrintf(comm, "]\n"));
58: PetscCall(PetscSynchronizedFlush(comm, PETSC_STDOUT));
59: PetscFunctionReturn(PETSC_SUCCESS);
60: }
62: /* Check set equality */
63: PetscErrorCode AssertSetsEqual(PetscInt64 *set, PetscInt64 *true_set)
64: {
65: PetscInt ii;
67: PetscFunctionBeginUser;
68: PetscAssert(set[0] == true_set[0], PETSC_COMM_WORLD, PETSC_ERR_ARG_INCOMP, "Sets of different sizes");
69: for (ii = 1; ii < set[0] + 1; ii++) PetscAssert(set[ii] == true_set[ii], PETSC_COMM_WORLD, PETSC_ERR_ARG_INCOMP, "Sets are different");
70: PetscFunctionReturn(PETSC_SUCCESS);
71: }
73: /* Parallel implementation of the sieve of Eratosthenes */
74: PetscErrorCode test_sieve(MPI_Comm comm)
75: {
76: PetscInt64 ii, local_p, maximum, n;
77: PetscInt64 *local_set, *cursor, *bootstrap_primes, *truth;
78: PetscMPIInt size, rank;
79: PetscReal x;
81: PetscFunctionBeginUser;
82: PetscCallMPI(MPI_Comm_rank(comm, &rank));
83: PetscCallMPI(MPI_Comm_size(comm, &size));
85: /* There should be at least `size + 1` primes smaller than
86: (size + 1)*(log(size + 1) + log(log(size + 1))
87: once `size` >=6
88: This is sufficient for each rank to create its own sieve based off
89: a different prime and calculate the size of the sieve.
90: */
91: x = (PetscReal)(size > 6) ? size + 1 : 7;
92: x = x * (PetscLogReal(x) + PetscLogReal(PetscLogReal(x)));
93: PetscCall(Prime(&bootstrap_primes, PetscCeilReal(x)));
95: /* Calculate the maximum possible prime, select a prime number for
96: each rank and allocate memorty for the sieve
97: */
98: maximum = bootstrap_primes[size + 1] * bootstrap_primes[size + 1] - 1;
99: local_p = bootstrap_primes[rank + 1];
100: n = maximum - local_p - (maximum / local_p) + 1 + rank + 1;
101: PetscCall(PetscMalloc1(n + 1, &local_set));
103: /* Populate the sieve first with all primes <= `local_p`, followed by
104: all integers that are not a multiple of `local_p`
105: */
106: local_set[0] = n;
107: cursor = &local_set[1];
108: for (ii = 0; ii < rank + 1; ii++) {
109: *cursor = bootstrap_primes[ii + 1];
110: cursor++;
111: }
112: for (ii = local_p + 1; ii <= maximum; ii++) {
113: if (ii % local_p != 0) {
114: *cursor = ii;
115: cursor++;
116: }
117: }
118: PetscCall(PetscPrintf(comm, "SIEVES:\n"));
119: PetscCall(PrintSet(comm, local_set));
121: PetscCall(PetscFree(bootstrap_primes));
123: /* Perform the intersection, testing parallel intersection routine */
124: PetscCall(GarbageKeyAllReduceIntersect_Private(PETSC_COMM_WORLD, &local_set[1], (PetscInt *)&local_set[0]));
126: PetscCall(PetscPrintf(comm, "INTERSECTION:\n"));
127: PetscCall(PrintSet(comm, local_set));
129: PetscCall(Prime(&truth, maximum));
130: PetscCall(PetscPrintf(comm, "TRUTH:\n"));
131: PetscCall(PrintSet(comm, truth));
133: /* Assert the intersection corresponds to primes calculated using
134: trial division
135: */
136: PetscCall(AssertSetsEqual(local_set, truth));
138: PetscCall(PetscFree(local_set));
139: PetscCall(PetscFree(truth));
140: PetscFunctionReturn(PETSC_SUCCESS);
141: }
143: /* Main executes the individual tests in a predefined order */
144: int main(int argc, char **argv)
145: {
146: PetscFunctionBeginUser;
147: PetscCall(PetscInitialize(&argc, &argv, NULL, help));
149: PetscCall(test_sieve(PETSC_COMM_WORLD));
151: PetscCall(PetscPrintf(PETSC_COMM_WORLD, "ALL PASSED\n"));
152: PetscCall(PetscFinalize());
153: return 0;
154: }
156: /*TEST
158: testset:
159: test:
160: nsize: 2
161: suffix: 2
162: output_file: output/ex63_2.out
163: test:
164: nsize: 3
165: suffix: 3
166: output_file: output/ex63_3.out
167: test:
168: nsize: 4
169: suffix: 4
170: output_file: output/ex63_4.out
172: TEST*/