找回密码
 注册
楼主: Kyoryu

同样的程序在Linux和Windows下速度差别如此之大?

[复制链接]
发表于 2005-11-27 19:50:22 | 显示全部楼层
晕,排版出来怎么变成上面这个样子了?
大家凑合着看吧
回复

使用道具 举报

发表于 2005-11-27 19:54:31 | 显示全部楼层
“GCC编译出来的代码速度实在令人失望,居然只能跟TC系列勉强打个平手。”:用这种方法还不能判定是gcc的问题,因为用gcc和微软的编译器,他们所用的c库是不一样的,也就是说rand()的实现也不一样,而这个程序全都是在执行rand(),glibc的rand()代码量比微软的rand()大一倍也不一定啊。

“在Windows2000下和Linux下运行时间居然差了有50%”:我这基本一样。
回复

使用道具 举报

发表于 2005-11-28 00:08:59 | 显示全部楼层
为了避免库函数对速度的影响,我又特意编制了下面这个程序:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{ int  i,j,k,count;
  long  start_time, end_time;
  printf("Please input loop times:");
  scanf("%ld",&count);
  start_time=time(NULL);
  for(k=0;k<count;k++)
   for(i=0;i<10000;i++)
    for(j=0;j<10000;j++)
          ;
  end_time=time(NULL);;
  printf("%d seconds lapsed.",end_time-start_time);
  return 0;
}

用BC5.5、TC2.0、TC3.0编译,无论是默认选项还是用优化速度选项,当输入100时,运行时间都是16秒。这说明对于简单的循环,能够做的优化实在不多,Borland这20年来都没找到更好的方法。
如果用DEV-C++的默认选项编译,则在Windows2000下的运行时间是41秒,如用-O3优化,则是16秒。
如果用gcc的的默认选项编译,则在Linux下的运行时间是41秒,如用-O3优化,则是16秒。
同样证明,大家对于这种简单循环的优化,已经到达了极限。

在前面PI程序的测试中,borland的编译器TC2.0->TC3.0->BC5.5,速度越来越快,而循环已经不可能优化了,说明borland在库函数rand()上下了不少功夫。反过来看gcc所用的库函数rand(),效率就差多了。
前面几位认为rand()的效率差,不算gcc之过。其实,一个成熟的编译器,对所用库函数效率(包括算法和实现细节方面)的优化也是非常重要的,否则的话,编译出来的代码不可能有很快的速度。
这里只测试了一个rand()函数,但我有理由相信,gcc所用到的其余库函数的效率也不会好到哪里去。还有gcc好像对自己的优化技术不太放心,没有象borland那样应用到默认情况中去。这至少说明gcc认为自己的优化技术还不太成熟。所以gcc要达到商用编译器的水平,要走的路还很长。
PS:gcc也有自己的理由:要做跨平台的全能战士,不太好针对某个平台进行代码优化...
想到Linux下的程序大多用gcc编译,汗...
回复

使用道具 举报

发表于 2005-11-28 19:28:21 | 显示全部楼层
[code:1]       POSIX  1003.1-2003  gives the following example of an implementation of
       rand() and srand(), possibly useful when one needs the same sequence on
       two different machines.

           static unsigned long next = 1;

           /* RAND_MAX assumed to be 32767 */
           int myrand(void) {
               next = next * 1103515245 + 12345;
               return((unsigned)(next/65536) % 32768);
           }

           void mysrand(unsigned seed) {
               next = seed;
           }[/code:1]
[code:1]NOTES
       The  versions of rand() and srand() in the Linux C Library use the same
       random number generator as random() and srandom(), so  the  lower-order
       bits  should  be as random as the higher-order bits.  However, on older
       rand() implementations, and on  current  implementations  on  different
       systems,  the  lower-order  bits  are much less random than the higher-
       order bits.  Do not use this function in applications  intended  to  be
       portable when good randomness is needed.
[/code:1]
[code:1]       The random() function uses a non-linear additive feedback random number
       generator employing a default table of size 31 long integers to  return
       successive  pseudo-random numbers in the range from 0 to RAND_MAX.  The
       period of this random number generator  is  very  large,  approximately
       16*((2**31)-1).[/code:1]
我觉得不是gcc的问题,随机数的生成不是越快越好吧?
以上来自man rand,man random
回复

使用道具 举报

发表于 2005-11-29 11:29:39 | 显示全部楼层
呵呵,
以前看的帖,翻过来贴一下,并非本人观点.


