做atoi()和atof()缓存?它们似乎在更多次调用时执行得更快

use*_*112 13 c c++ optimization performance caching

我曾经_rdtsc()时间atoi()atof()我注意到他们花了很长时间.因此,我编写了自己的这些函数版本,这些函数从第一次调用开始就快得多.

我使用的是Windows 7,VS2012 IDE,但使用的是英特尔C/C++编译器v13.我有 - /O3启用,还有 - /Ot("赞成快速代码").我的CPU是常春藤桥(移动).

经进一步调查,似乎更多的时间atoi()atof()被称为越快他们执行?我说话的速度更快:

当我atoi()从我的循环外部调用时,只需要一次,它需要5,892个CPU周期,但经过数千次迭代后,这减少到300 - 600个CPU周期(相当大的执行时间范围).

atof() 最初需要20,000到30,000个CPU周期,然后在几千次迭代之后需要18到28个CPU周期(这是我的自定义函数第一次调用时的速度).

有人可以解释这个效果吗?

编辑:忘了说 - 我的程序的基本设置是从文件解析字节的循环.在循环中我明显使用我的atof和atoi来注意上面的内容.然而,我还注意到,当我在循环之前进行调查时,只需调用atoi和atof两次,以及两次用户编写的等效函数,它似乎使循环执行得更快.循环处理了150,000行数据,每行需要3x atof()atoi()s.再一次,我无法理解为什么在我的主循环之前调用这些函数会影响调用这些函数500,000次的程序的速度?!

#include <ia32intrin.h>

int main(){

    //call myatoi() and time it
    //call atoi() and time it
    //call myatoi() and time it
    //call atoi() and time it

    char* bytes2 = "45632";
    _int64 start2 = _rdtsc();
    unsigned int a2 = atoi(bytes2);
    _int64 finish2 = _rdtsc();
    cout << (finish2 - start2) << " CPU cycles for atoi()" << endl;

    //call myatof() and time it
    //call atof() and time it
    //call myatof() and time it
    //call atof() and time it


    //Iterate through 150,000 lines, each line about 25 characters.
    //The below executes slower if the above debugging is NOT done.
    while(i < file_size){
        //Loop through my data, call atoi() or atof() 1 or 2 times per line
        switch(bytes[i]){
            case ' ':
                //I have an array of shorts which records the distance from the beginning
                //of the line to each of the tokens in the line. In the below switch
                //statement offset_to_price and offset_to_qty refer to this array.

            case '\n':

                switch(message_type){  
                    case 'A':
                        char* temp = bytes + offset_to_price;
                        _int64 start = _rdtsc();
                        price = atof(temp);
                        _int64 finish = _rdtsc();
                        cout << (finish - start) << " CPU cycles" << endl;
                        //Other processing with the tokens
                        break;

                    case 'R':
                        //Get the 4th line token using atoi() as above
                        char* temp = bytes + offset_to_qty;
                        _int64 start = _rdtsc();
                        price = atoi(temp);
                        _int64 finish = _rdtsc();
                        cout << (finish - start) << " CPU cycles" << endl;
                        //Other processing with the tokens
                        break;
                }
            break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

文件中的行是这样的(中间没有空行):

34605792 R dacb 100

34605794 A racb S 44.17 100

34605797 R kacb 100

34605799 A sacb S 44.18 100

34605800 R nacb 100

34605800 A tacb B 44.16 100

34605801 R gacb 100

我正在使用atoi()'R'消息中的第4个元素和'A'消息中的第5个元素,并使用'A'消息中atof()的第4个元素.

ama*_*rea 7

我猜你为什么看到这样的大幅改善的原因atoiatof,但不适合你自己的,更简单的功能,在于前者有以处理所有的边缘情况下,大量分支机构.前几次,这导致大量不正确的分支预测,这是昂贵的.但经过几次,预测变得更加准确.一个正确预测的分支几乎是免费的,这将使它们与你的简单版本竞争,后者不包括分支开头.

缓存肯定也很重要,但我不认为这可以解释为什么你自己的功能从一开始就很快,并且在重复执行后没有看到任何相关的改进(如果我理解正确的话).


Jef*_*tte 2

最可能的解释是,由于您如此频繁地调用 atoi/atof,它被识别为热点,因此被保存在 1 级或 2 级处理器代码缓存中。CPU 的替换策略(即确定发生高速缓存未命中时可以清除哪些高速缓存行的微代码)将标记此类热点以将其保留在高速缓存中。如果您有兴趣,维基百科上有一篇关于 cpu 缓存技术的不错的文章。

您的初始计时较低,因为您的代码尚未位于 CPU 性能最佳的缓存中,但一旦调用了一定次数,就会出现。

  • 缓存替换不是由微代码完成的,它是纯粹的硬件机制。它也不必被明确识别,它只是在每次使用时都会被提升,所以它永远不会被驱逐。 (5认同)