ejecutar con compilar compilador como c++ c gcc compiler-errors

c++ - compilar - GCC compila el error con> 2 GB de código



gcc compilador (11)

Tengo un gran número de funciones que suman alrededor de 2.8 GB de código objeto (lamentablemente no hay forma de evitarlo, la informática científica ...)

Cuando trato de vincularlos, obtengo (esperaba) la relocation truncated to fit: R_X86_64_32S errores relocation truncated to fit: R_X86_64_32S , que esperaba eludir especificando el indicador del compilador -mcmodel=medium . Todas las bibliotecas que están vinculadas además de las que tengo control se compilan con el indicador -fpic .

Aun así, el error persiste y supongo que algunas bibliotecas a las que enlazo no se compilan con PIC.

Aquí está el error:

/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

Y las bibliotecas del sistema con las que enlazo:

-lgfortran -lm -lrt -lpthread

¿Alguna pista sobre dónde buscar el problema?

EDITAR: Antes que nada, gracias por la discusión ... Para aclarar un poco, tengo cientos de funciones (cada una de aproximadamente 1 MB de tamaño en archivos 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; }

El objeto s es relativamente pequeño y mantiene las constantes necesarias x14, x15, ..., ds0, ..., etc. mientras que ti solo devuelve un doble de una biblioteca externa. Como puede ver, csc[] es un mapa de valores precalculado que también se evalúa en archivos de objetos separados (de nuevo cientos con aproximadamente ~ 1 MB de tamaño cada uno) de la siguiente 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)); } // ... }

Eso es todo. El último paso consiste en llamar a todos esos func[i] y sumar el resultado.

Con respecto al hecho de que este es un caso bastante especial e inusual: Sí, lo es. Esto es lo que la gente tiene que hacer frente al tratar de hacer cálculos de alta precisión para la física de partículas.

EDIT2: También debería agregar que x12, x13, etc. no son realmente constantes. Se establecen en valores específicos, todas esas funciones se ejecutan y se devuelve el resultado, y luego se elige un nuevo conjunto de x12, x13, etc. para producir el siguiente valor. Y esto tiene que hacerse 10 ^ 5 a 10 ^ 6 veces ...

EDIT3: Gracias por las sugerencias y la discusión hasta el momento ... Trataré de pasar los bucles hasta la generación de código de alguna manera, no estoy seguro de cómo exactamente esto, para ser sincero, pero esta es la mejor opción.

Por cierto, no traté de esconderme detrás de "esto es computación científica, no hay manera de optimizar". Es solo que la base de este código es algo que surge de una "caja negra" a la que no tengo acceso real y, además, todo funcionó muy bien con ejemplos simples, y principalmente me siento abrumado con lo que sucede en un entorno real. aplicación mundial ...

EDIT4: Así que, he logrado reducir el tamaño del código de las definiciones csc en aproximadamente una cuarta parte al simplificar las expresiones en un sistema de álgebra computacional ( Mathematica ). Ahora también veo una forma de reducirlo en otro orden de magnitud, aplicando algunos otros trucos antes de generar el código (que reduciría esta parte a unos 100 MB) y espero que esta idea funcione.

Ahora, relacionado con sus respuestas: estoy tratando de volver a hacer los loops en las func , donde un CAS no ayudará mucho, pero ya tengo algunas ideas. Por ejemplo, ordenar las expresiones por las variables como x12, x13,... , analizar las csc con Python y generar tablas que las relacionen entre sí. Entonces al menos puedo generar estas partes como bucles. Como esta parece ser la mejor solución hasta ahora, marcó esto como la mejor respuesta.

Sin embargo, me gustaría dar crédito a VJo. GCC 4.6 de hecho funciona mucho mejor, produce código más pequeño y es más rápido. El uso del modelo grande funciona en el código tal como está. Entonces, técnicamente esta es la respuesta correcta, pero cambiar el concepto completo es un enfoque mucho mejor.

Gracias a todos por sus sugerencias y ayuda. Si alguien está interesado, voy a publicar el resultado final tan pronto como esté listo.

