Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

OpenMp 3.0 and iterators

Tim
Beginner
1,004 Views

Hi,

I have two questions about the Intel Compiler and OpenMp 3.0:

1. The OpenMp 3.0 specification support loop parallelization for random_access_iterators. This works fine for icpc 11.1 and a iterator over a std::deque (see example 1). The compiler does NOT produce any error messages, but the parallel for loop is not executed! If i compile with gcc or portland compiler it works as expected!

example 1:

#include
#include
#include
#include
#include


int main (int argc, char** argv){
//typedef std::deque containerType;
typedef std::vector containerType;

containerType myList;

char c='a';
for(int i=0; i myList.push_back(c);
c++;
}

containerType::iterator itL;
int i=0;

#pragma omp parallel for
for(itL=myList.begin(); itL < myList.end(); itL++){
std::cout<< (char)*itL << ": " << ++i << std::endl;
}

std::cout<<i< return 0

}


So is this a bug in the intel compiler? Shouldn't it produce a warning at least?

2. The second question is even more specific:

Now i wrote my own iterator class for my own container (example code below). I inheritated this iterator class from the std::iterator class to get a STL conform iterator. This works fine with GNU g++ 4.4.1, but for icpc I get an internal error:

$ icpc -openmp -o main2 main2.cc
(0): internal error: backend signals
compilation aborted for main2.cc (code 4)


code:

#include
#include
#include
#include
#include
#include
#include

#define SIZE 26

class SpecialMap;

class SpecialMapIterator: public std::iterator{

public:
SpecialMapIterator() : it_(0){}
SpecialMapIterator& operator++(){++it_; return *this;}
SpecialMapIterator& operator++(int){it_++; return *this;}
SpecialMapIterator& operator--(){--it_; return *this;}
SpecialMapIterator& operator--(int){it_--; return *this;}

typedef ptrdiff_t difference_type;

SpecialMapIterator& operator+=(difference_type rhs){
while(rhs>0){
it_++;
rhs--;
}
return *this;
}

char& operator*() {return it_->second;}
const char& operator*() const{return it_->second;}

bool operatorbool operatorbool operator!=(const SpecialMapIterator& rhs){return it_!=rhs.it_;}
bool operator==(const SpecialMapIterator& rhs){return (it_==rhs.it_);}

friend class SpecialMap;
friend difference_type operator-(SpecialMapIterator it1, SpecialMapIterator it2);

private:
SpecialMapIterator(std::map::iterator it) : it_(it){}
std::map::iterator it_;
};


class SpecialMap{
public:
typedef SpecialMapIterator iterator;
typedef SpecialMapIterator const_iterator;

iterator begin(){return SpecialMapIterator(map_.begin());}
iterator end(){return SpecialMapIterator(map_.end());}

char& operator[](const int i){ return map_;}

private:
std::map map_;
};


SpecialMapIterator::difference_type operator-(SpecialMapIterator it1, SpecialMapIterator it2){
SpecialMapIterator::difference_type count = 0;
while(it2 != it1){
++it2;
++count;
}
return count;
}

int main (int argc, char** argv){
typedef SpecialMap maptype;
maptype myMap;

char c='a';
for(int i=0; imyMap=c;
c++;
}

maptype::iterator itM;
int i = 0;

#pragma omp parallel for
for(itM=myMap.begin(); itM < myMap.end(); itM++){

#pragma omp critical
{
std::cout << *itM << ": " <<omp_get_thread_num()<< ": " <}
}
return 0;
}


The openMP specification does not really say, in which case a iterator is a "RandomAccessIterator". So is this a feature in gcc or a bug in icpc? Or is there another possibility to write my own RandomAccessIterator or wrap it somehow?

PS: I asked the same question in porland group forum: http://www.pgroup.com/userforum/viewtopic.php?t=1556 , because the second example also does not work with the portland compiler. And they said it is a bug on their side...

0 Kudos
10 Replies
JenniferJ
Moderator
1,004 Views
Quoting - timiem
1. The OpenMp 3.0 specification support loop parallelization for random_access_iterators. This works fine for icpc 11.1 and a iterator over a std::deque (see example 1). The compiler does NOT produce any error messages, but the parallel for loop is not executed! If i compile with gcc or portland compiler it works as expected!
Hello,
First of all thanks for your posting with a testcase.

About #1 issue, it seems a bug on Linux with "std::vector". It works with -Od though. I'll file a bug report to the compiler.

I'll check on the #2 next.

Thanks again.
Jennifer
0 Kudos
Tim
Beginner
1,004 Views
Hello,
First of all thanks for your posting with a testcase.

About #1 issue, it seems a bug on Linux with "std::vector". It works with -Od though. I'll file a bug report to the compiler.

