2013-05-19 6 views
3

일부 수치 계산을 위해 GSL 라이브러리의 Monte Carlo 통합 서브 루틴을 호출하려고했습니다. my for 루프는 다소 단순하기 때문에 다른 실행 결과가 독립적이라는 것을 의미하므로 OpenMP를 사용하여 병렬 처리하는 것이 매우 간단해야합니다. 그러나 내가 컴파일 할 때 항상 "내부 컴파일러 오류 : 분할 오류"라고 말하며 아무것도 생성하지 않았습니다.OpenMP 병렬 영역에서 중첩 함수의 내부 컴파일러 오류

#include <stdlib.h> 
#include <omp.h> 
#include <gsl/gsl_math.h> 
#include <gsl/gsl_monte.h> 
#include <gsl/gsl_monte_vegas.h> 
#include <math.h>  

double 
Reg1 (double *x, double t, size_t dim, void *params) 
{ 
    return sin(x[1])*cos(t*t)*x[0]*x[0]*cos(x[0])*cos(3*x[0]); 
} 


void 
display_results (char *title, double result, double error) 
{ 
    printf ("%s ==================\n", title); 
    printf ("result = % .10f\n", result); 
    printf ("sigma = % .10f\n\n", error); 
} 


void 
VEGAS_integration_routine (double (*function)(double *, size_t, void *), 
          double xl[], double xu[], size_t calls, gsl_rng * r) 
{ 
double res, err; 
    gsl_monte_function Function = { function, 2, 0 }; 

    gsl_monte_vegas_state *s = gsl_monte_vegas_alloc (2); 

    gsl_monte_vegas_integrate (&Function, xl, xu, 2, 20000, r, s, &res, &err); 

    display_results ("vegas warm-up", res, err); 

    printf ("converging...\n"); 

    do 
     { 
     gsl_monte_vegas_integrate (&Function, xl, xu, 2, calls, r, s, &res, &err); 

     printf ("result = % .10f; sigma = % .10f; " 
       "chisq/dof = %.2f\n", res, err, gsl_monte_vegas_chisq (s)); 
     } 
    while (fabs (gsl_monte_vegas_chisq (s) - 1.0) > 0.05); 

    display_results ("vegas final", res, err); 

    gsl_monte_vegas_free (s); 
} 


int 
main (void) 
{ 
    int seg = 200; 

    double xl[2] = { 195.0, -1000.0 }; 
    double xu[2] = { 205.0, 1000.0 }; 

    const gsl_rng_type *T; 
    gsl_rng *r; 

    size_t calls = 1000000; 

    gsl_rng_env_setup(); 

    T = gsl_rng_default; 
    r = gsl_rng_alloc (T); 

    /* Calculate G1 */ 
    int i; 
    double j=0; 
    #pragma omp parallel for shared(xl,xu,calls,r,seg) private(i,j) 
    for(i=0; i<=seg; i=i+1) 
    { 
    j=(double)i * 0.05; 
    printf("Now it's t = %.2f \n", j); 
    printf("Compute Re(G1)...\n"); 
    double g(double * x, size_t dim, void *params) 
    { 
     return Reg1(x, j, dim, &params); 
     } 
     VEGAS_integration_routine (&g, xl, xu, calls, r); 
    } 
    gsl_rng_free (r); 

    return 0; 
} 

이 코드는 것은 기본적으로 GSL webpage에 샘플 코드에서 수정 : 여기 내 코드입니다. OpenMP를 사용하지 않으면 완벽하게 작동합니다. 내가 컴파일 할 수 있기 때문에

test2.c: In function 'main': 
test2.c:85: internal compiler error: Segmentation fault 
Please submit a full bug report, 
with preprocessed source if appropriate. 
See <http://bugzilla.redhat.com/bugzilla> for instructions. 
Preprocessed source stored into /tmp/ccAGFe3v.out file, please attach this to your bugreport. 
make: *** [test2.o] Error 1 

: 나는 우리의 서버에서 작동, (추가 -fopenmp로) 다음 명령을 사용하여 컴파일 GCC를 사용하지만

gcc -c -Wall -ansi -I/usr/include -L/usr/lib/gcc/x86_64-redhat-linux/4.4.4/ -lgomp -fopenmp test2.c -o test2.o 
gcc -L/usr/lib64/ test2.o -L/usr/lib/gcc/x86_64-redhat-linux/4.4.4/ -lgomp -fopenmp -lgsl -lgslcblas -lm -o test2.out 

