GCC编译速度很慢(大文件)

时间:2015-10-30 19:34:42

标签: c gcc mex

我正在尝试编译一个大的C文件(专门用于MATLAB mexing)。 C文件大约为20 MB(如果你想玩它,可用from the GCC bug tracker。)

以下是我正在运行的命令和屏幕输出。这已经运行了几个小时,如您所见,优化已被禁用(-O0)。为什么这么慢?有没有办法让我更快?

(供参考:Ubuntu 12.04(精确穿山甲)64位和GCC 4.7.3)

/usr/bin/gcc -c -DMX_COMPAT_32   -D_GNU_SOURCE -DMATLAB_MEX_FILE  -I"/usr/local/MATLAB/R2015a/extern/include" -I"/usr/local/MATLAB/R2015a/simulink/include" -ansi -fexceptions -fPIC -fno-omit-frame-pointer -pthread -O0 -DNDEBUG path/to/test4.c -o /tmp/mex_198714460457975_3922/test4.o -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.3-2ubuntu1~12.04' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04)
COLLECT_GCC_OPTIONS='-c' '-D' 'MX_COMPAT_32' '-D' '_GNU_SOURCE' '-D' 'MATLAB_MEX_FILE' '-I' '/usr/local/MATLAB/R2015a/extern/include' '-I' '/usr/local/MATLAB/R2015a/simulink/include' '-ansi' '-fexceptions' '-fPIC' '-fno-omit-frame-pointer' '-pthread' '-O0' '-D' 'NDEBUG' '-o' '/tmp/mex_198714460457975_3922/test4.o' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -I /usr/local/MATLAB/R2015a/extern/include -I /usr/local/MATLAB/R2015a/simulink/include -imultilib . -imultiarch x86_64-linux-gnu -D_REENTRANT -D MX_COMPAT_32 -D _GNU_SOURCE -D MATLAB_MEX_FILE -D NDEBUG path/to/test4.c -quiet -dumpbase test4.c -mtune=generic -march=x86-64 -auxbase-strip /tmp/mex_198714460457975_3922/test4.o -O0 -ansi -version -fexceptions -fPIC -fno-omit-frame-pointer -fstack-protector -o /tmp/ccxDOA5f.s
GNU C (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) version 4.7.3 (x86_64-linux-gnu)
    compiled by GNU C version 4.7.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/MATLAB/R2015a/extern/include
 /usr/local/MATLAB/R2015a/simulink/include
 /usr/lib/gcc/x86_64-linux-gnu/4.7/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) version 4.7.3 (x86_64-linux-gnu)
    compiled by GNU C version 4.7.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: c119948b394d79ea05b6b3986ab084cf

编辑:后续:我遵循chqrlie的建议并且tcc在<5秒内编译了我的函数(我不得不删除-ansi标志并将“gcc”变为“tcc”),这非常了不起,真。我只能想象GCC的复杂性。

然而,当尝试使用mex时,mex通常需要另外一个命令。第二个命令通常是:

/usr/bin/gcc -pthread -Wl,--no-undefined -Wl,-rpath-link,/usr/local/MATLAB/R2015a/bin/glnxa64 -shared  -O -Wl,--version-script,"/usr/local/MATLAB/R2015a/extern/lib/glnxa64/mexFunction.map" /tmp/mex_61853296369424_4031/test4.o   -L"/usr/local/MATLAB/R2015a/bin/glnxa64" -lmx -lmex -lmat -lm -lstdc++ -o test4.mexa64

我不能用tcc运行它,因为其中一些标志不兼容。如果我尝试使用GCC运行第二个编译步骤,我会得到:

/usr/bin/ld: test4.o: relocation R_X86_64_PC32 against undefined symbol `mxGetPr' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
编辑:解决方案似乎是铿锵有力。 tcc可以编译该文件,但mexing第二步中的参数与tcc的参数选项不兼容。 Clang非常快,可生成一个漂亮,小巧,优化的文件。

3 个答案:

答案 0 :(得分:15)

几乎整个文件都是一个表达式,即double f[24] = ...的赋值。这将生成 gigantic 抽象语法树树。如果只有专门的编译器可以有效地处理它,我会感到惊讶。

20兆字节的文件本身可能没问题,但一个巨大的表达可能是导致问题的原因。尝试作为初步步骤,将行分为double f[24] = {0},然后将f[0] = ...; f[1] = ...的24个分配分开,看看会发生什么。最糟糕的情况是,您可以将24个分配分成24个函数,每个函数都在自己的.c文件中,并单独编译。这不会减小AST的大小,它只会重新组织它,但GCC在处理许多语句时可能会更加优化,这些语句总共会增加很多代码,而不是一个巨大的表达式。

最终的方法是以更优化的方式生成代码。例如,如果我搜索s4*s5*s6,我会获得77,783次点击。这些s[4-6]变量不会更改。您应该生成一个临时变量double _tmp1 = s4*s5*s6;,然后使用它而不是重复表达式。您刚从抽象语法树中删除了311,132个节点(假设s4*s5*s6是5个节点,_tmp1是一个节点)。这就是GCC必须做的事情要少得多。这也应该生成更快的代码(你不会重复相同的乘法77,783次)。

如果您以递归方式智能地执行此操作(例如s4*s5*s6 - &gt; _tmp1(c4*c6+s4*s5*s6) - &gt; (c4*c6+_tmp1) - &gt; _tmp2c5*s6*(c4*c6+s4*s5*s6) - &gt; c5*s6*_tmp2 - &gt; _tmp3等等,您可以消除生成代码的大部分大小。

答案 1 :(得分:12)

经过测试,我发现Clang编译器编译大文件的问题似乎较少。虽然Clang在编译期间消耗了几乎1 GB的内存,但它成功地将OP的源代码形式转换为70 kB的目标文件。这适用于我测试的所有优化级别。

如果打开优化,gcc还能够快速编译此文件,而不会消耗太多内存。这个bug in gcc来自OPs代码中的大表达式,这给寄存器分配器带来了巨大的负担。启用优化后,编译器会执行一个名为公共子表达式消除的优化,它可以从OP代码中删除大量冗余,从而将编译时间和目标文件大小减少到可管理的值。

以下是上述错误报告中的测试用例的一些测试:

$ time gcc5 -O3 -c -o testcase.gcc5-O3.o testcase.c
real    0m39,30s
user    0m37,85s
sys     0m1,42s
$ time gcc5 -O0 -c -o testcase.gcc5-O0.o testcase.c
real    23m33,34s
user    23m27,07s
sys     0m5,92s
$ time tcc -c -o testcase.tcc.o testcase.c
real    0m2,60s
user    0m2,42s
sys     0m0,17s
$ time clang -O3 -c -o testcase.clang-O3.o testcase.c
real    0m13,71s
user    0m12,55s
sys     0m1,16s
$ time clang -O0 -c -o testcase.clang-O0.o testcase.c
real    0m17,63s
user    0m16,14s
sys     0m1,49s
$ time clang -Os -c -o testcase.clang-Os.o testcase.c
real    0m14,88s
user    0m13,73s
sys 0m1,11s
$ time clang -Oz -c -o testcase.clang-Oz.o testcase.c
real    0m13,56s
user    0m12,45s
sys     0m1,09

这是生成的对象文件大小:

    text       data     bss      dec        hex filename
39101286          0       0 39101286    254a366 testcase.clang-O0.o
   72161          0       0    72161      119e1 testcase.clang-O3.o
   72087          0       0    72087      11997 testcase.clang-Os.o
   72087          0       0    72087      11997 testcase.clang-Oz.o
38683240          0       0 38683240    24e4268 testcase.gcc5-O0.o
   87500          0       0    87500      155cc testcase.gcc5-O3.o
   78239          0       0    78239      1319f testcase.gcc5-Os.o
69210504    3170616       0 72381120    45072c0 testcase.tcc.o

答案 2 :(得分:6)

http://tinycc.org尝试Fabrice Bellard的微小C编译器tcc

chqrlie$ time tcc -c test4.c

real    0m1.336s
user    0m1.248s
sys     0m0.084s

chqrlie$ size test4.o
   text    data     bss     dec     hex filename
38953877        3170632       0 42124509        282c4dd test4.o

是的,非常基本的PC上的 1.336秒

当然我无法测试生成的可执行文件,但是目标文件应该可以与程序和库的其余部分链接。

对于此测试,我使用了文件mex.h的虚拟版本:

typedef struct mxArray mxArray;
double *mxGetPr(const mxArray*);
enum { mxREAL = 0 };
mxArray *mxCreateDoubleMatrix(int nx, int ny, int type);

gcc仍然没有完成编译......

编辑:gcc设法让我的Linux机箱很糟糕,我再也无法连接它了:(

相关问题