Hi,

thanks for your quick support.

Sorry, but I think it does not really work. The output is correct with -O0 (what is better than before), but the loop seems not to be executed in parallel! (I checked this by printing out omp_get_thread_num() within the loop!)
0 Kudos
JenniferJ
Moderator
1,004 Views
Quoting - timiem
Sorry, but I think it does not really work. The output is correct with -O0 (what is better than before), but the loop seems not to be executed in parallel! (I checked this by printing out omp_get_thread_num() within the loop!)
Yeh, you're right. I added this api to the test and saw the problem.

About #2 issue, it happens on Windows as well if changing following line. I've filed a bug report about this well.

When there's any update, I'll post here.

Jennifer
0 Kudos
JenniferJ
Moderator
1,004 Views

About the #2 issue, there's a work-around for it. It's to make the operator methods non-class member. Like:

[cpp]#if 0
        bool operator<=(const SpecialMapIterator& rhs){return it_!=rhs.it_; }
        bool operator<(const SpecialMapIterator& rhs){return it_!=rhs.it_;}
        bool operator!=(const SpecialMapIterator& rhs){return it_!=rhs.it_;}
        bool operator==(const SpecialMapIterator& rhs){return (it_==rhs.it_);}
#else
      friend bool operator<=(const SpecialMapIterator& lhs,
                               const SpecialMapIterator& rhs)
            {return lhs.it_!=rhs.it_; }
      friend bool operator<(const SpecialMapIterator& lhs,
                              const SpecialMapIterator& rhs)
            {return lhs.it_!=rhs.it_;}
      friend bool operator!=(const SpecialMapIterator& lhs,
                               const SpecialMapIterator& rhs)
            {return lhs.it_!=rhs.it_;}
      friend bool operator==(const SpecialMapIterator& lhs,
                               const SpecialMapIterator& rhs)
            {return (lhs.it_==rhs.it_);}
#endif
[/cpp]

The #2 bug just got fixed. It should be in the 3rd compiler update around end of October.

Jennifer
0 Kudos
JenniferJ
Moderator
1,004 Views
About issue #1 that the omp loop got optimized away, there is a work-around for it: it is to change the iterator to operator [].

The fix involves several modules, so it will take some time. Please use the work-around for now.When there is more news, I'll let you know.

Thanks,
Jennifer
0 Kudos
shane_stainsby
Beginner
1,004 Views

Hi Jennifer,

just tried example #2 with Intel compiler 11.1.073 and even with your suggested update it only runs on one thread. This also seems to true if I try deque.Is there a version of the compiler available that resolves this issue?

Thanks

Shane

0 Kudos
SergeyKostrov
Valued Contributor II
1,004 Views
What happens if the following is #pragma directive is used: #pragma omp parallel for num_threads( 8 ) ... Does it create 8 OpenMP threads?
0 Kudos
TimP
Honored Contributor III
1,004 Views

You could generate asm code to see if the OpenMP is implemented with an omp single, as is generally done for OpenMP 2.5 features.

I would agree, "support" for various levels of OpenMP might be expected to go beyond simply not breaking serial code.

Up to now, it's often been necessary to make multiple levels of loops, with an outer parallel for and inner STL loop, particularly for vectorizable cases.  Future OpenMP 4.0 omp simd parallel for directive would support combined vectorization and parallelization.

STL is designed to make things difficult for optimizing compilers, and each compiler team has had to implement specific machinery to handle vectorization of suitable STL operators.  Without vectorization, it's somewhat academic if you can get threaded parallelization.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,004 Views

I think iterators and parallel constructs are an oxymoron.

parallel for has the requirement to know the number of iterations in order to determine how (much) to partition the iteration space amongst threads. If the iterators are truely opaque, then the compiler could concievably make the parallel for into a parallel while. However, this may be at severe expense of performance.

Just for fun, consider a case where the iterator returns a random number: as does the List.begin() and List.end(), and itL++, and operator "less than". Although this is a "stupid" example, it is well within the scope of permissable activities for sequential "for(...".

I agree with Jennifer's suggestion to use operator[] with first obtaining the end[] number, replacing the iterator with size_t i.

Other complications with using containers in parallel is you must be careful not to alter the container disruptive to other threads. e.g. one thread causes container to resize, delete, move, etc...

Jim Dempsey

0 Kudos
SergeyKostrov
Valued Contributor II
1,004 Views
>> I think iterators and parallel constructs are an oxymoron... In the past I've asked a couple of times a question 'Why do you need iterator here?' and the answers were like 'Just 'cause!' So, developers could not explain it. My point of view is that unnecessary applications of some programming techniques are "killing" performance of an application.
0 Kudos
Reply