Browse Source

first commit

master
commit
233b7588e9
48 changed files with 5855 additions and 0 deletions
  1. +56
    -0
      ARM/addition/Makefile
  2. +102
    -0
      ARM/addition/add_threads.cpp
  3. +174
    -0
      ARM/addition/sched_mmap_100_add.cpp
  4. +174
    -0
      ARM/addition/sched_mmap_24_add.cpp
  5. +130
    -0
      ARM/addition/sched_mmap_add.cpp
  6. +75
    -0
      ARM/addition/single_add.cpp
  7. +56
    -0
      ARM/multiplication/Collective Forking/Makefile
  8. +148
    -0
      ARM/multiplication/Collective Forking/mmap_c_100_mul.cpp
  9. +148
    -0
      ARM/multiplication/Collective Forking/mmap_c_4_mul.cpp
  10. +136
    -0
      ARM/multiplication/Collective Forking/mmap_c_n_mul.cpp
  11. +56
    -0
      ARM/multiplication/Makefile
  12. +56
    -0
      ARM/multiplication/Prolific Forking/Makefile
  13. +187
    -0
      ARM/multiplication/Prolific Forking/mmap_pr_100_mul.cpp
  14. +187
    -0
      ARM/multiplication/Prolific Forking/mmap_pr_4_mul.cpp
  15. +170
    -0
      ARM/multiplication/Prolific Forking/mmap_pr_n_mul.cpp
  16. +120
    -0
      ARM/multiplication/mpimul_openmp.cpp
  17. +75
    -0
      ARM/multiplication/mul_openMP.cpp
  18. +76
    -0
      ARM/multiplication/single_mul.cpp
  19. +98
    -0
      ARM/multiplication/threads_100_mul.cpp
  20. +111
    -0
      ARM/multiplication/threads_n_mul.cpp
  21. +57
    -0
      CPU/addition/Makefile
  22. +174
    -0
      CPU/addition/mmap_100_add.cpp
  23. +174
    -0
      CPU/addition/mmap_24_add.cpp
  24. +130
    -0
      CPU/addition/mmap_add.cpp
  25. +75
    -0
      CPU/addition/single_add.cpp
  26. +102
    -0
      CPU/addition/threads_add.cpp
  27. +57
    -0
      CPU/multiplication/Collective Forking mmap/Makefile
  28. +148
    -0
      CPU/multiplication/Collective Forking mmap/mmap_c_100_mul.cpp
  29. +148
    -0
      CPU/multiplication/Collective Forking mmap/mmap_c_24_mul.cpp
  30. +136
    -0
      CPU/multiplication/Collective Forking mmap/mmap_c_n_mul.cpp
  31. +57
    -0
      CPU/multiplication/Makefile
  32. +57
    -0
      CPU/multiplication/Prolific Forking mmap/Makefile
  33. +187
    -0
      CPU/multiplication/Prolific Forking mmap/mmap_pr_100_mul.cpp
  34. +187
    -0
      CPU/multiplication/Prolific Forking mmap/mmap_pr_24_mul.cpp
  35. +170
    -0
      CPU/multiplication/Prolific Forking mmap/mmap_pr_n_mul.cpp
  36. +75
    -0
      CPU/multiplication/mul_openMP.cpp
  37. +76
    -0
      CPU/multiplication/single_mul.cpp
  38. +98
    -0
      CPU/multiplication/threads_100_mul.cpp
  39. +111
    -0
      CPU/multiplication/threads_n_mul.cpp
  40. +57
    -0
      GPU/Makefile
  41. +151
    -0
      GPU/multi_gpu_matrix_add_mmap.cu
  42. +159
    -0
      GPU/multi_gpu_matrix_mul_mmap.cu
  43. +187
    -0
      README.md
  44. +228
    -0
      Roadmap/cannon.cpp
  45. +221
    -0
      Roadmap/fox.cpp
  46. +182
    -0
      Roadmap/strassen.cpp
  47. +116
    -0
      Roadmap/summa.cpp
  48. BIN
      arch.png

+ 56
- 0
ARM/addition/Makefile View File

@ -0,0 +1,56 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g -fopenmp
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 102
- 0
ARM/addition/add_threads.cpp View File

@ -0,0 +1,102 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;
const int NUM_OF_THREADS = 100;
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void print_c(double **c,int n) {
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
std::cout <<c[i][j] <<"\t";
}
std::cout << std::endl;
}
}
void delete_matrix(double **matrix, int n) {
for (int i = 0; i < n; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
double **add(double **a,double **b,double **c, int n, int start,int end) {
for (int i=start;i<end;i++) {
for (int j=0;j<n;j++) {
//mtx.lock();
c[i][j] = a[i][j] + b[i][j];
//mtx.unlock();
}
}
return c;
}
int main(int argc, char ** argv) {
if (argc != 2) {
cerr << "Usage:" << argv[0] << "<matrix.size>" << endl;
}
int n=std::atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::thread_group tg;
//std::vector<boost::thread> threads;
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
t3 = boost::chrono::system_clock::now();
int rows_per_thread = n / NUM_OF_THREADS;
int remaining_rows = n % NUM_OF_THREADS;
int current_row = 0;
for(int i = 0; i < NUM_OF_THREADS && current_row < n; i++){
int rows_to_process = rows_per_thread + (i< remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
try {
tg.create_thread(boost::bind(add,a,b,c,n,current_row,end_row));
} catch (const exception &e) {
cerr << "create_thread failed, thread:" << i << "," << e.what() << endl;
}
current_row = end_row;
}
tg.join_all();
t4 = boost::chrono::system_clock::now();
boost::chrono::milliseconds res3 =boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
std::cout <<" n,setup(us),exec*(us)" << n<<","<<res.count() <<","<<res3.count()<< std::endl;
delete_matrix(a,n);
delete_matrix(b,n);
delete_matrix(c,n);
return 0;
}

+ 174
- 0
ARM/addition/sched_mmap_100_add.cpp View File

@ -0,0 +1,174 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
#define DEBUG 0
using namespace std;
const int MAX_PROCESSES = 100;
struct SharedMatrix {
vector<double*> chunks;
double** row_pointers;
int size;
};
void create_shared_matrix(SharedMatrix** matrix, int n) {
const size_t CHUNK_SIZE = 1024 * 1024; // 1MB chunks
size_t total_size = n * n * sizeof(double);
size_t num_chunks = (total_size + CHUNK_SIZE - 1) / CHUNK_SIZE;
*matrix = new SharedMatrix;
(*matrix)->size = n;
(*matrix)->chunks.reserve(num_chunks);
// Allocate memory chunks
for (size_t i = 0; i < num_chunks; ++i) {
size_t chunk_size = min(CHUNK_SIZE, total_size - i * CHUNK_SIZE);
void* ptr = mmap(NULL, chunk_size,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
if (ptr == MAP_FAILED) {
perror("mmap failed");
// Clean up already allocated chunks
for (auto chunk : (*matrix)->chunks) {
munmap(chunk, CHUNK_SIZE);
}
delete *matrix;
exit(1);
}
(*matrix)->chunks.push_back(static_cast<double*>(ptr));
}
// Create row pointers
(*matrix)->row_pointers = new double*[n];
size_t current_chunk = 0;
size_t offset_in_chunk = 0;
for (int i = 0; i < n; ++i) {
(*matrix)->row_pointers[i] = reinterpret_cast<double*>(
reinterpret_cast<char*>((*matrix)->chunks[current_chunk]) + offset_in_chunk);
offset_in_chunk += n * sizeof(double);
// Move to next chunk if needed
while (offset_in_chunk >= CHUNK_SIZE) {
offset_in_chunk -= CHUNK_SIZE;
current_chunk++;
// Handle case where row spans chunks
if (i < n - 1) {
(*matrix)->row_pointers[i] = reinterpret_cast<double*>(
reinterpret_cast<char*>((*matrix)->row_pointers[i]) - CHUNK_SIZE + offset_in_chunk);
}
}
}
}
void cleanup_matrix(SharedMatrix** matrix) {
for (auto chunk : (*matrix)->chunks) {
munmap(chunk, (*matrix)->chunks.size() > 1 ? 1024 * 1024 :
(*matrix)->size * (*matrix)->size * sizeof(double));
}
delete[] (*matrix)->row_pointers;
delete *matrix;
*matrix = nullptr;
}
void init_matrix(SharedMatrix** matrix, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < (*matrix)->size; ++i) {
for (int j = 0; j < (*matrix)->size; ++j) {
(*matrix)->row_pointers[i][j] = zero ? 0.0 : dis(gen);
}
}
}
int addV(int start_row, int end_row, SharedMatrix** a, SharedMatrix** b, SharedMatrix** c) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < (*a)->size; ++j) {
(*c)->row_pointers[i][j] = (*a)->row_pointers[i][j] + (*b)->row_pointers[i][j];
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
SharedMatrix *a = nullptr, *b = nullptr, *c = nullptr;
create_shared_matrix(&a, n);
create_shared_matrix(&b, n);
create_shared_matrix(&c, n);
init_matrix(&a);
init_matrix(&b);
init_matrix(&c, true);
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Calculate work distribution
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process
addV(current_row, end_row, &a, &b, &c);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all children
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
cleanup_matrix(&a);
cleanup_matrix(&b);
cleanup_matrix(&c);
return 0;
}

+ 174
- 0
ARM/addition/sched_mmap_24_add.cpp View File

@ -0,0 +1,174 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
#define DEBUG 0
using namespace std;
const int MAX_PROCESSES = 24;
struct SharedMatrix {
vector<double*> chunks;
double** row_pointers;
int size;
};
void create_shared_matrix(SharedMatrix** matrix, int n) {
const size_t CHUNK_SIZE = 1024 * 1024; // 1MB chunks
size_t total_size = n * n * sizeof(double);
size_t num_chunks = (total_size + CHUNK_SIZE - 1) / CHUNK_SIZE;
*matrix = new SharedMatrix;
(*matrix)->size = n;
(*matrix)->chunks.reserve(num_chunks);
// Allocate memory chunks
for (size_t i = 0; i < num_chunks; ++i) {
size_t chunk_size = min(CHUNK_SIZE, total_size - i * CHUNK_SIZE);
void* ptr = mmap(NULL, chunk_size,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
if (ptr == MAP_FAILED) {
perror("mmap failed");
// Clean up already allocated chunks
for (auto chunk : (*matrix)->chunks) {
munmap(chunk, CHUNK_SIZE);
}
delete *matrix;
exit(1);
}
(*matrix)->chunks.push_back(static_cast<double*>(ptr));
}
// Create row pointers
(*matrix)->row_pointers = new double*[n];
size_t current_chunk = 0;
size_t offset_in_chunk = 0;
for (int i = 0; i < n; ++i) {
(*matrix)->row_pointers[i] = reinterpret_cast<double*>(
reinterpret_cast<char*>((*matrix)->chunks[current_chunk]) + offset_in_chunk);
offset_in_chunk += n * sizeof(double);
// Move to next chunk if needed
while (offset_in_chunk >= CHUNK_SIZE) {
offset_in_chunk -= CHUNK_SIZE;
current_chunk++;
// Handle case where row spans chunks
if (i < n - 1) {
(*matrix)->row_pointers[i] = reinterpret_cast<double*>(
reinterpret_cast<char*>((*matrix)->row_pointers[i]) - CHUNK_SIZE + offset_in_chunk);
}
}
}
}
void cleanup_matrix(SharedMatrix** matrix) {
for (auto chunk : (*matrix)->chunks) {
munmap(chunk, (*matrix)->chunks.size() > 1 ? 1024 * 1024 :
(*matrix)->size * (*matrix)->size * sizeof(double));
}
delete[] (*matrix)->row_pointers;
delete *matrix;
*matrix = nullptr;
}
void init_matrix(SharedMatrix** matrix, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < (*matrix)->size; ++i) {
for (int j = 0; j < (*matrix)->size; ++j) {
(*matrix)->row_pointers[i][j] = zero ? 0.0 : dis(gen);
}
}
}
int addV(int start_row, int end_row, SharedMatrix** a, SharedMatrix** b, SharedMatrix** c) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < (*a)->size; ++j) {
(*c)->row_pointers[i][j] = (*a)->row_pointers[i][j] + (*b)->row_pointers[i][j];
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
SharedMatrix *a = nullptr, *b = nullptr, *c = nullptr;
create_shared_matrix(&a, n);
create_shared_matrix(&b, n);
create_shared_matrix(&c, n);
init_matrix(&a);
init_matrix(&b);
init_matrix(&c, true);
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Calculate work distribution
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process
addV(current_row, end_row, &a, &b, &c);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all children
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
cleanup_matrix(&a);
cleanup_matrix(&b);
cleanup_matrix(&c);
return 0;
}

+ 130
- 0
ARM/addition/sched_mmap_add.cpp View File

@ -0,0 +1,130 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
#define DEBUG 0
using namespace std;
// Create a mmap-allocated matrix with pointers
double** create_shared_matrix(int n) {
int data_size = n * n * sizeof(double);
void* hint = (void*)0x10000000; // Example hint address
double* data = (double*)mmap(hint, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (data == MAP_FAILED) {
perror("mmap");
exit(1);
}
// Create an index matrix locally (does not need to be shared)
double** mat = new double*[n];
for (int i = 0; i < n; ++i)
mat[i] = &data[i * n];
return mat;
}
// Detach mmap and delete indexes
void cleanup_matrix(double** mat, int n) {
munmap(mat[0], n * n * sizeof(double));
delete[] mat;
}
void init_matrix(double** mat, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
if (zero)
mat[i][j] = 0 ;
else
mat[i][j]=dis(gen);
}
//Add vector column
int addV(int p, double **a, double**b, double **c, int n, int offset) {
for (int j=0;j<n;j++)
c[offset-1][j]=a[offset-1][j]+b[offset-1][j];
return getpid()%getppid();
}
void print_matrix(double** mat, int n) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j)
cout << mat[i][j] << "\t";
cout << endl;
}
}
int main(int argc, char**argv) {
int mom_pid=getpid();
int status; int pid;
int n, num_processes;
n=atoi(argv[1]);
num_processes=n;
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=
boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
t3=boost::chrono::system_clock::now();
/*scheduler*/
int count=0;
while (true) {
pid = fork();
if (pid < 0) {
cout << "Fork failed!" << endl;
break;
} else {
count++;
if (pid == 0 && mom_pid==getppid() ) {
if (DEBUG)
cout <<"["<<count<<"]"<< " PID:" << getpid() << " Mom:" << getppid() << endl;
break;
} else if (mom_pid!=getpid()) {
return -1;
}
}
if (count>=num_processes)
break;
}
/*Task assign*/
if (pid==0) {
addV(count,a,b,c,n,count);
return getpid()%getppid();
} else {
// Parent waits for every child process to be finished
for (int i = 0; i < num_processes; ++i) {
wait(&status);
if (WIFEXITED(status))
if(DEBUG)
std::cout << "Child Process in:" << "<= Parent:"<< (int) getpid() << " exited with status" << WEXITSTATUS(status) << std::endl;
usleep(10);
}
t4=boost::chrono::system_clock::now();
boost::chrono::milliseconds res2 = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4-t3);
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
cout <<" n,setup(us),exec(us)" << n<<","<<res.count() <<","<<res2.count()<<endl;
}
return 0;
}

