首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

如其不是ICC BUG太多,ICC生成的代码是速度最快的

2012-06-20 
如果不是ICC BUG太多,ICC生成的代码是速度最快的今天无聊做了个实验,想看看各种编译器产生的代码效率,结果

如果不是ICC BUG太多,ICC生成的代码是速度最快的
今天无聊做了个实验,想看看各种编译器产生的代码效率,结果不出乎所料,在Windows下,GCC和VC差不多,ICC快得多。

ICC虽然很好很强大,但是BUG太多,许多程序根本无法编译,直接就给出“编译器内部错误”,想编译来加速PCSX2的夙愿一直未能实现,Intel要加油啊!

之前一直怀疑GCC在Windows下应该是比VC慢的,结果比较下来区别不大。

这段代码融合了随机数生成,浮点运算,字符串输出,字符串拷贝,内存分配、释放、拷贝等常见的编程操作。实际上最费时的是内存拷贝,因为要拷贝所有运算结果。

代码如下:

C/C++ code
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <math.h>#define LOOP 20#define LOOP_COUNT 1000#define FLOAT_COUNT 100#define NUM_STR_BUFFER_SIZE 256/* function table */typedef struct _ftable{    int func_id;    char name[10];    double (*func)(double);}function_table;function_table func_tb[] = {    {0, "  sin", sin},    {1, "  cos", cos},    {2, "  tan", tan},    {3, "  log", log},    {4, "log10", log10},    {5, " sqrt", sqrt},    {6, "  exp", exp}};int main(int argc, char **argv){    int i = 0, j = 0, k = 0, rand_num = 0, cal_num = 0;    double result = 0.0, cost = 0.0;    char *str = NULL, *temp_str = NULL, str_line[NUM_STR_BUFFER_SIZE];    clock_t start, finish;        printf("calculate %d loops...\n", LOOP);        start = clock();        srand(clock());    str = (char*)malloc(sizeof(char) * NUM_STR_BUFFER_SIZE);    *str = '\0';        /*     * 这段循环总共LOOP次,每次要做:     * 1. 进行LOOP_COUNT次浮点数运算,取两次随机数,一次用于选函数,一次用于计算     * 2. 拷贝一次运算结果,字符串拷贝 strncat     * 3. 搜索字符     * 4. 拷贝全部运算结果,内存拷贝 memcpy     * 5. 释放内存 */    for (j = 0; j < LOOP; ++j){        for (i = 0; i != LOOP_COUNT; ++i){            /* 取两次随机数 */            rand_num = rand() % 6;            cal_num = rand();                        /* 随机选出计算函数,并进行一次浮点函数 */            result = func_tb[rand_num].func(cal_num);                        /* 一次字符串输出 */            sprintf(str_line, "%6d : %s(%6d) = %4.10f\n",                     i + 1, func_tb[rand_num].name, cal_num, result);                                /* 分配内存用于拷贝结果 */            temp_str = str;                    str = (char*)malloc(sizeof(char) * (strlen(str_line) + strlen(temp_str) + 1));                        /* 进行内存拷贝,拷贝之前的全部结果 */            memcpy(str, temp_str, strlen(temp_str) + 1);                        /* 拷贝当前运算结果 */            strncat(str, str_line, strlen(str_line));                        /* 释放内存 */            free(temp_str);        }        printf("loop %2d of %2d is done.\n", j + 1, LOOP);    }    free(str);    finish = clock();        cost = (finish - start) / 1000.0;    printf("loop %d cost %.3f second.", LOOP, cost);    return 0;}


结果如下:
每次运行取第二次运行的结果。
C/C++ code
编译器  版本   编译参数           运行时间    备注cl      16.0   无                  6.703cl      16.0   /O2 /arch:SSE2     12.577      最常用的优化选项,得到了最慢的代码  icl     12.1   无                  2.744icl     12.1   /fast               2.934      同样,最“恐怖”的优化参数,稍慢一些GCC     4.5.3  无                  6.655GCC     4.5.3  -O2 -march=native   6.688      优化也没有效果


这段代码能优化的部分可能真的很少,各编译器的优化几乎都没有效果,甚至还有反效果。

结果显而易见了,GCC和VC差不多,ICC显然得到了比较“恐怖”的提升,负面效果也是有的,icl的代码尺寸也很大,纯粹以空间换时间。GCC的代码尺寸比VC稍大一些。

做这个比较,并非为了引起编译器之争,只是觉得,vc的编译器不能识别不带BOM的UTF-8中的字符,而GCC刚好相反,在进行Qt开发时,vc的编译器让我很难选择文件编码,一个小小的源文件编码问题,导致了很多移植问题。不过现在好了,既然GCC和VC差不多,我们就不必选择太肥胖的Visual Studio了。


[解决办法]
都不是同等比较
icl默认fastmath(无论什么参数)

至少比较时把fastmath禁用,而且该开关容易导致错误的结果,尤以3-4月份intel编译器事故最为严重

此外,icl默认循环展开,其他都没有

/fast又默认了全局优化(IPO)和内联,其他默认也没有,当然对单一源码没有什么影响

所以GCC应该用

-O2 (-O3) -march=native -finline-functions -funroll-loops -ffast-math -malign-double -fomit-frame-pointer -minline-all-stringops -ftree-parallelize-loops=n(n为你的cpu核心数,双核n=2)



4.5不要使用LTO作用单一源码

4.6.1之后应该用

-O2 (-O3) -march=native -funroll-loops -ffast-math -malign-double -fomit-frame-pointer -minline-all-stringops -ftree-parallelize-loops=n(n为你的cpu核心数,双核n=2) -flto -fuse-linker-plugin

热点排行