코드가 2GB 이상인 GCC 컴파일 오류

나는 총 2.8GB의 개체 코드에 해당하는 엄청난 수의 기능을 가지고 있습니다 (불행히도 주위에 방법이 없습니다, 과학 컴퓨팅 …)

링크를 시도 할 때 relocation truncated to fit: R_X86_64_32S컴파일러 플래그를 지정하여 우회하고자하는 (예상 된) 오류가 발생합니다 -mcmodel=medium. 내가 제어하는 ​​것 외에 링크 된 모든 라이브러리는 -fpic플래그 로 컴파일됩니다 .

그래도 오류가 지속되며 링크하는 일부 라이브러리가 PIC로 컴파일되지 않은 것으로 가정합니다.

오류는 다음과 같습니다.

/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x12): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_fini'     defined in .text section in /usr/lib64/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x19): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_init'    defined in .text section in /usr/lib64/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o: In function    `call_gmon_start':
(.text+0x7): relocation truncated to fit: R_X86_64_GOTPCREL against undefined symbol      `__gmon_start__'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o: In function `__do_global_dtors_aux':
crtstuff.c:(.text+0xb): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x13): relocation truncated to fit: R_X86_64_32 against symbol `__DTOR_END__' defined in .dtors section in /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtend.o
crtstuff.c:(.text+0x19): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0x28): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x38): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x3f): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0x46): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x51): additional relocation overflows omitted from the output
collect2: ld returned 1 exit status
make: *** [testsme] Error 1

그리고 내가 연결하는 시스템 라이브러리 :

-lgfortran -lm -lrt -lpthread

문제를 찾을 수있는 단서가 있습니까?

편집 : 우선, 토론에 감사드립니다 … 조금을 명확히하기 위해 다음과 같은 수백 가지 기능 (개별 개체 파일의 크기 약 1MB)이 있습니다.

double func1(std::tr1::unordered_map<int, double> & csc,
             std::vector<EvaluationNode::Ptr> & ti,
             ProcessVars & s)
{
    double sum, prefactor, expr;

    prefactor = +s.ds8*s.ds10*ti[0]->value();
    expr =       ( - 5/243.*(s.x14*s.x15*csc[49300] + 9/10.*s.x14*s.x15*csc[49301] +
           1/10.*s.x14*s.x15*csc[49302] - 3/5.*s.x14*s.x15*csc[49303] -
           27/10.*s.x14*s.x15*csc[49304] + 12/5.*s.x14*s.x15*csc[49305] -
           3/10.*s.x14*s.x15*csc[49306] - 4/5.*s.x14*s.x15*csc[49307] +
           21/10.*s.x14*s.x15*csc[49308] + 1/10.*s.x14*s.x15*csc[49309] -
           s.x14*s.x15*csc[51370] - 9/10.*s.x14*s.x15*csc[51371] -
           1/10.*s.x14*s.x15*csc[51372] + 3/5.*s.x14*s.x15*csc[51373] +
           27/10.*s.x14*s.x15*csc[51374] - 12/5.*s.x14*s.x15*csc[51375] +
           3/10.*s.x14*s.x15*csc[51376] + 4/5.*s.x14*s.x15*csc[51377] -
           21/10.*s.x14*s.x15*csc[51378] - 1/10.*s.x14*s.x15*csc[51379] -
           2*s.x14*s.x15*csc[55100] - 9/5.*s.x14*s.x15*csc[55101] -
           1/5.*s.x14*s.x15*csc[55102] + 6/5.*s.x14*s.x15*csc[55103] +
           27/5.*s.x14*s.x15*csc[55104] - 24/5.*s.x14*s.x15*csc[55105] +
           3/5.*s.x14*s.x15*csc[55106] + 8/5.*s.x14*s.x15*csc[55107] -
           21/5.*s.x14*s.x15*csc[55108] - 1/5.*s.x14*s.x15*csc[55109] -
           2*s.x14*s.x15*csc[55170] - 9/5.*s.x14*s.x15*csc[55171] -
           1/5.*s.x14*s.x15*csc[55172] + 6/5.*s.x14*s.x15*csc[55173] +
           27/5.*s.x14*s.x15*csc[55174] - 24/5.*s.x14*s.x15*csc[55175] +
           // ...
           ;

        sum += prefactor*expr;
    // ...
    return sum;
}

객체 s는 상대적으로 작고 필요한 상수 x14, x15, …, ds0, … 등을 유지하면서 ti외부 라이브러리에서 double을 반환합니다. 보시다시피, csc[]는 다음 형식의 개별 개체 파일 (각각 약 ~ 1MB 크기의 수백 개)에서도 평가되는 미리 계산 된 값 맵입니다.

void cscs132(std::tr1::unordered_map<int,double> & csc, ProcessVars & s)
{
    {
    double csc19295 =       + s.ds0*s.ds1*s.ds2 * ( -
           32*s.x12pow2*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x15*s.x35*s.x45*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x35*s.x45*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.mbpow4*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.x35*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.x45*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35*s.mbpow4*s.mWpowinv2 +
           32*s.x12pow2*s.x35pow2*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35pow2*s.x45*s.mWpowinv2 +
           64*s.x12pow2*s.x35*s.x45*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35*s.x45pow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.mbpow4*s.mWpowinv2 +
           64*s.x12*s.p1p3*s.x15pow2*s.mbpow2*s.mWpowinv2 +
           96*s.x12*s.p1p3*s.x15*s.x25*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.x45*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.mbpow4*s.mWpowinv2 +
           32*s.x12*s.p1p3*s.x25pow2*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.x45*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x45*s.mbpow2 +
           64*s.x12*s.x14*s.x15pow2*s.x35*s.mWpowinv2 +
           96*s.x12*s.x14*s.x15*s.x25*s.x35*s.mWpowinv2 +
           32*s.x12*s.x14*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.x14*s.x15*s.x35pow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x15*s.x35*s.x45*s.mWpowinv2 +
           32*s.x12*s.x14*s.x25pow2*s.x35*s.mWpowinv2 +
           32*s.x12*s.x14*s.x25*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x25*s.x35pow2*s.mWpowinv2 -
           // ...

       csc.insert(cscMap::value_type(192953, csc19295));
    }

    {
       double csc19296 =      // ... ;

       csc.insert(cscMap::value_type(192956, csc19296));
    }

    // ...
}

그게 다예요. 마지막 단계는 모든 것을 호출 func[i]하고 결과를 합산하는 것입니다.

이것이 다소 특별하고 특이한 경우라는 사실에 관하여 : 네, 그렇습니다. 이것은 사람들이 입자 물리학을위한 고정밀 계산을 시도 할 때 대처해야하는 것입니다.

EDIT2 : x12, x13 등이 실제로 상수가 아니라는 것도 추가해야합니다. 특정 값으로 설정되고 모든 함수가 실행되고 결과가 반환되며 다음 값을 생성하기 위해 새로운 x12, x13 등이 선택됩니다. 그리고 이것은 10 ^ 5에서 10 ^ 6 번해야합니다 …

EDIT3 : 지금까지 제안과 토론을 해주셔서 감사합니다 … 솔직히 말해서 정확히 어떻게해야할지 모르겠지만 어떻게 든 코드 생성시 루프를 롤업하려고 노력할 것입니다.하지만 이것이 최선의 방법입니다.

BTW, 나는 “이것은 과학적 컴퓨팅이다. 이 코드의 기초는 내가 실제로 접근 할 수없는 “블랙 박스”에서 나오는 것뿐입니다. 게다가 모든 것이 간단한 예제로 훌륭하게 작동했습니다. 그리고 저는 주로 실제에서 일어나는 일에 압도당했습니다. 세계 응용 …

EDIT4 : 그래서 저는 csc컴퓨터 대수 시스템 ( Mathematica ) 에서 표현을 단순화 하여 정의 의 코드 크기를 약 1/4로 줄일 수있었습니다 . 이제 코드를 생성하기 전에 다른 트릭 (이 부분을 약 100MB로 줄임)을 적용하여 다른 크기로 줄일 수있는 방법도 알고 있으며이 아이디어가 효과가 있기를 바랍니다.

이제 귀하의 답변과 관련이 있습니다. funcCAS가 많이 도움이되지 않는 s 에서 루프를 다시 롤백하려고 시도하고 있지만 이미 몇 가지 아이디어가 있습니다. 예를 들어,와 같은 변수를 기준으로 표현식을 정렬하면 s를 Python으로 x12, x13,...구문 분석하고 csc서로 관련된 테이블을 생성합니다. 그런 다음 적어도 이러한 부분을 루프로 생성 할 수 있습니다. 이것이 지금까지 최선의 해결책 인 것처럼 보이므로 이것을 최선의 답변으로 표시합니다.

그러나 VJo에게도 신용을 부여하고 싶습니다. GCC 4.6은 실제로 훨씬 더 잘 작동 하고 더 작은 코드를 생성하며 더 빠릅니다. 큰 모델을 사용하면 코드에서있는 그대로 작동합니다. 기술적으로 이것은 정답이지만 전체 개념을 변경하는 것이 훨씬 더 나은 접근 방식입니다.

귀하의 제안과 도움에 감사드립니다. 관심이 있으신 분은 준비가되는대로 최종 결과물을 게시하겠습니다.

비고 : 다른 답변에 대한 언급 : 제가 실행하려는 코드는 단순한 함수 / 알고리즘의 확장과 어리석은 불필요한 풀기에서 비롯된 것이 아닙니다. 실제로 일어나는 일은 우리가 시작하는 것은 매우 복잡한 수학적 객체이고 그것들을 수치 적으로 계산 가능한 형태로 가져 오면 이러한 표현이 생성 된다는 것 입니다. 문제는 실제로 근본적인 물리적 이론에 있습니다. 중간 표현의 복잡성은 팩토리얼로 확장되는데, 이는 잘 알려진 사실이지만,이 모든 것을 물리적으로 측정 할 수있는 것으로 결합하면 (관찰 가능한) 표현의 기초를 형성하는 매우 작은 함수 몇 개로 귀결됩니다. (일반적으로 사용할 수 있는이 점에서 “잘못된”것이 있습니다.ansatz ( “perturbation theory”라고 함)) 우리는이 ansatz를 더 이상 분석적으로 실행 불가능하고 필요한 기능의 기초가 알려지지 않은 다른 수준으로 가져 오려고합니다. 그래서 우리는 이것을 이렇게 무차별 대입하려고합니다. 최선의 방법은 아니지만 결국 물리학에 대한 우리의 이해를 돕는 방법 이길 바랍니다.

최종 편집 :
모든 제안 덕분에, 나는 티카와가 코드 생성기의 수정 사용, 상당히 코드 크기를 줄이기 위해 관리했습니다 func상단 응답의 라인을 따라 다소들 🙂

cscMathematica로 함수를 단순화하여 92MB로 줄였습니다. 이것은 환원 불가능한 부분입니다. 첫 번째 시도는 오랜 시간이 걸렸지 만 일부 최적화 후 단일 CPU에서 약 10 분 만에 실행됩니다.

에 미치는 영향 func은 극적이었습니다. 전체 코드 크기가 약 9MB로 줄어 들었으므로 이제 코드는 총 100MB 범위에 속합니다. 이제 최적화를 켜는 것이 합리적이며 실행이 매우 빠릅니다.

다시 한 번, 여러분의 제안에 감사드립니다. 많은 것을 배웠습니다.



답변

따라서이 텍스트를 생성하는 프로그램이 이미 있습니다.

prefactor = +s.ds8*s.ds10*ti[0]->value();
expr = ( - 5/243.*(s.x14*s.x15*csc[49300] + 9/10.*s.x14*s.x15*csc[49301] +
       1/10.*s.x14*s.x15*csc[49302] - 3/5.*s.x14*s.x15*csc[49303] -...

double csc19295 =       + s.ds0*s.ds1*s.ds2 * ( -
       32*s.x12pow2*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
       32*s.x12pow2*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
       32*s.x12pow2*s.x15*s.x35*s.x45*s.mWpowinv2 -...

권리?

모든 함수가 비슷한 “형식”(n 개의 숫자를 m 번 곱하고 결과를 더하거나 비슷한 것을 추가)하면 다음과 같이 할 수 있다고 생각합니다.

  • 생성기 프로그램을 문자열 대신 출력 오프셋으로 변경하십시오 (즉, 문자열 “s.ds0″대신 생성 offsetof(ProcessVars, ds0)
  • 이러한 오프셋의 배열을 만듭니다.
  • 위의 배열과 구조체 포인터의 기본 주소를 받아들이고 결과를 생성하는 평가자를 작성하십시오.

배열 + 평가자는 함수 중 하나와 동일한 논리를 나타내지 만 평가자 만 코드가됩니다. 배열은 “데이터”이며 런타임에 생성되거나 디스크에 저장되어 i 청크 또는 메모리 매핑 파일을 읽을 수 있습니다.

FUNC1의 특정 예를 들어,베이스의 주소에 대한 액세스 권한이 있다면 당신은 평가를 통해 기능을 다시 얼마나 상상 scsc와도 상수와 당신이 얻을 수있는 기본 주소에 추가해야하는 오프셋 (offset)의 표현과 같은 벡터 x14, ds8csc[51370]

수많은 함수에 전달하는 실제 데이터를 처리하는 방법을 설명하는 새로운 형태의 “데이터”를 만들어야합니다.


답변

ABI 리눅스 – 64에서 사용은 에 “L 모델”구체적 GOT 및 PLT 64 비트 재배치 타입을 포함하는 이러한 크기의 제한을 피할 수를 정의한다. (섹션 4.4.2의 표와 사용 방법을 보여주는 3.5.5의 명령어 시퀀스를 참조하십시오.)

함수가 2.8GB를 차지하므로 gcc가 대형 모델을 지원하지 않기 때문에 운이 좋지 않습니다. 할 수있는 일은 동적으로 링크 할 공유 라이브러리로 분할 할 수있는 방식으로 코드를 재구성하는 것입니다.

이것이 가능하지 않다면 누군가가 제안했듯이 데이터를 코드에 넣는 대신 (컴파일하고 연결하는 대신), 크기가 크므로 런타임에로드 할 수 있습니다 (일반 파일로로드하거나 mmap 할 수 있음).

편집하다

대형 모델이 gcc 4.6에서 지원되는 것 같습니다 ( 이 페이지 참조 ). 시도해 볼 수 있지만 위의 내용은 코드 재구성에 여전히 적용됩니다.


답변

그 쪽의 프로그램을 사용하면 코드에 대한 캐시 미스가 런타임에 루핑 비용을 초과 할 가능성이 매우 높습니다. 코드 생성기로 돌아가서 생성하도록 권장합니다. 평가하려는 항목 (즉, D- 캐시에 맞을 가능성이있는 것)에 대한 간결한 표현을 다음 프로그램의 인터프리터로 실행하는 것이 좋습니다. 여전히 상당한 수의 작업이있는 더 작은 커널을 제거 할 수 있는지 확인한 다음이를 해석 된 코드에서 ‘명령’으로 사용할 수 있습니다.


답변

데이터가 아닌 CODE가 너무 많기 때문에 오류가 발생합니다! 이것은 예를 들어 __libc_csu_fini(함수) 참조되는 것으로 표시되고 _start재배치는 적합하도록 잘립니다. 이것은_start (프로그램의 실제 진입 점) 범위가 2GB 인 SIGNED 32 비트 오프셋을 통해 해당 함수를 호출하려고합니다. 개체 코드의 총량이 ~ 2.8GB이므로 사실이 확인됩니다.

데이터 구조를 재 설계 할 수 있다면 거대한 표현식을 간단한 루프로 다시 작성하여 대부분의 코드를 “압축”할 수 있습니다.

또한 csc[]다른 프로그램에서 계산 하고 결과를 파일에 저장하고 필요할 때로드 할 수 있습니다.


답변

여러분이하고 싶은 일을 할 수있는 다른 방법이 있어야한다는 데 모두가 동의한다고 생각합니다. 수백 메가 바이트 (기가 바이트?)의 코드를 컴파일하고이를 멀티 기가 바이트 크기의 실행 파일에 연결하고 실행하는 것은 매우 비효율적으로 들립니다.

문제를 올바르게 이해하면 일종의 코드 생성기 G를 사용하여 여러 func1...Ncsc1...M을 입력으로 사용 하는 여러 함수를 생성합니다 . 당신이 원하는 것은 계산하고 csc1...M, 다른 입력과 매번 찾을 때마다 1,000,000 번의 루프를 실행하는 것 s = func1 + func2 + ... + funcN입니다. 그래도 어떻게 fucn1...N관련 되는지 지정하지 않았습니다 csc1...M.

모든 것이 사실이라면, 잠재적으로 훨씬 더 관리하기 쉽고 더 빠를 수있는 다른 방식으로 문제를 해결할 수 있어야합니다 (즉, 컴퓨터의 캐시가 실제로 작동하도록하는 것).

객체 파일 크기의 실질적인 문제 외에도 현재 프로그램은 데이터에 대한 액세스를 지역화하지 않고 (너무 많은 거대한 맵) 지역화 된 코드 실행 (너무 많은 매우 긴 함수)이 없기 때문에 효율적이지 않습니다.

프로그램을 3 단계로 나누는 방법 : 1 단계 빌드 csc1...M및 저장. 2 단계 func는 한 번에 하나씩 빌드 하고 각 입력으로 1,000,000 번 실행하고 결과를 저장합니다. 3 단계 func1...N에서는 1,000,000 회 중 각 실행에 대해 저장된 결과 의 합계를 찾습니다 . 이 솔루션의 좋은 점은 여러 독립 시스템에서 쉽게 병렬화 할 수 있다는 것입니다.

편집 : @bbtrb, 하나의 func와 하나의 csc를 사용 가능하게 만들 수 있습니까? 그들은 매우 규칙적이고 압축 가능한 것처럼 보입니다. 예를 들어 func1은 각각 1 개의 계수, s의 변수에 대한 2 개의 인덱스 및 csc에 대한 1 개의 인덱스로 구성된 표현식의 합계 인 것 같습니다. 따라서 멋진 루프로 줄일 수 있습니다. 완전한 예제를 제공한다면 긴 표현이 아닌 루프로 압축하는 방법을 찾을 수있을 것입니다.


답변

오류를 올바르게 읽으면 한계를 넘게 만드는 것은 초기화 된 데이터 섹션입니다 (코드라면 훨씬 더 많은 오류 IMHO가 발생합니다). 방대한 글로벌 데이터 배열이 있습니까? 이 경우 동적으로 할당되도록 프로그램을 재구성 할 것입니다. 데이터가 초기화되면 구성 파일에서 읽습니다.

이것을보고있는 BTW :

(.text + 0x20) :`main ‘에 대한 정의되지 않은 참조

