Колебания времени выполнения OpenMP - PullRequest
1 голос
/ 29 июня 2011

В настоящее время я тестирую OpenMP в большом цикле в моем коде FORTRAN.Код является частью модуля моделирования, который вызывается из пользовательского интерфейса VB.NET;этот интерфейс также выполняет измерения синхронизации.Итак, я запускаю симуляцию, и в конце программа показывает мне, сколько времени это заняло (я пишу это только для того, чтобы показать, что для временных измерений я не использую wtime или cpu_time).Теперь, когда я неоднократно запускаю симуляцию с моим параллельным циклом, я всегда получаю разное время симуляции, достигая, в одном примере, от 1 минуты 30 секунд до почти 3 минут!Результаты всегда правильные.

Я пробовал разные графики для цикла (статические, управляемые, динамические), я пытался вычислить фрагменты, которые назначены каждому потоку вручную (do i = 1, N -> doя = i_start, i_end), я пытался изменить количество потоков, участвующих в расчете цикла - без изменения ситуации.Когда я удаляю директивы OpenMP из кода, этого не происходит, поэтому они должны быть причиной такого поведения.Моя машина представляет собой четырехъядерный процессор Intel Xeon® X3470 @ 2.93 ГГц с установленной Win7.Я пытался запустить программу как с включенной, так и с отключенной многопоточностью (в BIOS), однако это также ничего не изменило.

У вас есть идеи, что может пойти не так?Поиск в сети подобной ситуации показал, что подобное поведение происходило и в тестовых средах других программистов, однако решение / причина никогда не упоминалась.Заранее спасибо за ваши мысли.

Мартин

РЕДАКТИРОВАТЬ

Вот код:

!$OMP PARALLEL DO DEFAULT(SHARED) &
!$OMP PRIVATE(n,k,nk,i,j,l,List,Vx,Vz,cS,AE1,RootCh,Ec1,Ec2,Ec3,FcE,GcE,VxE,VzE,SMuL1,SMuL2) &
!$OMP PRIVATE(W1,W2,W3,Wx,Wz,S,i1,j1,AcE,j2,ic,iB,iBound,i2) &
!$OMP FIRSTPRIVATE(NumSEL) REDUCTION(-:Cum0,Cum1) REDUCTION(+:CumR)
    DO n=1, NumEl
!       Loop on subelements    
        DO k=1, Elements(n)%nCorners-2
            nk = (k-1) * 3
            NumSEL=NumSEL+1
!            
            i=Elements(n)%KX(1)
            j=Elements(n)%KX(k+1)
            l=Elements(n)%KX(k+2)
            List(1)=i
            List(2)=j
            List(3)=l
!            
            IF(Level == NLevel) THEN
                Vx(1)=Nodes(i)%VxO
                Vx(2)=Nodes(j)%VxO
                Vx(3)=Nodes(l)%VxO
                Vz(1)=Nodes(i)%VzO
                Vz(2)=Nodes(j)%VzO
                Vz(3)=Nodes(l)%VzO
            ELSE
                Vx(1)=Nodes(i)%VxN
                Vx(2)=Nodes(j)%VxN
                Vx(3)=Nodes(l)%VxN
                Vz(1)=Nodes(i)%VzN
                Vz(2)=Nodes(j)%VzN
                Vz(3)=Nodes(l)%VzN
            END IF
!            
            cS=cBound(sol,5)
            cS=(MIN(cS,Nodes(i)%Conc(sol))+MIN(cS,Nodes(j)%Conc(sol))+MIN(cS,Nodes(l)%Conc(sol)))/3.0D0       

            AE1=Elements(n)%xMul(k)*Elements(n)%Area(k)*dt*Eps
            RootCh=AE1*cS*(Nodes(i)%Sink+Nodes(j)%Sink+Nodes(l)%Sink)/3.0D0
            Cum0=Cum0-AE1*(Nodes(i)%Gc1+Nodes(j)%Gc1+Nodes(l)%Gc1)/3.0D0
            Cum1=Cum1-AE1*(Nodes(i)%Fc1+Nodes(j)%Fc1+Nodes(l)%Fc1)/3.0D0
            CumR=CumR+RootCh
            Ec1=(Nodes(i)%Dispxx+Nodes(j)%Dispxx+Nodes(l)%Dispxx)/3.0D0
            Ec2=(Nodes(i)%Dispxz+Nodes(j)%Dispxz+Nodes(l)%Dispxz)/3.0D0
            Ec3=(Nodes(i)%Dispzz+Nodes(j)%Dispzz+Nodes(l)%Dispzz)/3.0D0
!
            IF (Level == NLevel) AcE=(Nodes(i)%Ac+Nodes(j)%Ac+Nodes(l)%Ac)/3.0D0
!
            FcE=(Nodes(i)%Fc+Nodes(j)%Fc+Nodes(l)%Fc)/3.0D0
            GcE=(Nodes(i)%Gc+Nodes(j)%Gc+Nodes(l)%Gc)/3.0D0
            VxE=(Vx(1)+Vx(2)+Vx(3))/3.0D0
            VzE=(Vz(1)+Vz(2)+Vz(3))/3.0D0
            SMul1=-Elements(n)%AMul(k)
            SMul2=Elements(n)%Area(k)/20.0D0*Elements(n)%XMul(k)