+ 75
- 0
ARM/addition/single_add.cpp View File

@ -0,0 +1,75 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
using namespace std;
int addV(int p, double **a, double**b, double **c, int n, int offset) {
for (int j=0;j<n;j++)
c[offset][j]=a[offset][j]+b[offset][j];
return getpid()%getppid();
}
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void print_c(double **c,int n) {
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
cout <<c[i][j] <<"\t";
}
cout << endl;
}
}
void delete_matrix(double **matrix, int n) {
for (int i = 0; i < n; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
int main(int argc, char ** argv) {
int n;
n=atoi(argv[1]);
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=
boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
t3=boost::chrono::system_clock::now();
for (int i=0;i<n;i++)
addV(i,a,b,c,n,i);
t4=boost::chrono::system_clock::now();
boost::chrono::milliseconds res2=
boost::chrono::duration_cast<boost::chrono::milliseconds>(t4-t3);
//print_c(c,n);
cout <<" n,setup(us),exec(us)" << n<<","<<res.count() <<","<<res2.count()<<endl;
delete_matrix(a,n);
delete_matrix(b,n);
delete_matrix(c,n);
return 0;
}

+ 56
- 0
ARM/multiplication/Collective Forking/Makefile View File

@ -0,0 +1,56 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g -fopenmp
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 148
- 0
ARM/multiplication/Collective Forking/mmap_c_100_mul.cpp View File

@ -0,0 +1,148 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
const int MAX_PROCESSES = 100;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for rows [start_row, end_row)
int mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
//double **a = nullptr, **b = nullptr, **c = nullptr;
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Distribute work among 100 processes
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned rows
mulV(current_row, end_row, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 148
- 0
ARM/multiplication/Collective Forking/mmap_c_4_mul.cpp View File

@ -0,0 +1,148 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
const int MAX_PROCESSES = 4;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for rows [start_row, end_row)
int mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
//double **a = nullptr, **b = nullptr, **c = nullptr;
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Distribute work among 100 processes
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned rows
mulV(current_row, end_row, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 136
- 0
ARM/multiplication/Collective Forking/mmap_c_n_mul.cpp View File

@ -0,0 +1,136 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for a single row
int mulV_single_row(int row, double** a, double** b, double** c, int n) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[row][k] * b[k][j];
}
c[row][j] = sum;
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
vector<pid_t> children;
// Create one process per row
for (int i = 0; i < n; ++i) {
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned row
mulV_single_row(i, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 56
- 0
ARM/multiplication/Makefile View File

@ -0,0 +1,56 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g -fopenmp
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 56
- 0
ARM/multiplication/Prolific Forking/Makefile View File

@ -0,0 +1,56 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g -fopenmp
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 187
- 0
ARM/multiplication/Prolific Forking/mmap_pr_100_mul.cpp View File

@ -0,0 +1,187 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
const int MAX_PROCESSES = 100;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for rows [start_row, end_row)
int mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
//double **a = nullptr, **b = nullptr, **c = nullptr;
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Distribute work among 100 processes
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
int mom_pid=getpid();
/*scheduler*/
int count =0;
int status;
int pid;
int end_row;
int rows_to_process;
while(true) {
rows_to_process = rows_per_process + (count < remaining_rows ? 1 : 0);
end_row = current_row + rows_to_process;
pid=fork();
if (pid<0) {
cout << "Error forking!" << endl;
exit(1);
} else {
count++;
if (pid==0 && mom_pid==getppid()) {
//cout << count << ":" << current_row << "-" << end_row << endl;
break;
} else if (mom_pid!=getpid()) {
return -1;
}
//main parent
current_row = end_row;
}
if (count >=MAX_PROCESSES)
break;
}
/*Task assign*/
if (pid==0) {
//DO
mulV(current_row, end_row, a, b, c, n);
return getpid()%getppid();
} else {
for (int i=0;i<MAX_PROCESSES;++i) {
wait(&status);
//usleep(1);
}
}
/* vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned rows
mulV(current_row, end_row, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}*/
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 187
- 0
ARM/multiplication/Prolific Forking/mmap_pr_4_mul.cpp View File

@ -0,0 +1,187 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
const int MAX_PROCESSES = 4;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for rows [start_row, end_row)
int mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
//double **a = nullptr, **b = nullptr, **c = nullptr;
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Distribute work among 100 processes
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
int mom_pid=getpid();
/*scheduler*/
int count =0;
int status;
int pid;
int end_row;
int rows_to_process;
while(true) {
rows_to_process = rows_per_process + (count < remaining_rows ? 1 : 0);
end_row = current_row + rows_to_process;
pid=fork();
if (pid<0) {
cout << "Error forking!" << endl;
exit(1);
} else {
count++;
if (pid==0 && mom_pid==getppid()) {
//cout << count << ":" << current_row << "-" << end_row << endl;
break;
} else if (mom_pid!=getpid()) {
return -1;
}
//main parent
current_row = end_row;
}
if (count >=MAX_PROCESSES)
break;
}
/*Task assign*/
if (pid==0) {
//DO
mulV(current_row, end_row, a, b, c, n);
return getpid()%getppid();
} else {
for (int i=0;i<MAX_PROCESSES;++i) {
wait(&status);
//usleep(1);
}
}
/* vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned rows
mulV(current_row, end_row, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}*/
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 170
- 0
ARM/multiplication/Prolific Forking/mmap_pr_n_mul.cpp View File

@ -0,0 +1,170 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for a single row
int mulV_single_row(int row, double** a, double** b, double** c, int n) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[row][k] * b[k][j];
}
c[row][j] = sum;
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
int num_processes=n;
int mom_pid=getpid();
/*scheduler*/
int count =0;
int status;
int pid;
while(true) {
pid=fork();
if (pid<0) {
cout << "Error forking!" << endl;
exit(1);
} else {
count++;
if (pid==0 && mom_pid==getppid()) {
break;
} else if (mom_pid!=getpid()) {
return -1;
}
}
if (count >=num_processes)
break;
}
/*Task assign*/
if (pid==0) {
//DO
mulV_single_row(count, a, b, c, n);
return getpid()%getppid();
} else {
for (int i=0;i<num_processes;++i) {
wait(&status);
//usleep(1);
}
}
/* vector<pid_t> children;
// Create one process per row
for (int i = 0; i < n; ++i) {
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned row
mulV_single_row(i, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}*/
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 120
- 0
ARM/multiplication/mpimul_openmp.cpp View File

@ -0,0 +1,120 @@
#include <mpi.h>
#include <iostream>
#include <random>
#include <chrono>
#include <boost/chrono.hpp>
#include <omp.h>
#define num_threads 4
using namespace std;
using namespace boost;
void generate_matrix(double* matrix, int n, std::mt19937& gen, std::uniform_real_distribution<double>& dist) {
#pragma omp parallel for
for (int i = 0; i < n * n; ++i) {
matrix[i] = dist(gen);
}
}
void multiply_rows(const double* a, const double* b, double* c, int n, int row_start, int row_end) {
int num_rows = row_end - row_start;
// Collapsed all three loops - best for very large matrices
#pragma omp parallel for schedule(dynamic, 100) collapse(2)
for (int i = 0; i < num_rows; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < n; ++k) {
c[i*n + j] += a[i*n + k] * b[k*n + j];
}
}
}
}
int main(int argc, char* argv[]) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
// Pre-MPI array generation
double* a_full = new double[n*n](); // Initialize to zero
double* b_full = new double[n*n]();
double* c_full = new double[n*n]();
std::mt19937 gen(static_cast<unsigned>(time(nullptr)));
std::uniform_real_distribution<double> dist(0.0, 1.0);
generate_matrix(a_full, n, gen, dist);
generate_matrix(b_full, n, gen, dist);
// Start timing
boost::chrono::high_resolution_clock::time_point start = boost::chrono::high_resolution_clock::now();
MPI_Init(&argc, &argv);
int rank, size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
// Set number of OpenMP threads
omp_set_num_threads(num_threads);
int rows_per_proc = n / size;
int extra = n % size;
int my_rows = rows_per_proc + (rank < extra ? 1 : 0);
int row_start = rank * rows_per_proc + min(rank, extra);
double* a_sub = new double[my_rows * n]();
double* c_sub = new double[my_rows * n]();
double* b = new double[n * n]();
// Distribute B
MPI_Bcast(b_full, n * n, MPI_DOUBLE, 0, MPI_COMM_WORLD);
std::copy(b_full, b_full + n * n, b);
// Distribute rows of A
if (rank == 0) {
for (int i = 0; i < size; ++i) {
int r_start = i * rows_per_proc + min(i, extra);
int r_count = rows_per_proc + (i < extra ? 1 : 0);
if (i == 0) {
std::copy(a_full, a_full + r_count * n, a_sub);
} else {
MPI_Send(a_full + r_start * n, r_count * n, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
}
}
} else {
MPI_Recv(a_sub, my_rows * n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
MPI_Barrier(MPI_COMM_WORLD);
multiply_rows(a_sub, b, c_sub, n, row_start, row_start + my_rows);
MPI_Barrier(MPI_COMM_WORLD);
// Gather results
if (rank == 0) {
std::copy(c_sub, c_sub + my_rows * n, c_full + row_start * n);
for (int i = 1; i < size; ++i) {
int r_start = i * rows_per_proc + min(i, extra);
int r_count = rows_per_proc + (i < extra ? 1 : 0);
::MPI_Recv(c_full + r_start * n, r_count * n, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
boost::chrono::high_resolution_clock::time_point end = boost::chrono::high_resolution_clock::now();
auto duration = boost::chrono::duration_cast<boost::chrono::milliseconds>(end - start);
cout << "Matrix multiplication completed in " << duration.count() << " ms" << endl;
} else {
MPI_Send(c_sub, my_rows * n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
}
// Clean up
delete[] a_sub;
delete[] c_sub;
delete[] b;
if (rank == 0) {
delete[] a_full;
delete[] b_full;
delete[] c_full;
}
MPI_Finalize();
return 0;
}

+ 75
- 0
ARM/multiplication/mul_openMP.cpp View File

@ -0,0 +1,75 @@
#include <iostream>
#include <boost/chrono.hpp>
#include <random>
#include <omp.h>
#include <cstdlib>
using namespace std;
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void delete_matrix(double **a, int n) {
for (int i = 0; i < n; i++) {
delete[] a[i];
}
delete[] a;
}
int main(int argc, char ** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n=atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
auto setup_start = boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
auto setup_end = boost::chrono::system_clock::now();
auto start = boost::chrono::system_clock::now();
#pragma omp parallel for schedule(static) collapse(2)
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
for (int k=0;k<n;k++) {
c[i][j]+=a[i][k]*b[k][j];
}
}
}
auto stop = boost::chrono::system_clock::now();
auto setup = boost::chrono::duration_cast<boost::chrono::milliseconds>(setup_end - setup_start);
auto comp = boost::chrono::duration_cast<boost::chrono::milliseconds>(stop - start);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup.count() << "," << comp.count() << endl;
delete_matrix(a, n);
delete_matrix(b, n);
delete_matrix(c, n);
return 0;
}

+ 76
- 0
ARM/multiplication/single_mul.cpp View File

@ -0,0 +1,76 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
using namespace std;
int mulV(int p, double **a, double **b, double **c, int n, int offset) {
for (int j = 0; j < n; j++) {
c[offset][j] = 0;
for (int k = 0; k < n; k++) {
c[offset][j] += a[offset][k] * b[k][j];
}
}
return getpid()%getppid();
}
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void print_c(double **c,int n) {
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
cout <<c[i][j] <<"\t";
}
cout << endl;
}
}
void delete_matrix(double **matrix, int n) {
for (int i = 0; i < n; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
int main(int argc, char ** argv) {
int n;
n=atoi(argv[1]);
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=
boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
//print_c(c,n);
t3 = boost::chrono::system_clock::now();
for(int i = 0; i < n; i++)
mulV(i, a, b, c, n, i);
t4 = boost::chrono::system_clock::now();
boost::chrono::milliseconds res2 =
boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout <<" n,setup(us),exec*(us)" << n<<","<<res.count() <<","<<res2.count()<<endl;
delete_matrix(a,n);
delete_matrix(b,n);
delete_matrix(c,n);
return 0;
}

+ 98
- 0
ARM/multiplication/threads_100_mul.cpp View File

@ -0,0 +1,98 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <vector>
const int NUM_OF_THREADS = 100;
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void print_c(double **c,int n) {
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
std::cout <<c[i][j] <<"\t";
}
std::cout << std::endl;
}
}
void delete_matrix(double **matrix, int n) {
for (int i = 0; i < n; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
double **multiply(double **a,double **b,double **c, int n, int start,int end) {
for (int i=start;i<end;i++) {
for (int j=0;j<n;j++) {
double sum = 0.0;
for (int k=0;k<n;k++) {
sum += a[i][k]*b[k][j];
}
c[i][j] = sum;
}
}
return c;
}
int main(int agrc, char ** argv) {
int n;
n=atoi(argv[1]);
boost::thread_group tg;
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
t3 = boost::chrono::system_clock::now();
int rows_per_thread = n / NUM_OF_THREADS;
int remaining_rows = n % NUM_OF_THREADS;
int current_row = 0;
int threads_left = std::min(NUM_OF_THREADS, n);
for(int i = 0; i < threads_left && current_row < n; i++){
int rows_to_process = rows_per_thread + (i< remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
try {
tg.create_thread(boost::bind(multiply,a,b,c,n,current_row,end_row));
} catch (const exception &e) {
cerr << "create_thread failed, thread:" << i << "," << e.what() << endl;
}
current_row = end_row;
}
tg.join_all();
t4 = boost::chrono::system_clock::now();
boost::chrono::milliseconds res3 =boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
std::cout <<" n,setup(ms),exec(ms)" << n<<","<<res.count() <<","<<res3.count()<< std::endl;
delete_matrix(a,n);
delete_matrix(b,n);
delete_matrix(c,n);
return 0;
}

+ 111
- 0
ARM/multiplication/threads_n_mul.cpp View File

@ -0,0 +1,111 @@
#include <iostream>
#include <cstdlib>
#include <random>
#include <boost/thread.hpp>
#include <boost/bind/bind.hpp>
#include <boost/chrono.hpp>
using namespace std;
using namespace boost::placeholders;
// Allocates a matrix with double**
double** create_matrix(int n) {
//double* data = new double[n * n];
double** matrix = new double*[n];
for (int i = 0; i < n; ++i)
matrix[i]=new double[n];
// matrix[i] = &data[i * n];
return matrix;
}
// Frees matrix memory
void cleanup_matrix(double** matrix) {
if (matrix) {
//delete[] matrix[0];
delete[] matrix;
}
}
// Initializes matrix with random values or zeros
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
matrix[i][j] = zero ? 0.0 : dis(gen);
}
// Matrix multiplication: C = A × B for rows [start_row, end_row)
void mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i)
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k)
sum += a[i][k] * b[k][j];
c[i][j] = sum;
}
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
const int MAX_THREADS = n;
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
double** a = create_matrix(n);
double** b = create_matrix(n);
double** c = create_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true);
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Use boost::thread_group with boost::bind
boost::thread_group group;
int rows_per_thread = n / MAX_THREADS;
int remaining_rows = n % MAX_THREADS;
int current_row = 0;
for (int i = 0; i < MAX_THREADS && current_row < n; ++i) {
int rows_to_process = rows_per_thread + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
group.create_thread(
boost::bind(mulV, current_row, end_row, a, b, c, n)
);
current_row = end_row;
}
group.join_all();
t4 = boost::chrono::system_clock::now();
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
cleanup_matrix(a);
cleanup_matrix(b);
cleanup_matrix(c);
return 0;
}

