c ++本地vs成员变量性能

时间:2013-06-17 04:07:34

标签: c++ performance local member

问题的意图是efficeincey使用局部变量的一个很好的理由而不是成员,我不是试图在这里测试编译器优化...请

如果您认为我的比较并不完美,请提供替代代码。

任何人都可以详细解释原因吗? 为什么本地访问速度更快,即使每次调用函数时都必须对堆栈进行crteate并拆除堆栈 成员只需要解除这个指针 我可以看到本地堆栈更快?


RESULT 当地时间:271 成员时间:418

代码:

class local {
public:
 void incr() {
        int i;
        ++i;
}


};


class Member {
int i;

public:
 void incr() {
        ++i;
}

};

#include <ctime>
#include <iostream>
#include <time.h>
int main(int argc, char**argv) {

        time_t star;
        time_t end;
        Member m;
        local l;
        time(&star);
        for(unsigned int j=0;j<200000;++j)
        for(unsigned int i=0;i<400000;++i) {
                l.incr();
        }
        time(&end);
        std::cout << "\nlocal time:" << end-star << "\n";

        time(&star);
        for(unsigned int j=0;j<200000;++j)
        for(unsigned int i=0;i<400000;++i) {
                m.incr();
        }
        time(&end);
        std::cout << "\nmember time:" << end-star<< "\n";
return 0;
}

新代码: g ++ -O1 localmember.cpp

当地时间:128 成员时间:117

代码:

class local {
public:
 int diff(int a, int b) {
        int d=0;
        d=a-b;
        return d;
}
};


class Member {
int d;

public:
 int diff(int a, int b) {
        d=0;
        d=a-b;
        return d;
}

};

