优化寄存器/L1中数据的每线程复制和0填充
Optimizing per-thread copying and 0-padding of data in registers/L1
我正在编写一个内核,它让每个线程用构成低位字节的数据填充一个变量,并填充其余部分(假设字节序很小)。这是在多个线程之间重复而非一致地完成的,因为有些线程可能有更多的字节要复制到其变量中,而填充量较小,而有些线程则需要复制的字节较少,填充量较大。结果和未填充的数据要么在寄存器中(对于较小的大小),要么在共享内存中,要么在本地内存中(应该由L1覆盖)。
换句话说,假设每个线程都执行:
T padded;
pad_high_bytes(padded, my_low_bytes, my_num_low_bytes);
do_stuff(padded);
我们有:
template <typename T>
__device__ __forceinline__
void pad_high_bytes(
T& result,
const unsigned char* __restrict__ low_bytes,
unsigned num_low_bytes);
如果T
很大(比如说struct { int data[50]; }
),那么我想我可能应该只使用CUDA的设备代码memcpy()
。然而,通常情况并非如此——T的大小通常为4或8,低字节数通常在1到3之间,甚至0也不罕见。
很明显,我可以在字节上循环,并抱着最好的希望。我也可以"在int上循环",只要还有超过4个字节要复制,然后在剩余的字节上循环。但是:
- 我能做得更好吗
- 我应该以某种方式解释对齐吗?还是麻烦太多了
- 复制和填充在代码中应该完全分开,还是应该以某种方式将它们组合在一起
- 切换到memcpy()的sizeof(T)的合理值是多少
记住,函数是在结果类型上模板化的,所以如果你只对较小/较大的T有意见,那会很有帮助。
我真的很难理解Q1-3是如何真正负责的,它可以被解释为"我的话是这个模糊描述的任务的最佳设计吗"。所以我甚至都不打算尝试。
Q4应负责:
设备侧memcpy
(或设备侧cudaMemcpy
,它只是memcpy
的一个薄薄的包装器)总是发出一个执行逐字节复制的循环。当您在编译时知道要复制的类型的大小时,总是可以通过自己编写复制循环来做得更好,该循环利用关于类型大小的先验知识(受对齐约束等)。如果你知道类型的大小和要复制的单词的数量,那么除了字节大小的事务之外,你还可以利用循环展开来做得更好
如果您不知道这两件事中的任何一件,那么memcpy
仍然是最佳选择,因为它简化了代码,并为工具链中的幕后惯用优化开辟了可能性。我唯一反对的一次是,如果你有机会将其他操作与副本融合在一起,在这种情况下,自己做一些事情可能仍然有意义。
- 适用于大型数组的无复制线程安全环形缓冲区
- std::shared_ptr::unique(),复制和线程安全
- 如何在不复制列表的情况下将列表传递给线程,同时销毁原始列表
- 多线程和共享资源:使用C++定期将数据从缓冲区(数据结构)复制到文件
- unordered_map中的C 线程(无复制构造函数)
- C 11线程汇编错误传递字符串作为复制的引用
- 标准::atomic_应该如何...<std::shared_ptr>用于线程安全类的复制和移动操作?
- CUDA 将大于线程计数的数组复制到共享内存
- 优化寄存器/L1中数据的每线程复制和0填充
- 为什么对于简单的数组复制来说,没有多线程加速
- 复制/调试一些多线程地狱
- C 11 STD :: Promise返回STD :: String从线程中返回String,数据指针看起来已复制
- 分叉式堆栈复制线程C++
- boost中的线程安全可复制循环缓冲区
- 如何停止std/boost::线程复制我的对象而不是传递引用
- C++11 std:原子<T>复制构造函数的线程安全性
- 复制提升::跨线程崩溃的异常
- 为什么 c++ 线程是可移动的,但不可复制
- std::带可移动、不可复制参数的线程
- 是复制线程安全的