我正在使用OMP尝试在小内核中获得一些加速。它基本上只是为成员资格查询无序集的向量。我试图进行优化,但令人惊讶的是我放慢了速度,我真的很好奇。
我的第一次传球是:
vector<unordered_set<uint16_t> > setList = getData();
#pragma omp parallel for default(shared) private(i, j) schedule(dynamic, 50)
for(i = 0; i < size; i++){
for(j = 0; j < 500; j++){
count = count + setList[i].count(val[j]);
}
}
然后我想通过将setList [i]子表达式向上移动一级嵌套并将其保存在临时变量中,我可以通过执行以下操作来获得加速:
#pragma omp parallel for default(shared) private(i, j, currSet) schedule(dynamic, 50)
for(i = 0; i < size; i++){
currSet = setList[i];
for(j = 0; j < 500; j++){
count = count + currSet.count(val[j]);
}
}
我原本以为这可能会为“j”for循环的每次迭代节省一个负载,并获得加速,但它实际上减慢了约3倍。我的意思是整个内核运行时间大约是3倍。关于为什么会这样的想法?
谢谢!
答案 0 :(得分:1)
添加一些整数真的不足以保证启动线程。
如果您忘记添加简化条款,您将遭受真正共享 - 所有线程都希望同时更新NSLog(@"Latitude: %g", self.coordLat);
变量。这使得所有内核都争夺包含tha变量的缓存行,这将对您的性能产生重大影响。
我刚注意到您将计划设置为动态。你不应该。此工作负载可以在编译时划分。所以不要指定时间表。
答案 1 :(得分:0)
正如已经陈述的循环间依赖性,即等待来自其他线程的数据的线程,或者多个线程连续访问的数据,可能导致并行程序经历减速并且应该作为经验法则避免。内置的功能(如缩减)可以收集单个结果并以优化的方式将它们编译在一起。
以下是与犹他大学类似案件中使用减少的一个很好的例子
int array[8] = { 1, 1, 1, 1, 1, 1, 1, 1};
int sum = 0, i;
#pragma omp parallel for reduction(+:sum)
for (i = 0; i < 8; i++) {
sum += array[i];
}
printf("total %d\n", sum);
来源:http://www.eng.utah.edu/~cs4960-01/lecture9.pdf
作为旁白:只有在并行区域内的局部变量时才需要分配私有变量。在这两种情况下,都不需要将i声明为私有变量。
请参阅维基百科:https://en.wikipedia.org/wiki/OpenMP#Data_sharing_attribute_clauses
数据共享属性子句
共享:共享并行区域内的数据,这意味着所有线程都可以同时查看和访问。默认情况下,工作共享区域中的所有变量都是共享的,但循环迭代计数器除外。
private :并行区域内的数据对每个线程都是私有的,这意味着每个线程都有一个本地副本并将其用作临时变量。未初始化私有变量,并且不维护该值以在并行区域之外使用。默认情况下,OpenMP循环结构中的循环迭代计数器是私有的。
请参阅堆栈交换答案:OpenMP: are local variables automatically private?