c++ - 为什么 std::sin() 在 CUDA 内核中工作?
问题描述
以下代码编译(使用nvcc test.cu -o test
)并运行没有错误,这意味着它std::sin()
可以在设备上运行:
#include <cmath>
#include <vector>
#include <cassert>
#include <numeric>
__global__ void map_sin(double* in, double* out, int n) {
const int i = blockIdx.x * 512 + threadIdx.x;
if (i < n) {
out[i] = std::sin(in[i]);
}
}
int main() {
const int n = 1024;
std::vector<double> in(n), out(n);
std::iota(in.begin(), in.end(), 1.);
double *in_, *out_;
cudaMalloc(reinterpret_cast<void**>(&in_), n * sizeof(double));
cudaMemcpy(in_, in.data(), n * sizeof(double), cudaMemcpyHostToDevice);
cudaMalloc(reinterpret_cast<void**>(&out_), n * sizeof(double));
map_sin<<<n / 512, 512>>>(in_, out_, n);
cudaMemcpy(out.data(), out_, n * sizeof(double), cudaMemcpyDeviceToHost);
cudaFree(in_);
cudaFree(out_);
for (int i = 0; i != 10; ++i) {
assert(std::abs(out[i] - std::sin(in[i])) < 1e-3);
}
}
为什么?如何?根据这个答案,CUDA 内核应该只能调用__device__
函数。编译时以某种std::sin()
方式标记?__device__
nvcc
解决方案
用 nvcc 编译时
std::sin()
以某种方式标记?__device__
不。它显然被sin
传递给GPU编译器的代码中的CUDA前端解析器替换,然后使用正常的重载机制来确保替换正确的GPU数学库函数。GPU 编译器看到的代码是(nvcc 版本 11.1.74):
__global__ __var_used__ void _Z7map_sinPdS_i( double *in, double *out, int n)
{
{
int __cuda_local_var_31644_13_non_const_i;
__cuda_local_var_31644_13_non_const_i = ((int)(((blockIdx.x) * 512U) + (threadIdx.x)));
if (__cuda_local_var_31644_13_non_const_i < n)
{
(out[__cuda_local_var_31644_13_non_const_i]) = (sin((in[__cuda_local_var_31644_13_non_const_i])));
}
}
}
如您所见,没有命名空间。
为什么?如何?
它没有记录,我也没有关于实现细节的特殊内幕信息,但我猜对于<cmath>
(CUDA 数学库具有 C++11 标准中定义的所有内容的实现)的内容,命名空间只是脱光,一切正常。对于其他 C++ 标准库函数,这是不可能发生的,您将遇到您期望的那种编译失败。
推荐阅读
- json - 从 Oracle 12c Enterprise Ed (12.1.0) 中的列值生成 JSON - 64 位
- r - 为流程中跳过的阶段添加行
- ios - 如何在 WKWebView 中自动播放 youtube 视频?
- pandas - 如何在操作后将两个 NaN 设为 NaN 而不是将其设为零?
- java - 用于插入 css 的 mvc 资源中的错误
- spring - configuration.setAllowedOrigins 不允许定义多个域名
- typescript - 打字稿将减速器类型转换为动作
- android - 即使我在发送意图时坐在 putExtra 上,意图在 MyAlarm 类的 onReceive 中为空
- python-3.x - “模块”对象在合并函数中不可调用
- c++ - 每个缓冲区或整个程序的大小前缀是什么?