我有大量的函数,总共大约2.8 GB 的目标代码(不幸的是,没有办法,科学计算...)
当我尝试链接它们时,我会得到(预期的) 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
在哪里可以找到问题的线索?
编辑:
首先,谢谢你们的讨论。
为了澄清一点,我有数百个函数(每个大小约为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[]
是一个预计算的值映射,它也是在单独的对象文件(同样是数百个,每个大约1MB)中计算的,形式如下:
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]
并总结结果。
事实上,这是一个相当特殊和不寻常的情况: 是的,它是。这就是人们在尝试为粒子物理学做高精度计算时必须应付的问题。
编辑2:
我还应该补充一点,x12、 x13等等并不是真正的常量。它们被设置为特定的值,运行所有这些函数并返回结果,然后选择一个新的 x12、 x13等值集来生成下一个值。这必须做105到106次..。
编辑3:
谢谢您的建议和讨论,到目前为止... 我将尝试滚动循环上的代码生成,不知道如何确切地,说实话,但这是最好的选择。
顺便说一句,我没有试图躲在“这是科学计算——没有办法优化”的背后。
只是这段代码的基础来自于一个我无法真正访问的“黑盒子”,而且,对于一些简单的例子,整个代码工作得很好,我主要是对现实世界中发生的事情感到不知所措..。
编辑4:
因此,我已经成功地通过简化计算机代数系统(Mathematica)中的表达式,将 csc
定义的代码大小减少了大约四分之一。我现在还看到了一些方法,通过在生成代码之前应用一些其他的技巧(这将使这部分代码降低到大约100MB)来减少数量级,我希望这个想法能够奏效。
现在谈谈你的回答:
我试图在 func
中再次回滚循环,在这里 CAS 帮助不大,但是我已经有了一些想法。例如,按变量(如 x12, x13,...
)对表达式进行排序,使用 Python 解析 csc
,并生成相互关联的表。然后我至少可以生成这些部分作为循环。由于这似乎是迄今为止最好的解决方案,我认为这是最好的答案。
不过,我还是要感谢 VJo。GCC 4.6确实可以更好地运行 很多,产生更小的代码,并且速度更快。使用大型模型可以按原样处理代码。所以从技术上讲,这是正确的答案,但是改变整个概念是一个更好的方法。
谢谢你们的建议和帮助。如果有人感兴趣的话,我会在我准备好的时候发布最终结果。
备注:
只是对其他答案的一些注释: 我试图运行的代码并不源于简单函数/算法的扩展和愚蠢的不必要的展开。实际情况是,我们开始的东西是相当复杂的数学对象,并把它们带到一个数字 可计算的形式生成这些表达式。问题实际上在于潜在的物理理论。众所周知,中间表达式的复杂性是阶乘性的,但是当把所有这些东西结合到物理上可测量的东西——一个可观察的东西上时,它只能归结为构成表达式基础的几个非常小的函数。(在这方面,通用和 只有可用的 回答(被称为“摄动理论”)肯定存在一些“错误”)。我们试图将这种分析方法提升到另一个层次,这在分析上已经不再可行,而且所需功能的基础尚不清楚。所以我们试着这样强迫它。虽然不是最好的方法,但希望能帮助我们最终理解手边的物理学。
最后编辑:
感谢您的所有建议,我已经成功地大大减少了代码大小,使用 Mathematica 和对 func
的代码生成器进行了一些修改,大致类似于上面的答案:)
我已经简化了 Mathematica 的 csc
功能,把它缩减到92MB。这是不可还原的部分。第一次尝试花了很长时间,但经过一些优化之后,现在在单个 CPU 上运行这个过程大约需要10分钟。
对 func
s 的影响是巨大的: 它们的整个代码大小降低到大约9 MB,因此现在代码总量在100 MB 范围内。现在打开优化是有意义的,而且执行速度非常快。
再次感谢大家的建议,我学到了很多。