DEV Community

sofaki000
sofaki000

Posted on • Edited on

OpenCilk tutorial

What is Parallel Programming?

In very simple terms, it is the use of multiple resources, in this case, processors, to solve a problem. This type of programming takes a problem, breaks it down into a series of smaller steps, delivers instructions, and processors execute the solutions at the same time.It is also a form of programming that offers the same results as concurrent programming but in less time and with more efficiency.

OpenCilk tutorial

Be aware that opencilk doesn't work for windows.
First we will download the docker image:

1)

wget https://github.com/OpenCilk/opencilk-project/releases/download/opencilk%2Fv1.0/docker-opencilk-v1.0.tar.gz
Enter fullscreen mode Exit fullscreen mode

Then load the image :(which loads the image from a tar archive. It restores both images and tags.)

docker load < docker-opencilk-v1.0.tar.gz
Enter fullscreen mode Exit fullscreen mode

2) Run a simple c program to confirm opencilk is installed:

#include <stdio.h>
#include <stdlib.h>
#define cilk_spawn _Cilk_spawn // the includes neccessary for openCilk
#define cilk_sync  _Cilk_sync
#define cilk_for   _Cilk_for

int main(){
printf("Hello world");
}

Enter fullscreen mode Exit fullscreen mode

3)Quick overview:
Cilk extends C and C++ with three keywords: cilk_spawn, cilk_sync, and cilk_for

cilk_spawn and cilk_sync:

example 1:

int64_t fib(int64_t n) {
  if (n < 2) return n;
  int x, y;
  x = cilk_spawn fib(n - 1);
  y = fib(n - 2);
  cilk_sync;
  return x + y;
}
Enter fullscreen mode Exit fullscreen mode

In the usage of cilk_spawn, parallel work is created when cilk_spawn precedes the invocation of a function, thereby causing the function to be spawned.The code immediately following the spawn — is allowed to execute in parallel with the child, instead of waiting for the child to complete as is done in C/C++.
In the example fib function, the cilk_spawn spawns the recursive invocation of fib(n-1), allowing it to execute in parallel with its continuation, which calls fib(n-2).
The cilk_sync is a local "barrier," not a global one as. In fib, the cilk_sync prevents the execution of fib from continuing past the cilk_sync until the spawned invocation of fib(n-1) has returned.

cilk_for:
example 1:

void daxpy(int n, double a, double *x, double *y) {
 cilk_for (int i = 0; i < n; ++i) {
    y[i] = a * x[i] + y[i];
  }
}
Enter fullscreen mode Exit fullscreen mode

The cilk_for parallel-loop construct indicates that all iterations of the loop are allowed to execute in parallel. At runtime, these iterations can execute in any order, at the discretion of the runtime scheduler.

example 2:

void mm(const double *restrict A,
        const double *restrict B,
        double *restrict C,
        int64_t n) {
  cilk_for (int64_t i = 0; i < n; ++i) {
    cilk_for (int64_t j = 0; j < n; ++j) {
      for (int64_t k = 0; k < n; ++k) {
        C[i*n + j] += A[i*n + k] * B[k*n + j];
      }
    }
  }
}
```



To sum up, a good start would be using cilk_for to replace all the for in your synchronous code. Also using cilk_spawn and cilk_sync
for all your recursive calls.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)