Mam ogromną liczbę funkcji w sumie około 2,8 GB kodu wynikowego (niestety nie ma sposobu obejścia, obliczenia naukowe ...)
Kiedy próbuję je połączyć, otrzymuję (oczekiwane) relocation truncated to fit: R_X86_64_32S
błędy, które miałem nadzieję ominąć, określając flagę kompilatora -mcmodel=medium
. Wszystkie biblioteki połączone dodatkowo, nad którymi mam kontrolę, są kompilowane z -fpic
flagą.
Mimo to błąd nadal występuje i zakładam, że niektóre biblioteki, do których odsyłam, nie są skompilowane za pomocą PIC.
Oto błąd:
/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
Biblioteki systemowe, do których odsyłam:
-lgfortran -lm -lrt -lpthread
Jakieś wskazówki, gdzie szukać problemu?
EDYCJA: Przede wszystkim dziękuję za dyskusję ... Aby trochę wyjaśnić, mam setki funkcji (każda o rozmiarze około 1 MB w oddzielnych plikach obiektowych), takich jak:
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;
}
Obiekt s
jest stosunkowo mały i zachowuje potrzebne stałe x14, x15, ..., ds0, ... itd., A ti
po prostu zwraca double z zewnętrznej biblioteki. Jak widać, csc[]
jest to wstępnie obliczona mapa wartości, która jest również oceniana w oddzielnych plikach obiektowych (ponownie setkach po około 1 MB każdy) o następującej postaci:
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));
}
// ...
}
O to chodzi. Ostatnim krokiem jest wtedy po prostu wywołanie wszystkich func[i]
i podsumowanie wyniku.
Jeśli chodzi o fakt, że jest to raczej szczególny i nietypowy przypadek: Tak, jest. To jest to, z czym ludzie muszą sobie radzić, próbując wykonać bardzo precyzyjne obliczenia dla fizyki cząstek elementarnych.
EDIT2: Powinienem też dodać, że x12, x13 itd. Nie są tak naprawdę stałymi. Są one ustawiane na określone wartości, wszystkie te funkcje są uruchamiane i zwracany jest wynik, a następnie wybierany jest nowy zestaw x12, x13 itd., Aby wygenerować następną wartość. I trzeba to zrobić 10 ^ 5 do 10 ^ 6 razy ...
EDIT3: Dziękuję za sugestie i dotychczasową dyskusję ... Spróbuję jakoś zwinąć pętle po wygenerowaniu kodu, nie jestem pewien, jak to dokładnie, szczerze mówiąc, ale to najlepszy wybór.
Swoją drogą, nie próbowałem się ukrywać za „to jest obliczenia naukowe - nie ma sposobu na optymalizację”. Tyle, że podstawą tego kodu jest coś, co wychodzi z „czarnej skrzynki”, do której nie mam realnego dostępu, a ponadto całość działała świetnie na prostych przykładach i głównie czuję się przytłoczony tym, co dzieje się w prawdziwym aplikacja światowa ...
EDIT4: Więc udało mi się zmniejszyć rozmiar kodu csc
definicji o około jedną czwartą, upraszczając wyrażenia w systemie algebry komputerowej ( Mathematica ). Widzę teraz również sposób na zmniejszenie go o inny rząd wielkości, stosując kilka innych sztuczek przed wygenerowaniem kodu (co zmniejszyłoby tę część do około 100 MB) i mam nadzieję, że ten pomysł zadziała.
Teraz związane z twoimi odpowiedziami: próbuję ponownie zwinąć pętle w func
s, gdzie CAS niewiele pomoże, ale mam już kilka pomysłów. Na przykład, sortując wyrażenia według zmiennych, takich jak x12, x13,...
, przeanalizuj je csc
w Pythonie i wygeneruj tabele, które będą ze sobą powiązane. Następnie mogę przynajmniej wygenerować te części jako pętle. Ponieważ wydaje się, że jest to do tej pory najlepsze rozwiązanie, oznaczam to jako najlepszą odpowiedź.
Chciałbym jednak również wyrazić uznanie dla VJo. GCC 4.6 rzeczywiście działa znacznie lepiej, tworzy mniejszy kod i jest szybsze. Korzystanie z dużego modelu działa w kodzie takim, jakim jest. Więc technicznie jest to poprawna odpowiedź, ale zmiana całej koncepcji jest znacznie lepszym podejściem.
Dziękuję wszystkim za sugestie i pomoc. Jeśli ktoś jest zainteresowany, opublikuję ostateczny wynik, gdy tylko będę gotowy.
UWAGI: Kilka uwag do innych odpowiedzi: Kod, który próbuję uruchomić, nie pochodzi z rozszerzenia prostych funkcji / algorytmów i głupiego, niepotrzebnego rozwijania. W rzeczywistości dzieje się tak, że rzeczy, od których zaczynamy, to dość skomplikowane obiekty matematyczne i doprowadzenie ich do postaci obliczalnej numerycznie generuje te wyrażenia. Problem tkwi w rzeczywistości w podstawowej teorii fizycznej. Złożoność wyrażeń pośrednich skaluje się silnie, co jest dobrze znane, ale gdy łączymy wszystkie te rzeczy w coś fizycznie mierzalnego - obserwowalnego - sprowadza się to tylko do kilku bardzo małych funkcji, które stanowią podstawę wyrażeń. (Zdecydowanie jest coś „nie tak” w tym względzie z ogólnym i dostępnym tylkoansatz, który jest nazywany „teorią perturbacji”). Próbujemy przenieść ten ansatz na inny poziom, który nie jest już wykonalny analitycznie i gdzie nie są znane podstawy potrzebnych funkcji. Więc próbujemy to brutalnie wymusić w ten sposób. Nie jest to najlepszy sposób, ale miejmy nadzieję, że taki, który w końcu pomoże nam w zrozumieniu fizyki ...
OSTATNIA EDYCJA:
Dzięki wszystkim waszym sugestiom udało mi się znacznie zmniejszyć rozmiar kodu, używając Mathematica i modyfikacji generatora kodu dla func
s, nieco zgodnej z górną odpowiedzią :)
Uprościłem csc
funkcje w Mathematica, zmniejszając je do 92 MB. To jest nieredukowalna część. Pierwsze próby trwały wieki, ale po kilku optymalizacjach trwa to teraz w ciągu około 10 minut na jednym procesorze.
Wpływ na func
s był dramatyczny: cały rozmiar kodu dla nich spadł do około 9 MB, więc teraz kod zawiera się w zakresie 100 MB. Teraz warto włączyć optymalizacje, a wykonanie jest dość szybkie.
Jeszcze raz dziękuję wszystkim za sugestie, wiele się nauczyłem.
źródło
mmap
tego samodzielnie z zewnętrznego pliku binarnego w czasie wykonywania.Odpowiedzi:
Więc masz już program, który generuje ten tekst:
i
dobrze?
Jeśli wszystkie twoje funkcje mają podobny „format” (pomnóż n liczb m razy i dodaj wyniki - lub coś podobnego), myślę, że możesz to zrobić:
offsetof(ProcessVars, ds0)
Tablica + ewaluator będzie reprezentować tę samą logikę, co jedna z twoich funkcji, ale tylko oceniający będzie kodem. Tablica jest „danymi” i może być generowana w czasie wykonywania lub zapisywana na dysku i odczytywana fragmentami lub w pliku mapowanym w pamięci.
Dla konkretnego przykładu w func1 wyobrazić jak można przepisać funkcji poprzez oceniającego gdybyś miał dostęp do adresu bazowego
s
icsc
oraz wektorem jak reprezentacji stałych i przesunięć trzeba dodać do adresów bazowych, aby dostać sięx14
,ds8
icsc[51370]
Musisz utworzyć nową formę „danych”, która będzie opisywać, jak przetwarzać rzeczywiste dane przekazywane do ogromnej liczby funkcji.
źródło
Interfejs ABI x86-64 używany przez Linuksa definiuje „duży model” specjalnie w celu uniknięcia takich ograniczeń rozmiaru, który obejmuje 64-bitowe typy relokacji dla GOT i PLT. (Zobacz tabelę w sekcji 4.4.2 i sekwencje instrukcji w 3.5.5, które pokazują, jak są używane.)
Ponieważ twoje funkcje zajmują 2,8 GB, nie masz szczęścia, ponieważ gcc nie obsługuje dużych modeli. To, co możesz zrobić, to zreorganizować swój kod w taki sposób, aby umożliwić podzielenie go na biblioteki współdzielone, które można by dynamicznie łączyć.
Jeśli nie jest to możliwe, jak ktoś sugerował, zamiast umieszczać dane w kodzie (kompilować i łączyć), ponieważ jest ogromny, możesz go załadować w czasie wykonywania (jako normalny plik lub możesz go mmap).
EDYTOWAĆ
Wygląda na to, że duży model jest obsługiwany przez gcc 4.6 (zobacz tę stronę ). Możesz tego spróbować, ale powyższe nadal dotyczy reorganizacji kodu.
źródło
W przypadku programu po tej stronie błędy pamięci podręcznej kodu z dużym prawdopodobieństwem przekroczą koszty zapętlenia w czasie wykonywania. Zalecałbym, abyś wrócił do swojego generatora kodu i wygenerował zwartą reprezentację tego, co chce ocenić (tj. Taką, która prawdopodobnie zmieści się w pamięci podręcznej D), a następnie uruchom ją za pomocą interpretera w programie. Możesz również sprawdzić, czy możesz wyodrębnić mniejsze jądra, które nadal mają znaczną liczbę operacji, a następnie użyć ich jako „instrukcji” w interpretowanym kodzie.
źródło
Błąd występuje, ponieważ masz za dużo KODU, a nie danych! Wskazuje na to na przykład
__libc_csu_fini
(która jest funkcją), do której się odwołujemy,_start
a relokacja jest obcinana w celu dopasowania. Oznacza to, że_start
(prawdziwy punkt wejścia programu) próbuje wywołać tę funkcję poprzez SIGNED 32-bitowe przesunięcie, które ma tylko zakres 2 GB. Ponieważ całkowita ilość kodu wynikowego wynosi ~ 2,8 GB, fakty się sprawdzają.Gdybyś mógł przeprojektować struktury danych, znaczną część kodu można by „skompresować”, przepisując ogromne wyrażenia na proste pętle.
Możesz także
csc[]
wykonać obliczenia w innym programie, zapisać wyniki w pliku i po prostu załadować je w razie potrzeby.źródło
csc[]
musi być obliczany bardzo często i chciałbym uniknąć operacji wejścia / wyjścia dysku.func1
wyżej, coś jak:for (int i = 0; i < N; ++i) expr += constants[i].*s.x14*s.x15*csc[49300 + i];
.Myślę, że wszyscy się zgadzają, że powinien być inny sposób robienia tego, co chcesz. Kompilowanie setek megabajtów (gigabajtów?) Kodu, łączenie go w plik wykonywalny o rozmiarze wielu gigabajtów i uruchamianie go po prostu brzmi bardzo nieefektywnie.
Jeśli dobrze rozumiem twój problem, używasz jakiegoś generatora kodu, G, do generowania zestawu funkcji,
func1...N
które pobierają kilka mapcsc1...M
jako dane wejściowe. To, co chcesz zrobić, to obliczyćcsc1...M
i uruchomić pętlę 1000000 razy dla różnych danych wejściowych i za każdym razem znaleźćs = func1 + func2 + ... + funcN
. Nie określiłeś jednak, jakfucn1...N
są one powiązanecsc1...M
.Jeśli to wszystko prawda, wydaje się, że powinieneś być w stanie postawić problem na głowie w inny sposób, który może być znacznie łatwiejszy w zarządzaniu, a nawet prawdopodobnie szybszy (tj. Pozwalając pamięci podręcznej komputera na faktyczne działanie).
Poza praktycznym problemem związanym z rozmiarami plików obiektowych, Twój obecny program nie będzie wydajny, ponieważ nie lokalizuje dostępu do danych (zbyt wiele dużych map) i nie ma zlokalizowanego wykonywania kodu (zbyt wiele bardzo długich funkcji).
Co powiesz na rozbicie programu na 3 fazy: Faza 1 kompilacja
csc1...M
i przechowywanie ich. Faza 2 buduj pojedynczofunc
, uruchamiaj ją 1000000 razy z każdym wejściem i zapisz wyniki. W fazie 3 znajdź sumę wyników zapisanychfunc1...N
wyników dla każdego wyczerpania 1 000 000 razy. Zaletą tego rozwiązania jest to, że można je łatwo ustawić równolegle na kilku niezależnych maszynach.Edycja: @bbtrb, czy możesz gdzieś udostępnić jedną funkcję i jedną CSC? Wydają się być bardzo regularne i ściśliwe. Na przykład func1 wydaje się być po prostu sumą wyrażeń, z których każde składa się z 1 współczynnika, 2 indeksów do zmiennych w si 1 indeksu do csc. Więc można to zredukować do ładnej pętli. Jeśli udostępnisz pełne przykłady, na pewno można znaleźć sposoby na skompresowanie ich w pętle zamiast długich wyrażeń.
źródło
func
zależą od prawie wszystkichcsc
s i te liczby też trzeba obliczyć 10 ^ 6 razy. 2. Dane wejściowe zostaną uzyskane z adaptacyjnego integratora Monte Carlo, co oznacza, że integrator musi znać pełny wynik w każdym punkcie, aby w razie potrzeby móc zredukować wynikowy błąd przez udoskonalenie siatki w pobliżu punktu. 3. Duże wyrażenia dlacsc
csc
w każdej iteracji niezależnie od pozostałych? Gdyby były niezależne, nadal można by uruchomić każdy z nich 10 ^ 6 razy i zapisać wyniki. Jeśli jednak są między nimi zależności, być może musisz dowiedzieć się, który z nich jest powiązany z którym, coś w rodzaju wykresu zależności, a następnie spróbować sprawdzić, czy możesz podzielić go na wiele niezależnych pod-grafów. Podsumowując, myślę, że kluczem jest rozbicie problemu na wiele niezależnych podproblemów.Jeśli poprawnie odczytam twoje błędy, tym, co sprawia, że przenosisz limit, jest zainicjowana sekcja danych (gdyby to był kod, miałbyś znacznie więcej błędów IMHO). Czy masz duże tablice globalnych danych? W takim przypadku zrestrukturyzowałbym program tak, aby były przydzielane dynamicznie. Jeśli dane są zainicjowane, odczytałbym je z pliku konfiguracyjnego.
BTW widząc to:
Myślę, że masz inny problem.
źródło
Wydaje mi się, że kod dokonuje integracji numerycznej przy użyciu jakiejś metody adaptacyjnej głębokości. Niestety, generator kodu (a raczej autor generatora kodu) jest tak głupi, że generuje jedną funkcję na łatkę zamiast jednej na typ poprawki. W związku z tym wygenerował zbyt dużo kodu, aby można go było skompilować, a nawet gdyby można go było skompilować, jego wykonanie byłoby bolesne, ponieważ nic nigdy nie jest nigdzie udostępniane. (Czy możesz sobie wyobrazić ból wynikający z konieczności ładowania każdej strony kodu wynikowego z dysku, ponieważ nic nie jest nigdy udostępniane, więc system operacyjny zawsze może go eksmitować. Nie wspominając o pamięci podręcznej instrukcji, która będzie bezużyteczna).
Rozwiązaniem jest zaprzestanie rozwijania wszystkiego; w przypadku tego rodzaju kodu, chcesz zmaksymalizować udostępnianie, ponieważ narzut dodatkowych instrukcji dostępu do danych w bardziej złożonych wzorcach zostanie i tak pochłonięty przez koszt obsługi (przypuszczalnie) dużego bazowego zbioru danych. Możliwe jest również, że generator kodu zrobi to nawet domyślnie i że naukowiec zobaczył kilka opcji rozwijania (z uwagą, że czasami poprawiają one prędkość) i włączył je wszystkie naraz i teraz nalega, aby ten wynikający bałagan został zaakceptowany przez komputer, zamiast akceptować rzeczywiste ograniczenia maszyny i używać numerycznie poprawnej wersji, która jest generowana domyślnie. Ale jeśli generator kodu tego nie zrobi, zdobądź taki, który to zrobi (lub zhakuje istniejący kod).
Podsumowując: kompilacja i linkowanie 2,8 GB kodu nie działa i nie powinno być zmuszane do pracy. Znajdź inny sposób.
źródło
Kilka sugestii: - Zoptymalizuj rozmiar (-Os). Wykonuj wywołania funkcji inline, zwykłe wywołania funkcji. Włącz buforowanie ciągów.
Spróbuj podzielić te rzeczy na różne DLL (obiekty współdzielone, .so dla Linuksa, .dylib dla Mac OS X). Upewnij się, że można je rozładować. Następnie zaimplementuj coś, co załaduje rzeczy na żądanie i zwolnij je, gdy nie są potrzebne.
Jeśli nie, podziel kod na różne pliki wykonywalne i użyj czegoś do komunikacji między nimi (potoki, gniazda, a nawet zapis / odczyt do pliku). Niezdarny, ale jakie masz opcje?
Całkowicie alternatywne: - Użyj dynamicznego języka z JIT . Zaraz na mojej głowie - użyj LuaJIT - i przepisz (zregeneruj?) Wiele z tych wyrażeń w Lua lub innych tego typu językach i środowiskach wykonawczych, które umożliwiają zbieranie kodu bezużytecznego.
LuaJIT jest dość wydajny, czasami pokonuje C / C ++ dla pewnych rzeczy, ale często jest bardzo blisko (czasami może być powolny z powodu słabego zbierania śmieci). Sprawdź sam:
http://luajit.org/performance_x86.html
Pobierz
scimark2.lua
plik stamtąd i porównaj go z wersją "C" (wygoogluj to) - często wyniki są bardzo zbliżone.źródło
Linker próbuje wygenerować 32-bitowe przesunięcia relokacji w pliku binarnym, które w jakiś sposób przekroczyły te ograniczenia. Spróbuj zmniejszyć wymagania dotyczące przestrzeni adresowej głównego programu.
Czy możesz podzielić część / większość kodu wynikowego na jedną lub więcej bibliotek (również skompilowanych z -fpic / -fPIC)? Następnie wygeneruj niestatyczny plik binarny, który łączy się z tymi bibliotekami. Biblioteki będą żyć w dyskretnych blokach pamięci, a przesunięcia relokacji będą dynamiczne / absolutne (64-bitowe), a nie względne (32-bitowe).
źródło
Te wyrażenia wyglądają dla mnie jak seria naprzemienna. Nie wiem, jak wygląda reszta kodu, ale nie wydaje się, aby wyprowadzenie wyrażenia generującego było takie trudne. Prawdopodobnie byłoby to warte również w czasie wykonywania, zwłaszcza jeśli masz 2,8 GB 2 KB niezrolowanego kodu.
źródło
Wygląda na to, że wynik generowania kodu poszedł źle, być może przez algebrę symboliczną i / lub ręczne rozwijanie. Powszechnie wiadomo, że manipulacje symboliczne rosną wykładniczo w głębi drzewa wyrażeń lub wykresu obliczeniowego. Jest prawdopodobne, że można tutaj zastosować automatyczne różnicowanie, co zmniejszyłoby rozmiar kodu, a także znacznie przyspieszyło wykonywanie.
źródło