将推力与 printf / cout 一起使用

Posted

技术标签:

【中文标题】将推力与 printf / cout 一起使用【英文标题】:Using thrust with printf / cout 【发布时间】:2016-08-19 17:21:40 【问题描述】:

我正在尝试学习如何将 CUDA 与推力一起使用,并且我看到了一些似乎在设备上使用了 printf 函数的代码。

考虑这段代码:

#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <cstdio>

struct functor

  __host__ __device__
  void operator()(int val)
  
      printf("Call for value : %d\n", val);
  
;

int main()

    thrust::host_vector<int> cpu_vec(100);
    for(int i = 0 ; i < 100 ; ++i)
      cpu_vec[i] = i;
    thrust::device_vector<int> cuda_vec = cpu_vec; //transfer to GPU
    thrust::for_each(cuda_vec.begin(),cuda_vec.end(),functor());

这似乎运行良好,并打印了 100 次消息“呼吁价值:”,后跟一个数字。

现在,如果我包含 iostream 并将 printf 行替换为基于 C++ 流的等效项

std::cout << "Call for value : " << val << std::endl;

我从 nvcc 收到编译警告,编译后的程序不会打印任何内容。

warning: address of a host variable "std::cout" cannot be directly taken in a device function
warning: calling a __host__ function from a __host__ __device__ function is not allowed
warning: calling a __host__ function("std::basic_ostream<char, std::char_traits<char> >::operator <<") from a __host__ __device__ function("functor::operator ()") is not allowed
    为什么它可以与 printf 一起使用? 为什么它与 cout 一起工作? GPU 上实际运行的是什么?我猜,至少发送到标准输出需要一些 CPU 工作。

【问题讨论】:

printf 被“重载”为 __device__ 函数,而 cout 不是。您需要显式“重载”打印功能,因为您需要正确处理输出缓冲区。看一下simplePrintf 示例,您就会对为什么需要显式重载以及如何做到这一点有所了解。由于cout 只是__host__ 函数,nvcc 无法编译它。 【参考方案1】:
    为什么它可以与 printf 一起使用?

因为 NVIDIA 为所有支持设备 ABI(计算能力 >= 2.0)的硬件添加了对内核中 printf 的运行时支持。在提供(几乎)标准 C 风格 printf 功能的设备代码中存在主机 printf 的模板重载。您必须在设备代码中包含 cstdiostdio.h 才能使此机制起作用。

    为什么它不适用于 cout?

因为 NVIDIA 尚未在 CUDA 设备运行时内实现任何形式的 C++ iostream 样式 I/O 支持。

    GPU 上实际运行的是什么?

设备运行时维护一个 FIFO 缓冲区,供内核代码在内核执行期间通过 printf 调用写入。设备缓冲区由 CUDA 驱动程序复制并在内核执行结束时回显到标准输出。确切的启发式和机制没有记录,但我假设格式字符串和输出存储到 FIFO 缓冲区,然后由 CPU 驱动程序解析,然后通过内核启动 API 的某种回调进行打印。运行时 API 提供了一个function 用于控制 printf FIFO 的大小。

【讨论】:

是否包含 cstdio 或 stdio.h 仅用于编译为目标代码?链接阶段是否会发生设备版本的printf重载?

以上是关于将推力与 printf / cout 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

push_back 使用推力库

如何将向量传递给基于推力的 odeint 观察者的构造函数,以便可以在函子中读取它

我必须做啥才能将 cout 与 opencv 一起使用?

在推力函子中使用 CURAND

我可以将 printf 与 PSTR 一起使用吗?

推力::设备向量使用推力::替换或推力::转换与自定义函子/谓词