!
            If (lUpw) THEN
                !W1=WeTab(1,NumSEl)
                !W2=WeTab(2,NumSEl)
                !W3=WeTab(3,NumSEl)
                W1=WeTab(1,(n-1)*(Elements(n)%nCorners-2)+k)
                W2=WeTab(2,(n-1)*(Elements(n)%nCorners-2)+k)
                W3=WeTab(3,(n-1)*(Elements(n)%nCorners-2)+k)
                Wx(1)=2.0D0*Vx(1)*(W2-W3)+Vx(2)*(W2-2.0D0*W3)+Vx(3)*(2.0D0*W2-W3)
                Wx(2)=Vx(1)*(2.0D0*W3-W1)+2.0D0*Vx(2)*(W3-W1)+Vx(3)*(W3-2.0D0*W1)
                Wx(3)=Vx(1)*(W1-2.0D0*W2)+Vx(2)*(2.0D0*W1-W2)+2.0D0*Vx(3)*(W1-W2)
                Wz(1)=2.0D0*Vz(1)*(W2-W3)+Vz(2)*(W2-2.0D0*W3)+Vz(3)*(2.0D0*W2-W3)
                Wz(2)=Vz(1)*(2.0D0*W3-W1)+2.0D0*Vz(2)*(W3-W1)+Vz(3)*(W3-2.0D0*W1)
                Wz(3)=Vz(1)*(W1-2.0D0*W2)+Vz(2)*(2.0D0*W1-W2)+2.0D0*Vz(3)*(W1-W2)
            END IF
!
            DO j1=1, 3
                i1=List(j1)
!$OMP           ATOMIC
                Nodes(i1)%F=Nodes(i1)%F+Elements(n)%GMul(k)*(GcE+Nodes(i1)%Gc/3.0D0)
                IF (Level==NLevel) then
!$OMP               ATOMIC
                    Nodes(i1)%DS=Nodes(i1)%DS+Elements(n)%GMul(k)*(Ace+Nodes(i1)%Ac/3.0D0)
                end if
                iBound=0
                IF (Nodes(i)%Kode/=0) THEN
                    BP_Loop : DO id=1, NumBP
                        IF((KXB(id)==i1) .AND. (KodCB(id) > 0)) THEN
                            iBound=1
                            EXIT BP_Loop
                        END IF
                    END DO BP_Loop
                END IF 
!
                DO j2=1, 3
                    i2=List(j2)
                    S(j1,j2)=SMul1*(Ec1*Elements(n)%dz(nk+j1)*Elements(n)%dz(nk+j2)+ &
                                    Ec3*Elements(n)%dx(nk+j1)*Elements(n)%dx(nk+j2)+ &
                                   Ec2*(Elements(n)%dz(nk+j1)*Elements(n)%dx(nk+j2)+ &
                                        Elements(n)%dx(nk+j1)*Elements(n)%dz(nk+j2)))

                    S(j1,j2)=S(j1,j2)-(Elements(n)%dz(nk+j2)/8.0D0*(VxE+Vx(j1)/3.0D0)+ & 
                                       Elements(n)%dx(nk+j2)/8.0D0*(VzE+Vz(j1)/3.0D0))*Elements(n)%xMul(k)

                    IF(lUpw) S(j1,j2)=S(j1,j2)-Elements(n)%xMul(k)* &
                                              (Elements(n)%dz(nk+j2)/40.0D0*Wx(j1)+ &
                                               Elements(n)%dx(nk+j2)/40.0D0*Wz(j1))

                    ic=1
                    IF (i1==i2) ic=2
                    S(j1,j2)=S(j1,j2)+SMul2*ic*(FcE+(Nodes(i1)%Fc+Nodes(i2)%Fc)/3.0D0)
                    IF (iBound==1) then
                        if(j2.eq.1) then
!$OMP                      ATOMIC
                                Nodes(i1)%Qc(sol)=Nodes(i1)%Qc(sol)-Eps*S(j1,j2)*Nodes(i2)%Conc(sol)-Eps*Elements(n)%GMul(k)*(GcE+Nodes(i1)%Gc/3.0D0)
                        else
!$OMP                       ATOMIC
                            Nodes(i1)%Qc(sol)=Nodes(i1)%Qc(sol)-Eps*S(j1,j2)*Nodes(i2)%Conc(sol)
                        end if
                    end if
                    IF (Level/=NLevel) THEN
!$OMP                   ATOMIC
                        B(i1)=B(i1)-alf*S(j1,j2)*Nodes(i2)%Conc(sol)
                    ELSE
                        IF (lOrt) THEN
                            CALL rFIND(i1,i2,kk,NumNP,MBandD,IAD,IADN)
                            iB=kk
                    ELSE
                        iB=MBand+i2-i1
                    END IF
!$OMP                   ATOMIC
                        A(iB,i1)=A(iB,i1)+epsi*S(j1,j2)
                    END IF
                END DO
            END DO
        END DO
    END DO
!$OMP END PARALLEL DO    

1 Ответ

0 голосов
/ 03 августа 2011

Если вы хотите проверить производительность в программе, я бы посоветовал вам выполнить синхронизацию в программе с функциями синхронизации OpenMP. См. OpenMP Ref. простынь. Так что вам нужно сделать что-то вроде:

USE omp_lib

t1 = omp_get_wtime()
! Big loop
t_final = omp_get_wtime() - t1

Некоторое время я нахожу, что они лучше отражают фактическое время парализации. Вы их используете?

Как говорит FFox, это может быть просто из-за операторов ATOMIC, которые задерживаются в разных имениях при каждом запуске. Помните, что потоки создаются во время выполнения, поэтому расположение потоков может не совпадать для каждого запуска.

С таким циклом я бы попытался выяснить, можно ли увеличить скорость, разделив ее. Конечно, это не нужно, если ускорение составляет около 2 для 2 потоков. Просто идея.

...