自动优化选项什么时候真正有用过?
象这类
for(k=0;k<count;k++)
for(i=0;i<10000;i++)
for(j=0;j<10000;j++)
的程序,
编译器优化把原来该放到数据区的数,放到寄存器中去,并采用最短执行时间的跳转命令.

需要经常调用的大运算量的算法,想办法让它长驻一级CACHE中.假如是并行算法,且有多处理器,则用多线程同时协调运算,提升线程优先级,提升线程CPU占有率等等方法.

即使不用O2/O3都可以设定的.

真的对速度要求很高的地方,
几乎见不到有人企图利用编译器的优化选项去获得更高的性能,
多数需要自己动手优化算法和简化程序结构.

在对代码或数据空间要求很高的地方(譬如那些需要在一级高速缓存运行的代码和数据,其实也是对速度要求高的程序和数据了),
又有谁打算用编译器的优化选项去优化?
回复

使用道具 举报

发表于 2005-11-29 12:04:37 | 显示全部楼层
linux和GCC是跨平台的系统和工具,
WIN则几乎不用考虑X86以外的平台,
MS和它的合作方有更多的精力去为一个平台进行优化,
但linux和gcc却要同时考虑N个平台.
回复

使用道具 举报

发表于 2005-11-29 16:27:53 | 显示全部楼层
改了一点地方,用gcc -O2 -static aa.c -lm在我的机器上能得到36s的成绩,不加-O2 -static是57s;怀疑时间是耗在x*x + y*y这些float point number运算上了,哪位数学好,能不能把 x*x + y*y <= 1.0 这个代数表达式用好点的算法表达出来?

windows下测试没做。

#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#include "math.h"

int main(int argc, char* argv[])
{
double x,y,sigma,pi=0.0;
long end=1,i,time1,time2,count;
long qr, remainder;

while(end)
{
count=0;
printf("\nPlease input uplimit of the rand numbers( 0 to stop ): ");
scanf("%ld",&end);
if(end<=0)
{
printf("Error: Wrong Uplimit!\n");
continue;
}
printf("Now is calculating the pi ...\n");
qr = end / 4;
remainder = end % 4;

time1=time(NULL);
srand(time1);
for(i=0;i<qr;++i)
{
x=(double)rand()/RAND_MAX;
y=(double)rand()/RAND_MAX;
if((x*x+y*y)<=1.0) ++count;
x=(double)rand()/RAND_MAX;
y=(double)rand()/RAND_MAX;
if((x*x+y*y)<=1.0) ++count;
x=(double)rand()/RAND_MAX;
y=(double)rand()/RAND_MAX;
if((x*x+y*y)<=1.0) ++count;
x=(double)rand()/RAND_MAX;
y=(double)rand()/RAND_MAX;
if((x*x+y*y)<=1.0) ++count;
}
for(i=0;i<remainder;++i)
{
x=(double)rand()/RAND_MAX;
y=(double)rand()/RAND_MAX;
if((x*x+y*y)<=1.0) ++count;
}
pi=(count/(double)end)*4;
sigma=sqrt(pi*(pi-1)/(double)end);
time2=time(NULL);
printf("Pi = %f +- %f\t\tTime use: %d seconds\n",pi,sigma,time2-time1);
}
return 0;
}
回复

使用道具 举报

发表于 2005-11-29 22:20:42 | 显示全部楼层
光从一个函数rand也许并不能说明太多问题。不过我在后面的测试程序中已经去掉了所有的库函数,
仅仅是个空循环,可GCC在默认选项上的表现也不如人意。

rushrush说rand并不是越快越好,这点我也同意,主要是看用在什么地方。如果是仿真,那么用线性
同余算法已经足够了。只有在需要加密的场合才会用到LSFR序列(其实如果要求很高,纯粹的LSFR
也不行,还需要加入噪声),这点在GCC的帮助中说得很清楚。
我查到了GCC所用的rand函数的实现,如下(注释是我加的):
int
__random_r (buf, result)
     struct random_data *buf;
     int32_t *result;
{
  int32_t *state;

  if (buf == NULL || result == NULL)
    goto fail;

  state = buf->state;
/* 这是用的线性同余算法*/
  if (buf->rand_type == TYPE_0)
    {
      int32_t val = state[0];
      val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
      state[0] = val;
      *result = val;
    }
/*这里用的是LFSR序列*/
else
    {
      int32_t *fptr = buf->fptr;
      int32_t *rptr = buf->rptr;
      int32_t *end_ptr = buf->end_ptr;
      int32_t val;

      val = *fptr += *rptr;
      *result = (val >> 1) & 0x7fffffff;
      ++fptr;
      if (fptr >= end_ptr)
        {
          fptr = state;
          ++rptr;
        }
      else
        {
          ++rptr;
          if (rptr >= end_ptr)
            rptr = state;
        }
      buf->fptr = fptr;
      buf->rptr = rptr;
    }
  return 0;

fail:
  __set_errno (EINVAL);
  return -1;
}

