ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer...

8
9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati Synchronization primitive : TAS, TTAS, BTAS Example of Parallel Programming Shared memory : C/C++ Pthread, C++11 thread, OpenMP, Cilk Distributed Memory : MPI Concurrent Objects Concurrent Queue, List, stack, Tree, Priority Queue, Hash, SkipList Use of Concurrent objects import java.util.concurrent.atomic public class AtomicBoolean { boolean value; public synchronized boolean getAndSet(boolean newValue){ getAndSet(boolean newValue) { boolean prior = value; value = newValue; return prior; } } Swap old and new values Locking Lock is free: value is false Lock is taken: value is true Acquire lock by calling TAS If result is false, you win If result is true, you lose Release lock by writing false Testandset Lock class TASlock { AtomicBoolean state = new AtomicBoolean(false); void lock() { while (state.getAndSet(true)) {} } void unlock() { state.set(false); } } Keep trying until lock acquired class TTASlock { AtomicBoolean state = new AtomicBoolean(false); void lock() { Then try to acquire it while (true) { while (state.get()) {} if (!state.getAndSet(true)) return; } } Wait until lock looks free

Transcript of ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer...

Page 1: ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati • Synchronization primitive : TAS, TTAS, BTAS

9/23/2014

1

Dr A SahuDept of Computer Science & 

Engineering IIT Guwahati

• Synchronization primitive : TAS, TTAS, BTAS• Example of Parallel Programming 

– Shared memory : C/C++ Pthread, C++11 thread, OpenMP, Cilk

– Distributed Memory : MPI

• Concurrent Objects– Concurrent Queue, List, stack, Tree, Priority Queue, Hash, SkipList

• Use of Concurrent objects

import java.util.concurrent.atomicpublic class AtomicBoolean {boolean value;

public synchronized booleangetAndSet(boolean newValue) {getAndSet(boolean newValue) {boolean prior = value;value = newValue;return prior;

}}

Swap old and new values

• Locking– Lock is free: value is false– Lock is taken: value is true

• Acquire lock by calling TAS– If result is false, you win– If result is true, you lose 

• Release lock by writing false

Test‐and‐set Lockclass TASlock {AtomicBoolean state =new AtomicBoolean(false);

void lock() {o d oc () {while (state.getAndSet(true)) {}

}

void unlock() {state.set(false);

}} Keep trying until lock acquired

class TTASlock {AtomicBoolean state =new AtomicBoolean(false);

void lock() { Then try to acquire itwhile (true) {while (state.get()) {}if (!state.getAndSet(true))return;

}}

Wait until lock looks free

Page 2: ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati • Synchronization primitive : TAS, TTAS, BTAS

9/23/2014

2

• Shared memory – Pthread, C++11 thread– Java– OpenMP– Cilk

• Distributed Memory – MPI

• We need to indentify parallelism– How to do extract parallelism manually – Parallel Decomposition 

C d i th d d d l• Code in threaded model

• OS is responsible for running it efficiently – Less control over runtime

• Data Parallelism • Function Parallelism• Pipeline Parallelism• Pipeline Parallelism• Mixed Parallelism (D+F+P)

• Data Parallelism 

a b            c d e       f

A B  C D E F

Cap Cap Cap Cap Cap Cap

• Function Parallelism

1 4  9 12 6 14   3

AVG MINIMUM BINARY OR GEO‐MEAN

7 1 15 5.243

• Pipeline Parallelism

a SPIN a CAP A Shad

Page 3: ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati • Synchronization primitive : TAS, TTAS, BTAS

9/23/2014

3

• Compiler directive: Automatic parallelization• Auto generate thread and get synchronized ##include <openmp.h>main(){#pragma omp parallelp g p p#pragma omp for schedule(static) {

for (int i=0; i<N; i++) { a[i]=b[i]+c[i];

}}}

$ gcc –fopenmp test.c$ export OMP_NUM_THREADS=4$./a.out

Sequential code

(Semi) manual 

ll l

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

#pragma omp parallel{int id = omp_get_thread_num();int Nthr = omp_get_num_threads();int istart id*N/Nthr iend (id+1)*N/Nthr;parallel

Auto parallelof the for loop

int istart = id*N/Nthr, iend = (id+1)*N/Nthr;for (int i=istart; i<iend; i++) { a[i]=b[i]+c[i]; }}

#pragma omp parallel#pragma omp for schedule(static){for (int i=0; i<N; i++) { a[i]=b[i]+c[i]; }}

Threads are assigned an

#pragma omp parallel

#pragma omp for

i = 1 i = 5 i = 9

#pragma omp parallel#pragma omp for

for(i =1;i<13; i++) c[i]=a[i]+b[i];

Threads are assigned an independent set of iterationsThreads must wait at the end of work‐sharing construct

Implicit barrier

i = 2

i = 3

i = 4

i = 6

i = 7

i = 8

i = 10

i = 11

i = 12

printf(“program begin\n”);N = 1000;

#pragma omp parallel forfor (i=0; i<N; i++)

A[i] B[i] C[i]

Serial

ParallelA[i] = B[i] + C[i];

M = 500;

#pragma omp parallel forfor (j=0; j<M; j++)

p[j] = q[j] – r[j];

printf(“program done\n”); Serial

e

Serial

Parallel

sum = 0;

#pragma omp parallel private (lsum)

{

lsum = 0;

#pragma omp for

}

for (i=0; i<N; i++) {

lsum = lsum + A[i];

}

#pragma omp critical

{ sum += lsum; }

}Threads wait their turn;only one thread at a time executes the critical section

sum = 0;

#pragma omp parallel for reduction (+:sum)

for (i 0; i N; i ) {

Shared variable

for (i=0; i<N; i++) {

sum = sum + A[i];

}

Page 4: ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati • Synchronization primitive : TAS, TTAS, BTAS

9/23/2014

4

OpenMP Schedule

Can help OpenMP decide how to handle parallelism

schedule(type [,chunk])S h d lSchedule Types◦Static – Iterations divided into size chunk, if specified, and statically assigned to threads◦Dynamic – Iterations divided into size chunk, if specified, and dynamically scheduled among threads

• Although the OpenMP standard does not specify how a loop should be partitioned

• Most compilers split the loop in N/p (N #iterations, p #threads) chunks by default.  

• This is called a static schedule (with chunk sizeThis is called a static schedule (with chunk size N/p)– For example, suppose we have a loop with 1000 iterations and 4 omp threads. The loop is partitioned as follows:

Thread 0 Thread 1 Thread 2 Thread 3

0 250 500 750 1000

• A loop with 1000 iterations and 4 ompthreads. Static Schedule with Chunk 10

#pragma omp parallel for schedule (static, 10){for (i=0; i<1000; i++)

0 1000

A[i] = B[i] + C[i];}

10 20 30 40

……………………………..

Thread0 

• With static scheduling the number of iterations is evenly distributed among all openmp threads (i.e. Every thread will be assigned similar number of iterations). 

• This is not always the best way to partition. Why is This?Iterations

Example: Sqrt timing is data dependent… 

This is called load imbalance. In this case threads 2,3, and 4 will be waiting very long for thread 1 to finish 

Time A[i] = sqrt(B[i]+C[i]);

• With a dynamic schedule new chunks are assigned to threads when they come available. 

• SCHEDULE(DYNAMIC,n)  – Loop iterations are divided into pieces of size chunk. When a thread finishes one chunk, it is dynamically assigned another.  g

• SCHEDULE(GUIDED,n) – Similar to DYNAMIC but chunk size is relative to number of iterations left.

• Although Dynamic scheduling might be the prefered choice to prevent load inbalance– In some  situations, there is a significant overhead involved compared to static scheduling.

• http://users.abo.fi/mats/PP2012/examples/OpenMP/

Page 5: ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati • Synchronization primitive : TAS, TTAS, BTAS

9/23/2014

5

• Developed by Leiserson at CSAIL, MIT• Addition of 6 keyword to standard C

– Easy to install in linux system: with gcc and pthread• Biggest principle 

– Programmer should be responsible for exposing the parallelism identifying elements that can safely beparallelism, identifying elements that can safely be executed in parallel; 

– Work of run‐time environment (scheduler) to decide during execution how to actually divide the work between processors

• Work Stealing Scheduler – Proved to be good scheduler– Now also in GCC, Intel CC, Intel acquire Cilk++

int fib (int n) {if (n<2) return (n);else {int x,y;x = fib(n-1);y = fib(n-2);return (x+y);

}}

cilk int fib (int n) {if (n<2) return (n);else {int x,y;x = spawn fib(n-1);

Cilk codeCilk code

}

C elisionC elisiony = spawn fib(n-2);sync;return (x+y);

}}

Cilk is a faithful extension of C.  A Cilk program’s serial elision is always a legal implementation of Cilk semantics.  Cilk provides no new data types.

cilk int fib (int n) {if (n<2) return (n);else {int x,y;x = spawn fib(n-1);y = spawn fib(n-2);sync;

Identifies a function as a Cilk procedure, capable of being spawned in parallel.

sync;return (x+y);

}}

The named childCilk procedure can execute in parallel with the parentcaller.Control cannot pass this 

point until all spawned children have returned.

Parallelizing Vector Additionvoid vadd (real *A, real *B, int n){int i; for (i=0; i<n; i++) A[i]+=B[i];

}C

Parallelizing Vector Addition

C

C if (n<=BASE) {int i; for (i=0; i<n; i++) A[i]+=B[i];

} else {

void vadd (real *A, real *B, int n){

/

void vadd (real *A, real *B, int n){int i; for (i=0; i<n; i++) A[i]+=B[i];

}

vadd (A, B, n/2);vadd (A+n/2, B+n/2, n-n/2);

}}}

}

