Error de compilación de GCC con> 2 GB de código

108

Tengo una gran cantidad de funciones que suman alrededor de 2.8 GB de código objeto (desafortunadamente no hay forma de evitarlo, computación científica ...)

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

Aún así, el error persiste y supongo que algunas bibliotecas con las que me vinculo no están compiladas 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 me vinculo:

-lgfortran -lm -lrt -lpthread

¿Alguna pista de dónde buscar el problema?

EDITAR: En primer lugar, 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 ses relativamente pequeño y mantiene las constantes necesarias x14, x15, ..., ds0, ..., etc., mientras que tisolo devuelve un doble de una biblioteca externa. Como puede ver, csc[]es un mapa precalculado de valores que también se evalúa en archivos de objetos separados (nuevamente 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 paso final entonces consiste en llamar a todos esos func[i]y resumir el resultado.

En cuanto al hecho de que este es un caso bastante especial e inusual: sí, lo es. Esto es lo que la gente tiene que afrontar cuando intenta 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, se ejecutan todas esas funciones y se devuelve el resultado, y luego se elige un nuevo conjunto de x12, x13, etc. para producir el siguiente valor. Y esto debe hacerse de 10 ^ 5 a 10 ^ 6 veces ...

EDIT3: Gracias por las sugerencias y la discusión hasta ahora ... Intentaré enrollar los bucles sobre la generación de código de alguna manera, no estoy seguro de cómo hacerlo exactamente, para ser honesto, pero esta es la mejor opción.

Por cierto, no traté de esconderme detrás de "esto es computación científica, no hay forma de optimizar". Es solo que la base de este código es algo que sale 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 aplicación mundial ...

EDIT4: Entonces, me las arreglé para reducir el tamaño del código de las cscdefiniciones en aproximadamente un cuarto simplificando expresiones en un sistema de álgebra por computadora ( Mathematica ). Ahora veo también alguna forma de reducirlo en otro orden de magnitud aplicando algunos otros trucos antes de generar el código (lo 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 enrollar los bucles en el funcs, donde un CAS no ayudará mucho, pero ya tengo algunas ideas. Por ejemplo, ordenar las expresiones por variables como x12, x13,..., analizar la cscs con Python y generar tablas que las relacionen entre sí. Entonces puedo al menos generar estas partes como bucles. Como esta parece ser la mejor solución hasta ahora, la marco como la mejor respuesta.

Sin embargo, también me gustaría darle crédito a VJo. De hecho, GCC 4.6 funciona mucho mejor, produce un código más pequeño y es más rápido. El uso del modelo grande funciona en el código tal cual. Entonces, técnicamente, esta es la respuesta correcta, pero cambiar todo el concepto 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 algunos comentarios a algunas otras respuestas: El código que estoy tratando de ejecutar no se origina en una expansión de funciones / algoritmos simples y un desenrollado innecesario estúpido. Lo que realmente sucede es que las cosas con las que comenzamos son objetos matemáticos bastante complicados y llevarlos a una forma numéricamente computable genera estas expresiones. El problema radica 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 combinan todas estas cosas con algo físicamente medible, un observable, solo se reduce a un puñado de funciones muy pequeñas que forman la base de las expresiones. (Definitivamente hay algo "incorrecto" a este respecto con el general y solo disponibleansatz que se llama "teoría de la perturbación") Tratamos de llevar este ansatz a otro nivel, que ya no es factible analíticamente y donde se desconoce la base de las funciones necesarias. Así que tratamos de usar la fuerza bruta de esta manera. No es la mejor manera, pero es de esperar que al final ayude con nuestra comprensión de la física en cuestión ...

ÚLTIMA EDICIÓN: Gracias a todas sus sugerencias, me las arreglé para reducir considerablemente el tamaño del código, usando Mathematica y una modificación del generador de código para la funcs algo similar a la respuesta principal :)

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

El efecto en los funcs fue dramático: el tamaño total del código para ellos se redujo a aproximadamente 9 MB, por lo que el código ahora totaliza 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.

bbtrb
fuente
17
Si tiene tantos datos, debe sacarlos de los archivos de origen y, en mmapsu lugar , sacarlos usted mismo de un binario externo en tiempo de ejecución.
R .. GitHub DEJA DE AYUDAR A ICE
3
¿Podría dar un ejemplo de una (o dos) de estas funciones? Esto realmente se ve extraño. También puede cargar estas funciones dinámicamente con la función dl *.
Patrick Schlüter
7
@bbtrb: Mi primer instinto es similar al de R .., parece un problema de diseño. Es cierto que no sé qué es común en los círculos de la informática científica, pero nunca he oído hablar de alguien que intente vincular un archivo de objeto de 2.8GB, o algo remotamente cercano a él, y no estoy seguro de que GCC realmente lo soporte. Francamente, esperaría que cualquier blob de código de ese tamaño sea puro espagueti.
Nicholas Knight
46
No hay absolutamente ninguna manera de que la solución óptima para el problema implique 2 GB de archivo objeto.
David Heffernan
35
no ponga sus datos en código
David Heffernan

Respuestas:

53

Entonces, ya tiene 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 -...

¿Derecha?

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:

  • cambiar el programa generador para generar compensaciones 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 la matriz anterior y las direcciones base de los punteros de estructura y produzca un resultado

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

Para su ejemplo particular en func1 Imagínese cómo se re-escribir la función a través de un evaluador si tuviera acceso a la dirección base sy csctambién un vector como representación de las constantes y las compensaciones que hay que añadir a las direcciones de base para llegar a x14, ds8ycsc[51370]

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

Andrei
fuente
45

La ABI x86-64 utilizada 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 utilizan).