容易看出,无论是线性同余还是LFSR,复杂程度都差不多,所需时间应该没有什么差异。

由于Borland和Microsoft都没有提供自己的rand实现的源代码,我不好多说。但显而易见的是:
GCC编译的PI程序执行速度上与VC、BC的有很大差距,并不是由于GCC采用了“更高级”LFSR序列,
而后两者采用了“更低级”的线性同余算法造成的。
回复

使用道具 举报

发表于 2005-11-29 22:23:17 | 显示全部楼层
TO Deep,我呆会试试这个程序在Windows下的表现
回复

使用道具 举报

发表于 2005-11-29 23:44:56 | 显示全部楼层
用Deep的程序在我的机器上运行情况如下:

Linux下:
GCC -o -pi -pi.c -lm        要87S
GCC -O2 -o -pi -pi.c -lm      要82S
GCC -static -o -pi -pi.c -lm    要73S
GCC -static -O2 -o -pi -pi.c -lm  要65S

Windows 2000下:
Dev-C++  默认选项          要62S
Dev-C++  加上-static -O2       要60S

BC5.5 无论怎样,都是30S。

结论:Deep的程序用GCC在Linux下编译比LZ的有进步,但在Windows下,对BC和Dev-C++都没什么影响。
回复

使用道具 举报

发表于 2005-12-7 07:20:53 | 显示全部楼层
我觉得楼主比较东西的时候,有点问题。
初中生都知道,我们做实验的时候,不能在多个变量下判断一个变量产生的结果。
有两点需要解决:

1.你把GCC和VC++编译出来的都放到Windows机器上分别执行,再都放到Linux上分别执行,才可以比较编译器。

2.你把GCC编译出来的分别放到Windows和Linux上执行,然后再把VC++编译出来的分别放到不同的系统上,才可以比较系统。

具体实现起来可能麻烦,但我认为这样才能叫做比较。
回复

使用道具 举报

发表于 2005-12-7 10:37:08 | 显示全部楼层
VC Relase版编译默认情况下已经带了优化处理了,光用gcc aa.c -lm编译出来的代码应该没有经过任何优化处理。
以下是我的测试(公司机器上,家里32位系统和64位系统不好比较):
-----------------------------------
硬件
CPU4 2.8G
内存:512MB(256x2) DDR400
-----------------------------------
MS WindowsXP SP2
编译器:VC 7.1 ( VS.NET 2003 )
Release版
编译参数: /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /EHsc /ML /GS /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /nologo /c /Wp64 /Zi /TP
链接参数:/OUT:"Release/PIE.exe" /INCREMENTAL:NO /NOLOGO /DEBUG /PDB:"Release/PIE.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /MACHINE:X86   kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
运行时间:26秒
------------------------------------------------------------------------------
Cygwin
编译器:gcc 3.4.4(cygwin)
命令行:gcc -lstdc++ -O2 -o pie pie.cpp
运行时间:41秒
-------------------------------------------------------------------------------
尴尬。。。。晚上回家再试试看
回复

使用道具 举报

发表于 2005-12-7 10:37:52 | 显示全部楼层
但实事上linux内核本身就是用 gcc 编译的 这就让问题变得复杂了 哈
回复

使用道具 举报

发表于 2005-12-7 17:49:06 | 显示全部楼层
我编了一个gtk的图形gui的程序,分别在win2000p和rh9里编译(rh9用的是g++)
运行速度差不多阿(总共9万行代码,49个窗口)
回复

使用道具 举报

发表于 2005-12-7 23:02:12 | 显示全部楼层
对于不需要考虑其他平台的编译器,其效率比起通用性更强的编译器要高似乎是必须的。gcc要保证在其支持的所有平台上可用,vc有吗?

我觉得比比gcc3和gcc4的效率或者vc6和vc8的效率来的更有意义。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2025-2-6 13:07 , Processed in 0.031257 second(s), 12 queries .

© 2001-2025 Discuz! Team. Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表