+ 57
- 0
CPU/addition/Makefile View File

@ -0,0 +1,57 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g -fopenmp
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
-lcudart
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 174
- 0
CPU/addition/mmap_100_add.cpp View File

@ -0,0 +1,174 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
#define DEBUG 0
using namespace std;
const int MAX_PROCESSES = 100;
struct SharedMatrix {
vector<double*> chunks;
double** row_pointers;
int size;
};
void create_shared_matrix(SharedMatrix** matrix, int n) {
const size_t CHUNK_SIZE = 1024 * 1024; // 1MB chunks
size_t total_size = n * n * sizeof(double);
size_t num_chunks = (total_size + CHUNK_SIZE - 1) / CHUNK_SIZE;
*matrix = new SharedMatrix;
(*matrix)->size = n;
(*matrix)->chunks.reserve(num_chunks);
// Allocate memory chunks
for (size_t i = 0; i < num_chunks; ++i) {
size_t chunk_size = min(CHUNK_SIZE, total_size - i * CHUNK_SIZE);
void* ptr = mmap(NULL, chunk_size,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
if (ptr == MAP_FAILED) {
perror("mmap failed");
// Clean up already allocated chunks
for (auto chunk : (*matrix)->chunks) {
munmap(chunk, CHUNK_SIZE);
}
delete *matrix;
exit(1);
}
(*matrix)->chunks.push_back(static_cast<double*>(ptr));
}
// Create row pointers
(*matrix)->row_pointers = new double*[n];
size_t current_chunk = 0;
size_t offset_in_chunk = 0;
for (int i = 0; i < n; ++i) {
(*matrix)->row_pointers[i] = reinterpret_cast<double*>(
reinterpret_cast<char*>((*matrix)->chunks[current_chunk]) + offset_in_chunk);
offset_in_chunk += n * sizeof(double);
// Move to next chunk if needed
while (offset_in_chunk >= CHUNK_SIZE) {
offset_in_chunk -= CHUNK_SIZE;
current_chunk++;
// Handle case where row spans chunks
if (i < n - 1) {
(*matrix)->row_pointers[i] = reinterpret_cast<double*>(
reinterpret_cast<char*>((*matrix)->row_pointers[i]) - CHUNK_SIZE + offset_in_chunk);
}
}
}
}
void cleanup_matrix(SharedMatrix** matrix) {
for (auto chunk : (*matrix)->chunks) {
munmap(chunk, (*matrix)->chunks.size() > 1 ? 1024 * 1024 :
(*matrix)->size * (*matrix)->size * sizeof(double));
}
delete[] (*matrix)->row_pointers;
delete *matrix;
*matrix = nullptr;
}
void init_matrix(SharedMatrix** matrix, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < (*matrix)->size; ++i) {
for (int j = 0; j < (*matrix)->size; ++j) {
(*matrix)->row_pointers[i][j] = zero ? 0.0 : dis(gen);
}
}
}
int addV(int start_row, int end_row, SharedMatrix** a, SharedMatrix** b, SharedMatrix** c) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < (*a)->size; ++j) {
(*c)->row_pointers[i][j] = (*a)->row_pointers[i][j] + (*b)->row_pointers[i][j];
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
SharedMatrix *a = nullptr, *b = nullptr, *c = nullptr;
create_shared_matrix(&a, n);
create_shared_matrix(&b, n);
create_shared_matrix(&c, n);
init_matrix(&a);
init_matrix(&b);
init_matrix(&c, true);
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Calculate work distribution
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process
addV(current_row, end_row, &a, &b, &c);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all children
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
cleanup_matrix(&a);
cleanup_matrix(&b);
cleanup_matrix(&c);
return 0;
}

+ 174
- 0
CPU/addition/mmap_24_add.cpp View File

@ -0,0 +1,174 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
#define DEBUG 0
using namespace std;
const int MAX_PROCESSES = 24;
struct SharedMatrix {
vector<double*> chunks;
double** row_pointers;
int size;
};
void create_shared_matrix(SharedMatrix** matrix, int n) {
const size_t CHUNK_SIZE = 1024 * 1024; // 1MB chunks
size_t total_size = n * n * sizeof(double);
size_t num_chunks = (total_size + CHUNK_SIZE - 1) / CHUNK_SIZE;
*matrix = new SharedMatrix;
(*matrix)->size = n;
(*matrix)->chunks.reserve(num_chunks);
// Allocate memory chunks
for (size_t i = 0; i < num_chunks; ++i) {
size_t chunk_size = min(CHUNK_SIZE, total_size - i * CHUNK_SIZE);
void* ptr = mmap(NULL, chunk_size,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
if (ptr == MAP_FAILED) {
perror("mmap failed");
// Clean up already allocated chunks
for (auto chunk : (*matrix)->chunks) {
munmap(chunk, CHUNK_SIZE);
}
delete *matrix;
exit(1);
}
(*matrix)->chunks.push_back(static_cast<double*>(ptr));
}
// Create row pointers
(*matrix)->row_pointers = new double*[n];
size_t current_chunk = 0;
size_t offset_in_chunk = 0;
for (int i = 0; i < n; ++i) {
(*matrix)->row_pointers[i] = reinterpret_cast<double*>(
reinterpret_cast<char*>((*matrix)->chunks[current_chunk]) + offset_in_chunk);
offset_in_chunk += n * sizeof(double);
// Move to next chunk if needed
while (offset_in_chunk >= CHUNK_SIZE) {
offset_in_chunk -= CHUNK_SIZE;
current_chunk++;
// Handle case where row spans chunks
if (i < n - 1) {
(*matrix)->row_pointers[i] = reinterpret_cast<double*>(
reinterpret_cast<char*>((*matrix)->row_pointers[i]) - CHUNK_SIZE + offset_in_chunk);
}
}
}
}
void cleanup_matrix(SharedMatrix** matrix) {
for (auto chunk : (*matrix)->chunks) {
munmap(chunk, (*matrix)->chunks.size() > 1 ? 1024 * 1024 :
(*matrix)->size * (*matrix)->size * sizeof(double));
}
delete[] (*matrix)->row_pointers;
delete *matrix;
*matrix = nullptr;
}
void init_matrix(SharedMatrix** matrix, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < (*matrix)->size; ++i) {
for (int j = 0; j < (*matrix)->size; ++j) {
(*matrix)->row_pointers[i][j] = zero ? 0.0 : dis(gen);
}
}
}
int addV(int start_row, int end_row, SharedMatrix** a, SharedMatrix** b, SharedMatrix** c) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < (*a)->size; ++j) {
(*c)->row_pointers[i][j] = (*a)->row_pointers[i][j] + (*b)->row_pointers[i][j];
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
SharedMatrix *a = nullptr, *b = nullptr, *c = nullptr;
create_shared_matrix(&a, n);
create_shared_matrix(&b, n);
create_shared_matrix(&c, n);
init_matrix(&a);
init_matrix(&b);
init_matrix(&c, true);
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Calculate work distribution
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process
addV(current_row, end_row, &a, &b, &c);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all children
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
cleanup_matrix(&a);
cleanup_matrix(&b);
cleanup_matrix(&c);
return 0;
}

