SIMD and Others

../_images/simd.png

In this exercise, we will try to add the simd clause to our existing problems, for example, vector addition.

Examples and Question: SIMD — Vector Addition
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <time.h>

#define N 5120
#define MAX_ERR 1e-6

float * Vector_Add(float *a, float *b, float *c, int n)
{
  for(int i = 0; i < n; i ++)
    { c[i] = a[i] + b[i]; }
  return c;
}

int main()
{
  float *a, *b, *c;
  a = (float*)malloc(sizeof(float) * N);
  b = (float*)malloc(sizeof(float) * N);
  c = (float*)malloc(sizeof(float) * N);

  for(int i = 0; i < N; i++)
    { a[i] = 1.0f; b[i] = 2.0f; }

  clock_t start = clock();
  Vector_Add(a, b, c, N);
  clock_t end = clock();
  printf("Time measured: %.3f seconds.\n", (double)(end - start)/CLOCKS_PER_SEC);

  for(int i = 0; i < N; i++)
    { assert(fabs(c[i] - a[i] - b[i]) < MAX_ERR); }

  printf("c[0] = %f\n", c[0]);
  printf("PASSED\n");

  free(a); free(b); free(c);
  return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <time.h>
#include <omp.h>

#define N 5120
#define MAX_ERR 1e-6

float * Vector_Add(float *a, float *b, float *c, int n)
{
// ADD YOUR PARALLEL REGION FOR THE LOOP SIMD
  for(int i = 0; i < n; i ++)
    { c[i] = a[i] + b[i]; }
  return c;
}

int main()
{
  float *a, *b, *c;
  a = (float*)malloc(sizeof(float) * N);
  b = (float*)malloc(sizeof(float) * N);
  c = (float*)malloc(sizeof(float) * N);

  for(int i = 0; i < N; i++)
    { a[i] = 1.0f; b[i] = 2.0f; }

  clock_t start = clock();
  // ADD YOUR PARALLEL REGION HERE
  Vector_Add(a, b, c, N);
  clock_t end = clock();
  printf("Time measured: %.3f seconds.\n", (double)(end - start)/CLOCKS_PER_SEC);

  for(int i = 0; i < N; i++)
    { assert(fabs(c[i] - a[i] - b[i]) < MAX_ERR); }

  printf("c[0] = %f\n", c[0]);
  printf("PASSED\n");

  free(a); free(b); free(c);
  return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <time.h>
#include <omp.h>

#define N 5120
#define MAX_ERR 1e-6

float * Vector_Add(float *a, float *b, float *c, int n)
{
#pragma omp for simd
  for(int i = 0; i < n; i ++)
    { c[i] = a[i] + b[i]; }
  return c;
}

int main()
{
  float *a, *b, *c;
  a = (float*)malloc(sizeof(float) * N);
  b = (float*)malloc(sizeof(float) * N);
  c = (float*)malloc(sizeof(float) * N);

  for(int i = 0; i < N; i++)
    { a[i] = 1.0f; b[i] = 2.0f; }

  double start = omp_get_wtime();
  #pragma omp parallel
  Vector_Add(a, b, c, N);
  double end = omp_get_wtime();
  printf("Work took %f seconds\n", end - start);

  for(int i = 0; i < N; i++)
    { assert(fabs(c[i] - a[i] - b[i]) < MAX_ERR); }

  printf("c[0] = %f\n", c[0]);
  printf("PASSED\n");

  free(a); free(b); free(c);
  return 0;
}
module Vector_Addition_Mod
implicit none
  contains
subroutine Vector_Addition(a, b, c, n)
use omp_lib
real(8), intent(in), dimension(:) :: a, b
real(8), intent(out), dimension(:) :: c
integer :: i, n
!$omp do simd
  do i = 1, n
    c(i) = a(i) + b(i)
  end do
!$omp end do simd
 end subroutine Vector_Addition
end module Vector_Addition_Mod

program main
use Vector_Addition_Mod
implicit none
real(8), dimension(:), allocatable :: a, b, c
double precision :: start, end
integer :: n, i

print *, "Please specify the vector size = "
read *, n

allocate(a(n)); allocate(b(n)); allocate(c(n))

do i = 1, n
  a(i) = sin(i*1D0) * sin(i*1D0)
  b(i) = cos(i*1D0) * cos(i*1D0)
enddo

start = omp_get_wtime()
!$omp parallel
call Vector_Addition(a, b, c, n)
!$omp end parallel
end = omp_get_wtime()
PRINT *, "Work took", end - start, "seconds"

do i = 1, n
  if (abs(c(i)-(a(i)+b(i)))/=0.00000) print *, "FAIL"
enddo
print *, "PASS"

deallocate(a); deallocate(b); deallocate(c)

end program main
Questions
  • Please try the examples without the simd clause. Do you notice any performance differences?

Critical, Single, and Master

We will explore how single, master and critical work in the OpenMP programming model.

Examples and Question: Critical, Single and Master
#include<iostream>
#include<omp.h>
using namespace std;
int main()
{
  cout << "Hello world from the master thread "<< endl;
  cout << endl;

  #pragma omp parallel
   {
        cout << "Hello world from thread id "
        << omp_get_thread_num() << " from the team size of "
        << omp_get_num_threads()
        << endl;
    }

cout << endl;
cout << "end of the programme from the master thread" << endl;
return 0;
}
program Hello_world_OpenMP
use omp_lib

!$omp parallel
print *, 'Hello world from thread id ', omp_get_thread_num(), 'from the team size of', omp_get_num_threads()
!$omp end parallel

end program
Questions
  • Try the single clause

  • Try the master clause

  • Try the critical clause