c++ - 为什么通过引用传递变量比全局定义变量慢?

标签 c++ performance

鉴于此代码:

#include <iostream>
#include <chrono>

typedef unsigned long long T;

namespace Benchmark
{
    T a, b;
    inline void L_Add() { a += b; b += a; }
    inline void Unroll_10() { L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); L_Add(); }
    inline void Unroll_100() { Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); Unroll_10(); }
    inline void Unroll_1000(T& a_, T& b_)
    {
        a = a_; b = b_;
        Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100(); Unroll_100();
        a_ = a; b_ = b;
    }
};

inline void L_Add(T& a, T& b) { a += b; b += a; }
inline void Unroll_10(T& a, T& b) { L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); L_Add(a, b); }
inline void Unroll_100(T& a, T& b) { Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); Unroll_10(a, b); }
inline void Unroll_1000(T& a, T& b) { Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); Unroll_100(a, b); }

int main()
{
    std::chrono::high_resolution_clock::time_point StartTime, EndTime;
    T a = 3;
    T b = 5;
    StartTime = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; ++i)
        Benchmark::Unroll_1000(a, b);
    EndTime = std::chrono::high_resolution_clock::now();
    std::cout << a << " : " << std::chrono::duration_cast<std::chrono::milliseconds>(EndTime - StartTime).count() / 2000.0 << "ns" << std::endl;

    a = 3;
    b = 5;
    StartTime = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; ++i)
        Unroll_1000(a, b);
    EndTime = std::chrono::high_resolution_clock::now();
    std::cout << a << " : " << std::chrono::duration_cast<std::chrono::milliseconds>(EndTime - StartTime).count() / 2000.0 << "ns" << std::endl;

    return 0;
}

这个输出:

12646046898197897264 : 0.3875ns
12646046898197897264 : 2.253ns

我想知道为什么“Benchmark::Unroll_1000(a, b)”的反汇编是:

add rax,rcx  
add rcx,rax 

而“Unroll_1000(a, b)”的反汇编为:

mov rax,qword ptr [rdx]  
add qword ptr [rcx],rax  
mov rax,qword ptr [rcx]  
add qword ptr [rdx],rax 

据我了解,他们应该生成相同的代码。有人可以启发我吗?在没有全局变量的情况下如何实现与“Benchmark::Unroll_1000(a, b)”相同的性能?

最佳答案

使用全局变量:编译器在编译时就知道变量所在的位置,并且可以直接使用该值。此外,您的编译器发现您使用了很多该变量并将其分配给寄存器,因此没有对 RAM 的加载/写入操作(这是真正的时间节省器)。

通过引用传递值:该方法传递一个指向变量实际位置的指针。它必须取消引用它并执行操作。此外,额外的操作可能意味着变量在内存中获取一个位置,因此必须加载/下载它。

在您的示例中,编译器可能足够聪明,可以生成相同的代码,因为它始终使用相同的实际值,但通常它不能假设编译后的代码将始终被调用(链接)来自相同的方法,因此生成的代码以“缓慢的方式”执行操作。

关于c++ - 为什么通过引用传递变量比全局定义变量慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19896757/

相关文章:

c++ - 如何通过 QFileSystemModel 获取选定文件的*完整*文件路径?

c++ - 删除 vector 行时如何更快?

performance - 使用 match_all VS 查询进行过滤

android - 在 AsyncTask onPostExecute 中使用 canvas.drawBitmap

android - FragmentStatePagerAdapter 性能问题

具有可移动节点、可访问属性和可靠 ID 的 C++ 图形

c++ - 为什么我不能将 std::begin/std::end 与 int(*p)[3] 一起使用,而我可以与 int(&p)[3] 一起使用?

c++ - 使用 Crypto++ 生成 ONVIF 身份验证摘要?

algorithm - 计算阶乘的快速算法

performance - 多态变体中的内联记录?