Tenho um grande número de funções, totalizando cerca de 2,8 GB de código-objeto (infelizmente não há como contornar, computação científica ...)
Quando tento vinculá-los, obtenho relocation truncated to fit: R_X86_64_32S
erros (esperados) que esperava contornar especificando o sinalizador do compilador -mcmodel=medium
. Todas as bibliotecas vinculadas, além das quais eu tenho controle, são compiladas com o -fpic
sinalizador.
Mesmo assim, o erro persiste, e suponho que algumas bibliotecas que vinculo não sejam compiladas com PIC.
Aqui está o erro:
/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
E as bibliotecas do sistema com as quais vinculo:
-lgfortran -lm -lrt -lpthread
Alguma pista de onde procurar o problema?
EDIT: Em primeiro lugar, obrigado pela discussão ... Para esclarecer um pouco, eu tenho centenas de funções (cada uma com aproximadamente 1 MB de tamanho em arquivos de objetos separados) como esta:
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;
}
O objeto s
é relativamente pequeno e mantém as constantes necessárias x14, x15, ..., ds0, ..., etc. enquanto ti
apenas retorna um duplo de uma biblioteca externa. Como você pode ver, csc[]
é um mapa pré-computado de valores que também é avaliado em arquivos de objetos separados (novamente centenas com cerca de 1 MB de tamanho cada) da seguinte forma:
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));
}
// ...
}
É sobre isso. A etapa final então consiste apenas em chamar todos aqueles func[i]
e somar o resultado.
Quanto ao fato de que este é um caso bastante especial e incomum: Sim, é. É com isso que as pessoas precisam lidar ao tentar fazer cálculos de alta precisão para a física de partículas.
EDIT2: Devo também acrescentar que x12, x13, etc. não são realmente constantes. Eles são definidos com valores específicos, todas essas funções são executadas e o resultado retornado e, em seguida, um novo conjunto de x12, x13, etc. é escolhido para produzir o próximo valor. E isso deve ser feito 10 ^ 5 a 10 ^ 6 vezes ...
EDIT3: Obrigado pelas sugestões e pela discussão até agora ... Vou tentar rolar os loops na geração de código de alguma forma, não tenho certeza de como fazer isso exatamente, para ser honesto, mas esta é a melhor aposta.
BTW, eu não tentei me esconder atrás de "isso é computação científica - nenhuma maneira de otimizar". É que a base desse código é algo que sai de uma "caixa preta" à qual não tenho acesso real e, além disso, a coisa toda funcionou muito bem com exemplos simples, e principalmente me sinto sobrecarregado com o que acontece em uma realidade aplicação mundial ...
EDIT4: Então, consegui reduzir o tamanho do código das csc
definições em cerca de um quarto, simplificando as expressões em um sistema de álgebra computacional ( Mathematica ). Vejo agora também uma maneira de reduzi-lo em outra ordem de magnitude ou mais, aplicando alguns outros truques antes de gerar o código (o que reduziria essa parte para cerca de 100 MB) e espero que essa ideia funcione.
Agora relacionado às suas respostas: Estou tentando rolar os loops de novo no func
s, onde um CAS não vai ajudar muito, mas já tenho algumas idéias. Por exemplo, classificando as expressões por variáveis como x12, x13,...
, analise os csc
s com Python e gere tabelas que os relacionem entre si. Então, posso pelo menos gerar essas partes como loops. Como esta parece ser a melhor solução até agora, eu a considero a melhor resposta.
No entanto, gostaria de dar crédito também a VJo. O GCC 4.6 realmente funciona muito melhor, produz código menor e é mais rápido. Usar o modelo grande funciona no código como está. Então, tecnicamente, essa é a resposta correta, mas mudar todo o conceito é uma abordagem muito melhor.
Obrigado a todos por suas sugestões e ajuda. Se alguém tiver interesse, postarei o resultado final assim que estiver pronto.
OBSERVAÇÕES: Apenas algumas observações para algumas outras respostas: O código que estou tentando executar não se origina em uma expansão de funções / algoritmos simples e estúpidos desdobramentos desnecessários. O que realmente acontece é que começamos com objetos matemáticos bastante complicados e trazê-los para uma forma computável numericamente gera essas expressões. O problema está, na verdade, na teoria física subjacente. A complexidade das expressões intermediárias escala fatorialmente, o que é bem conhecido, mas quando combinamos tudo isso com algo fisicamente mensurável - um observável - ela se reduz a apenas um punhado de funções muito pequenas que formam a base das expressões. (Definitivamente, há algo "errado" a esse respeito com o geral e apenas disponívelansatz que é chamado de "teoria da perturbação". Tentamos trazer este ansatz para outro nível, que não é mais viável analiticamente e onde a base das funções necessárias não é conhecida. Então, tentamos usar a força bruta assim. Não é a melhor maneira, mas espero que ajude no nosso entendimento da física em questão no final ...
ÚLTIMA EDIÇÃO:
Obrigado a todas as suas sugestões, eu consegui reduzir o tamanho do código consideravelmente, usando o Mathematica e uma modificação do gerador de código para os func
s um pouco ao longo das linhas da resposta principal :)
Simplifiquei as csc
funções com o Mathematica, diminuindo para 92 MB. Esta é a parte irredutível. As primeiras tentativas demoraram uma eternidade, mas depois de algumas otimizações, isso agora é executado em cerca de 10 minutos em uma única CPU.
O efeito sobre os func
s foi dramático: o tamanho do código inteiro para eles caiu para aproximadamente 9 MB, então o código agora totaliza na faixa de 100 MB. Agora faz sentido ativar as otimizações e a execução é bastante rápida.
Mais uma vez, obrigado a todos por suas sugestões, aprendi muito.
mmap
, retirá- los de um binário externo no tempo de execução.