From cb74936aa64cd7faa9560f70a85e4403105f34f0 Mon Sep 17 00:00:00 2001 From: tfk Date: Fri, 9 Dec 2022 21:22:26 +0000 Subject: [PATCH 1/7] =?UTF-8?q?Create=20Tutorials=20=E2=80=9Ctutorial-for-?= =?UTF-8?q?dprng=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/tutorials/tutorial-for-dprng.md | 68 +++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/doc/tutorials/tutorial-for-dprng.md diff --git a/src/doc/tutorials/tutorial-for-dprng.md b/src/doc/tutorials/tutorial-for-dprng.md new file mode 100644 index 00000000..a92c72a7 --- /dev/null +++ b/src/doc/tutorials/tutorial-for-dprng.md @@ -0,0 +1,68 @@ +--- +layout: layouts/page.njk +title: Tutorial for DPRNG +author: Timothy Kaler +date: 2022-12-09T21:21:12.291Z +attribution: true +--- +``` +#include +#include +#include +#include +#include + +// Generate a pseudorandom number using the built-in DPRNG in OpenCilk 2.0 +uint64_t generate_random_number() { + return __cilkrts_get_dprand(); +} + +// Reseed the built-in DPRNG in OpenCilk 2.0 +void reseed_dprng(uint64_t seed) { + __cilkrts_dprand_set_seed(seed); +} + +int main() { + // Reseed the DPRNG with a value of 12345 + reseed_dprng(12345); + + // Set the number of iterations to use for the Monte Carlo simulation + int num_iterations = 1000000; + + // Set the radius of the circle + double radius = 1.0; + + // Create reducer objects for the counters for the number of points inside and outside the circle + cilk::opadd_reducer inside_circle; + cilk::opadd_reducer outside_circle; + +// Run the Monte Carlo simulation in parallel +cilk_for(int i = 0; i < num_iterations; i++) { + // Generate two pseudorandom numbers for the x and y coordinates + double x = (double)generate_random_number() / UINT64_MAX; + double y = (double)generate_random_number() / UINT64_MAX; + + // Compute the distance of the point from the origin + double dist = sqrt(x * x + y * y); + + // Increment the counter for points inside or outside the circle based on the distance + if (dist <= radius) { + inside_circle++; + } else { + outside_circle++; + } +} + +// Compute the ratio of points inside the circle to the total number of points +double ratio = (double)inside_circle.get_value() / (double)(inside_circle.get_value() + outside_circle.get_value()); + +// Use this ratio to compute an estimate of pi +double pi_estimate = 4.0 * ratio; + +// Print the result +printf("Estimate of pi: %.10f\n", pi_estimate); + +return 0; +} + +``` \ No newline at end of file From f19c73a0f3618cb2fef14a492923dc5516ada103 Mon Sep 17 00:00:00 2001 From: tfk Date: Fri, 9 Dec 2022 21:26:35 +0000 Subject: [PATCH 2/7] =?UTF-8?q?Update=20Tutorials=20=E2=80=9Ctutorial-for-?= =?UTF-8?q?dprng=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/tutorials/tutorial-for-dprng.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/doc/tutorials/tutorial-for-dprng.md b/src/doc/tutorials/tutorial-for-dprng.md index a92c72a7..bdf55c55 100644 --- a/src/doc/tutorials/tutorial-for-dprng.md +++ b/src/doc/tutorials/tutorial-for-dprng.md @@ -5,6 +5,16 @@ author: Timothy Kaler date: 2022-12-09T21:21:12.291Z attribution: true --- +OpenCilk 2.0 is a programming framework that supports both pedigrees and deterministic pseudorandom number generation (DPRNG). To enable these features in a Cilk program, simply link the program with the `-lopencilk-pedigrees` library. No recompiling is necessary. + +There are three options for using DPRNG with OpenCilk 2.0: + +1. Use the OpenCilk runtime's built-in DPRNG. To generate a pseudorandom number, call the `__cilkrts_get_dprand()` function. This function returns a 64-bit unsigned integer, although the return value will be one of 2^64-59 possible results. The pseudorandom number generator can be reseeded at the beginning of the program by calling `__cilkrts_dprand_set_seed(seed)`, where `seed` is a 64-bit unsigned integer. The `__cilkrts_get_dprand()` function is easy to use and fast, but it offers only limited control over the DPRNG. +2. Use an existing DPRNG library that uses pedigrees. The only known such library is the DotMix implementation from CilkPub. CilkPub is implemented entirely in C++, so it may not be useful for programs written in other languages. +3. Write your own DPRNG library that uses pedigrees. The library can read the pedigree of the current strand by calling `__cilkrts_get_pedigree()`, which returns the pedigree as a singly-linked list. This option allows for flexible implementation of a new DPRNG in C or C++, but it may be more complicated than necessary. + +Here is a usage example for implementing DPRNG with OpenCilk 2.0 using the built-in pseudorandom number generator: + ``` #include #include @@ -64,5 +74,10 @@ printf("Estimate of pi: %.10f\n", pi_estimate); return 0; } +``` + + -``` \ No newline at end of file +The example above runs a Monte Carlo simulation to generate points in a two-dimensional plane. The points are generated using the `generate_random_number()` function, which uses the `__cilkrts_get_dprand()` function to generate pseudorandom numbers. The coordinates of the points are computed by scaling the pseudorandom numbers to the range $\[0, 1]$. The distance of each point from the origin is then computed, and the point is counted as inside or outside the circle with radius 1 based on its distance from the origin. After all points have been counted the ratio of the points inside and outside of the circle is used to estimate pi.\ +\ +This example uses the `cilk_opadd_reducer` reducer type to avoid race conditions on the `inside_circle` and `outside_circle` counters. These counters are now declared as reducer objects, and the `++` operator is used to increment them in the parallel loop. The final value of the counters can be accessed by calling the `get_value()` method on the reducer objects. This ensures that the counters are updated atomically and that their values are consistent across all strands. \ No newline at end of file From 627044dd390ea618e71ecb1512a7b32125beb503 Mon Sep 17 00:00:00 2001 From: tfk Date: Fri, 9 Dec 2022 21:27:52 +0000 Subject: [PATCH 3/7] =?UTF-8?q?Update=20Tutorials=20=E2=80=9Ctutorial-for-?= =?UTF-8?q?dprng=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/tutorials/tutorial-for-dprng.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/tutorials/tutorial-for-dprng.md b/src/doc/tutorials/tutorial-for-dprng.md index bdf55c55..739a51bd 100644 --- a/src/doc/tutorials/tutorial-for-dprng.md +++ b/src/doc/tutorials/tutorial-for-dprng.md @@ -15,7 +15,7 @@ There are three options for using DPRNG with OpenCilk 2.0: Here is a usage example for implementing DPRNG with OpenCilk 2.0 using the built-in pseudorandom number generator: -``` +```cilkcpp# #include #include #include From 4024eb0b590dc445dbd00bcbec96d0103b135b3d Mon Sep 17 00:00:00 2001 From: tfk Date: Fri, 9 Dec 2022 21:34:51 +0000 Subject: [PATCH 4/7] =?UTF-8?q?Update=20Tutorials=20=E2=80=9Ctutorial-for-?= =?UTF-8?q?dprng=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/tutorials/tutorial-for-dprng.md | 48 ++++++++++++------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/doc/tutorials/tutorial-for-dprng.md b/src/doc/tutorials/tutorial-for-dprng.md index 739a51bd..d9b273c9 100644 --- a/src/doc/tutorials/tutorial-for-dprng.md +++ b/src/doc/tutorials/tutorial-for-dprng.md @@ -46,38 +46,36 @@ int main() { cilk::opadd_reducer inside_circle; cilk::opadd_reducer outside_circle; -// Run the Monte Carlo simulation in parallel -cilk_for(int i = 0; i < num_iterations; i++) { - // Generate two pseudorandom numbers for the x and y coordinates - double x = (double)generate_random_number() / UINT64_MAX; - double y = (double)generate_random_number() / UINT64_MAX; - - // Compute the distance of the point from the origin - double dist = sqrt(x * x + y * y); - - // Increment the counter for points inside or outside the circle based on the distance - if (dist <= radius) { - inside_circle++; - } else { - outside_circle++; + // Run the Monte Carlo simulation in parallel + cilk_for(int i = 0; i < num_iterations; i++) { + // Generate two pseudorandom numbers for the x and y coordinates + double x = (double)generate_random_number() / UINT64_MAX; + double y = (double)generate_random_number() / UINT64_MAX; + + // Compute the distance of the point from the origin + double dist = sqrt(x * x + y * y); + + // Increment the counter for points inside or outside the circle based on the distance + if (dist <= radius) { + inside_circle++; + } else { + outside_circle++; + } } -} -// Compute the ratio of points inside the circle to the total number of points -double ratio = (double)inside_circle.get_value() / (double)(inside_circle.get_value() + outside_circle.get_value()); + // Compute the ratio of points inside the circle to the total number of points + double ratio = (double)inside_circle.get_value() / (double)(inside_circle.get_value() + outside_circle.get_value()); -// Use this ratio to compute an estimate of pi -double pi_estimate = 4.0 * ratio; + // Use this ratio to compute an estimate of pi + double pi_estimate = 4.0 * ratio; -// Print the result -printf("Estimate of pi: %.10f\n", pi_estimate); + // Print the result + printf("Estimate of pi: %.10f\n", pi_estimate); -return 0; + return 0; } ``` - - -The example above runs a Monte Carlo simulation to generate points in a two-dimensional plane. The points are generated using the `generate_random_number()` function, which uses the `__cilkrts_get_dprand()` function to generate pseudorandom numbers. The coordinates of the points are computed by scaling the pseudorandom numbers to the range $\[0, 1]$. The distance of each point from the origin is then computed, and the point is counted as inside or outside the circle with radius 1 based on its distance from the origin. After all points have been counted the ratio of the points inside and outside of the circle is used to estimate pi.\ +The example above runs a Monte Carlo simulation to generate points in a two-dimensional plane. The points are generated using the `generate_random_number()` function, which uses the `__cilkrts_get_dprand()` function to generate pseudorandom numbers. The coordinates of the points are computed by scaling the pseudorandom numbers to the range $\[0, 1]$. The distance of each point from the origin is then computed, and the point is counted as inside or outside the circle with radius 1 based on its distance from the origin. After all points have been generated and counted, the ratio of points inside the circle to the total number of points is computed and used to estimate the value of $\pi$. The result is printed to the console.\ \ This example uses the `cilk_opadd_reducer` reducer type to avoid race conditions on the `inside_circle` and `outside_circle` counters. These counters are now declared as reducer objects, and the `++` operator is used to increment them in the parallel loop. The final value of the counters can be accessed by calling the `get_value()` method on the reducer objects. This ensures that the counters are updated atomically and that their values are consistent across all strands. \ No newline at end of file From aad08db207f8522a1bc9d8cb893158ed2da61a38 Mon Sep 17 00:00:00 2001 From: tfk Date: Fri, 9 Dec 2022 21:38:38 +0000 Subject: [PATCH 5/7] =?UTF-8?q?Update=20Tutorials=20=E2=80=9Ctutorial-for-?= =?UTF-8?q?dprng=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/tutorials/tutorial-for-dprng.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/doc/tutorials/tutorial-for-dprng.md b/src/doc/tutorials/tutorial-for-dprng.md index d9b273c9..4619015b 100644 --- a/src/doc/tutorials/tutorial-for-dprng.md +++ b/src/doc/tutorials/tutorial-for-dprng.md @@ -32,6 +32,16 @@ void reseed_dprng(uint64_t seed) { __cilkrts_dprand_set_seed(seed); } +// Identity function for the reducer +void zero(void *v) { + *(int *)v = 0; +} + +// Reduce function for the reducer +void plus(void *l, void *r) { + *(int *)l += *(int *)r; +} + int main() { // Reseed the DPRNG with a value of 12345 reseed_dprng(12345); @@ -43,8 +53,8 @@ int main() { double radius = 1.0; // Create reducer objects for the counters for the number of points inside and outside the circle - cilk::opadd_reducer inside_circle; - cilk::opadd_reducer outside_circle; + int cilk_reducer(zero, plus) inside_circle = 0; + int cilk_reducer(zero, plus) outside_circle = 0; // Run the Monte Carlo simulation in parallel cilk_for(int i = 0; i < num_iterations; i++) { @@ -63,8 +73,9 @@ int main() { } } - // Compute the ratio of points inside the circle to the total number of points - double ratio = (double)inside_circle.get_value() / (double)(inside_circle.get_value() + outside_circle.get_value()); + // Compute the ratio of points inside the circle to + // the total number of points + double ratio = (double)inside_circle / (double)(inside_circle + outside_circle); // Use this ratio to compute an estimate of pi double pi_estimate = 4.0 * ratio; @@ -74,6 +85,7 @@ int main() { return 0; } + ``` The example above runs a Monte Carlo simulation to generate points in a two-dimensional plane. The points are generated using the `generate_random_number()` function, which uses the `__cilkrts_get_dprand()` function to generate pseudorandom numbers. The coordinates of the points are computed by scaling the pseudorandom numbers to the range $\[0, 1]$. The distance of each point from the origin is then computed, and the point is counted as inside or outside the circle with radius 1 based on its distance from the origin. After all points have been generated and counted, the ratio of points inside the circle to the total number of points is computed and used to estimate the value of $\pi$. The result is printed to the console.\ From 4628000b3a3e746d56b050d0967ed811e33f3ef8 Mon Sep 17 00:00:00 2001 From: tfk Date: Fri, 9 Dec 2022 21:40:15 +0000 Subject: [PATCH 6/7] =?UTF-8?q?Update=20Tutorials=20=E2=80=9Ctutorial-for-?= =?UTF-8?q?dprng=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/tutorials/tutorial-for-dprng.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/tutorials/tutorial-for-dprng.md b/src/doc/tutorials/tutorial-for-dprng.md index 4619015b..74ba14f2 100644 --- a/src/doc/tutorials/tutorial-for-dprng.md +++ b/src/doc/tutorials/tutorial-for-dprng.md @@ -88,6 +88,6 @@ int main() { ``` -The example above runs a Monte Carlo simulation to generate points in a two-dimensional plane. The points are generated using the `generate_random_number()` function, which uses the `__cilkrts_get_dprand()` function to generate pseudorandom numbers. The coordinates of the points are computed by scaling the pseudorandom numbers to the range $\[0, 1]$. The distance of each point from the origin is then computed, and the point is counted as inside or outside the circle with radius 1 based on its distance from the origin. After all points have been generated and counted, the ratio of points inside the circle to the total number of points is computed and used to estimate the value of $\pi$. The result is printed to the console.\ -\ -This example uses the `cilk_opadd_reducer` reducer type to avoid race conditions on the `inside_circle` and `outside_circle` counters. These counters are now declared as reducer objects, and the `++` operator is used to increment them in the parallel loop. The final value of the counters can be accessed by calling the `get_value()` method on the reducer objects. This ensures that the counters are updated atomically and that their values are consistent across all strands. \ No newline at end of file +The example above runs a Monte Carlo simulation to generate points in a two-dimensional plane. The points are generated using the `generate_random_number()` function, which uses the `__cilkrts_get_dprand()` function to generate pseudorandom numbers. The coordinates of the points are computed by scaling the pseudorandom numbers to the range $\[0, 1]$. The distance of each point from the origin is then computed, and the point is counted as inside or outside the circle with radius 1 based on its distance from the origin. After all points have been generated and counted, the ratio of points inside the circle to the total number of points is computed and used to estimate the value of $\pi$. The result is printed to the console. + +This example uses OpenCilk 2.0's reducer syntax to avoid race conditions. The `inside_circle` and `outside_circle` counters are declared as reducer objects using the `cilk_reducer` syntax, and the `zero` and `plus` functions are specified as the identity and reduce functions, respectively. This ensures that the counters are updated atomically and that their values are consistent across all strands. \ No newline at end of file From 7677dc153c99dce369f29dfd6eae14fc6d9a95c0 Mon Sep 17 00:00:00 2001 From: tfk Date: Fri, 9 Dec 2022 22:01:34 +0000 Subject: [PATCH 7/7] =?UTF-8?q?Update=20Tutorials=20=E2=80=9Ctutorial-for-?= =?UTF-8?q?dprng=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/tutorials/tutorial-for-dprng.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/doc/tutorials/tutorial-for-dprng.md b/src/doc/tutorials/tutorial-for-dprng.md index 74ba14f2..006a1acd 100644 --- a/src/doc/tutorials/tutorial-for-dprng.md +++ b/src/doc/tutorials/tutorial-for-dprng.md @@ -19,8 +19,8 @@ Here is a usage example for implementing DPRNG with OpenCilk 2.0 using the built #include #include #include +#include #include -#include // Generate a pseudorandom number using the built-in DPRNG in OpenCilk 2.0 uint64_t generate_random_number() { @@ -85,7 +85,6 @@ int main() { return 0; } - ``` The example above runs a Monte Carlo simulation to generate points in a two-dimensional plane. The points are generated using the `generate_random_number()` function, which uses the `__cilkrts_get_dprand()` function to generate pseudorandom numbers. The coordinates of the points are computed by scaling the pseudorandom numbers to the range $\[0, 1]$. The distance of each point from the origin is then computed, and the point is counted as inside or outside the circle with radius 1 based on its distance from the origin. After all points have been generated and counted, the ratio of points inside the circle to the total number of points is computed and used to estimate the value of $\pi$. The result is printed to the console.