我目前正在尝试使用多个内核进行编程。我想用C ++ / Python / Java编写/实现并行矩阵乘法(我猜Java是最简单的)。
但我自己无法回答的一个问题是RAM访问如何与多个CPU配合使用。
我们有两个矩阵A和B.我们想要计算C = A * B:
当n,m或p很大时,并行执行只会更快。因此假设n,m和p> = 10,000。为简单起见,假设n = m = p = 10,000 = 10 ^ 4.
我们知道我们可以计算每个$ c_ {i,j} $而不用查看C的其他条目。所以我们可以并行计算每个c_ {i,j}:
但是所有c_ {1,i}(i \ in 1,...,p)都需要A的第一行。由于A是一个10 ^ 8双精度数组,它需要800 MB。这绝对比CPU缓存大。但是一行(80kB)将适合CPU缓存。所以我想将每一行C分配给一个CPU(一旦CPU空闲)就是个好主意。因此,这个CPU至少会在其缓存中使用A并从中受益。
如何针对不同的内核(在普通的英特尔笔记本电脑上)管理RAM访问?
我想必须有一个“控制器”,一次可以独占访问一个CPU。这个控制器有一个特殊的名字吗?
偶然地,两个或更多CPU可能需要相同的信息。他们能同时得到它吗? RAM访问是否是矩阵乘法问题的瓶颈?
如果您知道一些介绍多核编程的好书(用C ++ / Python / Java编写),请让我知道。
答案 0 :(得分:3)
你应该以缓存友好的方式分离并行化矩阵乘法的问题(有很多方法 - 搜索" tiling"。here's a nice explanation from Berkeley),来自多核如何共享对某些资源的访问权限,例如共享缓存和内存。第一个是指如何避免高速缓存抖动并且可以实现数据的有效重用(在给定的高速缓存层次结构上),后者指的是存储器带宽利用率。确实,两者是相互连接的,但它们大多是相互排斥的,因为良好的缓存会降低出站带宽(当然,这对性能和功耗都是理想的)。然而,在数据不可重复使用或者算法无法修改以适应高速缓存的情况下,有时可能无法完成。在这些情况下,内存BW可能会成为你的瓶颈,而不同的内核只需要尽可能地共享它。
大多数现代CPU都有多个核心共享最后一级缓存(我不确定某些智能手机细分市场是这种情况,但对于笔记本电脑/台式机/服务器而言这通常适用)。反过来,该缓存与内存控制器(它曾经位于称为北桥的不同芯片上)进行对话,但是几年前它被集成到大多数CPU中以便更快地访问。 通过内存控制器,整个CPU可以与DRAM通信并告诉它要获取什么。 MC通常足够聪明,可以组合访问,这样他们只需要最少的时间和精力来获取(请记住,从DRAM中取出"页面"是一项长期任务,需要经常首先驱逐当前页面缓冲在读出放大器中。)
请注意,此结构意味着MC不必单独与多个内核通信,它只是将数据提取到最后一级缓存。核心也不需要直接与内存控制器通信,因为访问通过最后一级缓存进行过滤(少数例外情况,例如将通过它的不可访问访问,以及具有另一个控制器的IO访问)。除了自己的私有缓存之外,所有核心都将共享该缓存存储。
现在关于共享的说明 - 如果2个(或更多)核心同时需要相同的数据,那么你很幸运 - 它已经在缓存中(在这种情况下,两个访问都将依次提供通过将数据副本发送到每个核心,并将它们标记为“共享”#34;),或者如果数据不存在则两者都要等到MC可以带来它(一次),然后继续与命中案一样。 但是,一旦出现异常,一个或多个内核需要将新数据写入该行或其中的一部分。在这种情况下,修饰符将发出所有权读取请求(RFO),这将阻止共享线路并使其他核心中的所有副本无效,否则您将面临丢失缓存一致性或一致性的风险(如同一个核心可能会使用陈旧数据或感知不正确的内存排序)。这被称为并行算法中的竞争条件,并且是复杂的锁定/屏蔽机制的原因。再次 - 请注意,这与实际的RAM访问正交,并且可能同样适用于最后一级缓存访问。