Intel® C++ Compiler
Support and discussions for creating C++ code that runs on platforms based on Intel® processors.
Announcements
This community is designed for sharing of public information. Please do not share Intel or third-party confidential information here.

OpenMP task problem

xwuupb
Novice
830 Views

Hi, the following simple C and Fortran code compiled by Intel C and Fortran compilers gives runtime errors. Could you please take a look? Thank you in advance!

C code:

#include <stdio.h>
#include <omp.h>

#define NBALLS ( 8ULL)
#define MBOXES ( 4ULL)
#define ZERO   ( 0ULL)
#define ONE    ( 1ULL)

typedef unsigned long long int ui64;

void bb(ui64 nballs, ui64 mboxes, ui64 *n)
{
  if (ONE == mboxes) {
#pragma omp atomic
    ++*n;
  } else {
    for (ui64 iball = ZERO; iball <= nballs; ++iball)
#pragma omp task default(none) firstprivate(iball, mboxes) shared(n)
      bb(iball, mboxes - 1, n);
  }
}

int main(void)
{
  ui64 n = ZERO;

#pragma omp parallel default(none) shared(n)
#pragma omp single nowait
  bb(NBALLS, MBOXES, &n);
  printf("n = %llu\n", n);
  return 0;
}

Fortran code:

recursive subroutine bb(nballs, mboxes, n)
  implicit none
  integer(kind = 8), intent(in)    :: nballs, mboxes
  integer(kind = 8), intent(inout) :: n
  integer(kind = 8):: iball

  if (1 .eq. mboxes) then
!$omp atomic
    n = n + 1
!$omp end atomic
  else
    do iball = 0, nballs
!$omp task default(none) firstprivate(iball, mboxes) shared(n)
      call bb(iball, mboxes - 1, n)
!$omp end task
    end do
  endif
  return
end subroutine bb

program main
  use omp_lib
  implicit none
  integer(kind = 8), parameter :: nballs = 8, mboxes = 4
  integer(kind = 8):: n = 0

!$omp parallel default(none) shared(n)
!$omp single
  call bb(nballs, mboxes, n)
!$omp end single nowait
!$omp end parallel
  print *, "n = ", n
  stop
end program main
0 Kudos
1 Solution
Viet_H_Intel
Moderator
684 Views

Here are feedback from our Developer:


The problem with this test is the shared function parameter. That is:

the function parameter is located on stack;

created OpenMP tasks store address of shared function parameter in order to use it at execution time;

then a thread which created first set of tasks exits the function making stored by tasks stack address invalid;

then, when tasks are executed they access stale memory that may have unspecified value. 


Possible fixes:


change: #pragma omp task default(none) firstprivate(iball, mboxes) shared(n)

to:  #pragma omp task default(none) firstprivate(iball, mboxes, n)


or add #pragma omp taskwait at the end of "bb" routine making address on pointer "n" valid during tasks execution.


Let us know so that we can close this thread as it's not a compiler bug.


Thanks,



View solution in original post

9 Replies
jimdempseyatthecove
Black Belt
806 Views

I am surprised the C code compiled. line 11 has "ui64 *n" and line 19 has ", n)". IOW your call to bb is passing value "n" as opposed to "&n" as does the call to bb at line 29. You should have seen a compile time error as opposed to a runtime error. (though if the compiler did not report an error at compile time, it is likely that at runtime an error would be encountered either hidden or exposed).

 

The Fortran code is correct as it passes n by reference.

 

 

Jim Dempsey

xwuupb
Novice
789 Views

Thanks for your reply. But I see no problem in my C code:

  • line 11: the last formal argument is a pointer (n is a pointer).
  • line 19: the recursive function call passes n, which is a pointer, to bb. (I see no problem.)
  • line 29: the actual argument passed to bb is the address of the variable n, which is a pointer.

Therefore, the main function puts the address of n to bb (line 29). Then line 11 gets the address. If only one box remains (line 13), then the counter is incremented (line 15, ++*n; // n stores the address of the variable n in main). Otherwise call bb recursively with the pointer n (line 19 and please note that n stores the address of the variable n in main and it is consistent with line 11).

Hopefully the explanation makes the code clear.

VidyalathaB_Intel
Moderator
725 Views

Hi,

Thanks for reaching out to us.

>>compiled by Intel C and Fortran compilers

Could you please tell us which C and Fortran compilers you are using to run the codes

Regarding the fortran code, could you please try it using ifx compiler, as it is not showing any run time errors when checked from our end.

>> gives runtime errors

Meanwhile we are looking into this issue internally. we will get back to you soon.

Regards,

Vidya.




xwuupb
Novice
707 Views

Hi, thank you for the reply!

  • the OS is "5.4.0-66-generic #74~18.04.2-Ubuntu SMP"
  • the packages of "intel-oneapi-*" version 2021.3.0-3350 is installed via apt-get

I also tried "ifx -qopenmp". Sometimes the executable gives the correct answer (n = 165), but not always.

Thank you again for your effort!

Viet_H_Intel
Moderator
691 Views

Thanks for letting us know this issue. I've reported it to our Developer.

 

Viet_H_Intel
Moderator
685 Views

Here are feedback from our Developer:


The problem with this test is the shared function parameter. That is:

the function parameter is located on stack;

created OpenMP tasks store address of shared function parameter in order to use it at execution time;

then a thread which created first set of tasks exits the function making stored by tasks stack address invalid;

then, when tasks are executed they access stale memory that may have unspecified value. 


Possible fixes:


change: #pragma omp task default(none) firstprivate(iball, mboxes) shared(n)

to:  #pragma omp task default(none) firstprivate(iball, mboxes, n)


or add #pragma omp taskwait at the end of "bb" routine making address on pointer "n" valid during tasks execution.


Let us know so that we can close this thread as it's not a compiler bug.


Thanks,



xwuupb
Novice
662 Views

Hi, thanks for your quick response! Your explanation is clear and the fixes work as well.

 

Normally the shared variable is created by malloc in C or allocate in Fortran and thus it is on the heap. Nevertheless the OpenMP Specification has no requirement for the shared variable, that it must be on the heap or be on the stack. Anyway you can close this thread.

jimdempseyatthecove
Black Belt
646 Views

Good catch.

It is the difference between the pointer (C) or reference (Fortran) being shared (not desired) as opposed to that which it points to/references (desired behavior).

Jim Dempsey

Viet_H_Intel
Moderator
640 Views

This issue has been resolved and we will no longer respond to this thread. If you require additional assistance from Intel, please start a new thread. Any further interaction in this thread will be considered community only.

Thanks,


Reply