static int gr;
#include <ctime>
#include <iostream>
#include <time.h>
void dumpdiff(int r) {
gr=r ;
}
int main(int argc, char**argv) {

        time_t star;
        time_t end;
        Member m;
        local l;
        int r=0;
        int r2=0;
        time(&star);
        int in1=2,in2=0;
        for(unsigned int j=0;j<200000;++j)
        for(unsigned int i=0;i<200000;++i) {
                r = l.diff(in1*i,in2*i);
                in1+=1;
                in2+=1;
                if(r){r2=r;}
                dumpdiff(r);
        }
        time(&end);
        std::cout << "\nlocal time:" << end-star << "\n";

        time(&star);
        for(unsigned int j=0;j<200000;++j)
        for(unsigned int i=0;i<200000;++i) {
                r = m.diff(in1,in2);
                in1+=1;
                in2+=1;
                if(r){r2=r;}
                dumpdiff(r);
        }
        time(&end);
        std::cout << "\nmember time:" << end-star<< "\n";
return 0;

4 个答案:

答案 0 :(得分:3)

这是因为您的编译器可以看到您从未在i中阅读local::incr。如果你不读它,就没有必要增加它,所以编译器可以优化与local有关的任何东西。而 nothing 当然比做任何事都快。

但是,我怀疑你是否使用完全优化编译,否则编译器会看到与Member相关的东西也没有做任何事情,然后你会得到0和0两次,因为好的优化器可以看到足够优化甚至环路,因为它们没有副作用。

答案 1 :(得分:3)

变量是否是本地vs成员对于性能不如缓存位置和寄存器位移那么重要。

鉴于您对“不测试优化”的评论,我怀疑您的“问题”是“如何测试证明一个人是否比另一个更快?”

答案是:你必须查看程序集(例如gcc -o test.S -S test.cpp)。使用-O1或更高版本时,GCC完全取消了对Local.incr()函数的调用,这显然使测试无效。

但是:如果您(大概是使用-O0编译的话)那么您正在加载测试以支持局部变量,因为使用-O0会引起成员操作的成本 - 调用访问成员变量的成员函数会更加昂贵。 / p>

我拿了你的例子并将其更改为:

void incr() {
    int i;
    ++i;
}

class local {
public:
    void incr() {
        int i;
        ++i;
    }
};

class member {
    int m_i;
public:
    void incr() {
        ++m_i;
    }
};

int main(int argc, const char** argv)
{
    local l;
    member m;

    for(unsigned int j = 0; j < 200000; ++j) {
        for(unsigned int i = 0; i < 400000; ++i) {
            incr();
        }
    }

    for(unsigned int j = 0; j < 200000; ++j) {
        for(unsigned int i = 0; i < 400000; ++i) {
            l.incr();
        }
    }

    for(unsigned int j = 0; j < 200000; ++j) {
        for(unsigned int i = 0; i < 400000; ++i) {
            m.incr();
        }
    }

    return 0;
}

使用“g ++ -std = c ++ 11 -Wall -O0 -g -o test.S -S test.cpp”,“incr”的实现是

_Z4incrv:
.LFB0:
    .file 1 "test.cpp"
    .loc 1 1 0
    .cfi_startproc
    pushq   %rbp
.LCFI1:
    .cfi_def_cfa_register 6
.LBB2:
    .loc 1 3 0
    addl    $1, -4(%rbp)
.LBE2:
    .loc 1 4 0
    popq    %rbp
.LCFI2:
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

虽然local :: incr是

_ZN5local4incrEv:
.LFB1:
    .loc 1 8 0
    .cfi_startproc
    pushq   %rbp
.LCFI3:
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
.LCFI4:
    .cfi_def_cfa_register 6
    movq    %rdi, -24(%rbp)
.LBB3:
    .loc 1 10 0
    addl    $1, -4(%rbp)
.LBE3:
    .loc 1 11 0
    popq    %rbp
.LCFI5:
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

因为它必须接收“this”指针。但是它没有访问任何成员变量,因此它实际上不必以任何方式使用this指针。

_ZN6member4incrEv:
.LFB2:
    .loc 1 17 0
    .cfi_startproc
    pushq   %rbp
.LCFI6:
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
.LCFI7:
    .cfi_def_cfa_register 6
    movq    %rdi, -8(%rbp)
    .loc 1 18 0
    movq    -8(%rbp), %rax
    movl    (%rax), %eax
    leal    1(%rax), %edx
    movq    -8(%rbp), %rax
    movl    %edx, (%rax)
    .loc 1 19 0
    popq    %rbp
.LCFI8:
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

在这种使用-O0的调试版本中,成员访问总是会更昂贵。如果我向Member添加“m_j”并在Member :: incr()中增加它,编译器继续生成:

    .loc 1 20 0
    movq    -8(%rbp), %rax
    movl    4(%rax), %eax
    leal    1(%rax), %edx
    movq    -8(%rbp), %rax
    movl    %edx, 4(%rax)

所以是的 - 在一个未经优化的构建中,在大多数情况下,对于琐碎的情况,成员变量比局部变量更昂贵。

“大多数情景”?如果类型不是简单类型,使用昂贵的构造函数等,那么每次进入函数时都必须运行构造函数,而不必运行一次。考虑:

void simulated_work() { std::this_thread::sleep_for(std::chrono::milliseconds<5000>; }

struct DatabaseInteger {
    int m_i;
public:
    DatabaseInteger() {
        simulated_work();
    }
    inline DatabaseInteger& operator++() { ++m_i; }
    operator int() { return m_i; }
};

class local {
public:
    void incr() {
        DatabaseInteger i; // does simulated_work every time.
        ++i;
    }
};

“本地”变量随时都会比成员变量更有效,即:if:

  • 没有施工开销,
  • 你没有在导致寄存器位移的情况下使用它们,
  • 你的筹码不是很蠢,
  • 你不是强迫自己从函数中传递大量额外的参数,
  • 你不是强迫自己使用额外的寄存器来捕获大量的返回值。

答案 2 :(得分:1)

我的水晶球告诉我,编译器正在优化局部变量代码,而它无法证明以后没有访问成员变量,并且实际上已完成增量。

答案 3 :(得分:0)

我喜欢收件箱里的@Tony D答案 “必须在每次调用函数时创建堆栈和拆除堆栈”适用于两者(实际上,任何非内联函数),并且在调用函数时单个堆栈指针调整可能包含局部变量的空间 - 之后访问堆栈-pointer-relative数据不应该比object-this this-pointer相对慢。如果你想获得一种感觉,请查看优化的asm。 - Tony D