+ 130
- 0
CPU/addition/mmap_add.cpp View File

@ -0,0 +1,130 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
#define DEBUG 0
using namespace std;
// Create a mmap-allocated matrix with pointers
double** create_shared_matrix(int n) {
int data_size = n * n * sizeof(double);
void* hint = (void*)0x10000000; // Example hint address
double* data = (double*)mmap(hint, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (data == MAP_FAILED) {
perror("mmap");
exit(1);
}
// Create an index matrix locally (does not need to be shared)
double** mat = new double*[n];
for (int i = 0; i < n; ++i)
mat[i] = &data[i * n];
return mat;
}
// Detach mmap and delete indexes
void cleanup_matrix(double** mat, int n) {
munmap(mat[0], n * n * sizeof(double));
delete[] mat;
}
void init_matrix(double** mat, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
if (zero)
mat[i][j] = 0 ;
else
mat[i][j]=dis(gen);
}
//Add vector column
int addV(int p, double **a, double**b, double **c, int n, int offset) {
for (int j=0;j<n;j++)
c[offset-1][j]=a[offset-1][j]+b[offset-1][j];
return getpid()%getppid();
}
void print_matrix(double** mat, int n) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j)
cout << mat[i][j] << "\t";
cout << endl;
}
}
int main(int argc, char**argv) {
int mom_pid=getpid();
int status; int pid;
int n, num_processes;
n=atoi(argv[1]);
num_processes=n;
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=
boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
t3=boost::chrono::system_clock::now();
/*scheduler*/
int count=0;
while (true) {
pid = fork();
if (pid < 0) {
cout << "Fork failed!" << endl;
break;
} else {
count++;
if (pid == 0 && mom_pid==getppid() ) {
if (DEBUG)
cout <<"["<<count<<"]"<< " PID:" << getpid() << " Mom:" << getppid() << endl;
break;
} else if (mom_pid!=getpid()) {
return -1;
}
}
if (count>=num_processes)
break;
}
/*Task assign*/
if (pid==0) {
addV(count,a,b,c,n,count);
return getpid()%getppid();
} else {
// Parent waits for every child process to be finished
for (int i = 0; i < num_processes; ++i) {
wait(&status);
if (WIFEXITED(status))
if(DEBUG)
std::cout << "Child Process in:" << "<= Parent:"<< (int) getpid() << " exited with status" << WEXITSTATUS(status) << std::endl;
usleep(10);
}
t4=boost::chrono::system_clock::now();
boost::chrono::milliseconds res2 = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4-t3);
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
cout <<" n,setup(us),exec(us)" << n<<","<<res.count() <<","<<res2.count()<<endl;
}
return 0;
}

+ 75
- 0
CPU/addition/single_add.cpp View File

