【问题标题】:Optimization of the following block of code以下代码块的优化
【发布时间】:2017-01-04 17:05:06
【问题描述】:

考虑以下一段 C 代码。描述可能提高性能的三种不同优化(包括它们的名称)、它们提高性能的原因以及代码在优化之后的表现。假设所有变量都在代码序列之前声明并启动/具有某些值。

 condition2 = condition1 | input_flag; 

 for(i=0;i<10000;i++){

   if ( (t1==0) && (t2==0) && (t3==0) ) 
      a = sin(45∗b∗3.14/180);  

   else  
      a = sin(135∗b∗3.14/180);  

   if ( condition2 & COND1 ) 
      DoOneThing(a);

   else if ( condition2 & COND2 ) 
      DoAnotherThing(a); 

   else 
      DoYetAnotherThing(a); 
 } 

我有以下C代码示例。我正在学习性能优化的方法,但我对它很陌生,不知道如何优化以下代码......

也许一种方法是在循环中初始化a。但我想不出任何其他方法来优化它。

【问题讨论】:

  • 提示:a 依赖于i 吗?
  • 一种可能的“优化”是使用布尔运算符而不是按位运算符。否则不会发生短路。
  • 缩进现在几乎是正确的。
  • @MichaelWalz 不,它没有。这意味着我可以将第一个 if 语句放在循环之外吗?
  • 第一段听起来像是家庭作业,而且是糟糕的作业。这是糟糕的代码,即使它已经过优化。

标签: c performance optimization


【解决方案1】:

虽然大部分优化将由优化编译器自动执行,但了解编译器在背后执行的操作仍然是件好事。
以下是几种可能性:

  1. 不断折叠

    3.14 除以 180 涉及两个编译时常量,因此可以提前计算,并且只将结果存储在二进制文件中。这为我们节省了运行时的计算量,从而加快了代码的执行速度。

    3.14/180 = 0.0174444   // assume 64-bit precision, like a double
    

    因此,代码变为:

    for(i=0;i<10000;i++) {    
      if ( (t1==0) && (t2==0) && (t3==0) ) 
         a = sin(45*b*0.0174444);  
      else  
         a = sin(135*b*0.0174444);  
    
      if ( condition2 & COND1 ) 
         DoOneThing(a);
      else if ( condition2 & COND2 ) 
         DoAnotherThing(a); 
      else 
         DoYetAnotherThing(a); 
    } 
    
  2. 公共子表达式消除

    请注意,在对a 的赋值中,if 语句的两边都包含相同的计算。无论对条件的评估如何,任何相同的东西都可以无条件地吊出来并完成。因此:

    if ( (t1==0) && (t2==0) && (t3==0) ) 
       a = sin(45*b*0.0174444);  
    else  
       a = sin(135*b*0.0174444);  
    

    变成:

    a = b*0.0174444;
    if ( (t1==0) && (t2==0) && (t3==0) ) 
       a *= 45;  
    else  
       a *= 135; 
    a = sin(a); 
    

    这不会直接使代码执行得更快,尽管它可以减少代码的大小(因为同一事物不会在两个不同的地方被计算两次),并且有时减小大小可以提高速度(由于更优化地使用缓存等)。

    事实上,更仔细地观察,我们注意到tempfor 循环的所有迭代中都是不变的,因为b 在循环内部没有被修改。这意味着它可以被吊得更高:

     a = b*0.0174444;
     for(i=0;i<10000;i++) {
        if ( (t1==0) && (t2==0) && (t3==0) ) 
           a *= 45;  
        else  
           a *= 135; 
        a = sin(a); 
    
       // etc.
     } 
    

    导致速度提高,因为现在我们不需要计算temp 10000 次——我们只需计算一次、存储它并在每次循环中重复使用它.

  3. 循环不变代码提升

    我们刚刚体验了这种优化,但还有更多工作要做。查看for 循环,您会看到唯一被修改的变量是i。在循环体中,没有依赖于i 值的表达式,这意味着实际上不需要在循环内部计算这些结果。因此,我们可以将它们提升到循环之外,以便它们只执行一次,而不是重复 10000 次。

    只有一个警告:我们不知道函数调用(DoOneThingDoAnotherThingDoYetAnotherThing)在内部做什么,所以我们不能做出任何假设。 (编译器可以,如果函数的定义对其可见。)我们所知道的是它们只依赖于a 的值,所以我们只需要确保每个函数被调用 10000 次。

      a = b*0.0174444;
      if ( (t1==0) && (t2==0) && (t3==0) ) 
          a *= 45;  
      else  
          a *= 135;
      a = sin(a);  
    
      if ( condition2 & COND1 )
          for(i=0;i<10000;i++)
              DoOneThing(a);
      else if ( condition2 & COND2 ) 
          for(i=0;i<10000;i++)
              DoAnotherThing(a);
      else 
          for(i=0;i<10000;i++)
              DoYetAnotherThing(a);
    

    这将(显着)更快,因为我们不必在每次循环中都测试if 条件,或进行任何其他计算。

当然还有其他可能的优化,但这些是您可能会看到的大优化。正如其他人评论的那样,这是非常糟糕的代码。

【讨论】:

  • 你解释得很好。现在终于,这一切都说得通了。谢谢科迪。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-18
相关资源
最近更新 更多