0

私はそれをループに入れて、CPUがそれぞれの異なる操作を実行するのにかかるリアルタイムを取得する方法に興味があります

#include<iostream>
#include<cstdlib>
#include<time.h>

using namespace std;
typedef unsigned __int64 uint64;
const uint64 m1=0x5555555555555555;
const uint64 m2=0x3333333333333333;
const uint64 m4=0x0f0f0f0f0f0f0f0f;
const uint64 m8=0x00ff00ff00ff00ff;
const uint64 m16=0x0000ffff0000ffff;
const uint64 m32=0x00000000ffffffff;
const uint64 hff=0xffffffffffffffff;
const uint64 h01=0x0101010101010101;

uint64 popcount_1(uint64 x)
{
    x=(x&m1)+((x>>1)&m1);
    x=(x&m2)+((x>>2)&m2);
    x=(x&m4)+((x>>4)&m4);
    x=(x&m8)+((x>>8)&m8);
    x=(x&m16)+((x>>16)&m16);
    x=(x&m32)+((x>>32)&m32);
    return (uint64)x;
}

//This uses fewer arithmetic operations than any other known
//implementation on machines with slow multiplication.
//It uses 17 arithmetic operations.
int popcount_2(uint64 x)
{
    x-=(x>>1)&m1;//put count of each 2 bits into those 2 bits
    x=(x&m2)+((x>>2)&m2);//put count of each 4 bits into those 4 bits
    x=(x+(x>>4))&m4; //put count of each 8 bits into those 8 bits
    x+=x>>8;//put count of each 16 bits into their lowest 8 bits
    x+=x>>16;
    x+=x>>32;
    return x&0x7f;
}
////This uses fewer arithmetic operations than any other known
//implementation on machines with fast multiplication.
//It uses 12 arithmetic operations, one of which is a multiply.
int popcount_3(uint64 x)
{
    x-=(x>>1)&m1;
    x=(x&m2)+((x>>2)&m2);
    x=(x+(x>>4))&m4;
    return (x*h01)>>56;
}
uint64 popcount_4(uint64 x)
{
    uint64  count;
    for(count=0; x; count++)
    {
        x&=x-1;
    }
    return count;
}
uint64 random()
{
    uint64 r30=RAND_MAX*rand()+rand();
    uint64 s30=RAND_MAX*rand()+rand();
    uint64  t4=rand()&0xf;
    uint64 res=(r30<<34 )+(s30<<4)+t4;
    return res;
}
int main()
{
    int testnum;
    while (true)
    {
        cout<<"enter number of test "<<endl;
        cin>>testnum;
        uint64 x= random();
        switch(testnum)
        {
            case 1: {
                    clock_t start=clock();
                    popcount_1(x);
                    clock_t end=clock();
                    cout<<"execution time of first method"<<start-end<<" "<<endl;
                }
                break;
            case 2: {
                    clock_t start=clock();
                    popcount_2(x);
                    clock_t end=clock();
                    cout<<"execution time of first method"<<start-end<<" "<<endl;
                }
                break;
            case 3: {
                    clock_t start=clock();
                    popcount_3(x);
                    clock_t end=clock();
                    cout<<"execution time of first method"<<start-end<<" "<<endl;
                }
                break;
            case 4: {
                    clock_t start=clock();
                    popcount_4(x);
                    clock_t end=clock();
                    cout<<"execution time of first method"<<start-end<<" "<<endl;
                }
                break;
            default:
                cout<<"it is not correct number "<<endl;
                break;
        }
    }
    return 0;
}

どの番号のテストを入力しても、端末には常にゼロが書き込まれます。10または20と100の操作は現代のコンピューターでは何もないため、その理由は明らかですが、正確な答えではないにしても、近似値少なくとも?どうもありがとう

4

2 に答える 2

5

すべてのテストを何度も繰り返すだけです。

以下は、テストごとに1 Mio (1024*1024)を 2^25 回繰り返します。時間をナノ秒単位で取得するために時間を分割したい場合がありますが、比較のために合計数は問題ありません (そして読みやすくなります)。

