Erreur de compilation GCC avec> 2 Go de code

108

J'ai un grand nombre de fonctions totalisant environ 2,8 Go de code objet (malheureusement, il n'y a pas moyen de contourner, calcul scientifique ...)

Lorsque j'essaye de les lier, j'obtiens des relocation truncated to fit: R_X86_64_32Serreurs (attendues) , que j'espérais contourner en spécifiant l'indicateur du compilateur -mcmodel=medium. Toutes les bibliothèques liées en plus que je contrôle sont compilées avec le -fpicdrapeau.

Pourtant, l'erreur persiste et je suppose que certaines bibliothèques vers lesquelles je lie ne sont pas compilées avec PIC.

Voici l'erreur:

/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

Et les bibliothèques système avec lesquelles je lie:

-lgfortran -lm -lrt -lpthread

Des indices où chercher le problème?

EDIT: Tout d'abord, merci pour la discussion ... Pour clarifier un peu, j'ai des centaines de fonctions (chacune d'environ 1 Mo de taille dans des fichiers objets séparés) comme ceci:

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;
}

L'objet sest relativement petit et conserve les constantes nécessaires x14, x15, ..., ds0, ..., etc. tout en renvoyant tisimplement un double d'une bibliothèque externe. Comme vous pouvez le voir, csc[]est une carte précalculée de valeurs qui est également évaluée dans des fichiers objets séparés (encore des centaines avec environ ~ 1 Mo de taille chacun) de la forme suivante:

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));
    }

    // ...
}

C'est à peu près ça. La dernière étape consiste alors simplement à appeler tous ceux-ci func[i]et à résumer le résultat.

Concernant le fait qu'il s'agit d'un cas assez particulier et inhabituel: Oui, c'est le cas. C'est à cela que les gens doivent faire face lorsqu'ils essaient de faire des calculs de haute précision pour la physique des particules.

EDIT2: Je devrais également ajouter que x12, x13, etc. ne sont pas vraiment des constantes. Ils sont définis sur des valeurs spécifiques, toutes ces fonctions sont exécutées et le résultat est renvoyé, puis un nouvel ensemble de x12, x13, etc. est choisi pour produire la valeur suivante. Et cela doit être fait 10 ^ 5 à 10 ^ 6 fois ...

EDIT3: Merci pour les suggestions et la discussion jusqu'à présent ... J'essaierai de rouler les boucles lors de la génération de code d'une manière ou d'une autre, je ne sais pas comment faire exactement, pour être honnête, mais c'est le meilleur pari.

BTW, je n'ai pas essayé de me cacher derrière "c'est de l'informatique scientifique - aucun moyen d'optimiser". C'est juste que la base de ce code est quelque chose qui sort d'une «boîte noire» où je n'ai pas vraiment accès et, de plus, tout a très bien fonctionné avec des exemples simples, et je me sens principalement dépassé par ce qui se passe dans un vrai application mondiale ...

EDIT4: Donc, j'ai réussi à réduire la taille du code des cscdéfinitions d'environ un quart en simplifiant les expressions dans un système d'algèbre informatique ( Mathematica ). Je vois maintenant aussi un moyen de le réduire d'un autre ordre de grandeur ou plus en appliquant quelques autres astuces avant de générer le code (ce qui ramènerait cette partie à environ 100 Mo) et j'espère que cette idée fonctionne.

Maintenant lié à vos réponses: j'essaye de remonter les boucles dans le funcs, où un CAS n'aidera pas beaucoup, mais j'ai déjà quelques idées. Par exemple, trier les expressions par les variables telles que x12, x13,..., analyser les cscs avec Python et générer des tables qui les relient les unes aux autres. Ensuite, je peux au moins générer ces parties sous forme de boucles. Comme cela semble être la meilleure solution à ce jour, je la marque comme la meilleure réponse.

Cependant, j'aimerais également rendre hommage à VJo. GCC 4.6 fonctionne en effet beaucoup mieux, produit du code plus petit et est plus rapide. L'utilisation du grand modèle fonctionne au code tel quel. Donc, techniquement, c'est la bonne réponse, mais changer tout le concept est une bien meilleure approche.

Merci à tous pour vos suggestions et votre aide. Si quelqu'un est intéressé, je publierai le résultat final dès que je serai prêt.