OBSERVACIONES: Solo algunas observaciones sobre algunas otras respuestas: el código que trato de ejecutar no se origina en una expansión de funciones / algoritmos simples y un estúpido despliegue innecesario. Lo que sucede en realidad es que las cosas con las que empezamos son objetos matemáticos bastante complicados y llevarlos a una forma numéricamente computable genera estas expresiones. El problema yace en realidad en la teoría física subyacente. La complejidad de las expresiones intermedias escala factorialmente, lo cual es bien conocido, pero cuando se combina todo esto con algo físicamente medible -un observable- se reduce a solo un puñado de funciones muy pequeñas que forman la base de las expresiones. (Definitivamente hay algo "incorrecto" a este respecto con la ansatz general y única disponible que se llama "teoría de la perturbación"). Tratamos de llevar esta ansatz a otro nivel, que ya no es factible analíticamente y donde la base de las funciones necesarias es no conocida. Así que tratamos de usar la fuerza bruta de esta manera. No es la mejor manera, pero con suerte una que ayude con nuestra comprensión de la física en cuestión al final ...

ÚLTIMA EDICIÓN: gracias a todas sus sugerencias, he logrado reducir considerablemente el tamaño del código, usando Mathematica y una modificación del generador de código para las func alguna manera en la línea de la respuesta principal :)

He simplificado las funciones de csc con Mathematica, reduciéndolo a 92 MB. Esta es la parte irreducible. Los primeros intentos tomaron una eternidad, pero después de algunas optimizaciones ahora se ejecuta en aproximadamente 10 minutos en una sola CPU.

El efecto en las func fue dramático: el tamaño total del código para ellos es de aproximadamente 9 MB, por lo que el código ahora suma en el rango de 100 MB. Ahora tiene sentido activar las optimizaciones y la ejecución es bastante rápida.

Nuevamente, gracias a todos por sus sugerencias, he aprendido mucho.


¡El error ocurre porque tienes demasiado CÓDIGO, no datos! Esto se indica, por ejemplo, __libc_csu_fini (que es una función) a la que se hace referencia desde _start y la reubicación se trunca para ajustarse. Esto significa que _start (el verdadero punto de entrada del programa) está tratando de llamar a esa función mediante un desplazamiento SIGNED de 32 bits, que tiene solo un rango de 2 GB. Dado que la cantidad total de su código de objeto es ~ 2.8 GB, los hechos salen.

Si pudiera rediseñar sus estructuras de datos, gran parte de su código podría ser "comprimido" reescribiendo las enormes expresiones como simples bucles.

Además, puede calcular csc[] en un programa diferente, almacenar los resultados en un archivo y simplemente cargarlos cuando sea necesario.


Con un programa de ese lado, es muy probable que los errores de caché para el código excedan los costos de bucle en el tiempo de ejecución. Le recomendaría que vuelva a su generador de códigos, y le haga generar una representación compacta de lo que quiere evaluar (es decir, uno que pueda caber en D-caché), luego ejecútelo con un intérprete en su programa. También podría ver si puede factorizar kernels más pequeños que aún tienen un número significativo de operaciones, y luego usarlos como ''instrucciones'' en el código interpretado.


Creo que todos están de acuerdo en que debería haber una forma diferente de hacer lo que quieres hacer. ¿Compilar cientos de megabytes (gigabytes?) De código, vincularlo en un ejecutable de varios gigabytes y ejecutarlo suena muy ineficiente.

Si entiendo tu problema correctamente, utilizas algún tipo de generador de código, G, para generar un conjunto de funciones func1...N que toman un montón de mapas csc1...M como entrada. Lo que quiere hacer es calcular csc1...M , y ejecutar un bucle de 1,000,000 de veces para diferentes entradas y cada vez encontrar s = func1 + func2 + ... + funcN . No especificó cómo fucn1...N están relacionados con csc1...M embargo.

Si todo eso es cierto, parece que debería ser capaz de cambiar el problema de manera diferente, lo que potencialmente puede ser mucho más manejable e incluso posiblemente más rápido (es decir, permitir que la memoria caché de su máquina realmente funcione).