Dado que sus funciones ocupan 2,8 GB, no tiene suerte, porque gcc no admite modelos grandes. Lo que puede hacer es reorganizar su código de tal manera que le permita dividirlo en bibliotecas compartidas que vincularía dinámicamente.

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

EDITAR

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

BЈовић
fuente
Entonces, ¿lo que está diciendo es que cuando agruparía los archivos de objeto en varias bibliotecas compartidas pequeñas, superaría las limitaciones?
bbtrb
3
@bbtrb Correcto. Pero todavía buscaría otra forma de implementar sus funciones. Apuesto a que tu compilación lleva una eternidad
BЈовић
18
WTF? Este código debe ser generado por algún script; ¡nadie escribe megabytes de código a mano! La misma lógica que genera el código también podría usarse para ejecutar el cálculo.
zvrba
6
Recomiendo encarecidamente probar gcc 4.6, es muy probable que produzca un código superior para este programa que gcc 4.1; incluso podría ser capaz de comprimir todo en 2 GB sin tener que hacer nada inteligente, eliminando el problema (pruebe combinaciones de -Os, -fwhole-program y -flto) con este volumen de código, optimizar el tamaño es optimizando la velocidad). Sin embargo, si eso no ayuda lo suficiente, también debe tener en cuenta que para que el modelo grande funcione, tendrá que reconstruir al menos parte de la biblioteca C en el modelo grande (crt * .o, libc_nonshared.a y libpthread_nonshared.a).
zwol
1
@bdonlan La vinculación estática también es una posibilidad.
zvrba
37

Con un programa de ese lado, es muy probable que los errores de caché para el código excedan los costos de bucle en tiempo de ejecución. Le recomendaría que regrese a su generador de código y haga que genere alguna representación compacta para lo que quiere evaluar (es decir, una que probablemente quepa en D-cache), luego ejecute eso con un intérprete en su programa. También puede ver si puede descartar kernels más pequeños que todavía tienen un número significativo de operaciones, luego usarlos como 'instrucciones' en el código interpretado.

bdonlan
fuente
21

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

Si pudiera rediseñar sus estructuras de datos, gran parte de su código podría "comprimirse" 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.

zvrba
fuente
¿Podría dar un ejemplo de cómo reescribiría las funciones con ciclos simples? No te sigo exactamente. csc[]debe calcularse con mucha frecuencia y me gustaría evitar la E / S de disco.
bbtrb
4
@bbtr: Por ejemplo, para func1arriba, algo como: for (int i = 0; i < N; ++i) expr += constants[i].*s.x14*s.x15*csc[49300 + i];.
HighCommander4
@ HighCommander4: absolutamente, estoy de acuerdo. Está justo encima de mi cabeza sobre cómo generar algo como esto automáticamente. Tal vez con una matriz separada que almacena los índices ...
bbtrb
2
@bbtrb: Dado que no hay forma de que alguien escriba suficiente fuente para producir 2.8GB de código objeto a mano, especialmente con nombres de símbolos tan poco mnemotécnicos, se debe haber usado un generador de código . Trabaja con eso.
Donal Fellows
15

Creo que todo el mundo está 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, usas algún tipo de generador de código, G, para generar un montón de funciones func1...Nque toman un montón de mapas csc1...Mcomo entrada. Lo que quiere hacer es calcular csc1...My ejecutar un ciclo de 1,000,000 de veces para diferentes entradas y cada vez encontrar s = func1 + func2 + ... + funcN. Sin embargo, no especificó cómo fucn1...Nestán relacionados csc1...M.

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

Además del problema práctico de los tamaños de los archivos de objetos, 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é tal si divide su programa en 3 fases: Fase 1, compile csc1...My almacene. Fase 2 compile uno funca la vez, ejecútelo 1,000,000 veces con cada entrada y almacene los resultados. La fase 3 encuentra la suma de los resultados de los func1...Nresultados almacenados para cada ejecución 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ías hacer que una función y una csc estén disponibles en algún lugar? Parecen ser muy regulares y comprimibles. 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 sy 1 índice en csc. Por lo que se puede reducir a un bonito bucle. Si ofrece ejemplos completos, estoy seguro de que se pueden encontrar formas de comprimirlos en bucles en lugar de expresiones largas.

