Software Archive
Read-only legacy content
17060 Discussions

Xeon Phi - can' t offload an unordered_map

manrique__luis
Beginner
1,680 Views

I'm trying to run my code parallel in both CPU and MIC. When I run only the CPU code, everything is fine, but when I try to offload a few variables, I can't even compile my program. Here is the code:

*My error message is:

            error: no operator "!" matches these operands
            operand types are: ! std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const int, int>>>
          if (!rep[0])

std::unordered_map<int, int> repetido;

#pragma omp parallel sections
{
  #pragma omp section
  {
    std::unordered_map<int, int> * rep = &repetido;
    #pragma offload target(mic) in (r : length(repetido.size()))
        if (!rep[0])
        {
          #pragma omp parallel
          {
            #pragma omp for schedule(dynamic,1) nowait
              // Do somehting;
              }
          }  
        }
      }

    #pragma omp section
    {
      if (!repetido[0])
      {
        #pragma omp parallel
        {
          #pragma omp for schedule(dynamic,1) nowait
            //Do something;
           }
         }
       }
     }
   }
 }

 

 

0 Kudos
1 Solution
pbkenned1
Employee
1,680 Views

Hello Luis,

The shared virtual memory model doesn't use #pragma offload, but instead uses _Cilk_shared/_Cilk_offload constructs.  This is an entirely different way of offloading.  Functions and statically allocated data are given the _Cilk_shared attribute, and dynamically allocated data are allocated in shared memory.  This model is more complex than the #pragma offload model, but makes almost any C/C++ program viable for Phi applications.  Read all about it in the User's Guide -- search for 'Offload Using Shared Virtual Memory'

The #pragma offload model doesn't use virtual shared memory at all.  This is a data marshaling model which performs data exchanges between host and coprocessor.  This model doesn't use _Cilk_shared variables.

In the example you posted, you have:

 #pragma offload target(mic) in (myMap)

As we've seen, type std::unordered_map<int, int> is not bitwise copyable, so the compiler rejects this.

In the same way, if I were to replace '#pragma offload target(mic) in (myMap)' with the OpenMP equivalent construct:

#pragma omp target map(to: myMap)