int main()
{
    int testnum;
    while (true)
    {
        cout<<"enter number of test "<<endl;
        cin>>testnum;
        uint64 x= random();

        clock_t start=clock();
        switch(testnum)
        {
            case 1: for(unsigned long it=0; it<=(1ul<<26); ++it) popcount_1(x); break;
            case 2: for(unsigned long it=0; it<=(1ul<<26); ++it) popcount_2(x); break;
            case 3: for(unsigned long it=0; it<=(1ul<<26); ++it) popcount_3(x); break;
            case 4: for(unsigned long it=0; it<=(1ul<<26); ++it) popcount_4(x); break;
            default:
                cout<<"it is not correct number "<<endl;
                break;
        }
        clock_t end=clock();
        cout<<"execution time of method " << testnum << ": " << (end-start) <<" "<<endl;
    }
    return 0;
}

:)にも固定されていることに注意start-endしてください(end-start)

于 2011-11-14T11:33:18.630 に答える
3

非常に安価な操作のマイクロベンチマークを実行したいと考えています。必要がある:

  • 安価な操作をループします。合理的に時間を計るのに十分な時間がかかるもの。たとえば、約 1 秒。
  • コンパイラが本体を完全に省略しないように、1 つのループ反復の結果を次の反復で使用するようにしてください。
  • ループ全体を関数でラップし、関数をコンパイラ固有の属性でインライン化不可としてマークし(コンパイラが呼び出しを省略しないようにするため)、タイミング関数から この関数を呼び出します。または、すべてのループ反復に応じて値を返し、実際にその戻り値をメイン プログラムで使用(出力するか、変数に格納するなどvolatile) して、コンパイラがプログラムを最適化して削除できないようにします。
  • さらに、高解像度タイマーを使用する必要がありますclock()。WindowsQueryPerformanceCounter(&tick_count)では 、UNIXclock_gettime(CLOCK_PROCESS_CPUTIME_ID, &timespec_var)では 、MacOS では を参照してくださいmach_absolute_time()。これらのメソッド (の一部) のもう 1 つの利点は、ウォールクロック時間ではなく CPU 時間を測定するため、システム上の他のアクティビティに直面しても変動がわずかに少ないことです。

繰り返しますが、変数に格納するか、出力するか、インライン化されていない関数から返すことによって計算された値を実際に使用して、コンパイラがそれらを最適化して削除できないようにすることが絶対に重要です。また、関数呼び出しのオーバーヘッドがそのようなマイクロベンチマークを圧倒する可能性があるため、コアメソッドをインライン化できないとマークしたくありません。同様の理由で、おそらく避けるべきです。これが、実際に関心のある (インライン化可能な) 関数を呼び出すループを含む関数をベンチマークする必要がある理由です。volatilerandom

例えば:

#include <iostream>
#include <time.h>
typedef unsigned __int64 uint64;

inline uint64 popcount_1(uint64 x)// etc...

template<typename TF>
uint64 bench_intfunc_helper(TF functor, size_t runs){//benchmark this
    uint64 retval = 0;
    for(size_t i=0; i<runs; ++i) retval += functor(i); 
    // note that i may not have a representative distribution like this
    return retval;//depends on all loop iterations!
}
template<typename TF>
double bench_intfunc(TF functor, size_t runs){
    clock_t start=clock();//hi-res timers would be better
    volatile auto force_evalution = bench_intfunc_helper(functor,runs);
    clock_t end=clock();
    return (end-start)/1000.0;
}
#define BENCH(f) do {std::cout<<"Elapsed time for "<< RUNS <<" runs of " #f \
    ": " << bench_intfunc([](uint64 x) {return f(x);},RUNS) <<"s\n"; } while(0)

int main() {
    BENCH(popcount_1);
    BENCH(popcount_2);
    BENCH(popcount_3);
    BENCH(popcount_4);
    return 0;
}

たとえば、単純に を省略volatileすると、私のマシンの GCC 4.6.3 と MSC 10.0 が 0 を使用したと報告します。関数ポインタはこれらのコンパイラによってインライン化されていませんが、ラムダはインライン化されているため、ラムダを使用しています。

私のマシンでは、GCC でのこのベンチマークの出力は次のとおりです。

Elapsed time for 1073741824 runs of popcount_1: 3.7s
Elapsed time for 1073741824 runs of popcount_2: 3.822s
Elapsed time for 1073741824 runs of popcount_3: 4.091s
Elapsed time for 1073741824 runs of popcount_4: 23.821s

そしてMSCで:

Elapsed time for 1073741824 runs of popcount_1: 7.508s
Elapsed time for 1073741824 runs of popcount_2: 5.864s
Elapsed time for 1073741824 runs of popcount_3: 3.705s
Elapsed time for 1073741824 runs of popcount_4: 19.353s
于 2011-11-14T11:42:52.050 に答える