Parallelization strategy:1. Convert loops to recursion.

if (n<=BASE) {int i; for (i=0; i<n; i++) A[i]+=B[i];

} else {

Parallelizing Vector Addition

C

void vadd (real *A, real *B, int n){cilkC ilk

void vadd (real *A, real *B, int n){int i; for (i=0; i<n; i++) A[i]+=B[i];

}

Parallelization strategy:1. Convert loops to recursion.2. Insert Cilk keywords.

spawn vadd (A, B, n/2;vadd (A+n/2, B+n/2, n-n/2;spawn

Side benefit:D&C is generally good for caches!

}}}

}

sync;

Page 6: ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati • Synchronization primitive : TAS, TTAS, BTAS

9/23/2014

6

Cilksource cilk2c

C post‐

source‐to‐sourcetranslator

gccC compiler

Cilk

The cilkccompiler encapsulates the process.

psource gcc

objectcode

ld

RTS

binary

linkingloader

cilk2c translates straight C code into identical C postsource.

$ cilkc fib.cilk –o fib $ ./fib  ‐proc 4  5       // run using  4 threads. information at runtime 

• Message Passing Interface• Distributed memory  multiprocessor : ‐ cluster programming  

• Scalable to Large Number of Processorsg• Send (), Recv() construct• It uses processes not thread• Not part of this course

