c – 装配性能调整

前端之家收集整理的这篇文章主要介绍了c – 装配性能调整前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_404_1@我正在编写一个编译器(比别的更有趣),但是我想尝试尽可能的高效.例如,我被告知,在英特尔架构上,使用除EAX之外的任何注册表进行数学计算会产生一个代价(大概是因为它交换到EAX来做实际的数学计算).这里至少有一个来源说明了可能性(http://www.swansontec.com/sregisters.html).

我想验证和测量这些性能特征的差异.所以我写了这个程序在C:

#include "stdafx.h"
#include <intrin.h>
#include <iostream>

using namespace std;

int _tmain(int argc,_TCHAR* argv[])
{
    __int64 startval;
    __int64 stopval;
    unsigned int value; // Keep the value to keep from it being optomized out

    startval = __rdtsc(); // Get the cpu Tick Counter using assembly RDTSC opcode

    // Simple Math: a = (a << 3) + 0x0054E9
    _asm {
        mov ebx,0x1E532 // Seed
        shl ebx,3
        add ebx,0x0054E9
        mov value,ebx
    }

    stopval = __rdtsc();
    __int64 val = (stopval - startval);
    cout << "Result: " << value << " -> " << val << endl;

    int i;
    cin >> i;

    return 0;
}

我尝试这个代码交换eax和ebx,但我没有得到一个“稳定”的数字.我希望测试是确定性的(每次都是同一个数字),因为它的测试很短,因此在测试过程中不太可能发生上下文切换.因为它没有统计学差异,但数字如此波动,所以不可能做出这个决定.即使我拿了大量样本,这个数字仍然是不可能变化的.

我也想测试xor eax,eax vs mov eax,但有同样的问题.

有没有办法在Windows(或其他任何地方)进行这些类型的性能测试?当我习惯为我的TI-Calc编程Z80时,我有一个工具,我可以选择一些程序集,它会告诉我执行代码有多少个时钟周期 – 这可以不用我们的新风格的现代处理器吗?

编辑:有很多答案表明运行循环百万次.要澄清,这实际上使事情变得更糟. cpu更可能进行上下文切换,测试成为关于所有内容的一切,但我正在测试.

解决方法

为了甚至希望在RDTSC给出的水平上具有可重复性,确定性的时序,您需要采取一些额外的步骤.首先,RDTSC不是一个串行化指令,所以它可以按顺序执行,通常会在上面的代码段中使其无意义.

你通常想使用串行化指令,然后使用RDTSC,然后是有问题的代码,另一个串行化指令和第二个RDTSC.

用户模式下几乎只有可用的序列化指令是cpuID.然而,这又增加了一个小小的皱纹:IntelID记录了cpuID需要不同的执行时间 – 前两个执行速度可能比其他更慢.

因此,您的代码的正常计时顺序将是这样的:

XOR EAX,EAX
cpuID
XOR EAX,EAX
cpuID            ; Intel says by the third execution,the timing will be stable.
RDTSC            ; read the clock
push eax         ; save the start time
push edx

    mov ebx,0x1E532 // Seed // execute test sequence
    shl ebx,3
    add ebx,0x0054E9
    mov value,ebx

XOR EAX,EAX      ; serialize
cpuID   
rdtsc             ; get end time
pop ecx           ; get start time back
pop ebp
sub eax,ebp      ; find end-start
sbb edx,ecx

我们开始接近,但最后一点很难处理在大多数编译器上使用内联代码:还可能会从跨越缓存行中产生一些影响,因此您通常希望强制将代码与16对齐字节(段)边界.任何体面的汇编程序都会支持,但编译器中的内联汇编通常不会.

说完这一切,我想你在浪费你的时间.你可以猜到,我在这个级别做了相当数量的时间安排,我相当肯定你听说过的是一个完全的神话.实际上,所有最近的x86 cpu都使用一套所谓的“重命名寄存器”.为了缩短故事时间,这意味着您用于注册表的名称并不重要 – cpu对于实际操作使用了更大的一组寄存器(例如,英特尔约为40个),因此在EBX与EAX中放置一个值对于cpu在内部真正使用的寄存器几乎没有影响.可以映射到任何重命名寄存器,主要取决于哪个重命名寄存器在指令序列启动时恰好是空闲的.

猜你在找的C&C++相关文章