You'll see the compiler reject that similarly, since list items must also be bitwise copyable:

    #pragma omp section
    {
//      #pragma offload target(mic) in (myMap)
      #pragma omp target map(to: myMap)
        for (int i = 0; i < 100; i++)
        {
          if(myMap) std::cout << myMap << "\n";
        }

 

[U543338]$ icc -std=c++11 -qopenmp unordered_map-omp-tgt-map.cpp
unordered_map-omp-tgt-map.cpp(24): error: variable "myMap" used in this "omp target" region is not bitwise copyable
        #pragma omp target map(to: myMap)
                                   ^

compilation aborted for unordered_map-omp-tgt-map.cpp (code 2)

You'll need to redesign your program to use the _Clik_shared/_Cilk_offload shared virtual memory model if you want to share non-bitwise copyable data types between host and coprocessor. 

On the other hand, if you just want to use such types directly on Phi, you can do that with #pragma offload/#pragma omp target:

#pragma offload_attribute (push, target (mic))
#include <iostream>
#include <unordered_map>
#pragma offload_attribute (pop)

int main () {

  #pragma offload target(mic)
  {
     where_running();

     std::unordered_map<std::string,std::string> mymap;
     mymap = {{"Australia","Canberra"},{"U.S.","Washington"},{"France","Paris"}};

     std::cout << "mymap contains:";

     for ( auto it = mymap.begin(); it != mymap.end(); ++it )
       std::cout << " " << it->first << ":" << it->second;

     std::cout << std::endl;

     std::cout << "mymap's buckets contain:\n";
     for ( unsigned i = 0; i < mymap.bucket_count(); ++i)
     {
       std::cout << "bucket #" << i << " contains:";

       for ( auto local_it = mymap.begin(i); local_it!= mymap.end(i); ++local_it )
         std::cout << " " << local_it->first << ":" << local_it->second;

       std::cout << std::endl;
     }
  }

  return 0;
}

 

[U543338]$ icc unordered_map-omp-tgt.cpp -std=c++11 -o unordered_map-omp-tgt.cpp.x
 

[U543338]$ ./unordered_map-omp-tgt.cpp.x
Using offload compiler :  Hello from the coprocessor
mymap contains: U.S.:Washington France:Paris Australia:Canberra
mymap's buckets contain:
bucket #0 contains:
bucket #1 contains:
bucket #2 contains: U.S.:Washington
bucket #3 contains: France:Paris Australia:Canberra
bucket #4 contains:
bucket #5 contains:
bucket #6 contains:
bucket #7 contains:
bucket #8 contains:
bucket #9 contains:
bucket #10 contains:
[U543338]$
 

Patrick

View solution in original post

0 Kudos
6 Replies
pbkenned1
Employee
1,680 Views

Thanks for reporting the issue. Rather than copy/paste, please attach something that can be compiled.  Obviously 7 left braces and 10 right braces indicate something missing at the top.

Patrick

[ISN_Forums]$ icpc -c foo.cpp -qopenmp -std=c++11
foo.cpp(6): error: expected a declaration
   {
   ^

foo.cpp(7): error: this pragma must immediately precede a statement
     #pragma omp section
             ^

foo.cpp(10): error: this pragma must immediately precede a statement
       #pragma offload target(mic) in (r : length(repetido.size()))

0 Kudos
manrique__luis
Beginner
1,680 Views

Hi Patrick, I'm sorry for that. I've tried to copy only a few lines, where the error occurs. Now I'll paste a code using the same variables that I was trying on my program.

*I now that I need to change my std::cout line in offload section

#include <iostream>
#include <unordered_map>
#pragma offload_attribute(push, target(mic))
#include<iostream>
#include <unordered_map>
#pragma offload_attribute(pop)

int main () {

  std::unordered_map<int, int> myMap;
  myMap[10] = 2000;

  #pragma omp parallel sections
  {

    #pragma omp section
    {
      for (int i = 0; i < 100; i++)
      {
        if (myMap) std::cout << myMap << "\n";
      }
    }
    #pragma omp section
    {
      #pragma offload target(mic) in (myMap)
        for (int i = 0; i < 100; i++)
        {
          if(myMap) std::cout << myMap << "\n";
        }
    }

  }

}


/*[user@host ~]$ icpc -std=c++11 -openmp unordered_map.cpp
unordered_map.cpp(20): error: variable "myMap" used in this offload region is not bitwise copyable
      #pragma offload target(mic) in (myMap)
                                      ^

compilation aborted for unordered_map.cpp (code 2)*/

 

0 Kudos
pbkenned1
Employee
1,680 Views

Luis,

Thanks for providing a compete example.  std::unordered_map<int, int> myMap; is not bitwise copyable (as is the case with most std:: entities), so the error message is correct.  You'll need to use shared virtual memory for such arbitrarily complex variables (eg, declare them_Clik_shared). 

Patrick

0 Kudos
manrique__luis
Beginner
1,680 Views

Patrick, when a variable is declared as _Clik_shared, I need to use in and out on pragma offload or the variable in shared virtual memory will  be acessible for both CPU and Phi?

Thanks!!!

0 Kudos
pbkenned1
Employee
1,681 Views

Hello Luis,

The shared virtual memory model doesn't use #pragma offload, but instead uses _Cilk_shared/_Cilk_offload constructs.  This is an entirely different way of offloading.  Functions and statically allocated data are given the _Cilk_shared attribute, and dynamically allocated data are allocated in shared memory.  This model is more complex than the #pragma offload model, but makes almost any C/C++ program viable for Phi applications.  Read all about it in the User's Guide -- search for 'Offload Using Shared Virtual Memory'

The #pragma offload model doesn't use virtual shared memory at all.  This is a data marshaling model which performs data exchanges between host and coprocessor.  This model doesn't use _Cilk_shared variables.

In the example you posted, you have:

 #pragma offload target(mic) in (myMap)

As we've seen, type std::unordered_map<int, int> is not bitwise copyable, so the compiler rejects this.

In the same way, if I were to replace '#pragma offload target(mic) in (myMap)' with the OpenMP equivalent construct:

#pragma omp target map(to: myMap)

You'll see the compiler reject that similarly, since list items must also be bitwise copyable:

    #pragma omp section
    {
//      #pragma offload target(mic) in (myMap)
      #pragma omp target map(to: myMap)
        for (int i = 0; i < 100; i++)
        {
          if(myMap) std::cout << myMap << "\n";
        }

 

[U543338]$ icc -std=c++11 -qopenmp unordered_map-omp-tgt-map.cpp
unordered_map-omp-tgt-map.cpp(24): error: variable "myMap" used in this "omp target" region is not bitwise copyable
        #pragma omp target map(to: myMap)
                                   ^

compilation aborted for unordered_map-omp-tgt-map.cpp (code 2)

You'll need to redesign your program to use the _Clik_shared/_Cilk_offload shared virtual memory model if you want to share non-bitwise copyable data types between host and coprocessor. 

On the other hand, if you just want to use such types directly on Phi, you can do that with #pragma offload/#pragma omp target:

#pragma offload_attribute (push, target (mic))
#include <iostream>
#include <unordered_map>
#pragma offload_attribute (pop)

int main () {

  #pragma offload target(mic)
  {
     where_running();

     std::unordered_map<std::string,std::string> mymap;
     mymap = {{"Australia","Canberra"},{"U.S.","Washington"},{"France","Paris"}};

     std::cout << "mymap contains:";

     for ( auto it = mymap.begin(); it != mymap.end(); ++it )
       std::cout << " " << it->first << ":" << it->second;

     std::cout << std::endl;

     std::cout << "mymap's buckets contain:\n";
     for ( unsigned i = 0; i < mymap.bucket_count(); ++i)
     {
       std::cout << "bucket #" << i << " contains:";

       for ( auto local_it = mymap.begin(i); local_it!= mymap.end(i); ++local_it )
         std::cout << " " << local_it->first << ":" << local_it->second;

       std::cout << std::endl;
     }
  }

  return 0;
}

 

[U543338]$ icc unordered_map-omp-tgt.cpp -std=c++11 -o unordered_map-omp-tgt.cpp.x
 

[U543338]$ ./unordered_map-omp-tgt.cpp.x
Using offload compiler :  Hello from the coprocessor
mymap contains: U.S.:Washington France:Paris Australia:Canberra
mymap's buckets contain:
bucket #0 contains:
bucket #1 contains:
bucket #2 contains: U.S.:Washington
bucket #3 contains: France:Paris Australia:Canberra
bucket #4 contains:
bucket #5 contains:
bucket #6 contains:
bucket #7 contains:
bucket #8 contains:
bucket #9 contains:
bucket #10 contains:
[U543338]$
 

Patrick

0 Kudos
manrique__luis
Beginner
1,680 Views

Patrick, thank you so much for spend your time writing this example. Your example was clear and functional, now I can understand better how Cilk works.

I will read some articles or a book about this subject and rewrite my code.
Thanks!

0 Kudos
Reply