Además del problema práctico de los tamaños de los archivos objeto, su programa actual no será eficiente ya que no localiza el acceso a los datos (demasiados mapas enormes) y no tiene ejecución de código localizado (demasiadas funciones muy largas).

¿Qué hay de romper su programa en 3 fases: Fase 1 construir csc1...M y almacenarlos. La Fase 2 construye una func a la vez, la ejecuta 1,000,000 de veces con cada entrada y almacena los resultados. La Fase 3 encuentra la suma de los resultados de los func1...N resultados almacenados para cada corrida de 1,000,000 de veces. Lo bueno de esta solución es que se puede hacer fácilmente en paralelo en varias máquinas independientes.

Editar: @bbtrb, ¿podría hacer que una func y una csc estén disponibles? Parecen ser muy regulares y compresibles. Por ejemplo, func1 parece ser solo una suma de expresiones, cada una de las cuales consta de 1 coeficiente, 2 índices para las variables en s y 1 índice en csc. Por lo tanto, se puede reducir a un buen bucle. Si hace que los ejemplos completos estén disponibles, estoy seguro de que se pueden encontrar maneras de comprimirlos en bucles en lugar de expresiones largas.


El ABI x86-64 utilizado por Linux define un "modelo grande" específicamente para evitar tales limitaciones de tamaño, que incluye tipos de reubicación de 64 bits para GOT y PLT. (Consulte la tabla en la sección 4.4.2, y las secuencias de instrucciones en 3.5.5 que muestran cómo se usan).

Como tus funciones ocupan 2,8 GB, no tienes suerte, porque gcc no es compatible con modelos grandes. Lo que puede hacer es reorganizar su código de tal forma que le permita dividirlo en bibliotecas compartidas que vinculará dinámicamente.

Si eso no es posible, como alguien sugirió, en lugar de poner sus datos en el código (compilarlos y vincularlos), dado que es enorme, puede cargarlo en tiempo de ejecución (ya sea como un archivo normal, o puede mapearlo).

EDITAR

Parece que el modelo grande es compatible con gcc 4.6 (ver esta página ). Puede intentarlo, pero lo anterior aún se aplica a la reorganización de su código.


El enlazador está intentando generar compensaciones de reubicación de 32 bits dentro de un binario que de alguna manera ha excedido estas limitaciones. Intente reducir los requisitos de espacio de direcciones del programa principal.

¿Puedes dividir parte / la mayoría del código objeto en una o más bibliotecas (también compiladas con -fpic / -fPIC)? A continuación, genere un binario no estático que enlaza con estas libs. Las bibliotecas vivirán en bloques de memoria discretos y sus desplazamientos de reubicación serán dinámicos / absolutos (64 bits) en lugar de relativos (32 bits).


Entonces, ya tienes un programa que produce este texto:

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] -...

y

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 -...

¿derecho?

