Browse Source

Squash commit

master
Apostolos Fanakis 4 years ago
commit
a099063448
Signed by: Apostolof GPG Key ID: 8600B4C4163B3269
  1. 3
      .gitignore
  2. 292
      cilk/bitonic.c
  3. 274
      noOpt/bitonicCilk.c
  4. 285
      noOpt/bitonicOpenMP.c
  5. 380
      noOpt/bitonicPthreads.c
  6. 304
      openMP/bitonic.c
  7. 395
      pthreads/bitonic.c
  8. 249
      pthreads/bitonicImp.c
  9. 320
      pthreads/bitonicRec.c
  10. 110
      qsort/qsort.c
  11. 215
      seq/bitonic.c

3
.gitignore

@ -0,0 +1,3 @@
*.out
.idea
*.iml

292
cilk/bitonic.c

@ -0,0 +1,292 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <cilk/cilk.h>
#include <cilk/cilk_api.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threads; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
bool sortPass; //flag showing whether the test passed or not
const int ASCENDING = 1;
const int DESCENDING = 0;
//cilk for grainsize
const int REC_BITONIC_MERGE_PARALLEL_GRAINSIZE = 1 << 14;
//min lenght of an array to be sorted by bitonicMerge in parallel manner
const int REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN = (1 << 12) - 1;
//min lenght of an array to be merged by bitonicMerge in parallel manner
const int REC_BITONIC_MERGE_PARALLEL_CALL_MIN = (1 << 8) - 1;
//min lenght of an array to be sorted in parallel manner
const int REC_BITONIC_SORT_PARALLEL_MIN = (1 << 22) + 1;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
void sort(void);
void test(void);
void qSortTest(void);
void exchange(int i, int j);
void compare(int i, int j, int dir);
void bitonicMerge(int lo, int cnt, int dir);
void recBitonicSort(int lo, int cnt, int dir);
void impBitonicSort(void);
int qSortAscendingCompFuncWithTest (const void * a, const void * b);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
if (0!= __cilkrts_set_param("nworkers","0" + threads)){
printf("Failed to set worker count\n");
exit(1);
}
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("qSort wall clock time = %f\n\n", seq_time);
//Sorts using the imperative bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
impBitonicSort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("Imperative wall clock time = %f\n", seq_time);
test();
qSortTest();
//Sorts using the recursive bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
sort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("\nRecursive wall clock time = %f\n", seq_time);
test();
qSortTest();
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 3) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
threads = 1<<atoi(argv[1]);
N = 1<<atoi(argv[2]);
}
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf("\tTEST\t\t%s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure qSortTest() : verify sort results using qsort method **/
void qSortTest(){
sortPass = true;
qsort(a, N, sizeof(int), qSortAscendingCompFuncWithTest);
printf("\tQSORT TEST\t%s\n",(sortPass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
/** Procedure bitonicMerge()
It recursively sorts a bitonic sequence in ascending order,
if dir = ASCENDING, and in descending order otherwise.
The sequence to be sorted starts at index position lo,
the parameter cbt is the number of elements to be sorted.
**/
void bitonicMerge(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
int i;
if (cnt > REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN){
#pragma cilk_grainsize = 8192
cilk_for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
} else {
for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
}
if (cnt > REC_BITONIC_MERGE_PARALLEL_CALL_MIN){
cilk_spawn bitonicMerge(lo, k, dir);
cilk_spawn bitonicMerge(lo+k, k, dir);
cilk_sync;
} else{
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
}
}
}
/** function recBitonicSort()
first produces a bitonic sequence by recursively sorting
its two halves in opposite sorting orders, and then
calls bitonicMerge to make them in the same order
**/
void recBitonicSort(int lo, int cnt, int dir) {
if (cnt>1) {
if (cnt < REC_BITONIC_SORT_PARALLEL_MIN){
qsort(a+lo, cnt, sizeof(int), (dir == 1 ? qSortAscending : qSortDescending));
return;
}
int k=cnt/2;
cilk_spawn recBitonicSort(lo, k, ASCENDING);
cilk_spawn recBitonicSort(lo+k, k, DESCENDING);
cilk_sync;
bitonicMerge(lo, cnt, dir);
}
}
/** function sort()
Caller of recBitonicSort for sorting the entire array of length N
in ASCENDING order
**/
void sort() {
recBitonicSort(0, N, ASCENDING);
}
/*
imperative version of bitonic sort
*/
void impBitonicSort() {
int i,j,k;
for (k=2; k<=N; k+=k) {
for (j=k>>1; j>0; j=j>>1) {
#pragma cilk_grainsize = N/4
cilk_for (i=0; i<N; i++) {
int ij=i^j;
if ((ij)>i) {
if ((i&k)==0 && a[i] > a[ij])
exchange(i,ij);
if ((i&k)!=0 && a[i] < a[ij])
exchange(i,ij);
}
}
}
}
}
/** function used by qsort for comparing as well as testing **/
int qSortAscendingCompFuncWithTest (const void * a, const void * b) {
int result = ( *(int*)a - *(int*)b );
if (result > 0){
sortPass = false;
}
return result;
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

274
noOpt/bitonicCilk.c

@ -0,0 +1,274 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <cilk/cilk.h>
#include <cilk/cilk_api.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threads; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
bool sortPass; //flag showing whether the test passed or not
const int ASCENDING = 1;
const int DESCENDING = 0;
//cilk for grainsize
const int REC_BITONIC_MERGE_PARALLEL_GRAINSIZE = 1 << 14;
//min lenght of an array to be sorted by bitonicMerge in parallel manner
const int REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN = (1 << 12) - 1;
//min lenght of an array to be merged by bitonicMerge in parallel manner
const int REC_BITONIC_MERGE_PARALLEL_CALL_MIN = (1 << 8) - 1;
//min lenght of an array to be sorted in parallel manner
const int REC_BITONIC_SORT_PARALLEL_MIN = (1 << 22) + 1;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
void sort(void);
void test(void);
void qSortTest(void);
void exchange(int i, int j);
void compare(int i, int j, int dir);
void bitonicMerge(int lo, int cnt, int dir);
void recBitonicSort(int lo, int cnt, int dir);
void impBitonicSort(void);
int qSortAscendingCompFuncWithTest (const void * a, const void * b);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
if (0!= __cilkrts_set_param("nworkers","0" + threads)){
printf("Failed to set worker count\n");
exit(1);
}
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("qSort wall clock time = %f\n\n", seq_time);
//Sorts using the recursive bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
sort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("\nRecursive wall clock time = %f\n", seq_time);
test();
qSortTest();
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 3) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
threads = 1<<atoi(argv[1]);
N = 1<<atoi(argv[2]);
}
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf("\tTEST\t\t%s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure qSortTest() : verify sort results using qsort method **/
void qSortTest(){
sortPass = true;
qsort(a, N, sizeof(int), qSortAscendingCompFuncWithTest);
printf("\tQSORT TEST\t%s\n",(sortPass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
/** Procedure bitonicMerge()
It recursively sorts a bitonic sequence in ascending order,
if dir = ASCENDING, and in descending order otherwise.
The sequence to be sorted starts at index position lo,
the parameter cbt is the number of elements to be sorted.
**/
void bitonicMerge(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
int i;
if (cnt > REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN){
#pragma cilk_grainsize = 8192
cilk_for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
} else {
for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
}
if (cnt > REC_BITONIC_MERGE_PARALLEL_CALL_MIN){
cilk_spawn bitonicMerge(lo, k, dir);
cilk_spawn bitonicMerge(lo+k, k, dir);
cilk_sync;
} else{
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
}
}
}
/** function recBitonicSort()
first produces a bitonic sequence by recursively sorting
its two halves in opposite sorting orders, and then
calls bitonicMerge to make them in the same order
**/
void recBitonicSort(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
cilk_spawn recBitonicSort(lo, k, ASCENDING);
cilk_spawn recBitonicSort(lo+k, k, DESCENDING);
cilk_sync;
bitonicMerge(lo, cnt, dir);
}
}
/** function sort()
Caller of recBitonicSort for sorting the entire array of length N
in ASCENDING order
**/
void sort() {
recBitonicSort(0, N, ASCENDING);
}
/*
imperative version of bitonic sort
*/
void impBitonicSort() {
int i,j,k;
for (k=2; k<=N; k+=k) {
for (j=k>>1; j>0; j=j>>1) {
#pragma cilk_grainsize = N/4
cilk_for (i=0; i<N; i++) {
int ij=i^j;
if ((ij)>i) {
if ((i&k)==0 && a[i] > a[ij])
exchange(i,ij);
if ((i&k)!=0 && a[i] < a[ij])
exchange(i,ij);
}
}
}
}
}
/** function used by qsort for comparing as well as testing **/
int qSortAscendingCompFuncWithTest (const void * a, const void * b) {
int result = ( *(int*)a - *(int*)b );
if (result > 0){
sortPass = false;
}
return result;
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

285
noOpt/bitonicOpenMP.c

@ -0,0 +1,285 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <omp.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threads; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
bool sortPass; //flag showing whether the test passed or not
const int ASCENDING = 1;
const int DESCENDING = 0;
//min lenght of an array to be sorted by bitonicMerge in parallel manner
const int REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN = (1 << 12) - 1;
//min lenght of an array to be merged by bitonicMerge in parallel manner
const int REC_BITONIC_MERGE_PARALLEL_CALL_MIN = (1 << 8) - 1;
//min lenght of an array to be sorted in parallel manner
const int REC_BITONIC_SORT_PARALLEL_MIN = (1 << 22) + 1;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
void sort(void);
void test(void);
void qSortTest(void);
void exchange(int i, int j);
void compare(int i, int j, int dir);
void bitonicMerge(int lo, int cnt, int dir);
void recBitonicSort(int lo, int cnt, int dir);
void impBitonicSort(void);
int qSortAscendingCompFuncWithTest (const void * a, const void * b);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
omp_set_dynamic(0);
omp_set_num_threads(threads);
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("qSort wall clock time = %f\n\n", seq_time);
//Sorts using the recursive bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
sort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("\nRecursive wall clock time = %f\n", seq_time);
test();
qSortTest();
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 3) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
threads = 1<<atoi(argv[1]);
N = 1<<atoi(argv[2]);
}
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf("\tTEST\t\t%s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure qSortTest() : verify sort results using qsort method **/
void qSortTest(){
sortPass = true;
qsort(a, N, sizeof(int), qSortAscendingCompFuncWithTest);
printf("\tQSORT TEST\t%s\n",(sortPass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
/** Procedure bitonicMerge()
It recursively sorts a bitonic sequence in ascending order,
if dir = ASCENDING, and in descending order otherwise.
The sequence to be sorted starts at index position lo,
the parameter cbt is the number of elements to be sorted.
**/
void bitonicMerge(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
int i;
if (cnt > REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN){
#pragma omp parallel for
for (i=lo; i<lo+k; i++)
compare(i, i+k, dir);
} else {
for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
}
if (cnt > REC_BITONIC_MERGE_PARALLEL_CALL_MIN){
#pragma omp parallel sections
{
#pragma omp section
{
bitonicMerge(lo, k, dir);
}
#pragma omp section
{
bitonicMerge(lo+k, k, dir);
}
}
} else {
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
}
}
}
/** function recBitonicSort()
first produces a bitonic sequence by recursively sorting
its two halves in opposite sorting orders, and then
calls bitonicMerge to make them in the same order
**/
void recBitonicSort(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
#pragma omp task
{
recBitonicSort(lo, k, ASCENDING);
}
#pragma omp task
{
recBitonicSort(lo+k, k, DESCENDING);
}
#pragma omp taskwait
bitonicMerge(lo, cnt, dir);
}
}
/** function sort()
Caller of recBitonicSort for sorting the entire array of length N
in ASCENDING order
**/
void sort() {
#pragma omp parallel num_threads(threads)
#pragma omp single nowait
recBitonicSort(0, N, ASCENDING);
}
/*
imperative version of bitonic sort
*/
void impBitonicSort() {
int i,j,k;
for (k=2; k<=N; k=2*k) {
for (j=k>>1; j>0; j=j>>1) {
#pragma omp parallel for num_threads(threads)
for (i=0; i<N; i++) {
int ij=i^j;
if ((ij)>i) {
if ((i&k)==0 && a[i] > a[ij])
exchange(i,ij);
if ((i&k)!=0 && a[i] < a[ij])
exchange(i,ij);
}
}
}
}
}
/** function used by qsort for comparing as well as testing **/
int qSortAscendingCompFuncWithTest (const void * a, const void * b) {
int result = ( *(int*)a - *(int*)b );
if (result > 0){
sortPass = false;
}
return result;
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

380
noOpt/bitonicPthreads.c

@ -0,0 +1,380 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threadsNum; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
bool sortPass; //flag showing whether the test passed or not
const int ASCENDING = 1;
const int DESCENDING = 0;
//min lenght of an array to be sorted in parallel manner
const int REC_BITONIC_SORT_PARALLEL_MIN = (1 << 22) + 1;
//structs for parallel functions
typedef struct recBitonicSortData{
int threadID;
int lo;
int cnt;
int dir;
} recBitonicSortData;
typedef struct impBitonicSortThreadData{
int i;
int N;
int j;
int k;
} impBitonicSortThreadData;
pthread_t *threads; //array that holds pointers to all threads
int runningThreads = 0; //number of threads currently running
pthread_mutex_t runningThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
void sort(void);
void test(void);
void qSortTest(void);
void exchange(int i, int j);
void compare(int i, int j, int dir);
void bitonicMerge(int lo, int cnt, int dir);
void *recBitonicSort(void *threadArgs);
void *impBitonicSortThread(void * threadArgs);
void impBitonicSort(void);
int qSortAscendingCompFuncWithTest (const void * a, const void * b);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
//allocates space for an array that holds pointers to all threads
threads = (pthread_t *)malloc(sizeof(pthread_t)*threadsNum);
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("qSort wall clock time = %f\n\n", seq_time);
//Sorts using the recursive bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
sort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("\nRecursive wall clock time = %f\n", seq_time);
test();
qSortTest();
free(threads);
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 3) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
threadsNum = 1<<atoi(argv[1]);
N = 1<<atoi(argv[2]);
}
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf("\tTEST\t\t%s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure qSortTest() : verify sort results using qsort method **/
void qSortTest(){
sortPass = true;
qsort(a, N, sizeof(int), qSortAscendingCompFuncWithTest);
printf("\tQSORT TEST\t%s\n",(sortPass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
/** Procedure bitonicMerge()
It recursively sorts a bitonic sequence in ascending order,
if dir = ASCENDING, and in descending order otherwise.
The sequence to be sorted starts at index position lo,
the parameter cbt is the number of elements to be sorted.
**/
void bitonicMerge(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
int i;
for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
}
}
/** function recBitonicSort()
first produces a bitonic sequence by recursively sorting
its two halves in opposite sorting orders, and then
calls bitonicMerge to make them in the same order
**/
void *recBitonicSort(void *threadArgs) {
recBitonicSortData *thisData = (recBitonicSortData *) threadArgs;
int lo = thisData->lo;
int cnt = thisData->cnt;
int dir = thisData->dir;
if (cnt>1) {
if (false){ //small sub-arrays best sorted using qsort
qsort(a+lo, cnt, sizeof(int), (dir == 1 ? qSortAscending : qSortDescending));
} else {
//plitts problem in two halfs and tries to create a new thread for each
//holds each half's index (from threads array)
int firstHalf = -1, myOtherHalf = -1;
//attribute for joinable threads
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int k=cnt/2;
pthread_mutex_lock(&runningThreadsMutex); //locks running threads variable
if (runningThreads < threadsNum){
//arguments for first half
recBitonicSortData newThreadArgs;
newThreadArgs.lo = lo;
newThreadArgs.cnt = k;
newThreadArgs.dir = ASCENDING;
//tries to create a new thread with a pointer to it saved inside array "threads"
if (pthread_create(&threads[runningThreads], &attr, recBitonicSort, (void *) &newThreadArgs)){
printf("Error creating thread. Aborting.");
pthread_mutex_unlock(&runningThreadsMutex);
exit(1);
} else { //thread was successfully created
//keeps thread's index and updates running threads counter
firstHalf = runningThreads;
++runningThreads;
pthread_mutex_unlock(&runningThreadsMutex);
}
} else { //max threads number reached, does the job sequentially using qsort
pthread_mutex_unlock(&runningThreadsMutex);
qsort(a+lo, k, sizeof(int), qSortAscending);
}
pthread_mutex_lock(&runningThreadsMutex); //locks running threads variable
if (runningThreads < threadsNum){
//arguments for second half
recBitonicSortData newThreadArgs;
newThreadArgs.lo = lo+k;
newThreadArgs.cnt = k;
newThreadArgs.dir = DESCENDING;
//tries to create a new thread with a pointer to it saved inside array "threads"
if (pthread_create(&threads[runningThreads], &attr, recBitonicSort, (void *) &newThreadArgs)){
printf("Error creating thread. Aborting.");
pthread_mutex_unlock(&runningThreadsMutex);
exit(1);
} else { //thread was successfully created
//keeps thread's index and updates running threads counter
myOtherHalf = runningThreads;
++runningThreads;
pthread_mutex_unlock(&runningThreadsMutex);
}
} else { //max threads number reached, does the job sequentially using qsort
pthread_mutex_unlock(&runningThreadsMutex);
qsort(a+lo+k, k, sizeof(int), qSortDescending);
}
pthread_attr_destroy(&attr);
//achieves synchronization
if (firstHalf != -1){
pthread_join (threads[firstHalf], NULL);
}
if (myOtherHalf != -1){
pthread_join (threads[myOtherHalf], NULL);
}
bitonicMerge(lo, cnt, dir);
}
}
}
/** function sort()
Caller of recBitonicSort for sorting the entire array of length N
in ASCENDING order
**/
void sort() {
recBitonicSortData newThreadArgs;
newThreadArgs.threadID = 1;
newThreadArgs.lo = 0;
newThreadArgs.cnt = N;
newThreadArgs.dir = ASCENDING;
recBitonicSort((void *) &newThreadArgs);
}
void *impBitonicSortThread(void * threadArgs){
//get variable values from struct
impBitonicSortThreadData *thisThreadData = (impBitonicSortThreadData *) threadArgs;
int i;
int N = thisThreadData->N;
int j = thisThreadData->j;
int k = thisThreadData->k;
for (i; i<N; i++) {
int ij=i^j;
if ((ij)>i) {
if ((i&k)==0 && a[i] > a[ij])
exchange(i,ij);
if ((i&k)!=0 && a[i] < a[ij])
exchange(i,ij);
}
}
pthread_exit(NULL);
}
/*
imperative version of bitonic sort
*/
void impBitonicSort() {
int t,j,k;
//attribute for joinable threads
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int threadN = N/threadsNum; //splitts work into 2^q sub-problems
for (k=2; k<=N; k+=k) {
for (j=k>>1; j>0; j=j>>1) {
//creates a new thread for each sub-problem
for (t = 0; t < threadsNum; ++t){
impBitonicSortThreadData newThreadArgs;
newThreadArgs.i = t * threadN;
newThreadArgs.N = (t + 1) * threadN;
newThreadArgs.j = j;
newThreadArgs.k = k;
int rc = pthread_create(&threads[t], &attr, impBitonicSortThread, (void *) &newThreadArgs);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
//achieves synchronization
for(t = 0; t < threadsNum; ++t) {
pthread_join(threads[t], NULL);
}
}
}
pthread_attr_destroy(&attr);
}
/** function used by qsort for comparing as well as testing **/
int qSortAscendingCompFuncWithTest (const void * a, const void * b) {
int result = ( *(int*)a - *(int*)b );
if (result > 0){
sortPass = false;
}
return result;
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

304
openMP/bitonic.c

@ -0,0 +1,304 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <omp.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threads; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
bool sortPass; //flag showing whether the test passed or not
const int ASCENDING = 1;
const int DESCENDING = 0;
//min lenght of an array to be sorted by bitonicMerge in parallel manner
const int REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN = (1 << 12) - 1;
//min lenght of an array to be merged by bitonicMerge in parallel manner
const int REC_BITONIC_MERGE_PARALLEL_CALL_MIN = (1 << 8) - 1;
//min lenght of an array to be sorted in parallel manner
const int REC_BITONIC_SORT_PARALLEL_MIN = (1 << 22) + 1;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
void sort(void);
void test(void);
void qSortTest(void);
void exchange(int i, int j);
void compare(int i, int j, int dir);
void bitonicMerge(int lo, int cnt, int dir);
void recBitonicSort(int lo, int cnt, int dir);
void impBitonicSort(void);
int qSortAscendingCompFuncWithTest (const void * a, const void * b);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
omp_set_dynamic(0);
omp_set_num_threads(threads);
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("qSort wall clock time = %f\n\n", seq_time);
//Sorts using the imperative bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
impBitonicSort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("Imperative wall clock time = %f\n", seq_time);
test();
qSortTest();
//Sorts using the recursive bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
sort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("\nRecursive wall clock time = %f\n", seq_time);
test();
qSortTest();
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 3) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
threads = 1<<atoi(argv[1]);
N = 1<<atoi(argv[2]);
}
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf("\tTEST\t\t%s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure qSortTest() : verify sort results using qsort method **/
void qSortTest(){
sortPass = true;
qsort(a, N, sizeof(int), qSortAscendingCompFuncWithTest);
printf("\tQSORT TEST\t%s\n",(sortPass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
/** Procedure bitonicMerge()
It recursively sorts a bitonic sequence in ascending order,
if dir = ASCENDING, and in descending order otherwise.
The sequence to be sorted starts at index position lo,
the parameter cbt is the number of elements to be sorted.
**/
void bitonicMerge(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
int i;
if (cnt > REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN){
#pragma omp parallel for
for (i=lo; i<lo+k; i++)
compare(i, i+k, dir);
} else {
for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
}
if (cnt > REC_BITONIC_MERGE_PARALLEL_CALL_MIN){
#pragma omp parallel sections
{
#pragma omp section
{
bitonicMerge(lo, k, dir);
}
#pragma omp section
{
bitonicMerge(lo+k, k, dir);
}
}
} else {
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
}
}
}
/** function recBitonicSort()
first produces a bitonic sequence by recursively sorting
its two halves in opposite sorting orders, and then
calls bitonicMerge to make them in the same order
**/
void recBitonicSort(int lo, int cnt, int dir) {
if (cnt>1) {
if (cnt < REC_BITONIC_SORT_PARALLEL_MIN){
qsort(a+lo, cnt, sizeof(int), (dir == 1 ? qSortAscending : qSortDescending));
return;
}
int k=cnt/2;
#pragma omp task
{
recBitonicSort(lo, k, ASCENDING);
}
#pragma omp task
{
recBitonicSort(lo+k, k, DESCENDING);
}
#pragma omp taskwait
bitonicMerge(lo, cnt, dir);
}
}
/** function sort()
Caller of recBitonicSort for sorting the entire array of length N
in ASCENDING order
**/
void sort() {
#pragma omp parallel num_threads(threads)
#pragma omp single nowait
recBitonicSort(0, N, ASCENDING);
}
/*
imperative version of bitonic sort
*/
void impBitonicSort() {
int i,j,k;
for (k=2; k<=N; k=2*k) {
for (j=k>>1; j>0; j=j>>1) {
#pragma omp parallel for num_threads(threads)
for (i=0; i<N; i++) {
int ij=i^j;
if ((ij)>i) {
if ((i&k)==0 && a[i] > a[ij])
exchange(i,ij);
if ((i&k)!=0 && a[i] < a[ij])
exchange(i,ij);
}
}
}
}
}
/** function used by qsort for comparing as well as testing **/
int qSortAscendingCompFuncWithTest (const void * a, const void * b) {
int result = ( *(int*)a - *(int*)b );
if (result > 0){
sortPass = false;
}
return result;
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

395
pthreads/bitonic.c

@ -0,0 +1,395 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threadsNum; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
bool sortPass; //flag showing whether the test passed or not
const int ASCENDING = 1;
const int DESCENDING = 0;
//min lenght of an array to be sorted in parallel manner
const int REC_BITONIC_SORT_PARALLEL_MIN = (1 << 22) + 1;
//structs for parallel functions
typedef struct recBitonicSortData{
int threadID;
int lo;
int cnt;
int dir;
} recBitonicSortData;
typedef struct impBitonicSortThreadData{
int i;
int N;
int j;
int k;
} impBitonicSortThreadData;
pthread_t *threads; //array that holds pointers to all threads
int runningThreads = 0; //number of threads currently running
pthread_mutex_t runningThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
void sort(void);
void test(void);
void qSortTest(void);
void exchange(int i, int j);
void compare(int i, int j, int dir);
void bitonicMerge(int lo, int cnt, int dir);
void *recBitonicSort(void *threadArgs);
void *impBitonicSortThread(void * threadArgs);
void impBitonicSort(void);
int qSortAscendingCompFuncWithTest (const void * a, const void * b);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
//allocates space for an array that holds pointers to all threads
threads = (pthread_t *)malloc(sizeof(pthread_t)*threadsNum);
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("qSort wall clock time = %f\n\n", seq_time);
//Sorts using the imperative bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
impBitonicSort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("Imperative wall clock time = %f\n", seq_time);
test();
qSortTest();
//Sorts using the recursive bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
sort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("\nRecursive wall clock time = %f\n", seq_time);
test();
qSortTest();
free(threads);
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 3) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
threadsNum = 1<<atoi(argv[1]);
N = 1<<atoi(argv[2]);
}
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf("\tTEST\t\t%s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure qSortTest() : verify sort results using qsort method **/
void qSortTest(){
sortPass = true;
qsort(a, N, sizeof(int), qSortAscendingCompFuncWithTest);
printf("\tQSORT TEST\t%s\n",(sortPass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
/** Procedure bitonicMerge()
It recursively sorts a bitonic sequence in ascending order,
if dir = ASCENDING, and in descending order otherwise.
The sequence to be sorted starts at index position lo,
the parameter cbt is the number of elements to be sorted.
**/
void bitonicMerge(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
int i;
for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
}
}
/** function recBitonicSort()
first produces a bitonic sequence by recursively sorting
its two halves in opposite sorting orders, and then
calls bitonicMerge to make them in the same order
**/
void *recBitonicSort(void *threadArgs) {
recBitonicSortData *thisData = (recBitonicSortData *) threadArgs;
int lo = thisData->lo;
int cnt = thisData->cnt;
int dir = thisData->dir;
if (cnt>1) {
if (cnt < REC_BITONIC_SORT_PARALLEL_MIN){ //small sub-arrays best sorted using qsort
qsort(a+lo, cnt, sizeof(int), (dir == 1 ? qSortAscending : qSortDescending));
} else {
//plitts problem in two halfs and tries to create a new thread for each
//holds each half's index (from threads array)
int firstHalf = -1, myOtherHalf = -1;
//attribute for joinable threads
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int k=cnt/2;
pthread_mutex_lock(&runningThreadsMutex); //locks running threads variable
if (runningThreads < threadsNum){
//arguments for first half
recBitonicSortData newThreadArgs;
newThreadArgs.lo = lo;
newThreadArgs.cnt = k;
newThreadArgs.dir = ASCENDING;
//tries to create a new thread with a pointer to it saved inside array "threads"
if (pthread_create(&threads[runningThreads], &attr, recBitonicSort, (void *) &newThreadArgs)){
printf("Error creating thread. Aborting.");
pthread_mutex_unlock(&runningThreadsMutex);
exit(1);
} else { //thread was successfully created
//keeps thread's index and updates running threads counter
firstHalf = runningThreads;
++runningThreads;
pthread_mutex_unlock(&runningThreadsMutex);
}
} else { //max threads number reached, does the job sequentially using qsort
pthread_mutex_unlock(&runningThreadsMutex);
qsort(a+lo, k, sizeof(int), qSortAscending);
}
pthread_mutex_lock(&runningThreadsMutex); //locks running threads variable
if (runningThreads < threadsNum){
//arguments for second half
recBitonicSortData newThreadArgs;
newThreadArgs.lo = lo+k;
newThreadArgs.cnt = k;
newThreadArgs.dir = DESCENDING;
//tries to create a new thread with a pointer to it saved inside array "threads"
if (pthread_create(&threads[runningThreads], &attr, recBitonicSort, (void *) &newThreadArgs)){
printf("Error creating thread. Aborting.");
pthread_mutex_unlock(&runningThreadsMutex);
exit(1);
} else { //thread was successfully created
//keeps thread's index and updates running threads counter
myOtherHalf = runningThreads;
++runningThreads;
pthread_mutex_unlock(&runningThreadsMutex);
}
} else { //max threads number reached, does the job sequentially using qsort
pthread_mutex_unlock(&runningThreadsMutex);
qsort(a+lo+k, k, sizeof(int), qSortDescending);
}
pthread_attr_destroy(&attr);
//achieves synchronization
if (firstHalf != -1){
pthread_join (threads[firstHalf], NULL);
}
if (myOtherHalf != -1){
pthread_join (threads[myOtherHalf], NULL);
}
bitonicMerge(lo, cnt, dir);
}
}
}
/** function sort()
Caller of recBitonicSort for sorting the entire array of length N
in ASCENDING order
**/
void sort() {
recBitonicSortData newThreadArgs;
newThreadArgs.threadID = 1;
newThreadArgs.lo = 0;
newThreadArgs.cnt = N;
newThreadArgs.dir = ASCENDING;
recBitonicSort((void *) &newThreadArgs);
}
void *impBitonicSortThread(void * threadArgs){
//get variable values from struct
impBitonicSortThreadData *thisThreadData = (impBitonicSortThreadData *) threadArgs;
int i;
int N = thisThreadData->N;
int j = thisThreadData->j;
int k = thisThreadData->k;
for (i; i<N; i++) {
int ij=i^j;
if ((ij)>i) {
if ((i&k)==0 && a[i] > a[ij])
exchange(i,ij);
if ((i&k)!=0 && a[i] < a[ij])
exchange(i,ij);
}
}
pthread_exit(NULL);
}
/*
imperative version of bitonic sort
*/
void impBitonicSort() {
int t,j,k;
//attribute for joinable threads
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int threadN = N/threadsNum; //splitts work into 2^q sub-problems
for (k=2; k<=N; k+=k) {
for (j=k>>1; j>0; j=j>>1) {
//creates a new thread for each sub-problem
for (t = 0; t < threadsNum; ++t){
impBitonicSortThreadData newThreadArgs;
newThreadArgs.i = t * threadN;
newThreadArgs.N = (t + 1) * threadN;
newThreadArgs.j = j;
newThreadArgs.k = k;
int rc = pthread_create(&threads[t], &attr, impBitonicSortThread, (void *) &newThreadArgs);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
//achieves synchronization
for(t = 0; t < threadsNum; ++t) {
pthread_join(threads[t], NULL);
}
}
}
pthread_attr_destroy(&attr);
}
/** function used by qsort for comparing as well as testing **/
int qSortAscendingCompFuncWithTest (const void * a, const void * b) {
int result = ( *(int*)a - *(int*)b );
if (result > 0){
sortPass = false;
}
return result;
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

249
pthreads/bitonicImp.c

@ -0,0 +1,249 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threadsNum; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
bool sortPass; //flag showing whether the test passed or not
const int ASCENDING = 1;
const int DESCENDING = 0;
const int REC_BITONIC_MERGE_PARALLEL_GRAINSIZE = 1 << 14;
const int REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN = (1 << 12) - 1;
const int REC_BITONIC_MERGE_PARALLEL_CALL_MIN = (1 << 8) - 1;
const int REC_BITONIC_SORT_PARALLEL_MIN = (1 << 22) + 1;
typedef struct impBitonicSortThreadData{
int i;
int N;
int j;
int k;
} impBitonicSortThreadData;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
void sort(void);
void test(void);
void qSortTest(void);
void exchange(int i, int j);
void compare(int i, int j, int dir);
void *impBitonicSortThread(void * threadArgs);
void impBitonicSort(void);
int qSortAscendingCompFuncWithTest (const void * a, const void * b);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("qSort wall clock time = %f\n\n", seq_time);
//Sorts using the imperative bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
impBitonicSort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("Imperative wall clock time = %f\n", seq_time);
test();
qSortTest();
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 3) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
threadsNum = 1<<atoi(argv[1]);
N = 1<<atoi(argv[2]);
}
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf("\tTEST\t\t%s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure qSortTest() : verify sort results using qsort method **/
void qSortTest(){
sortPass = true;
qsort(a, N, sizeof(int), qSortAscendingCompFuncWithTest);
printf("\tQSORT TEST\t%s\n",(sortPass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
void *impBitonicSortThread(void * threadArgs){
impBitonicSortThreadData *thisThreadData = (impBitonicSortThreadData *) threadArgs;
int i;
int N = thisThreadData->N;
int j = thisThreadData->j;
int k = thisThreadData->k;
for (i; i<N; i++) {
int ij=i^j;
if ((ij)>i) {
if ((i&k)==0 && a[i] > a[ij])
exchange(i,ij);
if ((i&k)!=0 && a[i] < a[ij])
exchange(i,ij);
}
}
pthread_exit(NULL);
}
/*
imperative version of bitonic sort
*/
void impBitonicSort() {
int t,j,k;
impBitonicSortThreadData impBitonicSortThreadDataArray[threadsNum];
pthread_t threads[threadsNum];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int threadN = N/threadsNum;
for (k=2; k<=N; k+=k) {
for (j=k>>1; j>0; j=j>>1) {
for (t = 0; t < threadsNum; ++t){
impBitonicSortThreadDataArray[t].i = t * threadN;
impBitonicSortThreadDataArray[t].N = (t + 1) * threadN;
impBitonicSortThreadDataArray[t].j = j;
impBitonicSortThreadDataArray[t].k = k;
int rc = pthread_create(&threads[t], &attr, impBitonicSortThread, (void *) &impBitonicSortThreadDataArray[t]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
void *status;
for(t = 0; t < threadsNum; ++t) {
int rc = pthread_join(threads[t], &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
}
}
}
pthread_attr_destroy(&attr);
}
/** function used by qsort for comparing as well as testing **/
int qSortAscendingCompFuncWithTest (const void * a, const void * b) {
int result = ( *(int*)a - *(int*)b );
if (result > 0){
sortPass = false;
}
return result;
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

320
pthreads/bitonicRec.c

@ -0,0 +1,320 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threadsNum; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
bool sortPass; //flag showing whether the test passed or not
const int ASCENDING = 1;
const int DESCENDING = 0;
const int REC_BITONIC_MERGE_PARALLEL_GRAINSIZE = 1 << 14;
const int REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN = (1 << 12) - 1;
const int REC_BITONIC_MERGE_PARALLEL_CALL_MIN = (1 << 8) - 1;
const int REC_BITONIC_SORT_PARALLEL_MIN = (1 << 22) + 1;
typedef struct recBitonicSortData{
int threadID;
int lo;
int cnt;
int dir;
} recBitonicSortData;
pthread_t *threads;
int runningThreads = 1;
pthread_mutex_t runningThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
void sort(void);
void test(void);
void qSortTest(void);
void exchange(int i, int j);
void compare(int i, int j, int dir);
void bitonicMerge(int lo, int cnt, int dir);
void *recBitonicSort(void *threadArgs);
int qSortAscendingCompFuncWithTest (const void * a, const void * b);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
threads = (pthread_t *)malloc(sizeof(pthread_t)*threadsNum);
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("qSort wall clock time = %f\n\n", seq_time);
//Sorts using the recursive bitonic algorithm
init();
gettimeofday (&startwtime, NULL);
sort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("\nRecursive wall clock time = %f\n", seq_time);
test();
qSortTest();
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 3) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
threadsNum = 1<<atoi(argv[1]);
N = 1<<atoi(argv[2]);
}
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf("\tTEST\t\t%s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure qSortTest() : verify sort results using qsort method **/
void qSortTest(){
sortPass = true;
qsort(a, N, sizeof(int), qSortAscendingCompFuncWithTest);
printf("\tQSORT TEST\t%s\n",(sortPass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
/** Procedure bitonicMerge()
It recursively sorts a bitonic sequence in ascending order,
if dir = ASCENDING, and in descending order otherwise.
The sequence to be sorted starts at index position lo,
the parameter cbt is the number of elements to be sorted.
**/
void bitonicMerge(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
int i;
if (cnt > REC_BITONIC_MERGE_PARALLEL_COMPARE_MIN){
for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
} else {
for (i=lo; i<lo+k; i++){
compare(i, i+k, dir);
}
}
if (cnt > REC_BITONIC_MERGE_PARALLEL_CALL_MIN){
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
} else{
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
}
}
}
/** function recBitonicSort()
first produces a bitonic sequence by recursively sorting
its two halves in opposite sorting orders, and then
calls bitonicMerge to make them in the same order
**/
void *recBitonicSort(void *threadArgs) {
recBitonicSortData *thisData = (recBitonicSortData *) threadArgs;
int threadID = thisData->threadID;
int lo = thisData->lo;
int cnt = thisData->cnt;
int dir = thisData->dir;
if (cnt>1) {
if (cnt < REC_BITONIC_SORT_PARALLEL_MIN){
qsort(a+lo, cnt, sizeof(int), (dir == 1 ? qSortAscending : qSortDescending));
} else {
pthread_t firstHalf, myOtherHalf;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
int k=cnt/2;
pthread_mutex_lock(&runningThreadsMutex);
if (runningThreads < threadsNum){
recBitonicSortData newThreadArgs;
newThreadArgs.threadID = runningThreads + 1;
newThreadArgs.lo = lo;
newThreadArgs.cnt = k;
newThreadArgs.dir = ASCENDING;
if (pthread_create(&firstHalf, &attr, recBitonicSort, (void *) &newThreadArgs)){
printf("Error creating thread. Aborting.");
pthread_mutex_unlock(&runningThreadsMutex);
exit(1);
} else {
++runningThreads;
pthread_mutex_unlock(&runningThreadsMutex);
}
} else {
pthread_mutex_unlock(&runningThreadsMutex);
qsort(a+lo, k, sizeof(int), qSortAscending);
}
pthread_mutex_lock(&runningThreadsMutex);
if (runningThreads < threadsNum){
recBitonicSortData newThreadArgs;
newThreadArgs.threadID = runningThreads + 1;
newThreadArgs.lo = lo+k;
newThreadArgs.cnt = k;
newThreadArgs.dir = DESCENDING;
if (pthread_create(&myOtherHalf, &attr, recBitonicSort, (void *) &newThreadArgs)){
printf("Error creating thread. Aborting.");
pthread_mutex_unlock(&runningThreadsMutex);
exit(1);
} else {
++runningThreads;
pthread_mutex_unlock(&runningThreadsMutex);
}
} else {
pthread_mutex_unlock(&runningThreadsMutex);
qsort(a+lo+k, k, sizeof(int), qSortDescending);
}
pthread_attr_destroy(&attr);
if (&firstHalf != NULL){
pthread_join (firstHalf, NULL);
}
if (&firstHalf != NULL){
pthread_join (myOtherHalf, NULL);
}
bitonicMerge(lo, cnt, dir);
}
}
if (threadID > 1 && threadID < threadsNum){
pthread_exit(NULL);
}
}
/** function sort()
Caller of recBitonicSort for sorting the entire array of length N
in ASCENDING order
**/
void sort() {
recBitonicSortData newThreadArgs;
newThreadArgs.threadID = 1;
newThreadArgs.lo = 0;
newThreadArgs.cnt = N;
newThreadArgs.dir = ASCENDING;
recBitonicSort((void *) &newThreadArgs);
}
/** function used by qsort for comparing as well as testing **/
int qSortAscendingCompFuncWithTest (const void * a, const void * b) {
int result = ( *(int*)a - *(int*)b );
if (result > 0){
sortPass = false;
}
return result;
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

110
qsort/qsort.c

@ -0,0 +1,110 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
typedef enum { false, true } bool;
struct timeval startwtime, endwtime;
double seq_time;
int threads; //number of threads
int N; // data array size
int *a; // data array to be sorted
unsigned randSeed; //seed array initialisation
const int ASCENDING = 1;
const int DESCENDING = 0;
void getArgs(int argc, char** argv);
void init(void);
void print(void);
int qSortAscending (const void * a, const void * b);
int qSortDescending (const void * a, const void * b);
/** the main program **/
int main(int argc, char **argv) {
getArgs(argc, argv);
a = (int *) malloc(N * sizeof(int));
randSeed = (unsigned) time(NULL);
//Sorts using the qSort algorithm
init();
gettimeofday (&startwtime, NULL);
qsort(a, N, sizeof(int), qSortAscending);
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("%f\n", seq_time);
free(a);
}
/** -------------- SUB-PROCEDURES ----------------- **/
void getArgs(int argc, char** argv){
if (argc != 2) {
printf("Usage: %s p q\nwhere:\n\tP=2^p is the the number of threads(power of two)\n\tN=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
N = 1<<atoi(argv[1]);
}
/** procedure init() : initialize array "a" with data **/
void init() {
srand(randSeed);
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** function used by qsort for comparing **/
int qSortAscending (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
/** function used by qsort for comparing **/
int qSortDescending (const void * a, const void * b) {
return ( *(int*)b - *(int*)a );
}

215
seq/bitonic.c

@ -0,0 +1,215 @@
/*
bitonic.c
This file contains two different implementations of the bitonic sort
recursive version : recBitonicSort()
imperative version : impBitonicSort()
The bitonic sort is also known as Batcher Sort.
For a reference of the algorithm, see the article titled
Sorting networks and their applications by K. E. Batcher in 1968
The following codes take references to the codes avaiable at
http://www.cag.lcs.mit.edu/streamit/results/bitonic/code/c/bitonic.c
http://www.tools-of-computing.com/tc/CS/Sorts/bitonic_sort.htm
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/bitonic/bitonicen.htm
*/
/*
------- ----------------------
Nikos Pitsianis, Duke CS
-----------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
struct timeval startwtime, endwtime;
double seq_time;
int N; // data array size
int *a; // data array to be sorted
const int ASCENDING = 1;
const int DESCENDING = 0;
void init(void);
void print(void);
void sort(void);
void test(void);
inline void exchange(int i, int j);
void compare(int i, int j, int dir);
void bitonicMerge(int lo, int cnt, int dir);
void recBitonicSort(int lo, int cnt, int dir);
void impBitonicSort(void);
/** the main program **/
int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: %s q\n where n=2^q is problem size (power of two)\n",
argv[0]);
exit(1);
}
N = 1<<atoi(argv[1]);
a = (int *) malloc(N * sizeof(int));
init();
gettimeofday (&startwtime, NULL);
impBitonicSort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("Imperative wall clock time = %f\n", seq_time);
test();
init();
gettimeofday (&startwtime, NULL);
sort();
gettimeofday (&endwtime, NULL);
seq_time = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6
+ endwtime.tv_sec - startwtime.tv_sec);
printf("Recursive wall clock time = %f\n", seq_time);
test();
// print();
}
/** -------------- SUB-PROCEDURES ----------------- **/
/** procedure test() : verify sort results **/
void test() {
int pass = 1;
int i;
for (i = 1; i < N; i++) {
pass &= (a[i-1] <= a[i]);
}
printf(" TEST %s\n",(pass) ? "PASSed" : "FAILed");
}
/** procedure init() : initialize array "a" with data **/
void init() {
int i;
for (i = 0; i < N; i++) {
a[i] = rand() % N; // (N - i);
}
}
/** procedure print() : print array elements **/
void print() {
int i;
for (i = 0; i < N; i++) {
printf("%d\n", a[i]);
}
printf("\n");
}
/** INLINE procedure exchange() : pair swap **/
inline void exchange(int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
/** procedure compare()
The parameter dir indicates the sorting direction, ASCENDING
or DESCENDING; if (a[i] > a[j]) agrees with the direction,
then a[i] and a[j] are interchanged.
**/
inline void compare(int i, int j, int dir) {
if (dir==(a[i]>a[j]))
exchange(i,j);
}
/** Procedure bitonicMerge()
It recursively sorts a bitonic sequence in ascending order,
if dir = ASCENDING, and in descending order otherwise.
The sequence to be sorted starts at index position lo,
the parameter cbt is the number of elements to be sorted.
**/
void bitonicMerge(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
int i;
for (i=lo; i<lo+k; i++)
compare(i, i+k, dir);
bitonicMerge(lo, k, dir);
bitonicMerge(lo+k, k, dir);
}
}
/** function recBitonicSort()
first produces a bitonic sequence by recursively sorting
its two halves in opposite sorting orders, and then
calls bitonicMerge to make them in the same order
**/
void recBitonicSort(int lo, int cnt, int dir) {
if (cnt>1) {
int k=cnt/2;
recBitonicSort(lo, k, ASCENDING);
recBitonicSort(lo+k, k, DESCENDING);
bitonicMerge(lo, cnt, dir);
}
}
/** function sort()
Caller of recBitonicSort for sorting the entire array of length N
in ASCENDING order
**/
void sort() {
recBitonicSort(0, N, ASCENDING);
}
/*
imperative version of bitonic sort
*/
void impBitonicSort() {
int i,j,k;
for (k=2; k<=N; k=2*k) {
for (j=k>>1; j>0; j=j>>1) {
for (i=0; i<N; i++) {
int ij=i^j;
if ((ij)>i) {
if ((i&k)==0 && a[i] > a[ij])
exchange(i,ij);
if ((i&k)!=0 && a[i] < a[ij])
exchange(i,ij);
}
}
}
}
}
Loading…
Cancel
Save