REMARQUES: Juste quelques remarques à quelques autres réponses: Le code que j'essaie d'exécuter ne provient pas d'une expansion de fonctions / algorithmes simples et d'un déroulement inutile et stupide. Ce qui se passe en fait, c'est que les choses avec lesquelles nous commençons sont des objets mathématiques assez compliqués et les amener à une forme calculable numériquement génère ces expressions. Le problème réside en fait dans la théorie physique sous-jacente. La complexité des expressions intermédiaires évolue de manière factorielle, ce qui est bien connu, mais lorsque l'on combine tout cela en quelque chose de physiquement mesurable - un observable - cela se résume à seulement une poignée de très petites fonctions qui forment la base des expressions. (Il y a certainement quelque chose de "mal" à cet égard avec le général et uniquement disponibleansatz qui est appelé "théorie des perturbations") Nous essayons d'amener cet ansatz à un autre niveau, qui n'est plus réalisable analytiquement et où la base des fonctions nécessaires n'est pas connue. Nous essayons donc de le forcer brutalement comme ça. Ce n'est pas le meilleur moyen, mais j'espère que celui qui nous aidera à comprendre la physique à portée de main à la fin ...

DERNIÈRE MODIFICATION: Grâce à toutes vos suggestions, j'ai réussi à réduire considérablement la taille du code, en utilisant Mathematica et une modification du générateur de code pour les funcs un peu dans le sens de la réponse du haut :)

J'ai simplifié les cscfonctions avec Mathematica, en les ramenant à 92 Mo. C'est la partie irréductible. Les premières tentatives ont pris une éternité, mais après quelques optimisations, cela dure maintenant environ 10 minutes sur un seul processeur.

L'effet sur les funcs était dramatique: la taille totale du code pour eux est réduite à environ 9 Mo, de sorte que le code totalise maintenant dans la plage de 100 Mo. Il est maintenant logique d'activer les optimisations et l'exécution est assez rapide.

Encore une fois, merci à tous pour vos suggestions, j'ai beaucoup appris.

bbtrb
la source
17
Si vous avez autant de données, vous devez les déplacer hors des fichiers source et à la place mmapvous-même à partir d'un binaire externe au moment de l'exécution.
R .. GitHub STOP HELPING ICE
3
Pourriez-vous donner un exemple d'une (ou deux) de ces fonctions? Cela semble vraiment étrange. Vous pouvez également charger ces fonctions de manière dynamique avec la fonction dl *.
Patrick Schlüter le
7
@bbtrb: Mon premier instinct est similaire à celui de R .., cela ressemble à un problème de conception. Certes, je ne sais pas ce qui est commun dans les cercles informatiques scientifiques, mais je n'ai jamais entendu parler de quelqu'un essayant de lier un fichier objet de 2,8 Go, ou quoi que ce soit à distance, et je ne suis pas sûr que GCC le soutiendrait vraiment. Franchement, je m'attendrais à ce que tout blob de code de cette taille soit de purs spaghettis.
Nicholas Knight
46
il n'y a absolument aucun moyen que la solution optimale pour le problème implique 2 Go de fichier objet.
David Heffernan
35
ne mettez pas vos données dans le code
David Heffernan

Réponses:

53

Donc, vous avez déjà un programme qui produit ce texte:

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

et

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

droite?

Si toutes vos fonctions ont un "format" similaire (multipliez n nombres m fois et ajoutez les résultats - ou quelque chose de similaire), je pense que vous pouvez le faire:

  • changez le programme générateur pour afficher des décalages au lieu de chaînes (c'est-à-dire au lieu de la chaîne "s.ds0", il produira offsetof(ProcessVars, ds0)
  • créer un tableau de ces décalages
  • écrire un évaluateur qui accepte le tableau ci-dessus et les adresses de base des pointeurs de structure et produit un résultat

Le tableau + évaluateur représentera la même logique que l'une de vos fonctions, mais seul l'évaluateur sera code. Le tableau est des «données» et peut être soit généré au moment de l'exécution, soit enregistré sur le disque et lu des morceaux i ou avec un fichier mappé en mémoire.

Pour votre exemple particulier dans func1, imaginez comment vous réécririez la fonction via un évaluateur si vous aviez accès à l'adresse de base de set ainsi cscqu'à un vecteur comme une représentation des constantes et des décalages que vous devez ajouter aux adresses de base pour y accéder x14, ds8etcsc[51370]

Vous devez créer une nouvelle forme de «données» qui décrira comment traiter les données réelles que vous transmettez à votre grand nombre de fonctions.

Andrei
la source
45

L' ABI x86-64 utilisé par Linux définit un «grand modèle» spécifiquement pour éviter de telles limitations de taille, qui inclut des types de relocalisation 64 bits pour le GOT et le PLT. (Voir le tableau dans la section 4.4.2, et les séquences d'instructions dans 3.5.5 qui montrent comment elles sont utilisées.)