AlefSin
fuente
Sí, lo entiendes correctamente :) Sin embargo, existen varios problemas con tu sugerencia: 1. lo peor funcdepende de casi todos cscy esos números deben calcularse también 10 ^ 6 veces. 2. La entrada se obtendrá de un integrador de Monte Carlo adaptativo, lo que significa que el integrador debe conocer el resultado completo en cada punto para poder reducir el error resultante refinando la malla en las proximidades del punto si es necesario. 3. Las expresiones grandes para cscpersistir ...
bbtrb
1
Entonces, ¿significa que no puede calcular cada uno cscen cada iteración independientemente de los demás? Si fueran independientes, aún podría ejecutar cada uno 10 ^ 6 veces y almacenar los resultados. Sin embargo, si hay dependencias entre ellos, tal vez necesite averiguar cuál está relacionado con cuál, algo así como un gráfico de dependencia, y luego tratar de ver si puede dividirlo en múltiples subgráficos independientes. Considerándolo todo, creo que la clave es dividir el problema en múltiples subproblemas independientes.
AlefSin
5

Si leo tus errores correctamente, lo que te hace traspasar 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). ¿Tiene grandes conjuntos de datos globales? Si es el caso, reestructuraría el programa para que se asignen dinámicamente. Si se inicializan los datos, los leería de un archivo de configuración.

Por cierto, viendo esto:

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

Creo que tienes otro problema.

Un programador
fuente
1
Sí, tienes razón, error estúpido, pero no resuelve los demás errores.
bbtrb
3

Me parece que el código está realizando una integración numérica utilizando algún tipo de método de profundidad adaptativo. Desafortunadamente, el generador de código (o más bien el autor del generador de código) es tan estúpido como para generar una función por parche en lugar de una por tipo de parche. Como tal, ha producido demasiado código para ser compilado, e incluso si pudiera compilarse, su ejecución sería dolorosa porque nunca se ha compartido nada en ningún lugar. (¿Puede imaginarse el dolor que resulta de tener que cargar cada página de código objeto desde el disco porque nunca se comparte nada y, por lo tanto, siempre es un candidato para que el sistema operativo lo desaloje? Por no hablar de los 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 uso compartido, ya que la sobrecarga de instrucciones adicionales para acceder a 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ódigo incluso haga esto de forma predeterminada, y que el científico haya visto algunas opciones para desenrollar (con la nota de que a veces mejoran la velocidad) y las haya activado todas a la vez y ahora insiste en que se acepte este desastre resultante. 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 por defecto. Pero si el generador de código no lo hace, obtenga uno que lo haga (o piratee el código existente).

La conclusión: compilar y vincular 2,8 GB de código no funciona y no debería obligarse a hacerlo. Encontrar otra manera.

Becarios Donal
fuente
3

Un par de sugerencias: - Optimice el tamaño (-Os). Realice sus llamadas de función en línea, llamadas de función 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 bajo demanda y libérelas cuando no las necesite.

Si no es así, divida su código en diferentes ejecutables y use algo para comunicarse entre ellos (tuberías, sockets, incluso escritura / lectura en un archivo). Torpe, pero ¿qué opciones tienes?

Totalmente alternativo: - Utilizar un lenguaje dinámico con JIT . Justo encima de mi cabeza, use LuaJIT , y reescriba (¿regenerar?) Muchas de estas expresiones en Lua , u otros lenguajes y tiempos de ejecución similares que permiten que el código se recolecte basura.

LuaJIT es bastante eficiente, a veces superando a C / C ++ para ciertas cosas, pero a menudo muy cerca (a veces puede ser lento debido a la mala recolección de basura que aún existe). Compruébelo usted mismo:

http://luajit.org/performance_x86.html

Descargue el scimark2.luaarchivo desde allí y compárelo con la versión "C" (busque en Google); a menudo, los resultados son muy parecidos.

malkia
fuente
2

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

¿Puede dividir parte o la mayor parte del código objeto en una o más bibliotecas (también compiladas con -fpic / -fPIC)? Luego genere un binario no estático que se vincule con estas bibliotecas. Las bibliotecas vivirán en bloques de memoria discretos y sus compensaciones de reubicación serán dinámicas / absolutas (64 bits) en lugar de relativas (32 bits).

ajklbahu8geag
fuente
2

Esas expresiones me parecen una serie alternante. 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 valdría la pena en el momento de la ejecución, especialmente si tiene 2.8 GB de código sin enrollar de 2 KB.

Brian
fuente
1

Esto parece el resultado de la generación de código que salió mal, quizás por á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 aquí se pueda usar la diferenciación automática, lo que haría que el tamaño del código fuera bastante pequeño y también aceleraría la ejecución de manera espectacular.

Jed
fuente