#include <iostream>
#include <sys/mman.h>
#include <cstdlib>
#include <ctime>
#include <chrono>
#include "schedulers.hpp"
#include "../Homework1/sort_algorithms.hpp"
#include "../Homework1/row.hpp"
using namespace std;

double* tensor_A=nullptr;
double* tensor_B=nullptr;
int global_n=0;
int global_k=0;

double* shared_memory(size_t size){
	return (double*)mmap(NULL,size*sizeof(double),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
}

void sort_tensor_A_row(int row_index){
	double* row_start=tensor_A+(row_index*global_n);
	row<double> r(row_start,global_n);
	quick_sort(r);
	for(int i=0;i<global_n;i++){
		row_start[i]=r[i];
	}
}

void sort_tensor_B_matrix(int matrix_index){
	int start_index=matrix_index*(global_n*global_n);
	for(int i=0;i<global_n;i++){
		double* row_start=tensor_B+start_index+(i*global_n);
		row<double> r(row_start,global_n);
		quick_sort(r);
		for(int j=0;j<global_n;j++){
			row_start[j]=r[j];
		}
	}
}

int main(){
	srand(time(NULL));
	global_n=10;
	tensor_A=shared_memory(global_n*global_n);
	for(int i=0;i<global_n*global_n;i++){
		tensor_A[i]=(rand()%2001)-1000;
	}
	auto start_A=chrono::high_resolution_clock::now();
	Prolific:: run(global_n,global_n,sort_tensor_A_row);
	auto end_A=chrono::high_resolution_clock::now();
	cout<<"Tensor A sorted in "<<chrono::duration<double,milli>(end_A-start_A).count()<<" ms\n\n";
	global_n=100;
	int k_values[]={10,100};
	for(int k:k_values){
		global_k=k;
		size_t total_elements=global_n*global_n*global_k;
		tensor_B=shared_memory(total_elements);
		for(size_t i=0;i<total_elements;i++){
			tensor_B[i]=(rand()%2001)-1000;
		}
		cout<<"Benchmarking k = "<<k<<"...\n";
		auto start_prolific=chrono::high_resolution_clock::now();
		Prolific::run(k,k,sort_tensor_B_matrix);
		auto end_prolific=chrono::high_resolution_clock::now();
		cout<<" Prolific (k="<<k<<"): "<<chrono::duration<double,milli>(end_prolific-start_prolific).count()<<" ms\n";
		int levels=(k==10)?3:6;
		auto start_collective=chrono::high_resolution_clock::now();
		Collective::run(levels,k,sort_tensor_B_matrix);
		auto end_collective=chrono::high_resolution_clock::now();
		cout<<" Collective (k="<<k<<"): "<<chrono::duration<double,milli>(end_collective-start_collective).count()<<" ms\n";
		munmap(tensor_B,total_elements*sizeof(double));
	}
	munmap(tensor_A,global_n*global_n*sizeof(double));
	return 0;
}
