我尝试使用 OpenMP 并行我的程序的一些 for 循环,但未能显着提高速度(观察到实际降级)。我的目标机器将有 4-6 个内核,我目前依靠 OpenMP 运行时为我获取线程数,所以我还没有尝试任何线程数组合。
- 目标/开发平台:Windows 64bits
- 使用 MinGW64 4.7.2(rubenvb 构建)
使用 OpenMP 的示例输出
Thread count: 4
Dynamic :0
OMP_GET_NUM_PROCS: 4
OMP_IN_PARALLEL: 1
5.612 // <- returned by omp_get_wtime()
5.627 (sec) // <- returned by clock()
Wall time elapsed: 5.62703
没有 OpenMP 的示例输出
2.415 (sec) // <- returned by clock()
Wall time elapsed: 2.415
我如何测量时间
struct timeval start, end;
gettimeofday(&start, NULL);
#ifdef _OPENMP
double t1 = (double) clock();
double wt = omp_get_wtime();
sim->resetEnvironment(run);
tout << omp_get_wtime() - wt << std::endl;
timeEnd(tout, t1);
#else
double = (double) clock();
sim->resetEnvironment(run);
timeEnd(tout, t1);
#endif
gettimeofday(&end, NULL);
tout << "Wall time elapsed: "
<< ((end.tv_sec - start.tv_sec) * 1000000u + (end.tv_usec - start.tv_usec)) / 1.e6
<< std::endl;
编码
void Simulator::resetEnvironment(int run)
{
#pragma omp parallel
{
// (a)
#pragma omp for schedule(dynamic)
for (size_t i = 0; i < vector_1.size(); i++) // size ~ 20
reset(vector_1[i]);
#pragma omp for schedule(dynamic)
for (size_t i = 0; i < vector_2.size(); i++) // size ~ 2.3M
reset(vector_2[i]);
#pragma omp for schedule(dynamic)
for (size_t i = 0; i < vector_3.size(); i++) // size ~ 0.3M
reset(vector_3[i]);
for (int level = 0; level < level_count; level++) // (b) level = 3
{
#pragma omp for schedule(dynamic)
for (size_t i = 0; i < vector_4[level].size(); i++) // size ~500 - 1K
reset(vector_4[level][i]);
}
#pragma omp for schedule(dynamic)
for (long i = 0; i < populationSize; i++) // size ~7M
resetAgent(agents[i]);
} // end #parallel
} // end: Simulator::resetEnvironment()
随机性 在 reset() 函数调用中,我使用 RNG 为后续任务播种一些代理。下面是我的 RNG 实现,因为我看到建议每个线程使用一个 RNG 以确保线程安全。
class RNG {
public:
typedef std::mt19937 Engine;
RNG()
: real_uni_dist_(0.0, 1.0)
#ifdef _OPENMP
, engines()
#endif
{
#ifdef _OPENMP
int threads = std::max(1, omp_get_max_threads());
for (int seed = 0; seed < threads; ++seed)
engines.push_back(Engine(seed));
#else
engine_.seed(time(NULL));
#endif
} // end_ctor(RNG)
/** @return next possible value of the uniformed distribution */
double operator()()
{
#ifdef _OPENMP
return real_uni_dist_(engines[omp_get_thread_num()]);
#else
return real_uni_dist_(engine_);
#endif
}
private:
std::uniform_real_distribution<double> real_uni_dist_;
#ifdef _OPENMP
std::vector<Engine> engines;
#else
std::mt19937 engine_;
#endif
}; // end_class(RNG)
问题:
- 在 (a) 中,不使用快捷方式“parallel for”来避免创建团队的开销是否有益?
- 我的实施的哪一部分可能导致性能下降?
- 为什么 clock() 和 omp_get_wtime() 报告的时间如此相似,因为我预计 clock() 会比 omp_get_wtime() 长
[编辑]
- 在 (b) 处,我在内循环中包含 OpenMP 指令的意图是外循环的迭代非常小(只有 3 次),所以我想我可以跳过它并直接进入循环 vector_4[level] 的内循环. 这种想法是否不合适(或者这会指示 OpenMP 将外循环重复 4 次,因此实际上循环内循环 12 而不是 3(例如当前线程数为 4)?
谢谢