@ -0,0 +1,75 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
using namespace std;
int addV(int p, double **a, double**b, double **c, int n, int offset) {
for (int j=0;j<n;j++)
c[offset][j]=a[offset][j]+b[offset][j];
return getpid()%getppid();
}
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void print_c(double **c,int n) {
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
cout <<c[i][j] <<"\t";
}
cout << endl;
}
}
void delete_matrix(double **matrix, int n) {
for (int i = 0; i < n; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
int main(int argc, char ** argv) {
int n;
n=atoi(argv[1]);
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=
boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
t3=boost::chrono::system_clock::now();
for (int i=0;i<n;i++)
addV(i,a,b,c,n,i);
t4=boost::chrono::system_clock::now();
boost::chrono::milliseconds res2=
boost::chrono::duration_cast<boost::chrono::milliseconds>(t4-t3);
//print_c(c,n);
cout <<" n,setup(us),exec(us)" << n<<","<<res.count() <<","<<res2.count()<<endl;
delete_matrix(a,n);
delete_matrix(b,n);
delete_matrix(c,n);
return 0;
}

+ 102
- 0
CPU/addition/threads_add.cpp View File

@ -0,0 +1,102 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
using namespace std;
const int NUM_OF_THREADS = 100;
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void print_c(double **c,int n) {
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
std::cout <<c[i][j] <<"\t";
}
std::cout << std::endl;
}
}
void delete_matrix(double **matrix, int n) {
for (int i = 0; i < n; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
double **add(double **a,double **b,double **c, int n, int start,int end) {
for (int i=start;i<end;i++) {
for (int j=0;j<n;j++) {
//mtx.lock();
c[i][j] = a[i][j] + b[i][j];
//mtx.unlock();
}
}
return c;
}
int main(int argc, char ** argv) {
if (argc != 2) {
cerr << "Usage:" << argv[0] << "<matrix.size>" << endl;
}
int n=std::atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::thread_group tg;
//std::vector<boost::thread> threads;
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
t3 = boost::chrono::system_clock::now();
int rows_per_thread = n / NUM_OF_THREADS;
int remaining_rows = n % NUM_OF_THREADS;
int current_row = 0;
for(int i = 0; i < NUM_OF_THREADS && current_row < n; i++){
int rows_to_process = rows_per_thread + (i< remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
try {
tg.create_thread(boost::bind(add,a,b,c,n,current_row,end_row));
} catch (const exception &e) {
cerr << "create_thread failed, thread:" << i << "," << e.what() << endl;
}
current_row = end_row;
}
tg.join_all();
t4 = boost::chrono::system_clock::now();
boost::chrono::milliseconds res3 =boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
std::cout <<" n,setup(us),exec*(us)" << n<<","<<res.count() <<","<<res3.count()<< std::endl;
delete_matrix(a,n);
delete_matrix(b,n);
delete_matrix(c,n);
return 0;
}

+ 57
- 0
CPU/multiplication/Collective Forking mmap/Makefile View File

@ -0,0 +1,57 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g -fopenmp
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
-lcudart
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 148
- 0
CPU/multiplication/Collective Forking mmap/mmap_c_100_mul.cpp View File

@ -0,0 +1,148 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
const int MAX_PROCESSES = 100;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for rows [start_row, end_row)
int mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
//double **a = nullptr, **b = nullptr, **c = nullptr;
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Distribute work among 100 processes
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned rows
mulV(current_row, end_row, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 148
- 0
CPU/multiplication/Collective Forking mmap/mmap_c_24_mul.cpp View File

@ -0,0 +1,148 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
const int MAX_PROCESSES = 24;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for rows [start_row, end_row)
int mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
//double **a = nullptr, **b = nullptr, **c = nullptr;
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Distribute work among 100 processes
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned rows
mulV(current_row, end_row, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 136
- 0
CPU/multiplication/Collective Forking mmap/mmap_c_n_mul.cpp View File

@ -0,0 +1,136 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for a single row
int mulV_single_row(int row, double** a, double** b, double** c, int n) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[row][k] * b[k][j];
}
c[row][j] = sum;
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
vector<pid_t> children;
// Create one process per row
for (int i = 0; i < n; ++i) {
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned row
mulV_single_row(i, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 57
- 0
CPU/multiplication/Makefile View File

@ -0,0 +1,57 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g -fopenmp
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
-lcudart
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 57
- 0
CPU/multiplication/Prolific Forking mmap/Makefile View File

@ -0,0 +1,57 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g -fopenmp
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
-lcudart
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 187
- 0
CPU/multiplication/Prolific Forking mmap/mmap_pr_100_mul.cpp View File

@ -0,0 +1,187 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
const int MAX_PROCESSES = 100;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for rows [start_row, end_row)
int mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
//double **a = nullptr, **b = nullptr, **c = nullptr;
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Distribute work among 100 processes
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
int mom_pid=getpid();
/*scheduler*/
int count =0;
int status;
int pid;
int end_row;
int rows_to_process;
while(true) {
rows_to_process = rows_per_process + (count < remaining_rows ? 1 : 0);
end_row = current_row + rows_to_process;
pid=fork();
if (pid<0) {
cout << "Error forking!" << endl;
exit(1);
} else {
count++;
if (pid==0 && mom_pid==getppid()) {
//cout << count << ":" << current_row << "-" << end_row << endl;
break;
} else if (mom_pid!=getpid()) {
return -1;
}
//main parent
current_row = end_row;
}
if (count >=MAX_PROCESSES)
break;
}
/*Task assign*/
if (pid==0) {
//DO
mulV(current_row, end_row, a, b, c, n);
return getpid()%getppid();
} else {
for (int i=0;i<MAX_PROCESSES;++i) {
wait(&status);
//usleep(1);
}
}
/* vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned rows
mulV(current_row, end_row, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}*/
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 187
- 0
CPU/multiplication/Prolific Forking mmap/mmap_pr_24_mul.cpp View File

@ -0,0 +1,187 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
const int MAX_PROCESSES = 24;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for rows [start_row, end_row)
int mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i][k] * b[k][j];
}
c[i][j] = sum;
}
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
//double **a = nullptr, **b = nullptr, **c = nullptr;
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Distribute work among 100 processes
int rows_per_process = n / MAX_PROCESSES;
int remaining_rows = n % MAX_PROCESSES;
int current_row = 0;
int mom_pid=getpid();
/*scheduler*/
int count =0;
int status;
int pid;
int end_row;
int rows_to_process;
while(true) {
rows_to_process = rows_per_process + (count < remaining_rows ? 1 : 0);
end_row = current_row + rows_to_process;
pid=fork();
if (pid<0) {
cout << "Error forking!" << endl;
exit(1);
} else {
count++;
if (pid==0 && mom_pid==getppid()) {
//cout << count << ":" << current_row << "-" << end_row << endl;
break;
} else if (mom_pid!=getpid()) {
return -1;
}
//main parent
current_row = end_row;
}
if (count >=MAX_PROCESSES)
break;
}
/*Task assign*/
if (pid==0) {
//DO
mulV(current_row, end_row, a, b, c, n);
return getpid()%getppid();
} else {
for (int i=0;i<MAX_PROCESSES;++i) {
wait(&status);
//usleep(1);
}
}
/* vector<pid_t> children;
for (int i = 0; i < MAX_PROCESSES && current_row < n; ++i) {
int rows_to_process = rows_per_process + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned rows
mulV(current_row, end_row, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
current_row = end_row;
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}*/
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 170
- 0
CPU/multiplication/Prolific Forking mmap/mmap_pr_n_mul.cpp View File

@ -0,0 +1,170 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/chrono.hpp>
using namespace std;
// Allocates a shared matrix with double** row pointers
double** create_shared_matrix(int n) {
size_t data_size = n * n * sizeof(double);
double* data = static_cast<double*>(
mmap(NULL, data_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (data == MAP_FAILED) {
perror("mmap failed for matrix data");
exit(1);
}
size_t row_ptrs_size = n * sizeof(double*);
double** row_ptrs = static_cast<double**>(
mmap(NULL, row_ptrs_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
if (row_ptrs == MAP_FAILED) {
perror("mmap failed for row pointers");
munmap(data, data_size);
exit(1);
}
for (int i = 0; i < n; ++i) {
row_ptrs[i] = &data[i * n];
}
return row_ptrs;
}
// Frees the shared matrix
void cleanup_matrix(double** matrix, int n) {
if (matrix == nullptr) return;
double* data = matrix[0];
munmap(matrix, n * sizeof(double*));
munmap(data, n * n * sizeof(double));
}
// Initializes matrix with random values (or zeros)
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Computes C = A × B for a single row
int mulV_single_row(int row, double** a, double** b, double** c, int n) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[row][k] * b[k][j];
}
c[row][j] = sum;
}
return 0;
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
// Allocate matrices in shared memory
double** a = create_shared_matrix(n);
double** b = create_shared_matrix(n);
double** c = create_shared_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true); // Initialize c with zeros
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
int num_processes=n;
int mom_pid=getpid();
/*scheduler*/
int count =0;
int status;
int pid;
while(true) {
pid=fork();
if (pid<0) {
cout << "Error forking!" << endl;
exit(1);
} else {
count++;
if (pid==0 && mom_pid==getppid()) {
break;
} else if (mom_pid!=getpid()) {
return -1;
}
}
if (count >=num_processes)
break;
}
/*Task assign*/
if (pid==0) {
//DO
mulV_single_row(count, a, b, c, n);
return getpid()%getppid();
} else {
for (int i=0;i<num_processes;++i) {
wait(&status);
//usleep(1);
}
}
/* vector<pid_t> children;
// Create one process per row
for (int i = 0; i < n; ++i) {
pid_t pid = fork();
if (pid < 0) {
cerr << "Fork failed!" << endl;
break;
} else if (pid == 0) {
// Child process computes its assigned row
mulV_single_row(i, a, b, c, n);
exit(0);
} else {
children.push_back(pid);
}
}
// Wait for all child processes to finish
for (pid_t pid : children) {
waitpid(pid, nullptr, 0);
}*/
t4 = boost::chrono::system_clock::now();
// Print timing results
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
// Cleanup
cleanup_matrix(a, n);
cleanup_matrix(b, n);
cleanup_matrix(c, n);
return 0;
}

+ 75
- 0
CPU/multiplication/mul_openMP.cpp View File

@ -0,0 +1,75 @@
#include <iostream>
#include <boost/chrono.hpp>
#include <random>
#include <omp.h>
#include <cstdlib>
using namespace std;
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void delete_matrix(double **a, int n) {
for (int i = 0; i < n; i++) {
delete[] a[i];
}
delete[] a;
}
int main(int argc, char ** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n=atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
auto setup_start = boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
auto setup_end = boost::chrono::system_clock::now();
auto start = boost::chrono::system_clock::now();
#pragma omp parallel for schedule(static) collapse(2)
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
for (int k=0;k<n;k++) {
c[i][j]+=a[i][k]*b[k][j];
}
}
}
auto stop = boost::chrono::system_clock::now();
auto setup = boost::chrono::duration_cast<boost::chrono::milliseconds>(setup_end - setup_start);
auto comp = boost::chrono::duration_cast<boost::chrono::milliseconds>(stop - start);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup.count() << "," << comp.count() << endl;
delete_matrix(a, n);
delete_matrix(b, n);
delete_matrix(c, n);
return 0;
}

+ 76
- 0
CPU/multiplication/single_mul.cpp View File

@ -0,0 +1,76 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
using namespace std;
int mulV(int p, double **a, double **b, double **c, int n, int offset) {
for (int j = 0; j < n; j++) {
c[offset][j] = 0;
for (int k = 0; k < n; k++) {
c[offset][j] += a[offset][k] * b[k][j];
}
}
return getpid()%getppid();
}
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void print_c(double **c,int n) {
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
cout <<c[i][j] <<"\t";
}
cout << endl;
}
}
void delete_matrix(double **matrix, int n) {
for (int i = 0; i < n; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
int main(int argc, char ** argv) {
int n;
n=atoi(argv[1]);
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=
boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
//print_c(c,n);
t3 = boost::chrono::system_clock::now();
for(int i = 0; i < n; i++)
mulV(i, a, b, c, n, i);
t4 = boost::chrono::system_clock::now();
boost::chrono::milliseconds res2 =
boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout <<" n,setup(us),exec*(us)" << n<<","<<res.count() <<","<<res2.count()<<endl;
delete_matrix(a,n);
delete_matrix(b,n);
delete_matrix(c,n);
return 0;
}

+ 98
- 0
CPU/multiplication/threads_100_mul.cpp View File

@ -0,0 +1,98 @@
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <cstdlib>
#include <random>
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
#include <vector>
const int NUM_OF_THREADS = 100;
double **init_a(double **a, int n, bool zero=false) {
a=new double*[n];
for (int i=0;i<n;i++)
a[i]=new double[n];
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(0.0,1.0);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
if (zero)
a[i][j]=0;
else
a[i][j]=dis(gen);
}
}
return a;
}
void print_c(double **c,int n) {
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
std::cout <<c[i][j] <<"\t";
}
std::cout << std::endl;
}
}
void delete_matrix(double **matrix, int n) {
for (int i = 0; i < n; i++) {
delete[] matrix[i];
}
delete[] matrix;
}
double **multiply(double **a,double **b,double **c, int n, int start,int end) {
for (int i=start;i<end;i++) {
for (int j=0;j<n;j++) {
double sum = 0.0;
for (int k=0;k<n;k++) {
sum += a[i][k]*b[k][j];
}
c[i][j] = sum;
}
}
return c;
}
int main(int agrc, char ** argv) {
int n;
n=atoi(argv[1]);
boost::thread_group tg;
boost::chrono::system_clock::time_point t1,t2,t3,t4;
t1=boost::chrono::system_clock::now();
double **a=init_a(a,n);
double **b=init_a(b,n);
double **c=init_a(c,n,true);
t2=boost::chrono::system_clock::now();
boost::chrono::milliseconds res=boost::chrono::duration_cast<boost::chrono::milliseconds>(t2-t1);
t3 = boost::chrono::system_clock::now();
int rows_per_thread = n / NUM_OF_THREADS;
int remaining_rows = n % NUM_OF_THREADS;
int current_row = 0;
int threads_left = std::min(NUM_OF_THREADS, n);
for(int i = 0; i < threads_left && current_row < n; i++){
int rows_to_process = rows_per_thread + (i< remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
try {
tg.create_thread(boost::bind(multiply,a,b,c,n,current_row,end_row));
} catch (const exception &e) {
cerr << "create_thread failed, thread:" << i << "," << e.what() << endl;
}
current_row = end_row;
}
tg.join_all();
t4 = boost::chrono::system_clock::now();
boost::chrono::milliseconds res3 =boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
std::cout <<" n,setup(ms),exec(ms)" << n<<","<<res.count() <<","<<res3.count()<< std::endl;
delete_matrix(a,n);
delete_matrix(b,n);
delete_matrix(c,n);
return 0;
}

+ 111
- 0
CPU/multiplication/threads_n_mul.cpp View File

@ -0,0 +1,111 @@
#include <iostream>
#include <cstdlib>
#include <random>
#include <boost/thread.hpp>
#include <boost/bind/bind.hpp>
#include <boost/chrono.hpp>
using namespace std;
using namespace boost::placeholders;
// Allocates a matrix with double**
double** create_matrix(int n) {
//double* data = new double[n * n];
double** matrix = new double*[n];
for (int i = 0; i < n; ++i)
matrix[i]=new double[n];
// matrix[i] = &data[i * n];
return matrix;
}
// Frees matrix memory
void cleanup_matrix(double** matrix) {
if (matrix) {
//delete[] matrix[0];
delete[] matrix;
}
}
// Initializes matrix with random values or zeros
void init_matrix(double** matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
matrix[i][j] = zero ? 0.0 : dis(gen);
}
// Matrix multiplication: C = A × B for rows [start_row, end_row)
void mulV(int start_row, int end_row, double** a, double** b, double** c, int n) {
for (int i = start_row; i < end_row; ++i)
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k)
sum += a[i][k] * b[k][j];
c[i][j] = sum;
}
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
const int MAX_THREADS = n;
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
double** a = create_matrix(n);
double** b = create_matrix(n);
double** c = create_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true);
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
// Use boost::thread_group with boost::bind
boost::thread_group group;
int rows_per_thread = n / MAX_THREADS;
int remaining_rows = n % MAX_THREADS;
int current_row = 0;
for (int i = 0; i < MAX_THREADS && current_row < n; ++i) {
int rows_to_process = rows_per_thread + (i < remaining_rows ? 1 : 0);
int end_row = current_row + rows_to_process;
group.create_thread(
boost::bind(mulV, current_row, end_row, a, b, c, n)
);
current_row = end_row;
}
group.join_all();
t4 = boost::chrono::system_clock::now();
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
cleanup_matrix(a);
cleanup_matrix(b);
cleanup_matrix(c);
return 0;
}

+ 57
- 0
GPU/Makefile View File

