在比较Linux和Windows系统时,代码在Linux上运行速度较慢。

4

在修改了我的C代码后(最初是为Windows编写的,并在VS 2008下编译),我在Linux上运行它。令我惊讶的是,现在它至少比Windows版本慢10倍。

使用Profiler工具,我发现以下函数消耗了应用程序中大部分的时间:

/* advance by n bits */

void Flush_Buffer(N)
int N;
{
 int Incnt;


 ld->Bfr <<= N;

Incnt = ld->Incnt -= N;

if (Incnt <= 24)
{
if (System_Stream_Flag && (ld->Rdptr >= ld->Rdmax-4))
{
do
{
if (ld->Rdptr >= ld->Rdmax)
      Next_Packet();
    ld->Bfr |= Get_Byte() << (24 - Incnt);
    Incnt += 8;
  }
  while (Incnt <= 24);
}
else if (ld->Rdptr < ld->Rdbfr+2044)
{
  do
  {
    ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
    Incnt += 8;
  }
  while (Incnt <= 24);
}
else
{
  do
  {
    if (ld->Rdptr >= ld->Rdbfr+2048)
      Fill_Buffer();
    ld->Bfr |= *ld->Rdptr++ << (24 - Incnt);
    Incnt += 8;
  }
  while (Incnt <= 24);
}
ld->Incnt = Incnt;
}

}

这个功能在Windows上几乎不耗时。 在Linux上,它需要接近14秒钟的时间。我在这里犯了什么错误?
这里没有系统调用,因此此代码段应该独立于特定于操作系统的调用,因此应以相同的时间运行。
(我猜测:这个函数被调用了多次,所以可能分析器也累积了所有调用的时间。在这种情况下,我认为一个问题可能是该函数没有快速获取其输入参数,与Windows情况相比。)
我在这里犯了什么错误?有什么猜测吗?
问候,

4
除非您至少指定了(1)您使用的编译器选项和(2)您如何测量所花费时间,否则此问题毫无意义。 - R.. GitHub STOP HELPING ICE
你是如何编译你的代码的(使用了哪个编译器,哪些选项,(开启了哪个警告级别))? - Mat
3
不,你错了,因为你提出了一个问题,省略了所有相关信息,然后又无视提供信息的请求。 - R.. GitHub STOP HELPING ICE
1
你在Linux上使用过优化吗?使用gcc编译器的选项-O[1|2|3] - alk
3
Valgrind 可以让你的应用程序运行慢至多50倍……而且正确的写法是 -O3,不是 -o3。 - alk
显示剩余5条评论
2个回答

1

这更像是一条笔记而不是一个答案,但它并不完全适合于评论,所以我希望你不要因此而对我有所保留。

术语“分析”有几个相关但不同的含义。在抽象的上下文中,它意味着“测量”您的程序,通常与某些运行时数据相关。然而,它并不等同于简单地“计时”您的程序。计时是分析的一种形式,但还有许多其他形式。

例如,假设您不确定某个数据结构应该是std::set(一棵树)还是std::unordered_set(哈希表)。没有通用的答案,因为它取决于您使用它的方式和处理的数据。完全有可能直到您指定实际的现实数据之前,您都无法知道正确的答案。在这种情况下,“分析并决定”意味着您制作两个版本的程序,针对您的真实数据运行它们,并测量运行时间。速度更快的可能是您想要的那个。

另一方面,GCC 有一个被称为“分析器”的工具,它有着非常不同的用途。它是一个执行路径分析器,可以告诉你程序在哪里(即在哪个函数中)花费了大部分时间。如果你有一个包含许多子程序的复杂算法,你可能不知道哪些是重要的,而这实际上可能取决于你的真实输入。在这种情况下,分析器可以帮助你确定哪些函数在给定输入数据的情况下被调用最多,并且你可以将优化的精力集中在这些函数上。现在,“在优化之前进行分析”意味着你需要在开始工作之前确定优先级。
话虽如此,对于你所考虑的比较,你不能使用 GCC 分析器。相反,应该在两个平台上都启用所有优化并处于发布状态下编译,然后在相同的输入数据集上测量运行时间。

我建议永远不要使用gcc分析器。对于大型函数,开销很小,但对于小型函数,函数内的时间被分析开销所支配。这意味着,良好设计的程序在使用gcc分析器时表现非常糟糕(并且提供了极其扭曲的分析结果)。当然,还有各种问题,例如结果被选择性地内联所扭曲。如果您想测量程序中花费时间的位置,则唯一可行的方法是定期采样指令指针和堆栈,例如oprofile。 - R.. GitHub STOP HELPING ICE

0
你可以尝试在代码中注释所有的代码路径并计数。程序结束时,每个计数器将包含有关代码路径已执行多少次的信息。逐行比较Windows版本和Linux版本之间的这些数字,可能会发现程序正在遵循不同的代码路径。根据代码路径的性质,这些差异可能能够解释为什么Linux版本比Windows版本慢。
int count[100];

// Call this function at the end of program 
void PrintCounts() {
    int i;
    for(i=0; i<100; i++) printf("%d\n", count[i]);
}

void Flush_Buffer(int N) {
  int Incnt;

  ld->Bfr <<= N;

  Incnt = ld->Incnt -= N;

  if (Incnt <= 24) {
    count[0]++;
    if (System_Stream_Flag && (ld->Rdptr >= ld->Rdmax-4)) {
      count[1]++;
      do {
         count[2]++;
         ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接