Ich habe eine große Anzahl von Funktionen mit insgesamt rund 2,8 GB Objektcode (leider führt kein Weg daran vorbei, wissenschaftliches Rechnen ...)
Wenn ich versuche, sie zu verknüpfen, erhalte ich (erwartete) relocation truncated to fit: R_X86_64_32S
Fehler, die ich durch Angabe des Compiler-Flags umgehen wollte -mcmodel=medium
. Alle zusätzlich verknüpften Bibliotheken, auf die ich Einfluss habe, werden mit dem -fpic
Flag kompiliert .
Trotzdem bleibt der Fehler bestehen und ich gehe davon aus, dass einige Bibliotheken, mit denen ich verknüpfe, nicht mit PIC kompiliert wurden.
Hier ist der Fehler:
/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
Und Systembibliotheken, gegen die ich verlinke:
-lgfortran -lm -lrt -lpthread
Gibt es Hinweise, wo Sie nach dem Problem suchen können?
EDIT: Zunächst einmal vielen Dank für die Diskussion ... Zur Verdeutlichung habe ich Hunderte von Funktionen (jede ca. 1 MB groß in separaten Objektdateien) wie folgt:
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;
}
Das Objekt s
ist relativ klein und behält die erforderlichen Konstanten x14, x15, ..., ds0, ... usw. bei, während ti
nur ein Double aus einer externen Bibliothek zurückgegeben wird. Wie Sie sehen können, csc[]
handelt es sich um eine vorberechnete Wertekarte, die auch in separaten Objektdateien (wiederum Hunderte mit jeweils ca. 1 MB Größe) der folgenden Form ausgewertet wird:
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));
}
// ...
}
Das ist alles. Der letzte Schritt besteht dann nur darin, alle diese aufzurufen func[i]
und das Ergebnis zusammenzufassen.
In Bezug auf die Tatsache, dass dies ein ganz besonderer und ungewöhnlicher Fall ist: Ja, das ist es. Damit müssen sich die Menschen auseinandersetzen, wenn sie versuchen, hochpräzise Berechnungen für die Teilchenphysik durchzuführen.
EDIT2: Ich sollte auch hinzufügen, dass x12, x13 usw. keine wirklichen Konstanten sind. Sie werden auf bestimmte Werte gesetzt, alle diese Funktionen werden ausgeführt und das Ergebnis zurückgegeben. Anschließend wird ein neuer Satz von x12, x13 usw. ausgewählt, um den nächsten Wert zu erzeugen. Und das muss 10 ^ 5 bis 10 ^ 6 mal gemacht werden ...
EDIT3: Vielen Dank für die Vorschläge und die bisherige Diskussion ... Ich werde versuchen, die Schleifen bei der Codegenerierung irgendwie aufzurollen, nicht sicher, wie genau das geht, um ehrlich zu sein, aber das ist die beste Wahl.
Übrigens habe ich nicht versucht, mich dahinter zu verstecken "das ist wissenschaftliches Rechnen - keine Möglichkeit zur Optimierung". Es ist nur so, dass die Basis für diesen Code etwas ist, das aus einer "Black Box" stammt, auf die ich keinen wirklichen Zugriff habe, und außerdem hat das Ganze mit einfachen Beispielen großartig funktioniert, und ich fühle mich hauptsächlich überwältigt von dem, was in einem realen passiert Weltanwendung ...
EDIT4: Ich habe es also geschafft, die Codegröße der csc
Definitionen durch Vereinfachung der Ausdrücke in einem Computeralgebrasystem ( Mathematica ) um etwa ein Viertel zu reduzieren . Ich sehe jetzt auch eine Möglichkeit, es um eine weitere Größenordnung oder so zu reduzieren, indem ich einige andere Tricks anwende, bevor ich den Code generiere (was diesen Teil auf ungefähr 100 MB reduzieren würde), und ich hoffe, dass diese Idee funktioniert.
Nun zu Ihren Antworten: Ich versuche, die Schleifen im func
s wieder aufzurollen , wo ein CAS nicht viel hilft, aber ich habe bereits einige Ideen. Wenn Sie beispielsweise die Ausdrücke nach Variablen wie sortieren x12, x13,...
, analysieren Sie die csc
s mit Python und generieren Sie Tabellen, die sie miteinander in Beziehung setzen. Dann kann ich diese Teile zumindest als Schleifen erzeugen. Da dies bisher die beste Lösung zu sein scheint, bezeichne ich dies als die beste Antwort.
Ich möchte jedoch auch VJo Ehre machen. GCC 4.6 funktioniert in der Tat viel besser, produziert kleineren Code und ist schneller. Die Verwendung des großen Modells funktioniert mit dem Code wie er ist. Technisch gesehen ist dies die richtige Antwort, aber eine Änderung des gesamten Konzepts ist ein viel besserer Ansatz.
Vielen Dank für Ihre Vorschläge und Hilfe. Wenn jemand interessiert ist, werde ich das endgültige Ergebnis veröffentlichen, sobald ich bereit bin.
BEMERKUNGEN: Nur einige Anmerkungen zu einigen anderen Antworten: Der Code, den ich ausführen möchte, stammt nicht aus einer Erweiterung einfacher Funktionen / Algorithmen und dummem unnötigem Abrollen. Was tatsächlich passiert, ist, dass das, womit wir beginnen, ziemlich komplizierte mathematische Objekte sind und diese Ausdrücke in eine numerisch berechenbare Form bringen. Das Problem liegt tatsächlich in der zugrunde liegenden physikalischen Theorie. Die Komplexität von Zwischenausdrücken skaliert faktoriell, was bekannt ist, aber wenn all diese Dinge zu etwas physikalisch Messbarem kombiniert werden - einem Beobachtbaren -, läuft es nur auf eine Handvoll sehr kleiner Funktionen hinaus, die die Grundlage der Ausdrücke bilden. (Es gibt definitiv etwas "Falsches" in dieser Hinsicht mit dem Allgemeinen und nur verfügbarAnsatz, der als "Störungstheorie" bezeichnet wird) Wir versuchen, diesen Ansatz auf eine andere Ebene zu bringen, die analytisch nicht mehr realisierbar ist und bei der die Grundlage der benötigten Funktionen nicht bekannt ist. Also versuchen wir es so brutal zu erzwingen. Nicht der beste Weg, aber hoffentlich einer, der am Ende zu unserem Verständnis der vorliegenden Physik beiträgt ...
LAST EDIT:
Dank all Ihrer Vorschläge habe ich es geschafft, die Codegröße erheblich zu reduzieren, indem ich Mathematica und eine Modifikation des Codegenerators für das func
s etwas in Anlehnung an die Top-Antwort verwendet habe :)
Ich habe die csc
Funktionen mit Mathematica vereinfacht und auf 92 MB reduziert. Dies ist der irreduzible Teil. Die ersten Versuche haben ewig gedauert, aber nach einigen Optimierungen dauert dies nun in etwa 10 Minuten auf einer einzelnen CPU.
Die Auswirkung auf das func
s war dramatisch: Die gesamte Codegröße für sie beträgt ungefähr 9 MB, sodass der Code jetzt im Bereich von 100 MB liegt. Jetzt ist es sinnvoll, Optimierungen zu aktivieren und die Ausführung ist recht schnell.
Nochmals vielen Dank für Ihre Vorschläge, ich habe viel gelernt.
quelle
mmap
zur Laufzeit aus den Quelldateien und stattdessen selbst aus einer externen Binärdatei verschieben.Antworten:
Sie haben also bereits ein Programm, das diesen Text erzeugt:
und
richtig?
Wenn alle Ihre Funktionen ein ähnliches "Format" haben (n Zahlen m mal multiplizieren und die Ergebnisse hinzufügen - oder etwas Ähnliches), dann können Sie dies meiner Meinung nach tun:
offsetof(ProcessVars, ds0)
Der Array + Evaluator repräsentiert dieselbe Logik wie eine Ihrer Funktionen, aber nur der Evaluator ist Code. Das Array ist "Daten" und kann entweder zur Laufzeit generiert oder auf der Festplatte gespeichert und i Chunks oder mit einer Speicherzuordnungsdatei gelesen werden.
Für Ihr spezielles Beispiel in func1 vorstellen , wie Sie die Funktion über eine Evaluator umschreiben würden , wenn Sie den Zugriff auf die Basisadresse haben
s
undcsc
auch ein Vektor wie Darstellung der Konstanten und den Offsets Sie zu den Basisadressen hinzufügen müssen , um zu bekommenx14
,ds8
undcsc[51370]
Sie müssen eine neue Form von "Daten" erstellen, die beschreibt, wie die tatsächlichen Daten verarbeitet werden, die Sie an Ihre große Anzahl von Funktionen übergeben.
quelle
Das von Linux verwendete x86-64-ABI definiert ein "großes Modell" speziell zur Vermeidung solcher Größenbeschränkungen, das 64-Bit-Verschiebungstypen für GOT und PLT enthält. (Siehe die Tabelle in Abschnitt 4.4.2 und die Befehlssequenzen in 3.5.5, die zeigen, wie sie verwendet werden.)
Da Ihre Funktionen 2,8 GB belegen, haben Sie kein Glück, da gcc keine großen Modelle unterstützt. Was Sie tun können, ist, Ihren Code so zu reorganisieren, dass Sie ihn in gemeinsam genutzte Bibliotheken aufteilen können, die Sie dynamisch verknüpfen würden.
Wenn dies nicht möglich ist, wie jemand vorgeschlagen hat, können Sie Ihre Daten zur Laufzeit laden (entweder als normale Datei oder als MMAP), anstatt sie in Code zu setzen (zu kompilieren und zu verknüpfen), da sie sehr groß sind.
BEARBEITEN
Das große Modell scheint von gcc 4.6 unterstützt zu werden (siehe diese Seite ). Sie können das versuchen, aber das oben Gesagte gilt immer noch für die Reorganisation Ihres Codes.
quelle
Mit einem Programm dieser Seite übersteigen Cache-Fehler für Code sehr wahrscheinlich die Kosten für Schleifen zur Laufzeit. Ich würde empfehlen, dass Sie zu Ihrem Codegenerator zurückkehren und ihn eine kompakte Darstellung für das erstellen lassen, was ausgewertet werden soll (dh eine, die wahrscheinlich in den D-Cache passt), und diese dann mit einem Interpreter in Ihrem Programm ausführen. Sie können auch sehen, ob Sie kleinere Kernel herausrechnen können, die noch eine erhebliche Anzahl von Operationen ausführen, und diese dann als 'Anweisungen' im interpretierten Code verwenden.
quelle
Der Fehler tritt auf, weil Sie zu viel CODE haben, keine Daten! Dies wird dadurch angezeigt, dass beispielsweise
__libc_csu_fini
(was eine Funktion ist) darauf verwiesen wird_start
und die Verschiebung entsprechend abgeschnitten wird. Dies bedeutet, dass_start
(der wahre Einstiegspunkt des Programms) versucht, diese Funktion über einen SIGNIERTEN 32-Bit-Offset aufzurufen, der nur einen Bereich von 2 GB hat. Da die Gesamtmenge Ihres Objektcodes ~ 2,8 GB beträgt, werden die Fakten überprüft.Wenn Sie Ihre Datenstrukturen neu gestalten könnten, könnte ein Großteil Ihres Codes "komprimiert" werden, indem Sie die großen Ausdrücke als einfache Schleifen umschreiben.
Sie können auch
csc[]
in einem anderen Programm rechnen , die Ergebnisse in einer Datei speichern und sie bei Bedarf einfach laden.quelle
csc[]
muss sehr oft berechnet werden und ich möchte Festplatten-E / A vermeiden.func1
oben so etwas wie :for (int i = 0; i < N; ++i) expr += constants[i].*s.x14*s.x15*csc[49300 + i];
.Ich denke, alle sind sich einig, dass es einen anderen Weg geben sollte, um das zu tun, was Sie tun möchten. Das Kompilieren von Hunderten von Megabyte (Gigabyte?) Code, das Verknüpfen mit einer ausführbaren Datei mit einer Größe von mehreren Gigabyte und das Ausführen klingt einfach sehr ineffizient.
Wenn ich Ihr Problem richtig verstehe, verwenden Sie eine Art Codegenerator G, um eine Reihe von Funktionen zu generieren
func1...N
, die eine Reihe von Kartencsc1...M
als Eingabe verwenden. Was Sie tun möchten, ist zu berechnencsc1...M
und eine Schleife von 1.000.000 Mal für verschiedene Eingaben und jedes Mal zu führens = func1 + func2 + ... + funcN
. Sie haben jedoch nicht angegeben, wie siefucn1...N
zusammenhängencsc1...M
.Wenn all dies zutrifft, sollten Sie in der Lage sein, das Problem auf unterschiedliche Weise auf den Kopf zu stellen, was möglicherweise viel einfacher zu handhaben und sogar möglicherweise schneller sein kann (dh den Cache Ihres Computers tatsächlich funktionieren zu lassen).
Neben dem praktischen Problem der Größe der Objektdateien ist Ihr aktuelles Programm nicht effizient, da es den Zugriff auf die Daten nicht lokalisiert (zu viele große Karten) und keine lokalisierte Codeausführung hat (zu viele sehr lange Funktionen).
Wie wäre es, wenn Sie Ihr Programm in drei Phasen aufteilen: Phase 1 erstellen
csc1...M
und speichern. Phase 2 wird einzeln erstelltfunc
, 1.000.000 Mal mit jeder Eingabe ausgeführt und die Ergebnisse gespeichert. In Phase 3 wird die Summe der Ergebnisse der gespeichertenfunc1...N
Ergebnisse für jeden Lauf 1.000.000 Mal ermittelt. Das Gute an dieser Lösung ist, dass sie problemlos über mehrere unabhängige Maschinen hinweg parallel geschaltet werden kann.Edit: @bbtrb, könntest du irgendwo eine func und eine csc zur Verfügung stellen? Sie scheinen sehr regelmäßig und komprimierbar zu sein. Zum Beispiel scheint func1 nur eine Summe von Ausdrücken zu sein, die jeweils aus 1 Koeffizienten, 2 Indizes für die Variablen in s und 1 Index für csc bestehen. So kann es auf eine schöne Schleife reduziert werden. Wenn Sie vollständige Beispiele zur Verfügung stellen, können Sie sicher Wege finden, diese in Schleifen anstatt in langen Ausdrücken zu komprimieren.
quelle
func
s hängt von fast allencsc
s ab und diese Zahlen müssen ebenfalls 10 ^ 6 Mal berechnet werden. 2. Die Eingabe wird von einem adaptiven Monte-Carlo-Integrator erhalten, was bedeutet, dass der Integrator an jedem Punkt das vollständige Ergebnis kennen muss, um den resultierenden Fehler durch Verfeinern des Netzes in der Nähe des Punkts bei Bedarf reduzieren zu können. 3. Die großen Ausdrücke fürcsc
persist ...csc
in jeder Iteration unabhängig von den anderen berechnen können ? Wenn sie unabhängig wären, könnten Sie sie immer noch 10 ^ 6 Mal ausführen und die Ergebnisse speichern. Wenn es jedoch Abhängigkeiten zwischen ihnen gibt, müssen Sie möglicherweise herausfinden, welche mit welchen verwandt sind, beispielsweise mit einem Abhängigkeitsdiagramm, und dann versuchen, herauszufinden, ob Sie es in mehrere unabhängige Unterdiagramme aufteilen können. Alles in allem denke ich, dass der Schlüssel darin besteht, das Problem in mehrere unabhängige Unterprobleme aufzuteilen.Wenn ich Ihre Fehler richtig gelesen habe, ist das, was Sie dazu bringt, das Limit zu überschreiten, der initialisierte Datenabschnitt (wenn es der Code wäre, hätten Sie meiner Meinung nach weit mehr Fehler). Haben Sie große Mengen globaler Daten? In diesem Fall würde ich das Programm so umstrukturieren, dass sie dynamisch zugewiesen werden. Wenn die Daten initialisiert werden, würde ich sie aus einer Konfigurationsdatei lesen.
Übrigens:
Ich denke du hast ein anderes Problem.
quelle
Es sieht für mich so aus, als würde der Code eine numerische Integration mit einer Art adaptiver Tiefenmethode durchführen. Leider ist der Codegenerator (oder besser gesagt der Autor des Codegenerators) so dumm , dass er eine Funktion pro Patch und keine pro Patch- Typ generiert . Als solches wird zu viel Code produziert, um kompiliert zu werden, und selbst wenn er kompiliert werden könnte, wäre seine Ausführung schmerzhaft, da nichts jemals irgendwo geteilt wird. (Können Sie sich den Schmerz vorstellen, der dadurch entsteht, dass jede Seite des Objektcodes von der Festplatte geladen werden muss, weil nie etwas gemeinsam genutzt wird und es daher immer ein Kandidat für die Räumung des Betriebssystems ist? Ganz zu schweigen von Anweisungscaches, die nutzlos sein werden.)
Die Lösung besteht darin, nicht mehr alles abzuwickeln. Für diese Art von Code möchten Sie die Freigabe maximieren, da der Aufwand für zusätzliche Anweisungen für den Zugriff auf Daten in komplexeren Mustern ohnehin durch die Kosten für den Umgang mit dem (vermutlich) großen zugrunde liegenden Datensatz absorbiert wird. Es ist auch möglich, dass der Codegenerator dies sogar standardmäßig tut und dass der Wissenschaftler einige Optionen zum Abrollen sah (mit dem Hinweis, dass diese manchmal die Geschwindigkeit verbessern) und sie alle auf einmal einschaltete und nun darauf besteht, dass dieses resultierende Durcheinander akzeptiert wird vom Computer, anstatt die tatsächlichen Einschränkungen des Computers zu akzeptieren und die numerisch korrekte Version zu verwenden, die standardmäßig generiert wird. Aber wenn der Codegenerator dies nicht tut, besorgen Sie sich einen, der dies tut (oder hacken Sie den vorhandenen Code).
Fazit: Das Kompilieren und Verknüpfen von 2,8 GB Code funktioniert nicht und sollte nicht zum Arbeiten gezwungen werden. Finde einen anderen Weg.
quelle
Einige Vorschläge: - Für Größe optimieren (-Os). Machen Sie Ihre Inline-Funktionsaufrufe, normale Funktionsaufrufe. Aktivieren Sie das String-Pooling.
Versuchen Sie, die Dinge in verschiedene DLLs aufzuteilen (gemeinsam genutzte Objekte, .so für Linux, .dylib für Mac OS X). Stellen Sie sicher, dass sie entladen werden können. Implementieren Sie dann etwas, um Dinge bei Bedarf zu laden und sie freizugeben, wenn sie nicht benötigt werden.
Wenn nicht, teilen Sie Ihren Code in verschiedene ausführbare Dateien auf und verwenden Sie etwas, um zwischen ihnen zu kommunizieren (Pipes, Sockets, sogar Schreiben / Lesen in Dateien). Unbeholfen, aber welche Möglichkeiten haben Sie?
Völlig alternativ: - Verwenden Sie eine dynamische Sprache mit JIT . Ganz oben auf meinem Kopf - verwenden Sie LuaJIT - und schreiben Sie viele dieser Ausdrücke in Lua oder anderen solchen Sprachen und Laufzeiten neu (regenerieren Sie sie?) , Um Code zu sammeln.
LuaJIT ist sehr effizient und schlägt manchmal C / C ++ für bestimmte Dinge, aber oft sehr nahe (manchmal kann es aufgrund der schlechten Speicherbereinigung langsam sein). Überzeugen Sie sich selbst:
http://luajit.org/performance_x86.html
Laden Sie die
scimark2.lua
Datei von dort herunter und vergleichen Sie sie mit der "C" -Version (google it) - oft sind die Ergebnisse sehr ähnlich.quelle
Der Linker versucht, 32-Bit-Verschiebungsversätze innerhalb einer Binärdatei zu generieren, die diese Einschränkungen irgendwie überschritten hat. Versuchen Sie, den Adressraumbedarf des Hauptprogramms zu reduzieren.
Können Sie einen Teil / den größten Teil des Objektcodes in eine oder mehrere Bibliotheken aufteilen (auch kompiliert mit -fpic / -fPIC)? Generieren Sie dann eine nicht statische Binärdatei, die mit diesen Bibliotheken verknüpft ist. Die Bibliotheken befinden sich in diskreten Speicherblöcken, und Ihre Verschiebungsversätze sind eher dynamisch / absolut (64-Bit) als relativ (32-Bit).
quelle
Diese Ausdrücke sehen für mich sehr nach einer alternierenden Serie aus. Ich weiß nicht, wie der Rest des Codes aussieht, aber es scheint nicht so schwer zu sein, den generierenden Ausdruck abzuleiten. Es würde sich wahrscheinlich auch zur Ausführungszeit lohnen, insbesondere wenn Sie 2,8 GB 2 KB ungerollten Code haben.
quelle
Dies scheint das Ergebnis einer fehlerhaften Codegenerierung zu sein, möglicherweise durch symbolische Algebra und / oder manuelles Abrollen. Es ist bekannt, dass symbolische Manipulationen in der Tiefe des Ausdrucksbaums oder des Rechengraphen exponentiell wachsen. Es ist wahrscheinlich, dass hier eine automatische Differenzierung verwendet werden kann, was die Codegröße ziemlich klein machen und auch die Ausführung dramatisch beschleunigen würde.
quelle