Files
stencilparallelpattern/stencil.hpp

286 lines
11 KiB
C++
Raw Normal View History

2023-08-24 19:46:27 +02:00
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#pragma once
#ifndef STENCIL_HPP
#define STENCIL_HPP
#include <algorithm>
#include <cstdio>
#include <functional>
#include <future>
#include <iostream>
#include <utility>
#include <vector>
#include <ff/ff.hpp>
// importand order in includes
#include <ff/map.hpp>
#include <ff/parallel_for.hpp>
#include "task.hpp"
#include "threadPool.hpp"
template <typename T> class Stencil : public ff::ff_Map<Task<T>> {
public:
Stencil(std::function<T(std::vector<T>)> convolution,
std::vector<std::pair<int, int>> neighborhood, int iterations);
Stencil(std::function<T(std::vector<T>)> convolution,
std::vector<std::pair<int, int>> neighborhood, int iterations,
int maxworkers);
Task<T> *svc(Task<T> *);
std::vector<std::vector<T>> *operator()(std::vector<std::vector<T>> *matrix,
int iterations);
void stdthread(std::vector<std::shared_future<Task<T> *>> *ResultsVector,
std::vector<std::promise<Task<T> *> *> *OutputVector);
void sequential(std::vector<std::shared_future<Task<T> *>> *ResultsVector,
std::vector<std::promise<Task<T> *> *> *OutputVector);
private:
Task<T> *svc_helper(Task<T> *t, int iterations);
2023-08-24 19:46:27 +02:00
void constructor_helper(std::vector<std::pair<int, int>> neighborhood);
std::function<T(std::vector<T>)> Convolution;
std::vector<std::pair<int, int>> Neighborhood;
int Iterations = 0;
std::vector<int> Borders{0, 0, 0, 0}; // left, top, right, bottom
int MaxWorkers = 0;
};
template <typename T>
Stencil<T>::Stencil(std::function<T(std::vector<T>)> convolution,
std::vector<std::pair<int, int>> neighborhood,
int iterations)
: ff::ff_Map<Task<T>>(), Convolution(convolution), Neighborhood({{0, 0}}),
Iterations(iterations) {
constructor_helper(neighborhood);
}
template <typename T>
Stencil<T>::Stencil(std::function<T(std::vector<T>)> convolution,
std::vector<std::pair<int, int>> neighborhood,
int iterations, int maxworkers)
: ff::ff_Map<Task<T>>(maxworkers), Convolution(convolution),
Neighborhood({{0, 0}}), Iterations(iterations), MaxWorkers(maxworkers) {
constructor_helper(neighborhood);
}
template <typename T>
void Stencil<T>::constructor_helper(
std::vector<std::pair<int, int>> neighborhood) {
// copies neighborhood and adds the default element (0,0)
Neighborhood.insert(Neighborhood.end(), neighborhood.begin(),
neighborhood.end());
// finds the boundaries of the neighborhood
auto frst = [](std::pair<int, int> a, std::pair<int, int> b) {
return a.first < b.first;
};
auto scnd = [](std::pair<int, int> a, std::pair<int, int> b) {
return a.second < b.second;
};
if (neighborhood.size() > 0) {
Borders[0] =
std::abs(std::min(0, (*std::min_element(Neighborhood.begin(),
Neighborhood.end(), frst))
.first));
Borders[1] =
std::abs(std::min(0, (*std::min_element(Neighborhood.begin(),
Neighborhood.end(), scnd))
.second));
Borders[2] =
std::abs(std::max(0, (*std::max_element(Neighborhood.begin(),
Neighborhood.end(), frst))
.first));
Borders[3] =
std::abs(std::max(0, (*std::max_element(Neighborhood.begin(),
Neighborhood.end(), scnd))
.second));
}
}
// svc function for fastflow library
template <typename T> Task<T> *Stencil<T>::svc(Task<T> *task) {
task = svc_helper(task, this->Iterations);
2023-08-24 19:46:27 +02:00
ff::ff_node::ff_send_out(task);
return this->GO_ON;
}
// operator to apply to vector<vector<T>>
template <typename T>
std::vector<std::vector<T>> *
Stencil<T>::operator()(std::vector<std::vector<T>> *matrix, int iterations) {
if ((*matrix).size() == 0 || (*matrix)[0].size() == 0) {
return matrix;
}
std::vector<std::vector<T>> * arena = new std::vector<std::vector<T>>();
*arena = *matrix;
Task<T> *task = new Task<T>(arena, (*arena).size(), (*arena)[0].size());
task = svc_helper(task, iterations);
*matrix = *task->VectorData;
delete task;
return matrix;
2023-08-24 19:46:27 +02:00
}
// function for std thread
// ResultsVector: vector of futures where another thread will put the tasks
// OutputVector: where to put the processed tasks
template <typename T>
void Stencil<T>::stdthread(
std::vector<std::shared_future<Task<T> *>> *ResultsVector,
std::vector<std::promise<Task<T> *> *> *OutputVector) {
if (!ResultsVector || !OutputVector) {
std::cerr << "Error: input is NULL [Stencil<T>::stdthread]"
<< std::endl;
return;
}
ThreadPool thread_pool(MaxWorkers);
int MaxThreads = thread_pool.numberOfThreads();
int count = 0;
// for each task, create a new arena where to store the new computed values
// then send jobs to the threadpool
for (auto result : *ResultsVector) {
Task<T> *task = result.get();
int niter = Iterations;
int delta = task->Rows / MaxThreads;
2023-08-24 19:46:27 +02:00
std::vector<std::vector<T>> *arena = new std::vector<std::vector<T>>(0);
*arena = *(task->VectorData); // copy all from VectorData
while (niter > 0) {
for (int l = 0; l < MaxThreads - 1; ++l) {
thread_pool.addJob([&, l, delta] {
for (int x = l * delta; x < (l+1) * delta; ++x) {
for (int y = 0; y < task->Cols; ++y) {
if (x < Borders[1] || x >= task->Rows - Borders[3] ||
y < Borders[0] || y >= task->Cols - Borders[2]) {
continue;
}
std::vector<T> n;
n.resize(Neighborhood.size());
std::transform(
Neighborhood.begin(), Neighborhood.end(),
n.begin(),
[&task, x, y](std::pair<int, int> e) {
return (*task->VectorData)[x + e.second]
[y + e.first];
});
(*arena)[x][y] = Convolution(n);
}
}
});
}
thread_pool.addJob([&, delta, MaxThreads] {
for (int x = (MaxThreads - 1) * delta;
x < task->Rows; ++x) {
for (int y = 0; y < task->Cols; ++y) {
2023-08-24 19:46:27 +02:00
if (x < Borders[1] || x >= task->Rows - Borders[3] ||
y < Borders[0] || y >= task->Cols - Borders[2]) {
continue;
}
std::vector<T> n;
n.resize(Neighborhood.size());
std::transform(
Neighborhood.begin(), Neighborhood.end(), n.begin(),
[&task, x, y](std::pair<int, int> e) {
return (
*task->VectorData)[x + e.second][y + e.first];
2023-08-24 19:46:27 +02:00
});
(*arena)[x][y] = Convolution(n);
}
}
});
thread_pool.waitEnd();
std::swap(task->VectorData, arena);
--niter;
}
delete (arena);
// set the value of the promise
(*OutputVector)[count]->set_value(task);
++count;
}
}
template <typename T>
void Stencil<T>::sequential(
std::vector<std::shared_future<Task<T> *>> *ResultsVector,
std::vector<std::promise<Task<T> *> *> *OutputVector) {
if (!ResultsVector || !OutputVector) {
std::cerr << "Error: input is NULL [Stencil<T>::stdthread]"
<< std::endl;
return;
}
int count = 0;
for (auto result : *ResultsVector) {
Task<T> *task = result.get();
int niter = Iterations;
std::vector<std::vector<T>> *arena = new std::vector<std::vector<T>>(0);
*arena = *(task->VectorData); // copy all from VectorData
while (niter > 0) {
for (int x = 0; x < task->Rows; ++x) {
for (int y = 0; y < task->Cols; ++y) {
if (x < Borders[1] || x >= task->Rows - Borders[3] ||
y < Borders[0] || y >= task->Cols - Borders[2]) {
continue;
}
std::vector<T> n;
n.resize(Neighborhood.size());
std::transform(
Neighborhood.begin(), Neighborhood.end(), n.begin(),
[&task, x, y](std::pair<int, int> e) {
return (
*task->VectorData)[x + e.second][y + e.first];
});
(*arena)[x][y] = Convolution(n);
}
}
std::swap(task->VectorData, arena);
--niter;
}
delete (arena);
(*OutputVector)[count]->set_value(task);
++count;
}
}
template <typename T> Task<T> *Stencil<T>::svc_helper(Task<T> *task, int iterations) {
int niter = iterations;
2023-08-24 19:46:27 +02:00
std::vector<std::vector<T>> *arena = new std::vector<std::vector<T>>(0);
*arena = *(task->VectorData);
while (niter > 0) {
parallel_for(
0, task->Rows,
[&](const int x) {
for (int y = 0; y < task->Cols; ++y) {
2023-08-24 19:46:27 +02:00
if (x < Borders[1] || x >= task->Rows - Borders[3] ||
y < Borders[0] || y >= task->Cols - Borders[2]) {
continue;
2023-08-24 19:46:27 +02:00
}
std::vector<T> n;
n.resize(Neighborhood.size());
std::transform(
Neighborhood.begin(), Neighborhood.end(), n.begin(),
[&task, x, y](std::pair<int, int> e) {
return (*task->VectorData)[x + e.second][y + e.first];
});
(*arena)[x][y] = Convolution(n);
}
2023-08-24 19:46:27 +02:00
},
MaxWorkers);
std::swap(task->VectorData, arena);
--niter;
}
delete (arena);
return task;
}
#endif /* STENCIL_HPP */