나는 다음과 같은 오류 메시지를 받았습니다 그것과 위의 오류 메시지가 너무 제한되어있어 무엇이 잘못되었는지 정말 알고 싶습니다. 따라서 서브 루틴을 분해하여 VEGAS_integration_routine을 호출 한 다음 한 줄씩 실행하십시오. 내가 찾은 것은 두 번째 줄에서 컴파일이 중단되었다는 것입니다.

gsl_monte_function Function = { function, 2, 0 }; 

이렇게 혼란 스러웠습니다. 루프를 평탄화하기 위해 OpenMP를 사용할 때 루프에서 GSL 기능을 선언 할 수 있습니까? GSL과 OpenMP간에 내부 충돌이 있습니까? 나는 Stack Overflow와 Google에서 검색을했는데 관련 포스트가 존재하지 않는 것 같습니다 (너무 이상합니다!) 누군가가 여기에서 무슨 일이 일어나고 있는지 설명하거나 병렬 컴퓨팅을 수행하는 다른 방법을 지적 할 수 있다면 정말 고맙겠습니다. 나는 for 루프를 작성하는 방법이 가장 좋고 가장 깨끗한 것이 아님을 확신한다 ...

답변

4

GCC의 어휘 적 클로저 구현이 OpenMP 코드 변환 엔진과 상호 작용하는 방식에 a regression bug이있다. 이 버그는 이후 버전의 GCC 4.7 분기에서 수정 된 것으로 보입니다. GCC 4.4.4를 GCC 4.7.1 이상으로 대체 할 수 없다면 게시물에서 참조하는 GSL 예제 에서처럼 중첩 된 함수를 사용하지 않도록 코드를 다시 작성해야합니다. 게다가, 중첩 된 함수는 비표준 GCC C 확장이며, 가능하면 그것들을 사용하지 않는 것이 좋습니다.

GSL의 Monte Carlo 통합 인터페이스는 설명 된 인수를 통해 피력 인수에 추가 인수를 전달하는 것을 지원합니다 (here). 읽기 VEGAS_integration_routine의 두 번째 줄을

double 
Reg1 (double *x, size_t dim, void *params) 
{ 
    double t = *(double *)params; 
    return sin(x[1])*cos(t*t)*x[0]*x[0]*cos(x[0])*cos(3*x[0]); 
} 

및 업데이트 : 다음과 같이 Reg1을 변경해야 할 것

gsl_monte_function Function = { function, 2, &t }; 

또한 VEGAS_integration_routine와 패스의 더미 인수 목록에 t을 추가해야합니다 그 값은 main입니다. 따라서 관련 부분은 다음과 같습니다.

void 
VEGAS_integration_routine (double (*function)(double *, size_t, void *), 
          double t, 
          double xl[], double xu[], size_t calls, gsl_rng * r) 
{ 
    double res, err; 
    gsl_monte_function Function = { function, 2, &t }; 
    ... 
} 

#pragma omp parallel for 
for(i=0; i <= seg; i++) 
{ 
    double t = (double)i * 0.05; 
    ... 
    VEGAS_integration_routine (Reg1, t, xl, xu, calls, r); 
} 
+0

와우 감사합니다. @Hristo! 중첩 된 함수가 C에서 비표준임을 알지 못했습니다 ... 저는 중첩 함수를 지원하는 Mathematica를 사용하여 계산을했습니다. 어쨌든, 적어도 나는 뭔가를 배웁니다! 그러나이 경우에는 GSL 통합 서브 루틴 (즉,'Reg1'을 사용하여'gsl_monte_function' 객체를 선언 한 후'gsl_monte_vegas_integrate'에 전달)에 대한 적분 함수'Reg1'의 참조를 전달해야하므로 다른 t 값으로 계산하고 싶기 때문에 (for 루프가 필요한 이유입니다.) 중첩 된 함수를 사용하지 않고 다시 작성할 수 있습니까? –

+0

그것은 가능하며 GSL은이를 수행 할 수있는 특정 인터페이스를 제공합니다. 그에 따라 내 대답을 업데이트했습니다. –

+0

코드가 올바르게 작동하는 것보다 더 흥미로운 것은 없습니다! 나는 당신의 상세한 답변을 주셔서 감사합니다! (솔직히 말하면, 왜 무효 포인터'params'가 있는지 이해하지 못했습니다 (예 : [here] (http://www.gnu.org/software/gsl/manual/html_node/Monte-Carlo-Interface.html 참조).)) 내가 수정 된 코드를 읽을 때까지 ...) –