@ -0,0 +1,57 @@
# Compiler and flags
NVCC := nvcc
CXX := g++
NVCCFLAGS := -std=c++11 -O3 --expt-relaxed-constexpr
CXXFLAGS := -std=c++1z -g
INCLUDES := -I/usr/local/include/eigen3 \
-I/usr/local/include/third_party \
-I/usr/local/include/tensorflow \
-I/usr/local/cuda/include
LDFLAGS := -L/usr/local/lib \
-L/usr/local/cuda/lib64
LIBS := -ltensorflow_cc \
-ltensorflow_framework \
-lpthread \
-ldl \
-lrt \
-lboost_system \
-lboost_chrono \
-lboost_thread \
-lcudart
# Source files
CUDA_SRCS := $(wildcard *.cu)
SRC:=$(wildcard *.cpp)
# Object files
CUDA_OBJS := $(CUDA_SRCS:.cu=.o)
CPP_OBJS := $(SRC:.cpp=.o)
#EXECUTABLES:=$(SRC:.cpp=)
# Executables
CUDA_EXECS := $(CUDA_SRCS:.cu=)
EXECUTABLES := $(SRC:.cpp=)
all: $(CUDA_EXECS) $(EXECUTABLES)
# Rule for CUDA files
%.o: %.cu
$(NVCC) $(NVCCFLAGS) $(INCLUDES) -c $< -o $@
%: %.o
$(NVCC) $(NVCCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
# Rule for C++ files
#%.o: %.cpp
# $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
#%: %.o
# $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
%:%.cpp
$(CXX) $(CXXFLAGS) $(INCLUDES) $< -o $@ $(LDFLAGS) $(LIBS)
clean:
rm -f $(EXECUTABLES) $(CUDA_OBJS) $(CPP_OBJS) $(CUDA_EXECS)
.PHONY: all clean

+ 151
- 0
GPU/multi_gpu_matrix_add_mmap.cu View File

@ -0,0 +1,151 @@
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstring>
#include <cuda_runtime.h>
#include <boost/chrono.hpp>
void CHECK_CUDA(cudaError_t call) {
cudaError_t err = call;
if (err != cudaSuccess) {
std::cerr << "CUDA error at " << __FILE__ << ":" << __LINE__ << ": " << cudaGetErrorString(err) << std::endl;
exit(EXIT_FAILURE);
}
}
float* flatten(float** matrix, int N) {
float* flat = new float[N*N];
for (int i = 0; i < N; ++i)
memcpy(flat + i*N, matrix[i], N*sizeof(float));
return flat;
}
float** initMatrix(int N) {
float** matrix = new float*[N];
for (int i = 0; i < N; ++i) {
matrix[i] = new float[N];
for (int j = 0; j < N; ++j)
matrix[i][j] = static_cast<float>(rand()) / RAND_MAX;
}
return matrix;
}
__global__ void matrixAddKernel(float* A, float* B, float* C, int N,int start_row, int end_row) {
int row = blockIdx.y * blockDim.y + threadIdx.y + start_row;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if (row < end_row && col < N) {
C[(row-start_row) * N + col] = A[(row-start_row) * N + col] + B[(row-start_row) * N + col];
}
}
void printMatrix(float* matrix, int rows, int cols) {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
std::cout << matrix[i * cols + j] << "\t";
}
std::cout << std::endl;
}
}
int main() {
int n, k;
std::cout << "Enter matrix size (N): ";
std::cin >> n;
std::cout << "Enter number of GPUs (K): ";
std::cin >> k;
boost::chrono::system_clock::time_point setup_start = boost::chrono::system_clock::now();
float** A_2d = initMatrix(n);
float** B_2d = initMatrix(n);
float* A = flatten(A_2d, n);
float* B = flatten(B_2d, n);
/* printMatrix(A,n,n);
std::cout << "------------------------------------------" << std::endl;
printMatrix(B,n,n);
std::cout << "------------------------------------------" << std::endl; */
float* shm_ptr = (float*)mmap(NULL, n * n * sizeof(float),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
if (shm_ptr == MAP_FAILED) {
perror("mmap failed");
exit(EXIT_FAILURE);
}
memset(shm_ptr, 0, n * n * sizeof(float));
boost::chrono::system_clock::time_point setup_end = boost::chrono::system_clock::now();
boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
for (int gpu_id = 0; gpu_id < k; ++gpu_id) {
pid_t pid = fork();
if (pid == 0) {
CHECK_CUDA(cudaSetDevice(gpu_id));
int rows_per_gpu = n / k;
int remainder = n % k;
int start_row = gpu_id * rows_per_gpu;
int end_row = start_row + rows_per_gpu + (gpu_id == k-1 ? remainder : 0);
int rows_this_gpu = end_row - start_row;
float *d_A, *d_B, *d_C;
CHECK_CUDA(cudaMalloc(&d_A,rows_this_gpu * n * sizeof(float)));
CHECK_CUDA(cudaMalloc(&d_B, n * n * sizeof(float)));
CHECK_CUDA(cudaMalloc(&d_C, rows_this_gpu * n * sizeof(float)));
CHECK_CUDA(cudaMemcpy(d_A, A + start_row * n , rows_this_gpu * n * sizeof(float), cudaMemcpyHostToDevice));
CHECK_CUDA(cudaMemcpy(d_B, B + start_row * n , rows_this_gpu * n * sizeof(float), cudaMemcpyHostToDevice));
dim3 block(16, 16);
dim3 grid((n + block.x - 1) / block.x, (rows_this_gpu + block.y - 1) / block.y);
matrixAddKernel<<<grid, block>>>(d_A, d_B, d_C, n, start_row, end_row);
CHECK_CUDA(cudaDeviceSynchronize());
float* partial_C = new float[rows_this_gpu * n];
CHECK_CUDA(cudaMemcpy(partial_C, d_C , rows_this_gpu * n * sizeof(float), cudaMemcpyDeviceToHost));
for (int i = 0; i < rows_this_gpu; ++i)
memcpy(shm_ptr + (start_row + i) * n, partial_C + i * n, n * sizeof(float));
CHECK_CUDA(cudaFree(d_A));
CHECK_CUDA(cudaFree(d_B));
CHECK_CUDA(cudaFree(d_C));
delete[] partial_C;
exit(EXIT_SUCCESS);
} else if (pid < 0) {
perror("fork failed");
exit(EXIT_FAILURE);
}
}
for (int gpu_id = 0; gpu_id < k; ++gpu_id)
wait(NULL);
boost::chrono::system_clock::time_point end = boost::chrono::system_clock::now();
//printMatrix(shm_ptr,n,n);
auto setup = boost::chrono::duration_cast<boost::chrono::milliseconds>(setup_end - setup_start).count();
auto duration = boost::chrono::duration_cast<boost::chrono::milliseconds>(end - start).count();
std::cout << "Setup Time: " << setup << " ms" << std::endl;
std::cout << "Comp Time: " << duration << " ms" << std::endl;
// Clean up
for (int i = 0; i < n; ++i) {
delete[] A_2d[i];
delete[] B_2d[i];
}
delete[] A_2d;
delete[] B_2d;
delete[] A;
delete[] B;
munmap(shm_ptr, n * n * sizeof(float));
return 0;
}

+ 159
- 0
GPU/multi_gpu_matrix_mul_mmap.cu View File

@ -0,0 +1,159 @@
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <cstring>
#include <cuda_runtime.h>
#include <boost/chrono.hpp>
void CHECK_CUDA(cudaError_t call) {
cudaError_t err = call;
if (err != cudaSuccess) {
std::cerr << "CUDA error at " << __FILE__ << ":" << __LINE__ << ": " << cudaGetErrorString(err) << std::endl;
exit(EXIT_FAILURE);
}
}
float* flatten(float** matrix, int N) {
float* flat = new float[N*N];
for (int i = 0; i < N; ++i)
memcpy(flat + i*N, matrix[i], N*sizeof(float));
return flat;
}
float** initMatrix(int N) {
float** matrix = new float*[N];
for (int i = 0; i < N; ++i) {
matrix[i] = new float[N];
for (int j = 0; j < N; ++j)
matrix[i][j] = static_cast<float>(rand()) / RAND_MAX;
}
return matrix;
}
__global__ void matrixMulKernel(float* A, float* B, float* C, int N, int start_row, int end_row) {
int row = blockIdx.y * blockDim.y + threadIdx.y + start_row;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if (row < end_row && col < N) {
float sum = 0.0f;
for (int k = 0; k < N; ++k)
sum += A[row*N + k] * B[k*N + col];
C[(row-start_row)*N + col] = sum;
}
}
void printMatrix(float* matrix, int rows, int cols) {
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
std::cout << matrix[i * cols + j] << "\t";
}
std::cout << std::endl;
}
}
int main() {
int n, k;
std::cout << "Enter matrix size (N): ";
std::cin >> n;
std::cout << "Enter number of GPUs (K): ";
std::cin >> k;
// Initialize matrices
float** A_2d = initMatrix(n);
float** B_2d = initMatrix(n);
float* A = flatten(A_2d, n);
float* B = flatten(B_2d, n);
// Allocate shared memory using anonymous mmap (no shm_open needed)
float* shm_ptr = (float*)mmap(
NULL, // Let OS choose address
n * n * sizeof(float), // Size of mapping
PROT_READ | PROT_WRITE, // Read/write permissions
MAP_SHARED | MAP_ANONYMOUS, // Shared & anonymous (no file backing)
-1, // File descriptor (ignored for MAP_ANONYMOUS)
0 // Offset (ignored)
);
if (shm_ptr == MAP_FAILED) {
perror("mmap failed");
exit(EXIT_FAILURE);
}
memset(shm_ptr, 0, n * n * sizeof(float)); // Initialize to 0
boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
// Fork children
for (int gpu_id = 0; gpu_id < k; ++gpu_id) {
pid_t pid = fork();
if (pid == 0) { // Child process
CHECK_CUDA(cudaSetDevice(gpu_id));
int rows_per_gpu = n / k;
int remainder = n % k;
int start_row = gpu_id * rows_per_gpu;
int end_row = start_row + rows_per_gpu + (gpu_id == k-1 ? remainder : 0);
int rows_this_gpu = end_row - start_row;
// Allocate device memory
float *d_A, *d_B, *d_C;
CHECK_CUDA(cudaMalloc(&d_A, rows_this_gpu * n * sizeof(float)));
CHECK_CUDA(cudaMalloc(&d_B, n * n * sizeof(float)));
CHECK_CUDA(cudaMalloc(&d_C, rows_this_gpu * n * sizeof(float)));
// Copy data to device
CHECK_CUDA(cudaMemcpy(d_A, A + start_row * n, rows_this_gpu * n * sizeof(float), cudaMemcpyHostToDevice));
CHECK_CUDA(cudaMemcpy(d_B, B, n * n * sizeof(float), cudaMemcpyHostToDevice));
// Launch kernel
dim3 block(16, 16);
dim3 grid((n + block.x - 1) / block.x, (rows_this_gpu + block.y - 1) / block.y);
matrixMulKernel<<<grid, block>>>(d_A, d_B, d_C, n, start_row, end_row);
CHECK_CUDA(cudaDeviceSynchronize());
// Copy results to shared memory
float* partial_C = new float[rows_this_gpu * n];
CHECK_CUDA(cudaMemcpy(partial_C, d_C, rows_this_gpu * n * sizeof(float), cudaMemcpyDeviceToHost));
for (int i = 0; i < rows_this_gpu; ++i)
memcpy(shm_ptr + (start_row + i) * n, partial_C + i * n, n * sizeof(float));
// Cleanup
CHECK_CUDA(cudaFree(d_A));
CHECK_CUDA(cudaFree(d_B));
CHECK_CUDA(cudaFree(d_C));
delete[] partial_C;
exit(EXIT_SUCCESS);
}
else if (pid < 0) {
perror("fork failed");
exit(EXIT_FAILURE);
}
}
// Parent waits for children
for (int gpu_id = 0; gpu_id < k; ++gpu_id)
wait(NULL);
boost::chrono::system_clock::time_point end = boost::chrono::system_clock::now();
//printMatrix(shm_ptr, n, n);
auto duration = boost::chrono::duration_cast<boost::chrono::milliseconds>(end - start).count();
std::cout << "Time: " << duration << " ms" << std::endl;
// Cleanup
for (int i = 0; i < n; ++i) {
delete[] A_2d[i];
delete[] B_2d[i];
}
delete[] A_2d;
delete[] B_2d;
delete[] A;
delete[] B;
munmap(shm_ptr, n * n * sizeof(float)); // Release mmap memory
return 0;
}

+ 187
- 0
README.md View File

