OpenMP第一核比第二个内核慢得多
OpenMP first kernel much slower than the second kernel
我有一个巨大的98306乘98306 2D阵列初始化。我创建了一个内核函数,该函数计算以下阈值以下的元素总数。
#pragma omp parallel for reduction(+:num_below_threshold)
for(row)
for(col)
index = get_corresponding_index(row, col);
if (array[index] < threshold)
num_below_threshold++;
出于基准目的,我测量了当线程数设置为1时的内核执行时间。在同一数组上使用一个线程执行的内核的下一个呼叫只需大约3秒钟。我认为这可能是与缓存有关的问题,但似乎没有关系。引起这一点的可能原因是什么?
此数组的初始化为:
float *array = malloc(sizeof(float) * 98306 * 98306);
for (int i = 0; i < 98306 * 98306; i++) {
array[i] = rand() % 10;
}
将同一内核应用于此数组两次,第二个执行时间比第一个内核快得多。我虽然在Linux上分配了懒惰,但由于初始化功能,这应该不是问题。任何解释都会有所帮助。谢谢!
由于您没有提供任何最小,完整和可验证的例子,所以我必须在这里做出一些疯狂的猜测,但是我很有信心我有这个问题的要素。
首先,您必须注意,98,306 x 98,306是9,664,069,636,它比签名的32位整数可以存储的最大值大(2,147,483,647)。因此,您的for
初始化循环的上限在溢出后可能会变成1,074,135,044(尽管在我的机器上,尽管严格来说,这是不确定的行为,这一切可能发生),这可能比您预期的要小9倍。p>现在,在初始化循环之后,实际上只有11%的内存实际上是由操作系统分配和触摸的。但是,您的第一个减少循环在浏览阵列的各个元素方面做得很好,并且由于大约89%,因此在拳头时间内,操作系统在那里进行实际内存分配,然后需要一些重要的时间。
现在,对于您的第二次减少循环,所有内存都已正确分配和触摸,这使其更快。
所以这就是我相信发生的事情。也就是说,许多其他参数可以在这里发挥作用,例如:
- 交换:您尝试分配的数组代表大约36GB的内存。如果您的计算机没有太多的内存,那么您的代码可能会交换,这可能会使您可以提出的任何性能衡量范围都大致混乱
- numa效果:如果您的计算机具有多个NUMA节点,则在无法正确管理的情况下,线程固定和内存亲和力会对循环出现之间的性能产生很大的影响
- 编译器优化:您没有提及所需的哪个编译器以及所请求的优化级别。根据这一点,您会惊讶于代码的缩短。例如,编译器可以完全删除第二个循环,因为它与第一个循环一样,并变得无用,因为结果将是相同的……以及许多其他有趣且出乎意料的事物,使您的基准测试毫无意义
相关文章:
- 我有两个类需要在同一 cpp 文件中相互引用,但第一个类无法识别第二个类类型的对象
- 等待整个 omp 块完成,然后再调用第二个函数
- 我想在C++中读取一些多个字符,但它永远不会读取第二个字符
- 如何在创建自定义迭代器时获得 std::p air 的第一个和第二个?
- WinAPI 在单击第一个对话框上的按钮控件并销毁第一个对话框后创建第二个对话框
- 将第二个 GATT 服务添加到 Movesense 容器
- 如何在 c++ 中根据第二个元素按降序对列表进行排序
- 对的排序向量 (std::vector<pair<int, int>>) 按对的第一个元素搜索并更新第二个元素值
- 比较 2 个向量并从第二个向量中删除在第一个 - c++ 中找不到的元素
- 为什么这个程序没有打印返回的迭代器的正确第二个元素?
- 使第二个类的构造函数成为第一个类中的友元函数
- 为什么第二个代码给出了预期的结果,而第一个代码却没有?
- 为什么第一个代码块产生垃圾值,而第二个代码块将类成员的值相加?
- 打印无序映射的第二个元素,即集合
- 我有一个类,它创建了另一个类的实例.如何将变量通过第一个类传递到第二个类的实例化中?
- 需要使用模板查找数组的第二个最小和最小值
- c++:交换向量中所有元组的第一个和第二个元素
- 如果条件,当我想第二个参数时
- 将内容从第一个文件("constituencies")移动到第二个文件("temp")并在之后重命名时,我的文件被删除
- OpenMP第一核比第二个内核慢得多