Puisque vos fonctions occupent 2,8 Go, vous n'avez pas de chance, car gcc ne prend pas en charge les grands modèles. Ce que vous pouvez faire, c'est réorganiser votre code de manière à vous permettre de le diviser en bibliothèques partagées que vous lierez dynamiquement.

Si ce n'est pas possible, comme quelqu'un l'a suggéré, au lieu de mettre vos données dans du code (en les compilant et en les liant), car elles sont énormes, vous pouvez les charger au moment de l'exécution (soit en tant que fichier normal, soit vous pouvez les mmap).

ÉDITER

On dirait que le grand modèle est pris en charge par gcc 4.6 (voir cette page ). Vous pouvez essayer cela, mais ce qui précède s'applique toujours à la réorganisation de votre code.

BЈовић
la source
Donc, ce que vous dites, c'est que lorsque je regroupais les fichiers objets dans plusieurs petites bibliothèques partagées, je surmonterais les limitations?
bbtrb
3
@bbtrb Exactement. Mais je chercherais toujours une autre manière d'implémenter vos fonctions. Je parie que votre compilation prend une éternité
BЈовић
18
WTF? Ce code doit être généré par un script; personne n'écrit des mégaoctets de code à la main! La même logique qui génère le code pourrait également être utilisée pour exécuter le calcul.
zvrba
6
Je recommande fortement d'essayer gcc 4.6, il est très probable que ce programme produise un code supérieur à gcc 4.1; il peut même être capable de compresser le tout dans 2 Go sans que vous ayez à faire quoi que ce soit d'intelligent, éliminant le problème (essayez des combinaisons de -Os, -fwhole-program et -flto - avec ce volume de code, l'optimisation de la taille est optimisation de la vitesse). Cependant, si cela ne vous aide pas assez, vous devez également savoir que pour que le grand modèle fonctionne, vous devrez reconstruire au moins une partie de la bibliothèque C dans le grand modèle (crt * .o, libc_nonshared.a et libpthread_nonshared.a).
zwol le
1
@bdonlan La liaison statique est également une possibilité.
zvrba
37

Avec un programme de ce côté, les erreurs de cache pour le code sont très susceptibles de dépasser les coûts de bouclage au moment de l'exécution. Je vous recommanderais de retourner à votre générateur de code et de le faire générer une représentation compacte de ce qu'il veut évaluer (c'est-à-dire une représentation susceptible de tenir dans D-cache), puis de l'exécuter avec un interpréteur dans votre programme. Vous pouvez également voir si vous pouvez éliminer les noyaux plus petits qui ont encore un nombre important d'opérations, puis les utiliser comme «instructions» dans le code interprété.

bdonlan
la source
21

L'erreur se produit parce que vous avez trop de CODE, pas de données! Ceci est indiqué par exemple par __libc_csu_fini(qui est une fonction) référencé à partir de _startet le déplacement est tronqué pour s'adapter. Cela signifie que _start(le véritable point d'entrée du programme) tente d'appeler cette fonction via un offset de 32 bits SIGNÉ, qui n'a qu'une plage de 2 Go. Étant donné que le montant total de votre code objet est d'environ 2,8 Go, les faits sont vérifiés.

Si vous pouviez repenser vos structures de données, une grande partie de votre code pourrait être «compressée» en réécrivant les énormes expressions sous forme de simples boucles.

En outre, vous pouvez calculer csc[]dans un programme différent, stocker les résultats dans un fichier et les charger si nécessaire.

zvrba
la source
Pourriez-vous donner un exemple de la façon dont vous réécririez les fonctions avec de simples boucles? Je ne te suis pas exactement. csc[]doit être calculé très souvent et j'aimerais éviter les E / S disque.
bbtrb
4
@bbtr: Par exemple, pour func1ci - dessus, quelque chose comme: for (int i = 0; i < N; ++i) expr += constants[i].*s.x14*s.x15*csc[49300 + i];.
HighCommander4
@ HighCommander4: absolument, je suis d'accord. C'est juste au-dessus de ma tête de savoir comment générer automatiquement quelque chose comme ça. Peut-être avec un tableau
séparé
2
@bbtrb: Comme il n'y a aucun moyen de paniquer que quelqu'un a écrit la source suffisante pour produire 2.8GB de code objet à la main, en particulier avec de tels noms de symboles un-mnémotechnique, un générateur de code doit avoir été utilisé. Travaillez avec ça.
Donal Fellows
15

Je pense que tout le monde convient qu'il devrait y avoir une façon différente de faire ce que vous voulez faire. Compiler des centaines de mégaoctets (gigaoctets?) De code, le relier à un exécutable de plusieurs gigaoctets et l'exécuter semble tout simplement très inefficace.

Si je comprends bien votre problème, vous utilisez une sorte de générateur de code, G, pour générer un tas de fonctions func1...Nqui prennent un tas de cartes csc1...Men entrée. Ce que vous voulez faire est de calculer csc1...Met d'exécuter une boucle de 1 000 000 fois pour différentes entrées et à chaque recherche s = func1 + func2 + ... + funcN. Vous n'avez cependant pas précisé comment fucn1...Nsont liés csc1...M.

Si tout cela est vrai, il semble que vous devriez être capable de renverser le problème de manière différente, ce qui peut être potentiellement beaucoup plus gérable et même peut-être plus rapide (c'est-à-dire en laissant le cache de votre machine fonctionner réellement).

Outre le problème pratique de la taille des fichiers objets, votre programme actuel ne sera pas efficace car il ne localise pas l'accès aux données (trop de cartes énormes) et n'a pas d'exécution de code localisé (trop de fonctions très longues).

Que diriez-vous de diviser votre programme en 3 phases: Construction de la phase 1 csc1...Met stockage. Phase 2, créez un funcà la fois, exécutez-le 1 000 000 fois avec chaque entrée et stockez les résultats. La phase 3 trouve la somme des résultats des résultats stockés func1...Npour chaque exécution de 1 000 000 fois. L'avantage de cette solution est qu'elle peut être facilement mise en parallèle sur plusieurs machines indépendantes.

Edit: @bbtrb, pourriez-vous rendre un func et un csc disponibles quelque part? Ils semblent être très réguliers et compressibles. Par exemple, func1 semble être juste une somme d'expressions comprenant chacune 1 coefficient, 2 index des variables dans s et 1 index dans csc. Cela peut donc être réduit à une belle boucle. Si vous mettez à disposition des exemples complets, je suis sûr que des moyens peuvent être trouvés pour les compresser en boucles plutôt qu'en longues expressions.

AlefSin
la source
Oui, vous avez bien compris :) Il y a cependant plusieurs problèmes avec votre suggestion: 1. les pires funcdépendent de presque tous les cscs et ces nombres doivent également être calculés 10 ^ 6 fois. 2. L'entrée sera obtenue à partir d'un intégrateur Monte Carlo adaptatif, ce qui signifie que l'intégrateur doit connaître le résultat complet à chaque point pour pouvoir réduire l'erreur résultante en affinant le maillage au voisinage du point si nécessaire. 3. Les grandes expressions pour cscpersist ...
bbtrb
1
Cela signifie-t-il que vous ne pouvez pas calculer chacun cscdans chaque itération indépendamment des autres? S'ils étaient indépendants, vous pouviez toujours les exécuter 10 ^ 6 fois et stocker les résultats. Cependant, s'il y a des dépendances entre elles, vous devez peut-être savoir laquelle est liée à laquelle, quelque chose comme un graphe de dépendances, puis essayez de voir si vous pouvez le diviser en plusieurs sous-graphes indépendants. Dans l'ensemble, je pense que la clé est de diviser le problème en plusieurs sous-problèmes indépendants.
AlefSin
5

Si je lis correctement vos erreurs, ce qui vous fait reporter la limite est la section de données initialisées (si c'était le code, vous auriez beaucoup plus d'erreurs à mon humble avis). Avez-vous de grandes baies de données mondiales? Si c'est le cas, je restructurerais le programme afin qu'il soit alloué dynamiquement. Si les données sont initialisées, je les lirais à partir d'un fichier de configuration.

BTW voyant ceci:

(.text + 0x20): référence non définie à `main '

Je pense que vous avez un autre problème.

Programmeur
la source
1
Oui, vous avez raison, erreur stupide, mais cela ne résout pas les autres erreurs.
bbtrb
3

Il me semble que le code effectue une intégration numérique en utilisant une sorte de méthode de profondeur adaptative. Malheureusement, le générateur de code (ou plutôt l'auteur du générateur de code) est tellement stupide qu'il génère une fonction par patch plutôt qu'une par type de patch. En tant que tel, il a produit trop de code pour être compilé, et même s'il pouvait être compilé, son exécution serait douloureuse car rien n'est jamais partagé nulle part. (Pouvez-vous imaginer la douleur résultant de devoir charger chaque page de code objet à partir du disque parce que rien n'est jamais partagé et donc c'est toujours un candidat pour que le système d'exploitation expulse. Sans parler des caches d'instructions, qui vont être inutiles.)

Le correctif est d'arrêter de tout dérouler; pour ce type de code, vous voulez maximiser le partage car la surcharge des instructions supplémentaires pour accéder aux données dans des modèles plus complexes sera absorbée par le coût de traitement du (vraisemblablement) grand ensemble de données sous-jacent de toute façon. Il est également possible que le générateur de code le fasse même par défaut et que le scientifique ait vu certaines options pour le déroulement (avec la note que celles-ci améliorent parfois la vitesse) et les a toutes activées en même temps et insiste maintenant pour que ce désordre résultant soit accepté. par l'ordinateur, plutôt que d'accepter les restrictions réelles de la machine et d'utiliser la version numériquement correcte générée par défaut. Mais si le générateur de code ne le fait pas, obtenez-en un qui le fera (ou piratez le code existant).

L' essentiel : compiler et lier 2,8 Go de code ne fonctionne pas et ne devrait pas être forcé de fonctionner. Trouvez un autre moyen.

Boursiers Donal
la source
3

Quelques suggestions: - Optimiser pour la taille (-Os). Faites vos appels de fonction en ligne, appels de fonction normaux. Activez le regroupement de chaînes.

Essayez de diviser les choses en différentes DLL (objets partagés, .so pour Linux, .dylib pour Mac OS X). Assurez-vous qu'ils peuvent être déchargés. Ensuite, implémentez quelque chose pour charger les choses à la demande et libérez-les lorsque vous n'en avez pas besoin.

Sinon, divisez votre code en différents exécutables et utilisez quelque chose pour communiquer entre eux (tubes, sockets, même écriture / lecture dans un fichier). Maladroit, mais quelles options avez-vous?

Totalement alternative: - Utilisez un langage dynamique avec JIT . Juste au-dessus de ma tête - utilisez LuaJIT - et réécrivez (régénérez?) Beaucoup de ces expressions dans Lua , ou d'autres langages et environnements d'exécution qui permettent au code d'être ramassé.

LuaJIT est assez efficace, battant parfois C / C ++ pour certaines choses, mais souvent très proche (parfois peut être lent en raison d'un mauvais ramassage des ordures encore là). Vérifiez par vous-même:

http://luajit.org/performance_x86.html

Téléchargez le scimark2.luafichier à partir de là et comparez-le avec la version "C" (google it) - les résultats sont souvent très proches.

malkie
la source
2

L'éditeur de liens tente de générer des décalages de relocalisation 32 bits dans un binaire qui a en quelque sorte dépassé ces limitations. Essayez de réduire les exigences d'espace d'adressage du programme principal.

Pouvez-vous diviser une partie / la plupart du code objet en une ou plusieurs bibliothèques (également compilées avec -fpic / -fPIC)? Puis générez un binaire non statique qui établit un lien avec ces bibliothèques. Les bibliothèques vivront dans des blocs de mémoire discrets et vos décalages de relocalisation seront dynamiques / absolus (64 bits) plutôt que relatifs (32 bits).

ajklbahu8geag
la source
2

Ces expressions ressemblent beaucoup à une série alternée pour moi. Je ne sais pas à quoi ressemble le reste du code, mais il ne semble pas que ce soit si difficile de dériver l'expression génératrice. Cela en vaudrait probablement également la peine au moment de l'exécution, surtout si vous avez 2,8 Go de code déroulé de 2 Ko.

Brian
la source
1

Cela ressemble au résultat d'une génération de code qui a mal tourné, peut-être par algèbre symbolique et / ou déroulement manuel. Les manipulations symboliques sont bien connues pour croître de façon exponentielle dans la profondeur de l'arbre d'expression ou du graphe de calcul. Il est probable que la différenciation automatique puisse être utilisée ici, ce qui réduirait la taille du code et accélérerait considérablement l'exécution.

Jed
la source