考虑以下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
。但我想不出任何其他方法来优化它。
答案 0 :(得分:0)
虽然大多数这些优化都是由自动优化编译器执行的,但仍然很好理解编译器背后的操作。
以下是一些可能性:
常量折叠
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);
}
常见的子表达式消除
请注意,在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);
这并不能直接使代码执行得更快,尽管可以想象地减少代码的 size (因为同样的事情不会在两个不同的地方被评估两次地方),有时缩小尺寸可以提高速度(由于更好地利用缓存等)。
事实上,仔细观察,我们注意到temp
在for
循环的所有迭代中都是不变的,因为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次 - 我们只计算一次,存储它,并且每次重复使用它通过循环的时间。
循环不变代码促销
我们只是尝试了这种优化,但还有更多可以做的事情。查看for
循环,您会看到唯一被修改的变量是i
。在循环体中,没有表达式依赖于i
的值,这意味着这些结果实际上都不需要在循环内部计算。因此,我们可以将它们提升到循环之外,这样它们只能完成一次,而不是重复10000次。
只有一点需要注意:我们不知道函数调用的内容(DoOneThing
,DoAnotherThing
和DoYetAnotherThing
)是否在内部执行,因此我们无法做到做出任何假设。 (编译器可以,如果函数的定义是可见的。)我们所知道的只是它们只依赖于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
条件,或进行任何其他计算。
当然可以进行其他优化,但这些是您可能希望看到的重要优化。正如其他人所评论的那样,这是非常可怕的代码。