While the dartboard method is a general way of approximating areas, it converges very slowly at a rate of 1/sqrt(n) and is, therefore, also one of the least efficient ways to compute Pi. The Python program included in the OctaPi project computes the percentage of darts falling inside the circle at a speed of 25000 darts/second using a precision of 100 decimal digits. To compute all 100 decimal digits accurately would require approximately 0.4E197 darts and consequently about 0.5E185 years to finish. On the other hand, the age of the universe is estimated to be about 1.3E10 years and it follows in that amount of time that a Pi Zero could throw 4.1E18 darts to obtain an approximation good to about 8 significant digits. As in the OctaPi project, our goal is not to compute Pi, but to understand parallel processing and how the Slurm batch system works.

We begin by creating a batch job which runs the Python code from the OctaPi project on one of the available Pi Zeros in the cluster. Make a working directory called pi. Then download the program file pi_dartboard.py from the OctaPi project and move it to the working directory. Note this is the dartboard algorithm for a stand alone processor, not the version designed for clusters. Before continuing, we make one minor change to pi_dartboard.py to flush the output buffers after each status update. Without this change all output would be buffered until the program finishes and that would make it impossible to monitor the status of the program while it is running in the batch environment. To do this add the option flush=True to the print on line 63 to obtain

Code: Select all

` print(('Executed trial %i using random seed %i with result %i' % (i, ran_seed, inside)),flush=True)`

Code: Select all

```
#!/bin/bash
time {
printf '100\n10000\n' | python3 pi_dartboard.py
}
```

Now, submit a few copies of the batch job, check whether they have been scheduled and monitor their progress using

Code: Select all

```
$ sbatch pi_dartboard.slm
Submitted batch job 54
$ sbatch pi_dartboard.slm
Submitted batch job 55
$ sbatch pi_dartboard.slm
Submitted batch job 56
$ sbatch pi_dartboard.slm
Submitted batch job 57
$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
54 zero pi_dartb ejolson R 0:07 1 s0
55 zero pi_dartb ejolson R 0:04 1 s1
56 zero pi_dartb ejolson R 0:04 1 s2
57 zero pi_dartb ejolson R 0:04 1 s3
$ cat slurm-56.out
Number of random points to include in each trial =
Number of trials to run =
Doing 10000 trials of 100 points each
Executed trial 0 using random seed 43897 with result 86
Executed trial 1000 using random seed 52318 with result 79
Executed trial 2000 using random seed 59206 with result 80
```

Code: Select all

```
$ cat slurm-54.out
Number of random points to include in each trial = Number of trials to run = Doing 10000 trials of 100 points each
Executed trial 0 using random seed 41166 with result 74
Executed trial 1000 using random seed 36385 with result 79
Executed trial 2000 using random seed 39999 with result 87
Executed trial 3000 using random seed 55252 with result 79
Executed trial 4000 using random seed 9008 with result 79
Executed trial 5000 using random seed 28951 with result 81
Executed trial 6000 using random seed 22201 with result 79
Executed trial 7000 using random seed 54954 with result 74
Executed trial 8000 using random seed 65485 with result 74
Executed trial 9000 using random seed 53049 with result 78
The value of Pi is estimated to be 3.14902000000000015234036254696547985076904296875 using 1000000 points
real 0m40.572s
user 0m40.300s
sys 0m0.120s
$ cat slurm-55.out
Number of random points to include in each trial = Number of trials to run = Doing 10000 trials of 100 points each
Executed trial 0 using random seed 50261 with result 78
Executed trial 1000 using random seed 24993 with result 75
Executed trial 2000 using random seed 56492 with result 76
Executed trial 3000 using random seed 2695 with result 79
Executed trial 4000 using random seed 39028 with result 79
Executed trial 5000 using random seed 42505 with result 69
Executed trial 6000 using random seed 38572 with result 79
Executed trial 7000 using random seed 21871 with result 87
Executed trial 8000 using random seed 52748 with result 79
Executed trial 9000 using random seed 16073 with result 77
The value of Pi is estimated to be 3.1490960000000001173248165287077426910400390625 using 1000000 points
real 0m40.088s
user 0m39.830s
sys 0m0.080s
$ cat slurm-56.out
Number of random points to include in each trial = Number of trials to run = Doing 10000 trials of 100 points each
Executed trial 0 using random seed 43897 with result 86
Executed trial 1000 using random seed 52318 with result 79
Executed trial 2000 using random seed 59206 with result 80
Executed trial 3000 using random seed 16956 with result 82
Executed trial 4000 using random seed 44605 with result 82
Executed trial 5000 using random seed 11321 with result 76
Executed trial 6000 using random seed 46185 with result 77
Executed trial 7000 using random seed 23947 with result 76
Executed trial 8000 using random seed 29328 with result 74
Executed trial 9000 using random seed 62471 with result 85
The value of Pi is estimated to be 3.149503999999999859227273191208951175212860107421875 using 1000000 points
real 0m37.257s
user 0m36.980s
sys 0m0.100s
$ cat slurm-57.out
Number of random points to include in each trial = Number of trials to run = Doing 10000 trials of 100 points each
Executed trial 0 using random seed 17784 with result 77
Executed trial 1000 using random seed 18571 with result 76
Executed trial 2000 using random seed 11993 with result 81
Executed trial 3000 using random seed 58358 with result 75
Executed trial 4000 using random seed 60686 with result 84
Executed trial 5000 using random seed 38634 with result 79
Executed trial 6000 using random seed 34956 with result 80
Executed trial 7000 using random seed 11397 with result 81
Executed trial 8000 using random seed 54805 with result 77
Executed trial 9000 using random seed 1196 with result 78
The value of Pi is estimated to be 3.14919200000000021333335098461247980594635009765625 using 1000000 points
real 0m39.179s
user 0m38.910s
sys 0m0.090s
```