#include <stdio.h>     #include <stdlib.h>    #include <mpi.h>   #include <math.h>int main(  int argc, char *argv[])   {int myid, numprocs, tag, source, destination, count,  buffer; MPI_Status status;MPI_Init(&argc,&argv);MPI_Comm_size(MPI_COMM_WORLD,&numprocs);MPI_Comm_rank(MPI_COMM_WORLD,&myid);tag=1234; source=0;     destination=1;     count=1; 

if(myid == source){   buffer=5678;       MPI_Send(&buffer,count,MPI_INT, 

destination,tag,MPI_COMM_WORLD);printf("processor %d  sent %d\n",myid,buffer);}}if(myid == destination){MPI_Recv(&buffer,count,MPI_INT,

source,tag,MPI_COMM_WORLD,&status);printf("processor %d  got %d\n",myid,buffer);}MPI_Finalize();

}

• Exploits section that can be parallelized easily – Cuda GPU (Very simplistic, completely SPMD)– OpenMP (A bit of more complex SPMD with control of reduction, critical and scheduling )

• How to handle critical path efficiently• Testing for Good Driverg f

– Driving 120kmph in express high way or drive for 2 hour in Guwahati city in evening 4PM to 6PM near fancy bazar.

• How to overall speed up the application by trying to parallelize the not the easiest part  – The data storing, adding, removing and retrieving, organizing..

