1. ホーム
  2. c++

[解決済み] 2GBを超えるコードのコンパイル時に発生するGCCコンパイルエラーを修正するには?

2022-10-28 07:14:31

質問

合計で 2.8GB もの膨大な数のオブジェクト コードがあります (残念ながら、科学技術計算ではどうしようもありません......)。

それらをリンクしようとすると、(予想通り)次のようになります。 relocation truncated to fit: R_X86_64_32S というエラーが出ますが、コンパイラフラグの -mcmodel=medium . 私がコントロールできる追加でリンクされたすべてのライブラリは、コンパイル時に -fpic フラグでコンパイルされます。

それでもエラーは続くので、私がリンクしているライブラリの中にはPICでコンパイルされていないものがあると推測されます。

以下がそのエラーです。

/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

そして、私がリンクするシステムライブラリ。

-lgfortran -lm -lrt -lpthread

どこに問題があるのか、何か手がかりがあれば教えてください。

EDITです。

まず、議論に感謝します...。

少し明確にするために、私はこのような数百の関数(別々のオブジェクトファイルでそれぞれ約1MBのサイズ)を持っています。

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

オブジェクト s は比較的小さく、必要な定数 x14、x15、...、ds0、...などを保持する一方で ti は単に外部ライブラリからdoubleを返しているだけである。見てわかるように csc[] は事前に計算された値のマップであり、次のような形式の個別のオブジェクトファイル(これも数百個でそれぞれ約 ~1 MB のサイズです)でも評価されます。

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

    // ...
}

というところです。最後のステップは、これらすべての func[i] を呼び出して、その結果を合計するだけです。

これはかなり特殊で珍しいケースだということについて。はい、そうです。素粒子物理学で高精度の計算をしようとすると、このようなケースに対処しなければなりません。

EDIT2です。

x12、x13 などは実際には定数ではないことも付け加えておきます。それらは特定の値に設定され、すべての関数が実行されて結果が返され、そして次の値を生成するために新しい x12、x13 などのセットが選択されるのです。そして、これを10回行わなければならない 5 から10 6 倍...

EDIT3です。

提案とこれまでの議論に感謝します...。私は何とかしてコード生成時にループをロールアップするようにします。正直なところ、この具体的な方法はわかりませんが、これが最善の策だと思います。

ところで、私は、quot; this is scientific computing -- no way to optimize" の陰に隠れようとしたわけではありません。

ただ、このコードの基礎は、私が実際にアクセスできない "black box" から出てくるもので、さらに、全体は単純な例で素晴らしく動作し、私は主に現実世界のアプリケーションで起こることに圧倒される感じです...。

EDIT4です。

ということで、なんとかコードサイズを小さくして csc の定義をコンピュータ代数システムで式を簡略化することで、約1/4にすることができました ( Mathematica ). 私は今、コードを生成する前に他のいくつかのトリックを適用することによって、さらに1桁ほど削減する方法も考えており(この部分を約100MBに削減することができます)、このアイデアがうまくいくことを願っています。

今度はあなたの答えに関連しています。

ループを再び巻き戻そうとしているのは func の中で、CASはあまり役に立ちませんが、すでにいくつかのアイデアを持っています。例えば、式を変数でソートして x12, x13,... のように変数でソートして csc をPythonで解析し、それらを互いに関連付けるテーブルを生成します。それから私は少なくともこれらの部分をループとして生成することができます。これはこれまでのところ最良の解決策であるように思われるので、私はこれをベストアンサーとしてマークします。

しかし、私はVJoにも謝意を表したいと思います。GCC 4.6 は確かに動作します。 大いに より良く動作し、より小さなコードを生成し、より高速になります。大きなモデルを使うことは、そのままのコードで動作します。ですから、技術的にはこれは正しい答えですが、コンセプト全体を変更する方がはるかに良いアプローチです。

みなさん、提案と手助けをありがとうございました。どなたか興味があれば、準備ができ次第、最終的な結果を投稿するつもりです。

REMARKS:

他の回答に対するいくつかの指摘です。私が実行しようとしているコードは、単純な関数/アルゴリズムの拡張や愚かな不要なアンロールに由来しているわけではありません。実際に起こることは、私たちが始めるものはかなり複雑な数学的オブジェクトであり、それらを数値的に 計算可能な という式が生成されます。問題は、実は基礎となる物理理論にあるのです。中間的な表現の複雑さは指数関数的に増大することはよく知られていますが、これらすべてを物理的に測定可能なもの、つまり観測可能なものに結びつけると、表現の基礎となるほんの一握りの非常に小さな関数に集約されるだけなのです。(この点で、一般的な、そして のみ 使用可能 アンサッツ これは摂動論と呼ばれるものです) 私たちはこのansatzを、解析的にはもう実行不可能で、必要な関数の基底がわからない、別のレベルに持っていこうとしています。そこで、このようにブルートフォースでやってみる。ベストな方法ではありませんが、最終的には手元の物理を理解するのに役立つことを願っています。

最後の編集です。

皆さんの提案のおかげで、Mathematica を使って、コードサイズをかなり減らすことができました。 func のコードジェネレータをトップアンサーと同じように修正しました :)

を簡略化しました。 csc 関数を Mathematica で簡略化し,92MBまで下げました.これは不可逆的な部分です.最初の試みは時間がかかりましたが,いくつかの最適化の後,今ではシングルCPUで10分ほどで実行されます.

への影響は func への影響は劇的でした。これらのコード全体のサイズは約 9 MB に減少し、コードの合計は 100 MB の範囲になりました。今では、最適化をオンにすることは理にかなっており、実行は非常に高速になっています。

繰り返しになりますが、皆さんの提案に感謝します。

どのように解決するのですか?

このテキストを生成するプログラムはすでにあるわけです。

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

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

ということですよね?

すべての関数が似たような形式(n個の数値をm回掛けて結果を足す、または似たようなもの)であれば、これができると思います。

  • 文字列の代わりにオフセットを出力するようにジェネレーター プログラムを変更します (つまり、文字列 "s.ds0" の代わりに、以下を生成します)。 offsetof(ProcessVars, ds0)
  • そのようなオフセットの配列を作成します。
  • 上記の配列と構造体ポインタのベースアドレスを受け取り、結果を生成するエバリュエータを記述します。

配列と評価器は関数と同じロジックを表しますが、評価器だけがコードとなります。配列はデータで、実行時に生成するか、ディスクに保存してチャンク単位で読み込むか、メモリ マップ ファイルを使用します。

func1 の特定の例について、以下のベースアドレスにアクセスできる場合、評価器を通してどのように関数を書き換えるかを想像してみてください。 scsc に到達するためにベースアドレスに追加する必要がある定数とオフセットのベクトルのような表現もあります。 x14 , ds8csc[51370]

膨大な数の関数に渡す実際のデータをどのように処理するかを記述する、新しい形式の "data" を作成する必要があります。