如何通过#define在编译时获得CUDA Compute功能(版本)?例如,如果我使用__ballot并使用
nvcc -c -gencode arch=compute_20,code=sm_20 \
-gencode arch=compute_13,code=sm_13
source.cu
Run Code Online (Sandbox Code Playgroud)
我可以通过#define获取我的代码中的计算能力版本,以便选择带有__ballot的代码分支吗?
众所周知,Intel x86_64 处理器不仅是流水线架构,而且还是超标量架构。
这意味着 CPU 可以:
流水线- 在一个时钟下,执行一个操作的某些阶段。例如,与阶段转移并行的两个 ADD:
超标量- 在一个时钟上,执行一些不同的操作。例如,在同一阶段并行 ADD 和 MUL:

这是可能的,因为处理器有多个指令调度程序(英特尔酷睿有 4 个简单解码器)。
但是只有调度程序(4个简单解码器)的副本,还是算术单元的副本?
例如,我们可以在相同的阶段执行两个 ADD,但是在同一个 CPU 内核上的独立算术单元(例如,端口 0 上的 ALU 和端口 1上的ALU)?
是否有任何执行单元的副本,可以在同一个时钟执行两条相同的指令?
在现代x86_64 CPU上,AVX/SSE指数需要多少个时钟周期?
我是这样的: pow(x, y) = exp(y*log(x))
即两者兼而有之exp(),log()AVX x86_64指令需要一定的已知周期数?
_mm256_exp_ps()_mm256_log_ps()或者循环次数可能会根据指数级别而变化,是否有最大循环次数可以进行成本求幂?
有两个术语:
时间多线程:在细粒度时间多线程中,主处理器流水线可以包含多个线程,其中上下文切换有效地发生在管道级之间(例如,在桶处理器中).桶处理器是在每个周期内在执行线程之间切换的CPU.
超线程:是一种多线程,它允许单个处理器执行不同的线程,而无需同时真正执行它们.1这将其定性为时间切片或时间多线程而非同步多线程(SMT).观察到,由于长延迟事件,处理器的功能单元偶尔会在执行来自一个线程的指令时处于空闲状态.超线程试图通过执行来自另一个线程的指令来利用其他未使用的处理器周期,直到前一个线程准备好恢复执行.
TM和ST之间的主要区别在于,时间多线程(细粒度)使用C-slowing并在每个周期的执行线程之间切换,但是超线程在线程之间切换而不是每个周期并且仅在处理器的功能单元处于空闲状态时切换由于长延迟事件而从一个线程执行指令?
时间多线程(细粒度)和超线程之间有什么区别?
parallel-processing cpu concurrency multithreading cpu-architecture
蒂姆·哈里斯说:
\n\nhttps://en.wikipedia.org/wiki/Software_transactional_memory#Composable_operations
\n\n\n\n\n也许最基本的反对意见是基于锁的程序无法组合:正确的片段在组合时可能会失败。例如,考虑具有线程安全插入和删除操作的哈希表。现在假设我们要从表t1中删除一项A,并将其插入到表t2中;但中间状态(其中两个表都不包含该项)对于其他线程一定不可见。除非哈希表的实现者预见到这种需求,否则根本没有办法满足此要求。[...] 简而言之,单独正确的操作(插入、删除)不能组合成更大的正确操作。\xe2\x80\x94Tim Harris 等人,\n“可组合内存事务”,第 2 节:背景,第 2 页[6]
\n
这是什么意思?
\n\n如果我有 2 个哈希映射std::unordered_map和 2 个互斥体std::mutex(每个哈希映射一个),那么我可以简单地锁定它们: http: //ideone.com/6RSNyN
#include <iostream>\n#include <string>\n#include <mutex>\n#include <thread>\n#include <chrono>\n#include <unordered_map>\n\nstd::unordered_map<std::string, std::string> map1 ( {{"apple","red"},{"lemon","yellow"}} );\nstd::mutex mtx1;\n\nstd::unordered_map<std::string, std::string> map2 ( {{"orange","orange"},{"strawberry","red"}} );\nstd::mutex mtx2;\n\nvoid func() {\n std::lock_guard<std::mutex> lock1(mtx1);\n std::lock_guard<std::mutex> lock2(mtx2);\n\n std::cout << "map1: ";\n for (auto& x: map1) std::cout << " " << x.first << " => " << x.second << ", ";\n std::cout << std::endl …Run Code Online (Sandbox Code Playgroud) 众所周知:https://stackoverflow.com/a/32694707/1558037
页面1104:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
C++11§29.5/ 1说
有一个泛型类模板atomic.模板参数T的类型应该是可以轻易复制的(3.9).
§3.9告诉
标量类型,平凡可复制类类型(第9节),此类类型的数组以及这些类型的cv限定版本(3.9.3)统称为平凡可复制类型.
全文:
1 There is a generic class template atomic<T>. The type of the template argument T shall be trivially copyable (3.9). [ Note: Type arguments that are not also statically initializable may be difficult to use.
— end note ]
2 The semantics of the operations on specializations of atomic are defined in 29.6.
3 Specializations and instantiations of the atomic template shall have a deleted copy …Run Code Online (Sandbox Code Playgroud) 自C ++ 11起就知道有6个内存顺序,并且在文档中编写有关std::memory_order_acquire:
memory_order_acquire
具有此内存顺序的加载操作将在受影响的内存位置上执行获取操作:在此加载之前,无法重新排序当前线程中的任何内存访问。这样可确保在其他线程中释放相同原子变量的所有写操作在当前线程中可见。
1.非原子负载可以在atomic-acquire-load之后重新排序:
即,它不能保证非原子负载在获得原子负载后不能重新排序。
static std::atomic<int> X;
static int L;
...
void thread_func()
{
int local1 = L; // load(L)-load(X) - can be reordered with X ?
int x_local = X.load(std::memory_order_acquire); // load(X)
int local2 = L; // load(X)-load(L) - can't be reordered with X
}
Run Code Online (Sandbox Code Playgroud)
加载后int local1 = L;可以重新排序X.load(std::memory_order_acquire);吗?
2.我们可以认为非原子负载不能在atomic-acquire-load之后重新排序:
一些文章包含一幅图片,展示了获取释放语义的本质。这很容易理解,但是会引起混乱。
例如,我们可能认为std::memory_order_acquire不能对任何一系列的Load-Load操作进行重新排序,即使在atomic-acquire-load之后也无法对非atomic-load进行重新排序。
3.非原子负载可以在atomic-acquire-load之后重新排序:
澄清的好处是:Acquire语义可以防止对read-acquire进行任何以程序顺序进行的读或写操作对内存进行重新排序。http://preshing.com/20120913/acquire-and-release-semantics/
但也众所周知:在强排序的系统(x86,SPARC TSO,IBM大型机)上,大多数操作都是自动执行发布获取排序 …
众所周知,有两种锁定策略:乐观锁定与悲观锁定
悲观锁定是当您锁定记录以供您独占使用,直到您完成它为止。它比乐观锁具有更好的完整性,但要求您在应用程序设计时要小心以避免死锁。
还知道,乐观并发控制与多版本并发控制(Oracle 或 MSSQL-Snapshot/MVCC-RC)不同:乐观与多版本并发控制 - 差异?
但是如果在两个事务中都使用 OCC(乐观并发控制),是否会在两个事务之间发生死锁?
我们能说乐观锁通过降低一致性来降低死锁的可能性吗?并且只有当每个更新都在一个单独的事务中时,死锁的可能性才为 0%,但这样的一致性最小。
sql-server oracle locking optimistic-locking pessimistic-locking
众所周知,WaveFront (AMD OpenCL) 与 WARP (CUDA) 非常相似:http ://research.cs.wisc.edu/multifacet/papers/isca14-channels.pdf
GPGPU 语言,如 OpenCL™ 和 CUDA,被称为 SIMT,因为它们将程序员的线程视图映射到 SIMD 通道。在同一个 SIMD 单元上以锁步方式执行的线程称为波前(CUDA 中的扭曲)。
众所周知,AMD 建议我们使用本地内存(减少)添加数字。并且为了加速加法(减少)建议使用向量类型:http : //amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/01/AMD_OpenCL_Tutorial_SAAHPC2010.pdf
但是在WaveFront 中的项目(线程)之间是否有任何优化的寄存器到寄存器数据交换指令:
例如int __shfl_down(int var, unsigned int delta, int width=warpSize);在 WARP (CUDA):https : //devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/
或例如__m128i _mm_shuffle_epi8(__m128i a, __m128i b);x86_64 上的 SIMD 通道:https : //software.intel.com/en-us/node/524215
例如,此 shuffle 指令可以执行来自 8 个线程/通道的 8 个元素的 Reduce(相加数量),持续 3 个周期,无需任何同步且不使用任何缓存/本地/共享内存(具有约 3 个周期的延迟)每次访问)。
即线程将其值直接发送到其他线程的注册:https : //devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/
或者在 …
我们可以使用默认的 linux TCP/IP 堆栈对 TCP 发送/接收使用零拷贝吗?
例子:
int packet_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); // raw-sockets
struct tpacket_req3 req;
setsockopt(packet_socket, SOL_PACKET , PACKET_RX_RING , (void*)&req , sizeof(req));
mapped_buffer = (uint8_t*)mmap(NULL, req.tp_block_size * req.tp_block_nr,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, packet_socket, 0);
Run Code Online (Sandbox Code Playgroud)
那么我们是否可以将接收到有效载荷的套接字缓冲区的一部分从内核空间映射到用户空间以避免零复制?