2010-03-06 3 views
6

other question과 관련하여 Sar (Successive Over-Relaxation) 방법을 사용하도록 스파 스 매트릭스 행 솔버를 수정했습니다. 코드는 다음과 지금과 같이이 SOR 솔버의 속도가 입력에 의존하는 이유는 무엇입니까?

void SORSolver::step() { 
    float const omega = 1.0f; 
    float const 
     *b = &d_b(1, 1), 
     *w = &d_w(1, 1), *e = &d_e(1, 1), *s = &d_s(1, 1), *n = &d_n(1, 1), 
     *xw = &d_x(0, 1), *xe = &d_x(2, 1), *xs = &d_x(1, 0), *xn = &d_x(1, 2); 
    float *xc = &d_x(1, 1); 
    for (size_t y = 1; y < d_ny - 1; ++y) { 
     for (size_t x = 1; x < d_nx - 1; ++x) { 
      float diff = *b 
       - *xc 
       - *e * *xe 
       - *s * *xs - *n * *xn 
       - *w * *xw; 
      *xc += omega * diff; 
      ++b; 
      ++w; ++e; ++s; ++n; 
      ++xw; ++xe; ++xs; ++xn; 
      ++xc; 
     } 
     b += 2; 
     w += 2; e += 2; s += 2; n += 2; 
     xw += 2; xe += 2; xs += 2; xn += 2; 
     xc += 2; 
    } 
} 

이제 이상한 일이다 : 나는 omega (이완 인자)를 증가하는 경우, 실행 속도는 다양한 스토리지 내부의 값에 대한 극적으로을 따라하기 시작!

omega = 1.0f의 경우 실행 시간이 다소 일정합니다. omega = 1.8의 경우 처음에는 일반적으로이 step()을 실행하는 데 5 밀리 초가 걸리지 만 시뮬레이션 중에 점진적으로 100 밀리 초까지 증가합니다. omega = 1.0001f으로 설정하면 그에 따라 실행 시간이 약간 증가합니다. omega이 높을수록 시뮬레이션 중에 더 빠른 실행 시간이 증가합니다.

모든 것이 유체 해석기 안에 내장되어 있기 때문에 독립 실행 형 예제를 찾기가 어렵습니다. 그러나 나는 초기 상태를 저장하고 실제 시간 단계를 해결할 때마다 그 상태에서 솔버를 다시 실행합니다. 초기 상태의 경우 속도가 빠르며 후속 시간 간격이 점차적으로 느려집니다. 나머지는 동일하기 때문에이 코드의 실행 속도는 6 개 배열의 값에 따라 달라진다는 것을 증명합니다.

이것은 VS2008로 32 비트 용으로 컴파일 할 때 64 비트 Windows 7뿐만 아니라 g ++가있는 Ubuntu에서도 재생성 가능합니다.

NaN 및 Inf 값이 부동 소수점 계산을 위해 느려질 수 있지만 NaN 또는 Infs는 존재하지 않는다고 들었습니다. 그렇지 않으면 부동 소수점 연산의 속도가 입력 숫자의 값에 따라 달라질 수 있습니까?

+0

계산 값에 의존하는 다른 codepath를 측정하지 않겠습니까? – ebo

+0

성능 문제가 계속 발생하면 이러한 계산에 GPU 사용을 고려하십시오. GPU는 드문 드문 매트릭스 작업에 능숙합니다. – Mark

+0

@ebo : 저는이 호출을 측정하기 위해 Linux에서 실시간 클럭을 사용했습니다. 그래서 예, 저는 아주 확신합니다. – Thomas

답변

5

마지막 질문에 대한 짧은 대답은 "예"입니다. 비정규 화 된 (매우 가깝게) 숫자는 특별한 처리가 필요하며 훨씬 느릴 수 있습니다. 시간이 지남에 따라 시뮬레이션에 뛰어 들었다고 생각합니다. 관련 게시물을 참조하십시오 : Floating Point Math Execution Time

비정규 값을 0으로 플러시하도록 설정하면 시뮬레이션 품질에 무시할 수있는 사항을 처리해야합니다.

+0

비정규 화 된 값이 실제로 들어갑니다. 나는 가능한 한 제로에 가깝게 발산 (위의 'd_b')을 얻으려는 유체 압력에 대해 해결할 것입니다. 그래서 이것이 그것을 설명하고, 당신은 다시 한 번 뭔가 가르쳐 줬습니다. 많은 감사합니다!('1-omega'에 대한 혼란은 행렬의 크기가 대각선에 '1'이되도록 스케일링 되었기 때문일 것입니다 .' - * xc '는 그곳에 오지 않지만'-omega * *'라는 용어입니다. xc'를 사용하여 합리적인 답을 얻을 수 있습니다. – Thomas

+0

트릭을 수행 한 것을 기쁘게 생각합니다. 최근 몇 년 전 큰 무역 박람회가 있기 직전에 데모 프로그램이 몇 분 동안 실행 된 후 크롤링 속도가 느려지고있었습니다. 그래픽 드라이버의 버그가 부동 소수점 제어 플래그를 제대로 재설정하지 못하고 리지드 본문 시뮬레이션에서 댐핑 팩터를 반복적으로 곱하여 비정상적인 값을 얻었습니다. 문제를 알았을 때 간단하게 해결할 수있을 정도로 간단하지만 추적하기 위해 하루나 이틀 정도의 디버깅을했습니다. 어쨌든, 나는 당신의 설명을 읽을 때 즉시 그것을 생각했다. – celion

+0

답변을 더 명확하게하기 위해 1-omega에 대한 내 (부정확 한) 편집 내용을 제거했습니다 ... – celion

0

celion's answer이 올바른 것으로 밝혀졌습니다. 그는에 링크 포스트는 0으로 플러시 비정규 값을 켭 말한다 :

#include <float.h> 
_controlfp(_MCW_DN, _DN_FLUSH); 

을하지만, 이것은 Windows 전용입니다. 리눅스에서 GCC를 사용하여, 나는 인라인 어셈블리의 냄새와 같은 일을했다 :

int mxcsr; 
__asm__("stmxcsr %0" : "=m"(mxcsr) : :); 
mxcsr |= (1 << 15); // set bit 15: flush-to-zero mode 
__asm__("ldmxcsr %0" : : "m"(mxcsr) :); 

아마 향상시킬 수 있도록이 사상 처음으로 86 어셈블리입니다. 그러나 그것은 나를 위해 트릭을합니다.

+0

fenv.h (C99)를 사용하여 FP 환경을 이식 가능하게 설정할 수 있습니다. – Jed

+0

이것은 C++이므로 직접 작동하지 않습니다. 그러나 그 구현을 훔칠 수도 있습니다. 감사! – Thomas

관련 문제