Reputation: 71
#include<iostream>
#include<vector>
#include<ctime>
#include<cmath>
#include<omp.h>
#include<array>
using namespace std;
double counter = 0;
vector<int> vec;
vector<double> reduction;
#pragma omp threadprivate(reduction)
vector<double> eet;
int fish;
void mario( int current_node, int current_depth) {
int q = current_node % 4;
#pragma omp simd
for( int i = 3 ; i < current_node; i+=4){
reduction[i]+=4;
mario(i, current_depth);
mario(i - 1,current_depth);
mario(i - 2,current_depth);
mario(i - 3,current_depth);
}
#pragma omp simd
for(int x = 1; x <= q; x++){
reduction[0]++;
mario(current_node - x,current_depth);
}
#pragma omp task firstprivate(current_node,current_depth)
{
if(current_depth > 0){
int new_depth = current_depth - 1;
#pragma omp simd
for(int i = current_node;i <= vec[current_node];i++){
reduction[i]++;
mario(i + 1,new_depth);
}
}
}
}
int main() {
omp_proc_bind_true;
omp_set_dynamic(0);
int nodes;
int timesteps;
int threadz;
cout << "enter number of nodes" << endl;
cin >> nodes;
cout << "enter number of timesteps" << endl;
cin >> timesteps;
cout << "enter number threads" << endl;
cin >> threadz;
omp_set_num_threads(threadz);
int mushroom = nodes - 2;
fish = nodes - 1;
vec.assign( nodes, mushroom );
clock_t t = clock();
vector<double> zed(mushroom + 1 , 0 );
eet = zed;
reduction = eet;
#pragma omp parallel copyin(reduction)
{
#pragma omp single
{
mario(nodes - 1, timesteps - 1);
}
#pragma omp critical
{
#pragma omp simd
for(int x = 0; x < zed.size();x++){
eet[x] += reduction[x];
}
}
#pragma omp barrier
}
for(int j = 0; j < eet.size(); j++){
counter += eet[j];
}
t = clock() - t;
double time_taken = ((double)t) / CLOCKS_PER_SEC;
cout << "mario took " << fixed << counter << " steps" << endl;
cout << "It took him " << time_taken << " seconds" << endl;
return 0;
}
In my code I declare the vector reduction: vector<double> reduction;
Then I immediately use threadprivate: #pragma omp threadprivate(reduction)
, but when I compile my code I get the errors.
error: 'reduction' declared 'threadprivate' after first use
13 | #pragma omp threadprivate(reduction)
error: 'reduction' must be 'threadprivate' for 'copyin'
82 | #pragma omp parallel copyin(reduction)
What is causing these errors? I just declared the variable without doing anything else.
Is the error avoidable?
Are there any other methods for reduction across openMP tasks for recursive functions
or alternative methods for combating the problem?
Is there something fundamentally wrong with the way I am trying to write my code?
I am using gcc 9.3
, sorry if my question is unclear please suggest improvements.
Upvotes: 1
Views: 389
Reputation: 71
A bodge of an solution that only works with gcc, it is unfortunately just a workaround and not a proper solution.
#include<iostream>
#include<vector>
#include<ctime>
#include<cmath>
#include<omp.h>
#include<array>
#include<thread>
using namespace std;
double counter = 0;
vector<int> vec;
thread_local vector<double> reduction;
vector<double> eet;
int fish;
void mario( int current_node, int current_depth) {
int q = current_node % 4;
#pragma omp simd
for( int i = 3 ; i < current_node; i+=4){
reduction[i]+=4;
mario(i, current_depth);
mario(i - 1,current_depth);
mario(i - 2,current_depth);
mario(i - 3,current_depth);
}
#pragma omp simd
for(int x = 1; x <= q; x++){
reduction[0]++;
mario(current_node - x,current_depth);
}
#pragma omp task firstprivate(current_node,current_depth)
{
if(current_depth > 0){
int new_depth = current_depth - 1;
#pragma omp simd
for(int i = current_node;i <= vec[current_node];i++){
reduction[i]++;
mario(i + 1,new_depth);
}
}
}
}
int main() {
omp_proc_bind_true;
omp_set_dynamic(0);
int nodes;
int timesteps;
int threadz;
cout << "enter number of nodes" << endl;
cin >> nodes;
cout << "enter number of timesteps" << endl;
cin >> timesteps;
cout << "enter number threads" << endl;
cin >> threadz;
omp_set_num_threads(threadz);
int mushroom = nodes - 2;
fish = nodes - 1;
vec.assign( nodes, mushroom );
clock_t t = clock();
vector<double> zed(mushroom + 1 , 0 );
eet = zed;
#pragma omp parallel
{
reduction = zed;
#pragma omp barrier
#pragma omp single
{
mario(nodes - 1, timesteps - 1);
}
#pragma omp critical
{
for(int x = 0; x < reduction.size();x++){
eet[x] += reduction[x];
}
}
#pragma omp barrier
}
for(int j = 0; j < eet.size(); j++){
counter += eet[j];
}
t = clock() - t;
double time_taken = ((double)t) / CLOCKS_PER_SEC;
cout << "mario took " << fixed << counter << " steps" << endl;
cout << "It took him " << time_taken << " seconds" << endl;
return 0;
}
This is a terrible method happens to work, apparently gcc's c++ implementation uses POSIX threads and,gcc implementation of openMP is just POSIX under the hood. source: Using C++11 thread_local with other parallel libraries
So with gcc if a variable is sent thread local storage that way it is equivalent to a 'threadprivate' variable to the openMP.
Someone else please suggest a proper solution.
Upvotes: 2