@ -0,0 +1,187 @@
# 💻 Matrix Computations on Diverse Platforms: A Multiprocessing Evaluation Across CPU, GPU and ARM Architectures
This project contains multiple matrix addition and multiplication implementations using different computing machines and methods. \
The following is a layout showing how the files are distributed.
## Implementations - File Map
### 📁CPU
---
<table>
<tr>
<td style="vertical-align: top; padding-right: 40px;">
#### 📁addition
| Method | File |
|---------------------|-----------------------|
| Single Core | `single_add.cpp` |
| mmap + n forks | `mmap_add.cpp` |
| mmap + 24 forks | `mmap_24_add.cpp` |
| mmap + 100 forks | `mmap_100_add.cpp` |
| 100 Threads | `threads_add.cpp` |
</td>
<td style="padding-left: 40px;">
#### 📁multiplication
| Method | File/Folder | | | |
|-----------------------------------|------------------------------|--------------------|-------------------------|--|
| Single Core | `single_mul.cpp` | | ||
| |📁Prolific Forking |Number of Processes | File ||
| | |n processes | `mmap_pr_n_mul.cpp` ||
| | |24 processes | `mmap_pr_24_mul.cpp` ||
| | |100 processes | `mmap_pr_100_mul.cpp` ||
| |📁Collective Forking | | ||
| | |n processes | `mmap_c_n_mul.cpp` ||
| | |24 processes | `mmap_c_24_mul.cpp` ||
| | |100 processes | `mmap_c_100_mul.cpp` ||
| 100 Threads | `threads_100_mul.cpp` | | ||
| n Threads | `threads_n_mul.cpp` | | ||
| OpenMP | `mul_openMP.cpp` | | ||
</td>
</tr>
</table>
### 📁ARM
---
<table>
<tr>
<td style="vertical-align: top; padding-right: 40px;">
#### 📁addition
| Method | File |
|---------------------|-----------------------|
| Single Core | `single_add.cpp` |
| mmap + n forks | `mmap_add.cpp` |
| mmap + 24 forks | `mmap_24_add.cpp` |
| mmap + 100 forks | `mmap_100_add.cpp` |
| 100 Threads | `threads_add.cpp` |
</td>
<td style="padding-left: 40px;">
#### 📁multiplication
| Method | File/Folder | | | |
|-----------------------------------|------------------------------|--------------------|-------------------------|--|
| Single Core | `single_mul.cpp` | | ||
| |📁Prolific Forking |Number of Processes | File ||
| | |n processes | `mmap_pr_n_mul.cpp` ||
| | |24 processes | `mmap_pr_24_mul.cpp` ||
| | |100 processes | `mmap_pr_100_mul.cpp` ||
| |📁Collective Forking | | ||
| | |n processes | `mmap_c_n_mul.cpp` ||
| | |24 processes | `mmap_c_24_mul.cpp` ||
| | |100 processes | `mmap_c_100_mul.cpp` ||
| 100 Threads | `threads_100_mul.cpp` | | ||
| n Threads | `threads_n_mul.cpp` | | ||
| OpenMP | `mul_openMP.cpp` | | ||
| OpenMPI | `mpimul_openMP.cpp` | | ||
</td>
</tr>
</table>
### 📁GPU
---
| Operation | Method | File |
|-----------|---------------------|-------------------------------|
| Addition | GPU (CUDA) | `multi_gpu_matrix_add_mmap.cu`|
| Multiplication | GPU (CUDA) | `multi_gpu_matrix_mul_mmap.cu`|
### 📁Roadmap
| Implementation | File |
|---------------------|-----------------|
| Summa Algorithm | `summa.cpp` |
| Strassen Algorithm | `strassen.cpp` |
| Cannon Algoritmhm | `cannon.cpp` |
| Fox Algorithm | `fox.cpp` |
## 🛠️ Requirements
![Architecture Diagram](arch.png) \
*NFS: Network File System \
**NIS: Network Information Service
### x86-64
- Linux Ubuntu LTS
- C++ boost library
- OpenMP library for C++
- OpenMPI
- C++ NVIDIA CUDA SDK any version later than 10
### ARM
At least 5 Raspberry Pi4
- Linux Ubuntu Mate LTS 64bit
- 512MB
- Cloud Core
### GPU
At least 4 GeForce GT 630 :
- 980MHz
- 981MB RAM
One GeForce RTX 3060Ti :
- 1.6GHz
- 8GB RAM
## 🛠️ Compilation-Execution
Each folder contains a corresponding Makefile for the specific machine it is intended to run on.
After downloading the appropriate folder, the user should run
```bash
make clean
```
before compiling for the first time. This ensures a clean build and helps avoid possible build errors.
Then, by running
```bash
make
```
all files are compiled, and on subsequent runs, only the files that have been changed are recompiled.
In CPU and ARM versions of our code about threads and processes, the program expects the user to input the matrix size directly via the command line when starting the program (this is handled using atoi to convert the input to an integer). \
For example, if we want to run "single_mul.cpp" with n = 1000:
```bash
./single_mul 1000
```
With the according output :
```bash
n,setup(us),exec*(us)1000,244,14474
```
In the GPU version, once the user starts the program, it will prompt for the matrix size, followed by a prompt to select the number of available GPUs to distribute the workload across.
In the same way as in the previous versions, if we want to run "multi_gpu_matrix_mul_mmap.cu":
```bash
./multi_gpu_matrix_mul_mmap
```
After that, the following messages will be displayed, asking the user to input the matrix size(n) and the available GPUs to use:
```bash
Enter matrix size (N): 1000
Enter number of GPUs (K): 4
```
then the according output will appear:
```bash
Setup Time:47ms
Comp Time: 1642 ms
```
The OpenMP scenario works similarly to the GPU's one. The only difference is that the user is asked to enter the chunk size instead of the number of GPUs, so the message looks like this:
```bash
Enter matrix size N: 1000
Enter chunk size: 100
```
Then, as the program is made to compute with all three OpenMP scheduling methods, the output bellow will be appeared:
```bash
Schedule: static (chunk = 100), Time: 627 ms
Schedule: dynamic (chunk = 100), Time: 606 ms
Schedule: guided (chunk = 100), Time: 614 ms
```
Afterwards, MPI's compilation is done as follows:
```bash
mpic++ mpimul_openmp.cpp -fopenmp -lboost_chrono -lboost_system -o mpimul
```
The user can then run the program using the following command
```bash
mpirun --hostfile /etc/hostfile --mca btl_tcp_if_exclude docker0,lo -np 13 ./mpimul 1000
```

+ 228
- 0
Roadmap/cannon.cpp View File

