mysql C openmp_c ++-OpenMP中的“静态”和“动态”时间表有什么区别?
此后,其他人回答了大多数问题,但我想指出一些特定的情况,其中特定的调度类型比其他类型更适合。 调度控制如何在线程之间分配循环迭代。 选择正确的时间表可能会对应用程序的速度产生重大影响。
schedule(runtime)调度表示以循环方式将迭代块静态映射到执行线程。 静态调度的好处在于,OpenMP运行时可以确保,如果您有两个具有相同迭代次数的单独循环,并使用静态调度以相同数量的线程执行它们,那么每个线程将获得完全相同的迭代范围( s)在两个平行区域中。 这在NUMA系统上非常重要:如果在第一个循环中触摸一些内存,它将驻留在执行线程所在的NUMA节点上。 然后,在第二个循环中,同一线程可以更快地访问相同的内存位置,因为它位于同一NUMA节点上。
假设有两个NUMA节点:节点0和节点1,例如 一个两个插槽的Intel Nehalem板,两个插槽均带有4核CPU。 然后,线程0、1、2和3将驻留在节点0上,线程4、5、6和7将驻留在节点1上:
| | core 0 | thread 0 |
| socket 0 | core 1 | thread 1 |
| NUMA node 0 | core 2 | thread 2 |
| | core 3 | thread 3 |
| | core 4 | thread 4 |
| socket 1 | core 5 | thread 5 |
| NUMA node 1 | core 6 | thread 6 |
| | core 7 | thread 7 |
每个内核都可以从每个NUMA节点访问内存,但是远程访问的速度比本地节点访问的速度慢(Intel的速度是1.5倍-1.9倍)。 您运行的是这样的:
char *a = (char *)malloc(8*4096);
#pragma omp parallel for schedule(static,1) num_threads(8)
for (int i = 0; i < 8; i++)
memset(&a[i*4096], 0, 4096);
在这种情况下,如果不使用大页面,则x86上Linux上一个内存页面的标准大小为4096字节。 此代码将整个32 KiB阵列schedule(runtime)归零。dynamic调用仅保留虚拟地址空间,但实际上并未“接触”物理内存(这是默认行为,除非使用其他版本的dynamic,例如将内存归零的版本)。 像guided一样)。 现在,此数组是连续的,但仅在虚拟内存中。 在物理内存中,一半将位于与套接字0相连的内存中,一半在与套接字1相连的内存中。之所以如此,是因为不同的部分被不同的线程置零,并且这些线程位于不同的内核上,并且有一种叫做“首次触摸”的东西。 NUMA策略,这意味着将内存页面分配在首先“接触”内存页面的线程所在的NUMA节点上。
| | core 0 | thread 0 | a[0] ... a[4095]
| socket 0 | core 1 | thread 1 | a[4096] ... a[8191]
| NUMA node 0 | core 2 | thread 2 | a[8192] ... a[12287]
| | core 3 | thread 3 | a[12288] ... a[16383]
| | core 4 | thread 4 | a[16384] ... a[20479]
| socket 1 | core 5 | thread 5 | a[20480] ... a[24575]
| NUMA node 1 | core 6 | thread 6 | a[24576] ... a[28671]
| | core 7 | thread 7 | a[28672] ... a[32768]
现在让我们运行另一个循环,如下所示:
#pragma omp parallel for schedule(static,1) num_threads(8)
for (i = 0; i < 8; i++)
memset(&a[i*4096], 1, 4096);
每个线程将访问已映射的物理内存,并且与第一个循环期间的线程到内存区域的映射相同。 这意味着线程将仅访问位于其本地内存块中的内存,这将是快速的。
现在想象第二个循环使用另一个调度方案:schedule(runtime)。这将把迭代空间“砍”成两个迭代的块,总共将有4个这样的块。 将会发生的是,我们将具有以下线程到内存的位置映射(通过迭代编号):
| | core 0 | thread 0 | a[0] ... a[8191]
| socket 0 | core 1 | thread 1 | a[8192] ... a[16383]
| NUMA node 0 | core 2 | thread 2 | a[16384] ... a[24575]
| | core 3 | thread 3 | a[24576] ... a[32768]
| | core 4 | thread 4 |
| socket 1 | core 5 | thread 5 |
| NUMA node 1 | core 6 | thread 6 |
| | core 7 | thread 7 |
这里发生两件事:
线程4至7保持空闲状态,并且一半的计算能力丢失;
线程2和3会访问非本地内存,这将花费它们大约两倍的时间来完成,在此期间线程0和1将保持空闲状态。
因此,使用静态调度的优点之一是它可以提高内存访问的局部性。 缺点是调度参数选择不当会破坏性能。
schedule(runtime)调度工作以“先到先得”为基础。 两次运行具有相同数量的线程可能(并且很可能会)产生完全不同的“迭代空间”->“线程”映射,因为一个映射可以轻松验证:
$ cat dyn.c
#include
#include
int main (void)
{
int i;
#pragma omp parallel num_threads(8)
{
#pragma omp for schedule(dynamic,1)
for (i = 0; i < 8; i++)
printf("[1] iter %0d, tid %0d\n", i, omp_get_thread_num());
#pragma omp for schedule(dynamic,1)
for (i = 0; i < 8; i++)
printf("[2] iter %0d, tid %0d\n", i, omp_get_thread_num());
}
return 0;
}
$ icc -openmp -o dyn.x dyn.c
$ OMP_NUM_THREADS=8 ./dyn.x | sort
[1] iter 0, tid 2
[1] iter 1, tid 0
[1] iter 2, tid 7
[1] iter 3, tid 3
[1] iter 4, tid 4
[1] iter 5, tid 1
[1] iter 6, tid 6
[1] iter 7, tid 5
[2] iter 0, tid 0
[2] iter 1, tid 2
[2] iter 2, tid 7
[2] iter 3, tid 3
[2] iter 4, tid 6
[2] iter 5, tid 1
[2] iter 6, tid 5
[2] iter 7, tid 4
(当使用schedule(runtime)时,观察到相同的行为)
如果使用dynamic调度运行了schedule(runtime)部分的示例代码,则保留原始位置的机会只有1/70(1.4%),发生远程访问的机会只有69/70(98.6%)。 这个事实经常被忽略,因此实现了次优的性能。
在schedule(runtime)和dynamic调度之间进行选择还有另一个原因-工作负载平衡。 如果每次迭代所花费的时间与平均时间相差很大,那么在静态情况下可能会出现很高的工作失衡。 例如,完成迭代的时间随迭代次数线性增长的情况。 如果在两个线程之间静态分配迭代空间,则第二个线程的工作量将是第一个线程的三倍,因此在2/3的计算时间内,第一个线程将处于空闲状态。 动态计划会带来一些额外的开销,但在这种情况下将导致更好的工作负载分配。 dynamic的一种特殊调度是guided,其中随着工作的进行,每个任务的迭代块越来越小。
由于预编译的代码可以在各种平台上运行,因此,如果最终用户可以控制调度,那就很好了。 这就是OpenMP提供特殊的schedule(runtime)子句的原因。 使用runtime进行调度时,该类型取自环境变量OMP_SCHEDULE的内容。这允许测试不同的调度类型而无需重新编译应用程序,并且还允许最终用户针对其平台进行微调。
mysql C openmp_c ++-OpenMP中的“静态”和“动态”时间表有什么区别?相关推荐
- 静态页面和动态页面中的静态和动态到底指的是什么
今天讨论一个话题,这是在考研的专业课考试中的一个问题:静态页面和动态页面的联系和区别 ,这考的我就很猝不及防 ,这个方面虽然以前有了解 ,但是理解得并不深刻,网安方向涉及到的东西太多了,慢慢学习吧~首 ...
- java中的静态、动态代理模式以及Spring中的CgLib动态代理解读(面试必问)
java中的静态.动态代理模式以及Spring中的CgLib动态代理解读(面试必问) 静态代理 动态代理 CgLib动态代理 基础知: 反射知识 代理(Proxy)是一种设计模式,提供了对目标 ...
- angr原理与实践(三)——Arbiter:一种弥合二进制程序漏洞发现中的静态和动态鸿沟
转载请说明出处:信安科研人 please subscribe my official wechat :信安科研人 获取更多安全资讯 原文链接:sec22-vadayath.pdf (usenix.or ...
- fragment在activity中的静态和动态用法_使用Matlab修改压缩Gif动态图片制作微信表情...
脚本之家 你与百万开发者在一起 作者:theOwlAndPussyCat/焦旭光 引言 电脑里存了很多有意思的Gif动态图片,闲暇想把这些动图全导入微信表情,可是这些动图很多大小超过了微信表情大小1M ...
- Eclipse中的静态和动态web项目
在Eclipse中奖web项目分为了Dynamic Web Project和Static Web Project.那么这两种有什么区别呢?其实这里的Dynamic和Static是通过页面来区分的.创建 ...
- html的动态页面包含,在html页面中包含静态或动态页面方法
1.可以用 download 行为下载后再用 innerHTML 特性显示出来. 具体步骤: style="behavior:url(#default#download)"> ...
- 静态和动态include
今天突然意识到野猪对静态和动态的include的区别理解有点模糊,现在总结一下: 动态include:<jsp: include page="include.jsp" ful ...
- 如何在nginx中缓存静态文件
这篇教程说明你应该怎样配置 nginx.设置 HTTP 头部过期时间,用 Cache-Control 中的 max-age 标记为静态文件(比如图片. CSS 和 Javascript 文件)设置一个 ...
- mysql 在大型应用中的架构演变
文正整理自:http://www.csdn.net/article/2014-06-10/2820160 可扩展性 架构的可扩展性往往和并发是息息相关,没有并发的增长,也就没有必要做高可扩展性的架构, ...
最新文章
- SQL拆分实现与注意事项
- 云栖Android精华文章合集
- 开箱即用Bumblebee独立部署搭建webapi网关详解
- [Python] 制作启动uiautomator2 的web版 uiautomatorviewer2 批处理启动
- numpy ndarray可用的常规函数
- 公司git服务器记录
- [数字图像处理·冈萨雷斯 ] 图像文件格式
- asp.net/net/c#电子购物商城系统-成品
- 传送带计数器c语言程序,脉搏计数器的程序(用C语言编写程序)
- PS去掉图片上的文字的6种基本方法
- php除数不能为零,0为什么不能做除数(为什么0不能作为除数)
- 如何撰写搜索引擎广告创意
- 人工智能时代,数据标注产业将迎来黄金时期?丨曼孚科技
- 安卓虚拟机_VMOS虚拟大师-独立的安卓虚拟机系统(已ROOT)「安卓」
- SCORM标准及支持SCORM标准学习平台的设计
- linux下iconv()函数的用法
- 汪源:数据分析热词迭出,“三个统一”值得关注
- 关于error: The following untracked working tree files would be overwritten by checkout的解决方案
- K12526 找双亲和孩子
- MindManager思维导图制作教程案例