1

プロセスごとの計算時間を測定するための次の簡単な関数があります。

double get_cpu_time()
{
  //LINUX      
  const static int64_t NANOS_PER_SEC = 1000000000L;
  struct timespec time;
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time);
  return (((int64_t) time.tv_sec) * NANOS_PER_SEC) + ((int64_t) time.tv_nsec);

}


ini_time = get_cepu_time();

//intesive computation code

end_time = get_cepu_time();


end_time = end_time - ini_time

;

この関数は、各プロセスの計算時間を返します。簡単な方程式では、次のようになります。

Tcomp = Tcpu + Taccmen => inst * ILP + #misscache*レイテンシー時間

Tcpu時間(データを探す時間を考慮せずに命令を実行する時間)だけを取得することに興味がありますが、この時間を取得するための関数、またはメモリアクセス時間を返す関数を知っていますか? --Taccmem)

よろしくお願いします、

ジェン

4

2 に答える 2

3

perfLinuxでコマンドを使用して、この種のパフォーマンスデータを取得します。

たとえば、x86プラットフォームの場合

perf stat -B sleep 5

Performance counter stats for 'sleep 5':

      0.344308 task-clock                #    0.000 CPUs utilized          
             1 context-switches          #    0.003 M/sec                  
             0 CPU-migrations            #    0.000 M/sec                  
           154 page-faults               #    0.447 M/sec                  
        977183 cycles                    #    2.838 GHz                    
        586878 stalled-cycles-frontend   #   60.06% frontend cycles idle   
        430497 stalled-cycles-backend    #   44.05% backend  cycles idle   
        720815 instructions              #    0.74  insns per cycle        
                                         #    0.81  stalled cycles per insn
        152217 branches                  #  442.095 M/sec                  
          7646 branch-misses             #    5.02% of all branches        

   5.002763199 seconds time elapsed

これにより、sleep 5コマンドが実行され、x86プロセッサのパフォーマンスカウンタから収集された詳細が表示されます。実行された命令の数とサイクル数を確認することは興味深いことです。比率は、計算される1サイクルあたりの命令数であり、プロセッサが1命令あたり平均で何サイクル停止したかも示します。キャッシュ参照の数とミスの数を取得するには、それを明示的に要求する必要があります

perf stat -B -e cache-references,cache-misses,cycles,instructions

perfがキャッシュミスを報告しないのはなぜですか?を参照してください。

于 2013-02-06T22:35:38.153 に答える
0

...コメントスペースが不足しました...

アルゴリズムのプロファイリングに興味があり、メモリアクセス時間も抽象化したい場合は、テストデータを汎用レジスタに直接配置する必要があります...そのため、アセンブリになります。しかし、スタックメモリアクセス時間に問題がなければ、いくつかのスタック変数をスタブしてそれらを使用できます...おそらく実際にはそれを行う必要はありません。

struct timespec time;
struct timespec time2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time); 
something();
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);

次に、終了後に時間をデコードすることを心配します... get time 関数で大量の計算を行いたくありません...実際に意味のあるデータを取得しようとすると問題が発生します..

時間については心配していないが、計算の複雑さと命令の数について心配している場合は、アセンブリにコンパイルして、それを最後まで実行する必要があります... (言うは易く行うは難しです...)

    void simple()
{
    int i = 0;
    for (int j=0;j<25;j++)
        i+=j;
}

//-> gcc -S -std=c99 simple.c

_simple:

Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $0, -4(%rbp)
    movl    $0, -8(%rbp)
    jmp LBB1_2
LBB1_1:
    movl    -4(%rbp), %eax
    movl    -8(%rbp), %ecx
    addl    %ecx, %eax
    movl    %eax, -4(%rbp)
    movl    -8(%rbp), %eax
    addl    $1, %eax
    movl    %eax, -8(%rbp)
LBB1_2:
    movl    -8(%rbp), %eax
    cmpl    $24, %eax
    jle LBB1_1
    popq    %rbp
    ret
Leh_func_end1:

LBB1_2:for ループの条件部分に対応し、for ループの内部を実行するためにジャンプしてLBB1_1:、for ループのインクリメント部分に戻り、再びフォールスルーすることをある程度理解できますLBB1_2:...一種のいいね。

于 2013-02-06T22:54:43.447 に答える