- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这里是 CUDA 的新手,但希望它的使用可以减少单线程 CPU 代码计算均方根所需的时间(具体来说,每个 u
连续不相交的 RMS长度为 v
的子数组包含在长度为 u*v
的数组 A
中,在 1 和 -1 之间 float 。
我曾希望使用 this示例来完成绝大多数工作*,但我发现即使是将 A
的子数组与 0
分开的第一步也是为了内存合并目的(这我正在通过单线程 CPU 代码进行)比使用“ballpark”值 u=200、v=5000 的整个基于 CPU 的 RMS 计算花费的时间更长!
我隐约意识到可能有一种方法可以同时应用填充 A
被复制到设备内存,因为我认为也许可以使用第二个内核来执行填充,但我不确定探索这些方法是否值得。我也知道 Thrust 和 cuBLAS,但在我简单的头脑中,链接的样本似乎更有可能提供所需的加速(假设必须小心准备内核输入)。
上面的“大概”值(类似于示例中的值)是否太小以至于无法让 GPU 发挥作用?唉,这两个数字都不太可能提高到 10 的下一个幂。非常感谢那些比我更熟悉 GPU 计算的人提供的任何意见。 FWIW,这是我试图改进的单线程 CPU 代码(rms
函数)和它的一些上下文:
const size_t num = 5000; // might be able to increase by a factor of <2
const size_t numSegs = 200; // might be able to increase by a factor of <5
float rms(const float a[], const size_t origin, const size_t length)
{
float sumOfSquares = 0.0f;
for (size_t i = 0; i < length; ++i)
sumOfSquares += a[origin + i] * a[origin + i];
return std::sqrt(sumOfSquares / float(length));
}
int main()
{
...
float* array = (float*)malloc(num * numSegs * sizeof(float));
float* RMSes = (float*)malloc(numSegs * sizeof(float));
// array fill omitted; A[i] lies between -1 and 1 inclusive
for (size_t segNum = 0; segNum < numSegs; ++segNum)
{
RMSes[segNum] = rms(array, segNum * num, num);
}
...
}
*假设 RMS(A)=sqrt(B/C),其中 B 是“A 点 A”,C 是 A 的长度
编辑:基于 CUDA 的方法确实有效,但目前比主机代码慢很多
编辑(再次):
objective-c PU:x86
目标 GPU:RTX3070(计算能力为 8.6 的“Ampere”)
执行时间:
在 main()
中循环(上图):2227-2259us(6 次运行)
使用 dot_product_avx2
在 main()
中循环 @Michael Roy 的回答:445-491us(3 次运行)
填充 array[]
:2279-3748us(6 次运行)
this 的第 119-134 行(不是通过 &hTimer
的行)+ 使用 h_C_GPU
计算 RMS:2050-2306us(3 次运行)
this 的第 119-134 行(不是通过 &hTimer
的行)+ 使用 h_C_GPU
without padding array[]
计算 RMS:2125-2382us (3运行)
看到填充对基于 GPU 的方法的影响如此之小,我感到非常惊讶(尽管示例建议“ElementN 强烈推荐为 warp 大小的倍数以满足内存合并的对齐约束”)
并行代码只是链接示例的最小修改版本。 VECTOR_N
对应于 u
,ELEMENT_N
对应于大于 v
且可被 warp 大小整除的最小数字, cudaMemcpyHostToDevice
只出现一次,A[i]
可能为负数,StopWatchInterface
相关代码省略,h_C_GPU
中的每个点积> 用于计算 RMS 值。
最佳答案
这是一个使用 Thrust/CUB 的实现。它应该作为您提出的任何 CUDA 解决方案的性能引用。由于 CUB 算法不知道问题的规律性,因此理论上完全可以编写比这个更快的 CUDA 实现。但在实践中,通过此引用获得显着加速可能非常重要。
这个问题完全适合 GPU 计算,但您的问题规模可能仍然太小,GPU 无法发挥作用。
我决定在这里使用 cub::DeviceSegmentedReduce
而不是 thrust::reduce_by_key
(在后端使用 CUB)以获得更好的性能,因为它更容易获得围绕测量分配临时存储的开销。
#include <cmath>
#include <iostream>
#include <cub/cub.cuh>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/iterator/transform_output_iterator.h>
#include <thrust/random.h>
#include <thrust/random/uniform_real_distribution.h>
constexpr size_t num = 5000; // might be able to increase by a factor of <2
constexpr size_t numSegs = 200; // might be able to increase by a factor of <5
template <typename T>
class ScaleBy
{
T factor_;
public:
ScaleBy(T factor) noexcept : factor_{factor} {}
__host__ __device__
T operator()(T val) const noexcept { return factor_ * val; }
};
template <typename T>
struct Square
{
__host__ __device__
T operator()(T val) const noexcept { return val * val; }
};
template <typename T>
class RootMean
{
T norm_;
public:
RootMean(T norm) noexcept : norm_{norm} {}
__host__ __device__
T operator()(T sum) const noexcept { return sqrt(sum / norm_); }
};
void segmented_rms_device(thrust::device_vector<float> const &d_array,
thrust::device_vector<float> &d_RMSes,
uint8_t *d_temp_storage,
size_t &temp_storage_bytes)
{
auto seg_size = d_array.size() / d_RMSes.size();
auto origin_iter = thrust::make_transform_iterator(
thrust::make_counting_iterator(0ull),
ScaleBy<size_t>{seg_size});
auto input_iter = thrust::make_transform_iterator(
d_array.cbegin(),
Square<float>{});
auto output_iter = thrust::make_transform_output_iterator(
d_RMSes.begin(),
RootMean<float>{static_cast<float>(seg_size)});
cub::DeviceSegmentedReduce::Sum(d_temp_storage,
temp_storage_bytes,
input_iter,
output_iter, numSegs,
origin_iter, origin_iter + 1);
}
float rms(thrust::host_vector<float> const &a, const size_t origin, const size_t length)
{
float sumOfSquares = 0.0f;
for (size_t i = 0; i < length; ++i)
sumOfSquares += a[origin + i] * a[origin + i];
return std::sqrt(sumOfSquares / float(length));
}
void segmented_rms_host(thrust::host_vector<float> const &array,
thrust::host_vector<float> &RMSes)
{
for (size_t segNum = 0; segNum < numSegs; ++segNum)
{
RMSes[segNum] = rms(array, segNum * num, num);
}
}
int main()
{
thrust::default_random_engine rng(123456789);
thrust::uniform_real_distribution<float> dist(-1.0f, 1.0f); // excludes 1.0f, but ok for testing
thrust::host_vector<float> array(num * numSegs);
thrust::host_vector<float> RMSes_ref(numSegs);
for (size_t i = 0ull; i < array.size(); ++i)
{
array[i] = dist(rng);
}
segmented_rms_host(array, RMSes_ref);
thrust::device_vector<float> d_array(array);
thrust::device_vector<float> d_RMSes(numSegs);
// Determine temporary device storage requirements
size_t temp_storage_bytes = 0;
segmented_rms_device(d_array, d_RMSes, nullptr, temp_storage_bytes);
// Allocate temporary storage
thrust::device_vector<uint8_t> d_temp_storage(temp_storage_bytes);
segmented_rms_device(d_array, d_RMSes,
thrust::raw_pointer_cast(d_temp_storage.data()), temp_storage_bytes);
thrust::host_vector<float> RMSes(d_RMSes);
for (size_t i = 0ull; i < numSegs; ++i)
{
if (std::abs(RMSes_ref[i] - RMSes[i]) / RMSes_ref[i] > 1.0e-4f)
{
std::cout << "Big deviation detected at i = " << i
<< ": RMS_ref = " << RMSes_ref[i]
<< " while RMS = " << RMSes[i] << '\n';
}
}
return 0;
}
关于c++ - CUDA 'dot product' 内核能否加速批量 RMS 计算?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75104734/
总的来说,我对 Linux 内核和操作系统非常感兴趣。我想知道的是,内核的文件类型或扩展名是什么?它显然没有 .exe 或 .out 扩展名,因为它们用于安装在操作系统上的应用程序。 内核只是一个二进
我需要为 Raspbian Linux 内核添加一个自己的系统调用。现在我在搜索了大约 2 天以找到解决方案后陷入困境。 要加一个系统调用,我基本上是按照大纲来的( http://elinux.org
对于一个学术项目,我希望将源文件 (myfile.c) 添加到 kernel/目录,与exit.c相同的目录和 fork.c .构建系统似乎不会自动获取新文件,因为我在 myfile.c 中定义的函数
浏览器排行榜 浏览器市占率排行榜全球榜 。 浏览器市占率排行榜中国榜 -快科技 。 如果按照浏览器内核来看, Chromium 内核的市场占有率无疑是最大的,一家独大
给定一个进程或线程的任务结构,迭代属于同一进程的所有其他线程的习惯用法是什么? 最佳答案 Linux 不区分进程(任务)和线程。库调用 fork() 和 pthread_create() 使用相同的系
我正在用c(不是linux。完全从头开始)从头开始制作一个内核,但我遇到了一些问题。我有这个代码: #include "timer.h" int ms = 0; void timer_handler(
我正在从头开始制作一个 C 内核,我实际上只是从网站上复制了这段代码,因为我的代码无法工作,所以我很困惑。 void kmain(void) { const char *str = "my f
我不确定,如果我完全理解上述差异,所以我想自己解释一下,你可以打断我,只要我有错:“内核是创建内核线程的初始代码段。内核线程是由内核管理的进程。用户线程是进程的一部分。如果你有一个单线程进程,那么整个
看一下struct file 定义from this code Linux 内核版本 2.6.18。 我正在尝试比较代码中的两个 struct file 变量,并确定它们是否指的是同一个文件。该结构中
我试图在 Linux 启动时使嵌入式设备中的 LED 闪烁。基本上,LED 闪烁表明 Linux 正在启动。为了使 LED 闪烁,我正在做以下事情 在 init/main.c 中创建了一个全局定时器(
我有一些在 FreeBSD 和 Linux 上运行的特定硬件。 我必须做一个用户空间应用程序,它将使用内核/用户空间应用程序之间的共享内存与驱动程序一起工作。我的应用程序对来自用户空间的共享内存进行忙
我在哪里可以找到 linux 内核中相应函数的解释,特别是对于 ICMPv4? 例如:icmp_reply、icmp_send等 感谢您的帮助。 最好的,阿里木 最佳答案 探索 Linux 内核中的
我在 Linux Kernel 3.4 上工作,我有以下代码: /* Proximity sensor calibration values */ unsigned int als_kadc;
我正在阅读“罗伯特·洛夫 (Robert Love) 撰写的 Linux 内核开发第 3 版”,以大致了解 Linux 内核的工作原理..(2.6.2.3) 我对等待队列的工作方式感到困惑,例如这段代
我之前也问过同样的问题,但是我的帖子不知为何被删除了。 无论如何,我正在尝试使用 C++ 并编写一个允许我直接访问内存并向其中写入内容的程序。我听说我需要对内核做一些事情,因为它是连接操作系统和应用程
在尝试了解 Ruby 执行方法时,我找到了这篇关于在 Ruby 中运行命令的五种方法的博文 http://mentalized.net/journal/2010/03/08/5_ways_to_run
是否有 Linux 发行版(Minix 除外)包含良好的源代码文档?或者,是否有一些好的文档来描述一般的 Linux 源代码? 我已经下载了内核源代码,但是(不出所料)我有点不知所措,我想知道是否有一
有谁知道 linux 中的哪个函数或文件包含查找用于 bind() 系统调用的随机端口的算法?我到处寻找,在 Linux 源代码中找不到包含此算法的方法。 谢谢! 最佳答案 这是一段又长又复杂的代码,
前言 首先,对于有科班背景的读者,可以跳过本系列文章。这些文章的主要目的是通过简单易懂的汇总,帮助非科班出身的读者理解底层知识,进一步了解为什么在面试中会涉及这些底层问题。否则,某些概念将始终
CentOS7.2与CentOS6区别及特点 Linux 操作系统的启动首先从 BIOS 开始,接下来进入 boot loader,由 bootloader 载入内核,进行内核初始化。内核初始化的
我是一名优秀的程序员,十分优秀!