【问题标题】:calling a __host__ function from a __host__ __device__ function从 __host__ __device__ 函数调用 __host__ 函数
【发布时间】:2020-10-29 18:40:05
【问题描述】:

编译 MWE 时

#include <iostream>
#include "cuda.h"

struct Foo{
///*
    Foo( ){
      std::cout << "Construct" << std::endl;
    }

    Foo( const Foo & that ){
      std::cout << "Copy construct" << std::endl;
    }
//*/
   __host__ __device__
   int bar( ) const {
     return 0;
   }
};

template<typename CopyBody>
__global__ 
void kernel( CopyBody cBody ){
  cBody( );
}

template <typename CopyBody>
void wrapper( CopyBody && cBody ){
  std::cout << "enquing kernel" << std::endl;
  kernel<<<1,32>>>( cBody );
  std::cout << "kernel enqued" << std::endl;
}

int main(int argc, char** argv) {

  Foo foo;

  std::cout << "enquing kernel" << std::endl;
  kernel<<<1,32>>>( [=] __device__ ( ) { foo.bar( ); } );
  std::cout << "kernel enqued" << std::endl;
  cudaDeviceSynchronize( );

  wrapper( [=] __device__ ( ) { foo.bar( ); } );
  cudaDeviceSynchronize( );
  
  return 0;
}

对于 CUDA 10.1 (nvcc --expt-extended-lambda test.cu -o test),编译器会针对 test.cu(16): warning: calling a __host__ function("Foo::Foo") from a __host__ __device__ function("") is not allowed 发出警告。但是,永远不会在设备上调用复制构造函数。 CUDA 9.1 不会产生此警告。

  • 直接调用kernel(不产生警告)和wrapper版本有什么区别?
  • 忽略此警告是否安全?
  • #pragma hd_warning_disable#pragma nv_exec_check_disable 放在哪里可以摆脱它?

给定的 MWE 是基于一个更大的项目,其中wrapper 决定是使用__device__ 还是__host__ lambda。构造函数/析构函数不能标记为__host__ __device__,因为它们只需要在 CPU 上调用((取消)分配 CUDA 内存) - 这或删除构造函数/析构函数(并让编译器创建默认的 __host__ 和 @ 987654333@ 版本)否则会有所帮助。

【问题讨论】:

    标签: cuda nvcc


    【解决方案1】:

    通过以下修改,我没有得到提及的警告:(我在 Windows 10 上使用了 CUDA 10.1)

    #include <stdio.h>
    
    #include "cuda_runtime.h"
    #include "device_launch_parameters.h"
    
    struct Baz {
    
       Baz() {
          printf("%s: Construct\n", __FUNCTION__);
       }
    
       Baz(const Baz & that) {
          printf("%s: Copy Construct\n", __FUNCTION__);
       }
    
    };
    
    struct Foo: 
       public Baz {
    
       __host__ __device__ 
       int bar() const  {
          return 0;
       } 
    };
    
    template<typename CopyBody>
    __global__
    void kernel(CopyBody cBody) {
       cBody();
    }
    
    template <typename CopyBody>
    void wrapper(CopyBody && cBody) {
       printf("%s: enquing kernel\n",__FUNCTION__);
       kernel << <1, 32 >> > (cBody);
       printf("%s: kernel enqued\n", __FUNCTION__);
    }
    
    int main(int argc, char** argv) {
    
       Foo foo;
    
       printf("%s: enquing kernel\n", __FUNCTION__);   
       kernel << <1, 32 >> > ([=] __device__() { foo.bar(); });
       printf("%s: kernel enqued\n", __FUNCTION__);   
       cudaDeviceSynchronize();
    
       wrapper([=] __device__() { foo.bar(); });
       cudaDeviceSynchronize();
    
       return 0;
    }
    

    以上代码产生以下输出:

    Foo::Foo: Construct
    main: enquing kernel
    Foo::Foo: Copy Construct
    Foo::Foo: Copy Construct
    main: kernel enqued
    Foo::Foo: Copy Construct
    Foo::Foo: Copy Construct
    wrapper: enquing kernel
    Foo::Foo: Copy Construct
    wrapper: kernel enqued
    

    为方便起见,我将&lt;iostream&gt; 替换为&lt;stdio.h>。 printf() 在内核中工作。

    【讨论】:

    • 嗨,谢谢。但是,正如我上面所描述的,构造函数/析构函数不能标记为__host__ __device__,因为它们只需要在 CPU 上调用((取消)分配 CUDA 内存)。
    • 嗨,Jan,我确认没有在设备上调用 ctors,尽管有标记。无论如何,我重新安排了代码以确保仅在 CPU 上调用 ctor。
    • 是的,感谢您的努力,但不幸的是,该帖子没有回答任何问题。
    • Jan,您的问题与恕我直言无关。 1)假设直接调用产生警告,包装调用不。不是这种情况。 2)修复代码后,没有警告可以忽略。 3)您不需要那些编译指示来忽略不存在的警告。
    • Laszlo,我很抱歉,但你真的把这个问题作为一个整体阅读了吗?我不能将 ctor 标记为 _device_ 函数,因为它调用 CUDA 内存分配。提供的代码只是用于查看警告的 MWE。此外,还有一些我不完全理解的方面,比如调用复制 ctor 的次数。
    猜你喜欢
    • 2021-08-30
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多