g++ -O optimizations

g++ -O optimizations

本文关键字:optimizations g++      更新时间:2023-10-16

我有以下代码:

#include <iostream>
int main()
{
        int n = 100;
        long a = 0;
        int *x = new int[n];
        for(int i = 0; i < n; ++i)
                for(int j = 0; j < n; ++j)
                        for(int k = 0; k < n; ++k)
                                for(int l = 0; l < n; ++l)
                                {   
                                        a += x[(j + k + l) % 100];
                                }   
        std::cout << a << std::endl;
        delete[] x;
        return 0;
}

如果我编译没有优化g++测试。Cc,然后运行时间。输出将显示0.7秒。然而,当我用- 0编译它时,时间减少了2倍。

编译器使用

g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2

我的问题

我如何重写代码,以便在编译时没有-O我可以获得相同的时间(或接近它)?换句话说,如何手动优化嵌套循环 ?

为什么我问

我有一个类似的代码,如果我使用-O优化,运行速度大约快4倍。

PS:我已经看了编译器的手册,但是那里有太多的标志来测试哪一个真正起作用

编译器使用-O优化的大多数事情都是在c++以下级别的事情。例如,所有变量都存在于内存中,包括循环变量。因此,如果没有优化,编译器很可能在每次内部循环迭代时首先读取循环变量以将其与0进行比较,在循环内部再次加载它以将其用作索引,然后在循环结束时再次读取该值,将其自增,并将其写回。通过优化,它会注意到循环变量在循环体中没有改变,因此不需要每次都从内存中重新读取。此外,它还会注意到变量的地址永远不会被占用,因此没有其他代码将访问它,因此将它写入内存也可以省略。也就是说,循环变量将只存在于内存中。在函数执行期间,仅这种优化就可以节省3亿次内存读取和1亿次内存写入。但是,由于像处理器寄存器和内存读/写这样的事情没有在语言级别上公开,因此无法在语言级别上对其进行优化。

此外,手工优化编译器优化的东西是没有意义的。你最好把时间花在编译器无法优化的事情上。

这段代码有未定义的行为,所以实际上优化器可以做任何它想做的…

a += x[j + k + l % 100];
应:

a += x[(j + k + l) % 100];

如果你解决了这个问题,我仍然不明白为什么你要优化一些实际上什么都不做的东西…

我个人会将其优化为::)

std::cout << 0 << std::endl;

注意:去掉i的循环,再做std::cout << a * n << std::endl;

您可以观察到您的循环形成一组系数coeff[i],使得单个循环对a[i] * coeff[i]求和产生与嵌套循环相同的总数。如果我们假设你的索引是(i + j + k) % 100,那么所有i的索引都是coeff[i] = n * n * n,所以你的整个程序简化为

long coeff = n * n * n;
for (int i = 0; i < n; ++n)
    a += x[i] * coeff;

我敢肯定它的运行时间远少于0.7秒。

您正在使用多项式时间算法(n ** 4),因此它会很慢,特别是对于较大的n。也许一个复杂度较低的算法会对你有所帮助?

如果你想优化你的代码,你可以让编译器为你优化,或者直接用汇编语言写,然后完成它。不要试图猜测c++编译器

我如何重写代码,以便在编译时没有-O我可以获得相同的时间(或接近它)?换句话说,如何手动优化嵌套循环?

用汇编语言编写。祝你在上好运,顺便说一句。

编译器中优化开关的目的是让你说,"编译器,我想让你试着生成快速的汇编。"默认情况下,编译器不进行优化,因为这些优化可能会抑制结果代码的可调试性。所以你必须明确地要求他们。

编译器为优化代码所做的事情,一般来说,不是你可以手动完成的。有些可以(如循环展开),但有些则不能。