在下面的代码中,我试图将数组的所有元素与嵌套for循环中的所有其他元素进行比较。 (这是运行一个简单的n体仿真。我只测试了4个核心上的4个线程的4个物体)。没有OpenMP修改的相同顺序版本的代码在大约15秒内运行25M次迭代。昨晚这段代码在大约30秒内完成。现在它运行大约1分钟!我认为问题可能在于线程必须写入通过指针传递给函数的数组 该数组在其他地方动态分配,由我定义的结构组成。这只是一种预感。我已经验证了4个线程在100%的4个独立核心上运行,并且它们正在正确访问阵列的元素。有什么想法吗?
void runSimulation (particle* particles, int numSteps){
//particles is a pointer to an array of structs I've defined and allocated dynamically before calling the function
//Variable Initializations
#pragma omp parallel num_threads(4) private(//The variables inside the loop) shared(k,particles) // 4 Threads for four cores
{
while (k<numSteps){ //Main loop.
#pragma omp master //Check whether it is time to report progress.
{
//Some simple if statements
k=k+1; //Increment step counter for some reason omp doesn't like k++
}
//Calculate new velocities
#pragma omp for
for (i=0; i<numParticles; i++){ //Calculate forces by comparing each particle to all others
Fx = 0;
Fy = 0;
for (j=0; j<numParticles; j++){
//Calcululate the cumulative force by comparing each particle to all others
}
//Calculate accelerations and set new velocities
ax = Fx / particles[i].mass;
ay = Fy / particles[i].mass;
//ARE THESE TWO LINES THE PROBLEM?!
particles[i].xVelocity += deltaT*ax;
particles[i].yVelocity += deltaT*ay;
}
#pragma omp master
//Apply new velocities to create new positions after all forces have been calculated.
for (i=0; i<numParticles; i++){
particles[i].x += deltaT*particles[i].xVelocity;
particles[i].y += deltaT*particles[i].yVelocity;
}
#pragma omp barrier
}
}
}
答案 0 :(得分:1)
你正在颠倒缓存。所有内核都写入相同的共享结构,这将通过L2(最佳情况),L3或主内存/内存总线(最坏情况)在内核之间不断反弹。取决于共享内容的方式,这需要20到300个周期,而在L1中对私有内存的写入在理想条件下需要1个周期或更短的时间。
这解释了你的减速。
如果增加粒子数量,情况可能会变得不那么严重,因为你经常会写入不同的缓存行,所以会有更少的颠簸。上面的btown是建议私人阵列的正确想法。
答案 1 :(得分:0)
不确定这是否能解决问题,但您可能会尝试为每个线程提供完整数组的副本;问题可能是线程正在争夺访问共享内存,并且您看到很多缓存未命中。
我不确定你用来执行此操作的确切openmp语法,但请尝试这样做:
与你的O(N ^ 2)计算相比,新操作只有O(N),所以从长远来看,它们不应该占用太多时间。绝对有办法优化我为你布置的步骤,Gabe,但我会留给你。
答案 2 :(得分:0)
我不同意问题是缓存抖动,因为struct粒子的大小必须超过缓存行的大小,只是从成员数量。
我认为更可能的罪魁祸首是初始化omp for
的开销是1000个周期http://www.ualberta.ca/CNS/RESEARCH/Courses/2001/PPandV/OpenMP.Eric.pdf,并且循环中只有少量计算。我不会惊讶于只有4个机体的循环速度较慢。如果你有几个100的身体,情况会有所不同。我曾经在这样的循环上工作过,最后直接使用了pthreads。