Si todas sus funciones tienen un "formato" similar (multiplique n números m veces y agregue los resultados, o algo similar), entonces creo que puede hacer esto:

  • cambie el programa del generador a compensaciones de salida en lugar de cadenas (es decir, en lugar de la cadena "s.ds0" producirá offsetof(ProcessVars, ds0)
  • crear una matriz de tales compensaciones
  • escriba un evaluador que acepte el conjunto de arriba y las direcciones de base de los punteros de estructura y produzca un resultado

El conjunto + evaluador representará la misma lógica que una de sus funciones, pero solo el evaluador será el código. La matriz es "datos" y puede generarse en tiempo de ejecución o guardarse en un disco y leer i fragmentos o con un archivo mapeado en la memoria.

Para su ejemplo particular en func1 imagínese cómo reescribiría la función a través de un evaluador si tuviera acceso a la dirección base de s csc y también una representación vectorial de las constantes y los desplazamientos que necesita agregar a las direcciones base para obtener a x14 , ds8 y csc[51370]

Necesita crear una nueva forma de "datos" que describa cómo procesar los datos reales que pasa a su gran cantidad de funciones.


Esas expresiones se parecen mucho a una serie alterna para mí. No sé cómo se ve el resto del código, pero no parece que sea tan difícil derivar la expresión generadora. Probablemente también valga la pena en el momento de la ejecución, especialmente si tiene 2,8 GB de código desenrollado de 2 KB.


Me parece que el código está haciendo integración numérica usando algún tipo de método de profundidad adaptativa. Desafortunadamente, el generador de códigos (o más bien el autor del generador de códigos) es tan estúpido como para generar una función por parche en lugar de uno por tipo de parche. Como tal, ha producido demasiados códigos para ser compilados, e incluso si pudiera compilarse, su ejecución sería dolorosa porque nunca se ha compartido nada en ninguna parte. (¿Te imaginas el dolor resultante de tener que cargar cada página del código de objeto del disco porque nunca se comparte nada y siempre es un candidato para el sistema operativo desalojar. Por no mencionar las cachés de instrucciones, que serán inútiles).

La solución es dejar de desenrollar todo; para este tipo de código, desea maximizar el intercambio ya que la carga de las instrucciones adicionales para acceder a los datos en patrones más complejos será absorbida por el costo de lidiar con el (presumiblemente) gran conjunto de datos subyacente de todos modos. También es posible que el generador de códigos lo haga de manera predeterminada, y que el científico haya visto algunas opciones para desenrollar (con la nota de que a veces esto mejora la velocidad) y las haya encendido todas a la vez, y ahora insiste en que este lío resultante sea aceptado por la computadora, en lugar de aceptar las restricciones reales de la máquina y usar la versión numéricamente correcta que se genera de manera predeterminada. Pero si el generador de códigos no lo hace, obtenga uno que lo haga (o piratee el código existente).

El resultado final: compilar y vincular 2.8GB de código no funciona y no debería forzarse a funcionar. Encontrar otra forma.


Parece el resultado de la generación incorrecta de códigos, tal vez mediante álgebra simbólica y / o desenrollado manual. Es bien sabido que las manipulaciones simbólicas crecen exponencialmente en la profundidad del árbol de expresión o gráfico computacional. Es probable que la diferenciación automática se pueda usar aquí, lo que haría que el tamaño del código sea bastante pequeño y también aceleraría la ejecución de forma espectacular.


Si leo tus errores correctamente, lo que te hace superar el límite es la sección de datos inicializados (si fuera el código, tendrías muchos más errores en mi humilde opinión). ¿Tienes grandes conjuntos de datos globales? Si es el caso, reestructuraría el programa para que se asignen dinámicamente. Si los datos se inicializan, los leería desde un archivo de configuración.

Por cierto, viendo esto:

(.text + 0x20): referencia indefinida a `main ''

Creo que tienes otro problema.


Un par de sugerencias: - Optimizar para el tamaño (-Os). Haga sus llamadas a funciones en línea, llamadas a funciones normales. Habilite la agrupación de cadenas.

Intente dividir las cosas en diferentes DLL (objetos compartidos, .so para Linux, .dylib para Mac OS X). Asegúrese de que se puedan descargar. Luego implemente algo para cargar cosas a pedido y libérelas cuando no las necesite.

De lo contrario, divida su código en diferentes archivos ejecutables y use algo para comunicarse entre ellos (tuberías, conectores, incluso escribir / leer en el archivo). Torpe, pero ¿qué opciones tienes?

Totalmente alternativo: - Utiliza un lenguaje dinámico con JIT . Justo encima de mi cabeza - use LuaJIT - y LuaJIT escribir (¿regenerar?) Muchas de estas expresiones en Lua u otros idiomas y tiempos de ejecución que permitan que el código sea basura.

LuaJIT es bastante eficiente, a veces supera C / C ++ para ciertas cosas, pero a menudo muy cerca (a veces puede ser lento debido a la mala recolección de basura aún allí). Compruébalo tú mismo

http://luajit.org/performance_x86.html

Descargue el archivo scimark2.lua desde allí y compárelo con la versión "C" (google it); a menudo los resultados son muy similares.