For performance reasons, scientific computing is usually done using a combination of Fortran and C programming languages. While Fortran remains a domain-specific language with little popularity outside scientific computing, the C programming language is equally suited for scientific computing but also widely used in many other application areas. We rewrite the Monte-Carlo method for computing Pi in C as an example of a single-threaded non-parallel code that might be run on computing clusters. The C program looks like

Code: Select all

```
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
typedef unsigned int uint;
uint no_of_trials = 1000;
uint no_of_points = 100000;
uint compute(uint s,uint n){
srandom(s);
uint inside=0;
for(uint i=0;i<n;i++){
double x=(double)random()/RAND_MAX;
double y=(double)random()/RAND_MAX;
double z=x*x+y*y;
if(z<=1.0){
inside++;
}
}
return inside;
}
static double tic_time;
void tic() {
struct timeval tp;
gettimeofday(&tp,0);
tic_time=tp.tv_sec+tp.tv_usec*1.0e-6;
}
double toc() {
struct timeval tp;
gettimeofday(&tp,0);
return (tp.tv_sec+tp.tv_usec*1.0e-6)-tic_time;
}
int main(){
printf("Estimating Pi using Dartboard/Monte-Carlo Method\n"
"with %u trials of %u points.\n\n",
no_of_trials,no_of_points);
fflush(stdout);
double pi=0;
tic();
double tprint=5;
FILE *urandom=fopen("/dev/urandom","r");
for(uint i=1;i<=no_of_trials;i++){
uint ran_seed;
fread(&ran_seed,sizeof(ran_seed),1,urandom);
uint inside=compute(ran_seed,no_of_points);
double tnow=toc();
if(tnow>tprint){
printf("Trial %u using seed %u with %u inside"
" (ETA %g seconds)\n",
i,ran_seed,inside,tnow/i*(no_of_trials-i));
fflush(stdout);
tprint=tnow+5;
}
pi+=(double)inside/no_of_points;
}
fclose(urandom);
pi*=4.0/no_of_trials;
printf("\nThe value of Pi is estimated to be %.15f\n"
"using %u trials of %u points each.\n\n",
pi,no_of_trials,no_of_points);
double ttime=toc();
printf("Total running time %g seconds\n"
"with average rate of %g darts/second.\n",
ttime,no_of_trials/ttime*no_of_points);
return 0;
}
```

Code: Select all

```
#!/bin/bash
./pi
```

Code: Select all

```
$ gcc -std=gnu99 -Wall -O2 -o pi pi.c -lm
$ sbatch pi.slm
Submitted batch job 66
$ sbatch pi.slm
Submitted batch job 67
$ sbatch pi.slm
Submitted batch job 68
$ sbatch pi.slm
Submitted batch job 69
$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
66 zero pi.slm ejolson R 0:04 1 s0
67 zero pi.slm ejolson R 0:04 1 s1
68 zero pi.slm ejolson R 0:01 1 s2
69 zero pi.slm ejolson R 0:01 1 s3
$ cat slurm-68.out
Estimating Pi using Dartboard/Monte-Carlo Method
with 1000 trials of 100000 points.
Trial 168 using seed 1638688743 with 78596 inside (ETA 24.894 seconds)
Trial 337 using seed 76444161 with 78365 inside (ETA 19.7693 seconds)
Trial 506 using seed 1246513006 with 78327 inside (ETA 14.7182 seconds)
```

Code: Select all

```
$ cat slurm-68.out
Estimating Pi using Dartboard/Monte-Carlo Method
with 1000 trials of 100000 points.
Trial 168 using seed 1638688743 with 78596 inside (ETA 24.894 seconds)
Trial 337 using seed 76444161 with 78365 inside (ETA 19.7693 seconds)
Trial 506 using seed 1246513006 with 78327 inside (ETA 14.7182 seconds)
Trial 675 using seed 3803787632 with 78665 inside (ETA 9.67678 seconds)
Trial 844 using seed 1400931100 with 78663 inside (ETA 4.64343 seconds)
The value of Pi is estimated to be 3.141761479999999
using 1000 trials of 100000 points each.
Total running time 29.7284 seconds
with average rate of 3.36379e+06 darts/second.
```