@ -0,0 +1,228 @@
#include <iostream>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/chrono.hpp>
using namespace std;
namespace chrono = boost::chrono;
// Matrix structure to hold data and dimensions
struct Matrix {
int n;
double** data;
Matrix(int size) : n(size) {
data = new double*[n];
for (int i = 0; i < n; ++i) {
data[i] = new double[n](); // Initialize to zero
}
}
~Matrix() {
for (int i = 0; i < n; ++i) {
delete[] data[i];
}
delete[] data;
}
};
// Initialize matrix with random values
void init_matrix(Matrix& mat, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < mat.n; ++i) {
for (int j = 0; j < mat.n; ++j) {
mat.data[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Print matrix (for debugging)
void print_matrix(const Matrix& mat, const string& name) {
cout << name << ":\n";
for (int i = 0; i < mat.n; ++i) {
for (int j = 0; j < mat.n; ++j) {
cout << mat.data[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
// Worker thread for Cannon's algorithm
class CannonWorker {
int block_size;
int grid_size;
int row, col;
Matrix& a;
Matrix& b;
Matrix& c;
boost::barrier& sync_barrier;
vector<boost::barrier*>& row_barriers;
vector<boost::barrier*>& col_barriers;
public:
CannonWorker(int bs, int gs, int r, int c, Matrix& ma, Matrix& mb, Matrix& mc,
boost::barrier& sb, vector<boost::barrier*>& rb, vector<boost::barrier*>& cb)
: block_size(bs), grid_size(gs), row(r), col(c),
a(ma), b(mb), c(mc), sync_barrier(sb), row_barriers(rb), col_barriers(cb) {}
void operator()() {
// Calculate block boundaries
int row_start = row * block_size;
int row_end = row_start + block_size;
int col_start = col * block_size;
int col_end = col_start + block_size;
// Initial skewing: A left by row, B up by column
// Shift A left by row positions
for (int shift = 0; shift < row; ++shift) {
for (int i = 0; i < block_size; ++i) {
double temp = a.data[row_start + i][col_start];
for (int j = 0; j < block_size - 1; ++j) {
a.data[row_start + i][col_start + j] = a.data[row_start + i][col_start + j + 1];
}
a.data[row_start + i][col_start + block_size - 1] = temp;
}
}
// Shift B up by column positions
for (int shift = 0; shift < col; ++shift) {
for (int j = 0; j < block_size; ++j) {
double temp = b.data[row_start][col_start + j];
for (int i = 0; i < block_size - 1; ++i) {
b.data[row_start + i][col_start + j] = b.data[row_start + i + 1][col_start + j];
}
b.data[row_start + block_size - 1][col_start + j] = temp;
}
}
// Synchronize all threads after initial skewing
sync_barrier.wait();
// Main computation loop
for (int step = 0; step < grid_size; ++step) {
// Local matrix multiplication
for (int i = 0; i < block_size; ++i) {
for (int j = 0; j < block_size; ++j) {
for (int k = 0; k < block_size; ++k) {
c.data[row_start + i][col_start + j] +=
a.data[row_start + i][(col_start + k) % a.n] *
b.data[(row_start + k) % b.n][col_start + j];
}
}
}
// Shift A left by 1
for (int i = 0; i < block_size; ++i) {
double temp = a.data[row_start + i][col_start];
for (int j = 0; j < block_size - 1; ++j) {
a.data[row_start + i][col_start + j] = a.data[row_start + i][col_start + j + 1];
}
a.data[row_start + i][col_start + block_size - 1] = temp;
}
// Shift B up by 1
for (int j = 0; j < block_size; ++j) {
double temp = b.data[row_start][col_start + j];
for (int i = 0; i < block_size - 1; ++i) {
b.data[row_start + i][col_start + j] = b.data[row_start + i + 1][col_start + j];
}
b.data[row_start + block_size - 1][col_start + j] = temp;
}
// Synchronize all threads before next step
sync_barrier.wait();
}
}
};
// Cannon's algorithm using Boost Threads
void cannon_multiply(Matrix& a, Matrix& b, Matrix& c, int grid_size) {
int block_size = a.n / grid_size;
// Create synchronization barriers
boost::barrier sync_barrier(grid_size * grid_size);
vector<boost::barrier*> row_barriers(grid_size);
vector<boost::barrier*> col_barriers(grid_size);
for (int i = 0; i < grid_size; ++i) {
row_barriers[i] = new boost::barrier(grid_size);
col_barriers[i] = new boost::barrier(grid_size);
}
// Create worker threads
boost::thread_group workers;
for (int i = 0; i < grid_size; ++i) {
for (int j = 0; j < grid_size; ++j) {
workers.create_thread(CannonWorker(block_size, grid_size, i, j,
a, b, c, sync_barrier, row_barriers, col_barriers));
}
}
// Wait for all threads to complete
workers.join_all();
// Clean up barriers
for (int i = 0; i < grid_size; ++i) {
delete row_barriers[i];
delete col_barriers[i];
}
}
int main(int argc, char** argv) {
if (argc != 3) {
cerr << "Usage: " << argv[0] << " <matrix_size> <grid_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
int grid_size = atoi(argv[2]);
if (n <= 0 || grid_size <= 0) {
cerr << "Matrix size and grid size must be positive" << endl;
return 1;
}
if (n % grid_size != 0) {
cerr << "Matrix size must be divisible by grid size" << endl;
return 1;
}
chrono::system_clock::time_point setup_start, setup_end;
chrono::system_clock::time_point comp_start, comp_end;
setup_start = chrono::system_clock::now();
Matrix a(n), b(n), c(n);
init_matrix(a);
init_matrix(b);
init_matrix(c, true); // Initialize to zero
setup_end = chrono::system_clock::now();
if (n <= 8) {
print_matrix(a, "Matrix A");
print_matrix(b, "Matrix B");
}
comp_start = chrono::system_clock::now();
cannon_multiply(a, b, c, grid_size);
comp_end = chrono::system_clock::now();
if (n <= 8) {
print_matrix(c, "Result Matrix C");
}
auto setup_time = chrono::duration_cast<chrono::milliseconds>(setup_end - setup_start);
auto comp_time = chrono::duration_cast<chrono::milliseconds>(comp_end - comp_start);
cout << "n,grid_size,setup(ms),exec(ms)" << endl;
cout << n << "," << grid_size << "," << setup_time.count() << "," << comp_time.count() << endl;
return 0;
}

+ 221
- 0
Roadmap/fox.cpp View File

@ -0,0 +1,221 @@
#include <iostream>
#include <cstdlib>
#include <random>
#include <vector>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/chrono.hpp>
/*g++ -std=c++11 fox_boost.cpp -o fox_boost -lboost_thread -lboost_chrono -lboost_system
./fox_boost 8 2
Note that this implementation:
Uses shared memory (all threads access the full matrices)
Requires careful synchronization to avoid race conditions
May not be as efficient as MPI for large matrices due to shared memory contention
*/
using namespace std;
namespace chrono = boost::chrono;
// Matrix structure to hold data and dimensions
struct Matrix {
int n;
double** data;
Matrix(int size) : n(size) {
data = new double*[n];
for (int i = 0; i < n; ++i) {
data[i] = new double[n](); // Initialize to zero
}
}
~Matrix() {
for (int i = 0; i < n; ++i) {
delete[] data[i];
}
delete[] data;
}
};
// Initialize matrix with random values
void init_matrix(Matrix& mat, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < mat.n; ++i) {
for (int j = 0; j < mat.n; ++j) {
mat.data[i][j] = zero ? 0.0 : dis(gen);
}
}
}
// Print matrix (for debugging)
void print_matrix(const Matrix& mat, const string& name) {
cout << name << ":\n";
for (int i = 0; i < mat.n; ++i) {
for (int j = 0; j < mat.n; ++j) {
cout << mat.data[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
// Worker thread for Fox algorithm
class FoxWorker {
int block_size;
int grid_size;
int row, col;
Matrix& a;
Matrix& b;
Matrix& c;
boost::barrier& sync_barrier;
vector<boost::barrier*>& row_barriers;
public:
FoxWorker(int bs, int gs, int r, int c, Matrix& ma, Matrix& mb, Matrix& mc,
boost::barrier& sb, vector<boost::barrier*>& rb)
: block_size(bs), grid_size(gs), row(r), col(c),
a(ma), b(mb), c(mc), sync_barrier(sb), row_barriers(rb) {}
void operator()() {
// Calculate block boundaries
int row_start = row * block_size;
int row_end = row_start + block_size;
int col_start = col * block_size;
int col_end = col_start + block_size;
// Temporary storage for broadcast block
Matrix temp_block(block_size);
for (int step = 0; step < grid_size; ++step) {
// Determine broadcast root for this step
int bcast_root = (row + step) % grid_size;
// Broadcast phase - only one thread per row participates
if (col == bcast_root) {
// Copy my block of A to temp_block
for (int i = 0; i < block_size; ++i) {
for (int j = 0; j < block_size; ++j) {
temp_block.data[i][j] = a.data[row_start + i][col_start + j];
}
}
}
// Wait for all threads in this row to reach broadcast point
row_barriers[row]->wait();
// All threads in row now have access to temp_block
// Local multiplication phase
for (int i = 0; i < block_size; ++i) {
for (int j = 0; j < block_size; ++j) {
for (int k = 0; k < block_size; ++k) {
c.data[row_start + i][col_start + j] +=
temp_block.data[i][k] * b.data[row_start + k][col_start + j];
}
}
}
// Shift blocks of B upwards
if (row > 0) {
// Send my block of B to the neighbor above
for (int i = 0; i < block_size; ++i) {
for (int j = 0; j < block_size; ++j) {
double temp = b.data[row_start + i][col_start + j];
b.data[row_start + i][col_start + j] = b.data[(row_start + i - block_size + a.n) % a.n][col_start + j];
b.data[(row_start + i - block_size + a.n) % a.n][col_start + j] = temp;
}
}
}
// Synchronize all threads before next step
sync_barrier.wait();
}
}
};
// Fox algorithm using Boost Threads
void fox_multiply(Matrix& a, Matrix& b, Matrix& c, int grid_size) {
int block_size = a.n / grid_size;
// Create synchronization barriers
boost::barrier sync_barrier(grid_size * grid_size);
vector<boost::barrier*> row_barriers(grid_size);
for (int i = 0; i < grid_size; ++i) {
row_barriers[i] = new boost::barrier(grid_size);
}
// Create worker threads
boost::thread_group workers;
for (int i = 0; i < grid_size; ++i) {
for (int j = 0; j < grid_size; ++j) {
workers.create_thread(FoxWorker(block_size, grid_size, i, j,
a, b, c, sync_barrier, row_barriers));
}
}
// Wait for all threads to complete
workers.join_all();
// Clean up barriers
for (int i = 0; i < grid_size; ++i) {
delete row_barriers[i];
}
}
int main(int argc, char** argv) {
if (argc != 3) {
cerr << "Usage: " << argv[0] << " <matrix_size> <grid_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
int grid_size = atoi(argv[2]);
if (n <= 0 || grid_size <= 0) {
cerr << "Matrix size and grid size must be positive" << endl;
return 1;
}
if (n % grid_size != 0) {
cerr << "Matrix size must be divisible by grid size" << endl;
return 1;
}
chrono::system_clock::time_point setup_start, setup_end;
chrono::system_clock::time_point comp_start, comp_end;
setup_start = chrono::system_clock::now();
Matrix a(n), b(n), c(n);
init_matrix(a);
init_matrix(b);
init_matrix(c, true); // Initialize to zero
setup_end = chrono::system_clock::now();
if (n <= 8) {
print_matrix(a, "Matrix A");
print_matrix(b, "Matrix B");
}
comp_start = chrono::system_clock::now();
fox_multiply(a, b, c, grid_size);
comp_end = chrono::system_clock::now();
if (n <= 8) {
print_matrix(c, "Result Matrix C");
}
auto setup_time = chrono::duration_cast<chrono::milliseconds>(setup_end - setup_start);
auto comp_time = chrono::duration_cast<chrono::milliseconds>(comp_end - comp_start);
cout << "n,grid_size,setup(ms),exec(ms)" << endl;
cout << n << "," << grid_size << "," << setup_time.count() << "," << comp_time.count() << endl;
return 0;
}

+ 182
- 0
Roadmap/strassen.cpp View File

@ -0,0 +1,182 @@
/*Strassen 1D - Matrix sizes at the power of to to subdivice properly*/
/*All matrices use 1D arrays with flattened indexing.
Recursion is threaded for the 7 Strassen multiplications up to threshold 64 using boost::bind*/
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <boost/thread.hpp>
#include <boost/bind/bind.hpp>
#include <boost/chrono.hpp>
#include <random>
using namespace std;
using namespace boost::placeholders;
double* create_matrix(int size) {
return new double[size * size]();
}
void cleanup_matrix(double* matrix) {
delete[] matrix;
}
void add(double* a, double* b, double* result, int size) {
for (int i = 0; i < size * size; ++i)
result[i] = a[i] + b[i];
}
void subtract(double* a, double* b, double* result, int size) {
for (int i = 0; i < size * size; ++i)
result[i] = a[i] - b[i];
}
void naive_mul(double* a, double* b, double* c, int size) {
for (int i = 0; i < size; ++i)
for (int j = 0; j < size; ++j)
for (int k = 0; k < size; ++k)
c[i * size + j] += a[i * size + k] * b[k * size + j];
}
void strassen(double* a, double* b, double* c, int size, int threshold = 64) {
if (size <= threshold) {
naive_mul(a, b, c, size);
return;
}
int newSize = size / 2;
int block = newSize * newSize;
double *a11 = a;
double *a12 = a + newSize;
double *a21 = a + newSize * size;
double *a22 = a + newSize * size + newSize;
double *b11 = b;
double *b12 = b + newSize;
double *b21 = b + newSize * size;
double *b22 = b + newSize * size + newSize;
double *c11 = c;
double *c12 = c + newSize;
double *c21 = c + newSize * size;
double *c22 = c + newSize * size + newSize;
// Allocate temp matrices
double *m1 = create_matrix(newSize), *m2 = create_matrix(newSize), *m3 = create_matrix(newSize);
double *m4 = create_matrix(newSize), *m5 = create_matrix(newSize), *m6 = create_matrix(newSize), *m7 = create_matrix(newSize);
double *aTemp = create_matrix(newSize), *bTemp = create_matrix(newSize);
boost::thread_group group;
// M1 = (A11 + A22) * (B11 + B22)
add(a11, a22, aTemp, newSize);
add(b11, b22, bTemp, newSize);
group.create_thread(boost::bind(strassen, aTemp, bTemp, m1, newSize, threshold));
// M2 = (A21 + A22) * B11
add(a21, a22, aTemp, newSize);
group.create_thread(boost::bind(strassen, aTemp, b11, m2, newSize, threshold));
// M3 = A11 * (B12 - B22)
subtract(b12, b22, bTemp, newSize);
group.create_thread(boost::bind(strassen, a11, bTemp, m3, newSize, threshold));
// M4 = A22 * (B21 - B11)
subtract(b21, b11, bTemp, newSize);
group.create_thread(boost::bind(strassen, a22, bTemp, m4, newSize, threshold));
// M5 = (A11 + A12) * B22
add(a11, a12, aTemp, newSize);
group.create_thread(boost::bind(strassen, aTemp, b22, m5, newSize, threshold));
// M6 = (A21 - A11) * (B11 + B12)
subtract(a21, a11, aTemp, newSize);
add(b11, b12, bTemp, newSize);
group.create_thread(boost::bind(strassen, aTemp, bTemp, m6, newSize, threshold));
// M7 = (A12 - A22) * (B21 + B22)
subtract(a12, a22, aTemp, newSize);
add(b21, b22, bTemp, newSize);
group.create_thread(boost::bind(strassen, aTemp, bTemp, m7, newSize, threshold));
group.join_all();
// C11 = M1 + M4 - M5 + M7
for (int i = 0; i < block; ++i)
c11[i] = m1[i] + m4[i] - m5[i] + m7[i];
// C12 = M3 + M5
for (int i = 0; i < block; ++i)
c12[i] = m3[i] + m5[i];
// C21 = M2 + M4
for (int i = 0; i < block; ++i)
c21[i] = m2[i] + m4[i];
// C22 = M1 - M2 + M3 + M6
for (int i = 0; i < block; ++i)
c22[i] = m1[i] - m2[i] + m3[i] + m6[i];
cleanup_matrix(m1);
cleanup_matrix(m2);
cleanup_matrix(m3);
cleanup_matrix(m4);
cleanup_matrix(m5);
cleanup_matrix(m6);
cleanup_matrix(m7);
cleanup_matrix(aTemp);
cleanup_matrix(bTemp);
}
void init_matrix(double* mat, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n * n; ++i)
mat[i] = zero ? 0.0 : dis(gen);
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size (power of 2)>" << endl;
return 1;
}
int n = atoi(argv[1]);
if ((n & (n - 1)) != 0) {
cerr << "Matrix size must be a power of 2!" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
double* a = create_matrix(n);
double* b = create_matrix(n);
double* c = create_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true);
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
strassen(a, b, c, n);
t4 = boost::chrono::system_clock::now();
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
cleanup_matrix(a);
cleanup_matrix(b);
cleanup_matrix(c);
return 0;
}

+ 116
- 0
Roadmap/summa.cpp View File

@ -0,0 +1,116 @@
/*Scalable Universal Matrix Multiplication Algorithm) works by dividing matrices into blocks and processing them in phases.*/
/*Matrix size n is divisible by sqrt(p) where p = number of threads.*/
/*Flat (1D) memory is used for all matrices.*/
/*Blocked computation is handled with explicit loop tiling. -1990*/
/*Partitions the matrices A and B across a 2D processor grid
Performs a series of broadcasts of matrix blocks along rows and columns
Computes partial results at each processor
Accumulates results to form the final product matrix C = A × B*/
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <random>
#include <boost/thread.hpp>
#include <boost/bind/bind.hpp>
#include <boost/chrono.hpp>
using namespace std;
using namespace boost::placeholders;
const int MAX_THREADS = 100;
// Allocate 1D array matrix
double* create_matrix(int n) {
return new double[n * n];
}
void cleanup_matrix(double* matrix) {
delete[] matrix;
}
void init_matrix(double* matrix, int n, bool zero = false) {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < n * n; ++i)
matrix[i] = zero ? 0.0 : dis(gen);
}
// SUMMA worker thread: computes block (i_block) of C
void summa_block(int block_row_start, int block_row_end, int n, int block_size,
double* a, double* b, double* c) {
for (int i = block_row_start; i < block_row_end; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < n; ++k) {
sum += a[i * n + k] * b[k * n + j];
}
c[i * n + j] = sum;
}
}
}
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <matrix_size>" << endl;
return 1;
}
int n = atoi(argv[1]);
if (n <= 0) {
cerr << "Matrix size must be positive" << endl;
return 1;
}
boost::chrono::system_clock::time_point t1, t2, t3, t4;
t1 = boost::chrono::system_clock::now();
double* a = create_matrix(n);
double* b = create_matrix(n);
double* c = create_matrix(n);
init_matrix(a, n);
init_matrix(b, n);
init_matrix(c, n, true);
t2 = boost::chrono::system_clock::now();
t3 = boost::chrono::system_clock::now();
boost::thread_group group;
int rows_per_thread = n / MAX_THREADS;
int remaining = n % MAX_THREADS;
int current_row = 0;
for (int i = 0; i < MAX_THREADS && current_row < n; ++i) {
int rows_to_process = rows_per_thread + (i < remaining ? 1 : 0);
int end_row = current_row + rows_to_process;
group.create_thread(
boost::bind(summa_block, current_row, end_row, n, rows_to_process, a, b, c)
);
current_row = end_row;
}
group.join_all();
t4 = boost::chrono::system_clock::now();
auto setup_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);
auto exec_time = boost::chrono::duration_cast<boost::chrono::milliseconds>(t4 - t3);
cout << "n,setup(ms),exec(ms)" << endl;
cout << n << "," << setup_time.count() << "," << exec_time.count() << endl;
cleanup_matrix(a);
cleanup_matrix(b);
cleanup_matrix(c);
return 0;
}

BIN
arch.png View File

Before After
Width: 677  |  Height: 319  |  Size: 21 KiB

Loading…
Cancel
Save