– This leads to design Concurrent Data Strcuture

• Classical Data structure (simply DS)– Complexity of Add, Del, Search, Modify, Rearrange

• Concurrent Data Structure  (CDS)– Many thread access to CDS– Consistency and Serialization – Performance of locking– Property should hold– No: live lock, deadlock, starvation

• Wait free and lock free CDS

Page 7: ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati • Synchronization primitive : TAS, TTAS, BTAS

9/23/2014

7

• Java, C++11 and C# (Microsoft VC++)– Java thread safe/concurrent collections

• /usr/share/javadoc/java‐1.6.0‐openjdk/api/java/util/concurrent/

– C++11  : through Boost  library  or  Libcds– C# The Parallel Patterns Library (PPL) 

• concurrent_vector_class, Concurrent_queue_class

• All have competitive memory model• Use Java

– Still I think Java is better in CDS..– Shavit: author of AMP Book used Java

• List, Queue, Stack, Hash, Priority queue, skiplist

• Discussion on internal implementation of some of these : list q stack pq hashsome of these : list, q, stack, pq, hash..

• Use this CDS to make parallel application faster 

• Ensure no thread can see a state where invariant of the DS have broken by the action of other thread. 

• Take care to avoid race condition inherent in the interface to the DS by proving function for complete functions for the operation rather than f di i ( dfor operation steps.  Race condition (unexpected output)

• Pay attention to how the DS behaves in the presence of exceptions to ensure that the invariants are not broken.

• Minimized the opportunities for deadlock when using the DS by restricting the scope of locked and avoid nested locks where possible.

• Can the scope of locks be restricted to allow some parts of an operation to be performed outside the lock?

• Can different part of the DS be protected by different locks?different locks? 

• Do all operations require the same level of protection?

• Can a simple change to the DS improve the improve the opportunities for concurrency without affecting the operational semantics ? 

• More than one thread must be able to access the DS concurrently – Example: A Queue might allow one thread to push and others to pop but may not same push/pop. 

• If one thread accessing DS and get suspended by OS in midway , other thread should be able to access   without waiting for suspended thread

• Lock free may not be wait free: it may have starvation    – 1TS  2T  1TS  2T, …..sequence lead to starvation by a RR scheduler

• Lock free DS with property: every thread accessing the DS can complete its operation within bounded number of steps, regardless of behavior of other threadsof behavior of other threads.  

• Coding for wait free DS correctly is extremely hard

Page 8: ConcurProgTut2 - Indian Institute of Technology Guwahati · 9/23/2014 1 Dr A Sahu Dept of Computer Science & Engineering IIT Guwahati • Synchronization primitive : TAS, TTAS, BTAS

9/23/2014

8

CS

Resets lock upon exit

spin lock

critical section

...

• Each method locks the object–Avoid contention using queue locks –Easy to reason about

• In simple cases

• So, are we done?

• NOPE

• Sequential bottleneck– Threads “stand in line”

• Adding more threadsi h h

CS

Resets lock upon exit

spin lock

critical section

...

– Does not improve throughput– Struggle to keep it from getting worse

• So why even use a multiprocessor?– Well, some apps inherently parallel …