다른 문제가 있다고 생각합니다.


답변

코드가 일종의 적응 깊이 방법을 사용하여 수치 적분을 수행하는 것처럼 보입니다. 불행히도 코드 생성기 (또는 코드 생성기의 작성자)는 유형 당 하나가 아닌 패치 당 하나의 함수를 생성하는 것이 너무 어리 석습니다. . 따라서 컴파일하기에는 너무 많은 코드가 생성되고 컴파일 될 수 있다고하더라도 어디에도 공유되는 것이 없기 때문에 실행이 고통 스러울 것입니다. (아무것도 공유되지 않았기 때문에 디스크에서 개체 코드의 각 페이지를로드해야하는 고통을 상상할 수 있습니까? 따라서 항상 OS가 제거 할 후보입니다. 쓸모 없게 될 명령 캐시는 말할 것도 없습니다.)

수정 사항은 모든 것을 풀지 않는 것입니다. 이런 종류의 코드의 경우 공유최대화하고 더 복잡한 패턴의 데이터에 액세스하기위한 추가 명령의 오버 헤드가 어쨌든 대규모 기본 데이터 세트를 처리하는 비용으로 흡수되기 때문에 합니다. 코드 생성기가 기본적으로이 작업을 수행 할 수도 있으며 과학자는 언 롤링 옵션 (때때로 속도가 향상된다는 메모 포함)을 확인하고 한꺼번에 모두 켜고이 결과로 인한 혼란을 받아 들여야한다고 주장 할 수도 있습니다. 컴퓨터의 실제 제한을 받아들이고 기본적으로 생성되는 수치 적으로 올바른 버전을 사용하는 대신 컴퓨터에 의해. 그러나 코드 생성기가이를 수행하지 않을 경우 해당 생성기를 가져 오거나 기존 코드를 해킹하십시오.

결론 : 2.8GB의 코드를 컴파일하고 연결하는 것은 작동하지 않으며 강제로 작동해서는 안됩니다. 다른 방법을 찾으십시오.