2016-06-19 5 views
2

説明が分からないので、これは詳細なしの質問になります。ごめんなさい。私は、メモリ集中型のCプログラム(多くのポインタ)を持っています。私はソースを持っています。それはgcc -O2で私のものです。私はUbuntu Linuxです。プログラムの開始時と終了時にclock()を呼び出して経過時間を計測します。また、時刻を確認するためにtimeコマンドを使用しています。問題は、同じプログラムが何も変更せずに20%以上速くなる(または遅くなる)ことがあることです。なぜ同じCプログラムがより高速になるのですか

$ date; time ./cudd-example-8queens 
pon jun 20 00:49:05 CEST 2016 
CPU TIME = 6.46 
real 0m6.475s 
user 0m6.405s 
sys 0m0.067s 

$ date; time ./cudd-example-8queens 
pon jun 20 00:49:16 CEST 2016 
CPU TIME = 8.03 
real 0m8.051s 
user 0m7.995s 
sys 0m0.048s 

$ date; time ./cudd-example-8queens 
pon jun 20 00:49:33 CEST 2016 
CPU TIME = 6.48 
real 0m6.490s 
user 0m6.445s 
sys 0m0.040s 

$ date; time ./cudd-example-8queens 
pon jun 20 00:49:42 CEST 2016 
CPU TIME = 6.45 
real 0m6.469s 
user 0m6.424s 
sys 0m0.040s 

$ date; time ./cudd-example-8queens 
pon jun 20 00:49:56 CEST 2016 
CPU TIME = 8.04 
real 0m8.058s 
user 0m7.982s 
sys 0m0.068s 

私の質問は次のとおりです。この違いを説明する方法、すなわち、ここで、(時には悪化)1.5秒この追加が費やされていますか?それはメモリアクセスの何かでなければならないが、これをチェックする方法は?

編集:私はperfをインストールしました。ここには2つの結果があります(私はcpupowerから得た情報も表示するように更新しました)。目標については、私は科学的アルゴリズムを比較しています。 1つは他のものより10%高速です。

$ date; cpupower -c all frequency-info -f; perf stat -B ./cudd-example-8queens 
pon jun 20 12:39:21 CEST 2016 
analyzing CPU 0: 
1300000 
analyzing CPU 1: 
1300000 
analyzing CPU 2: 
1300000 
analyzing CPU 3: 
1300000 
clock() TIME = 6.70 
clock_gettime() TIME = 6.70 

Performance counter stats for './cudd-example-8queens': 

     6705,796274 task-clock (msec)   # 0,999 CPUs utilized   
       104 context-switches   # 0,016 K/sec     
       3 cpu-migrations   # 0,000 K/sec     
      30861 page-faults    # 0,005 M/sec     
     17295862806 cycles     # 2,579 GHz      
    <not supported> stalled-cycles-frontend 
    <not supported> stalled-cycles-backend 
     7361712951 instructions    # 0,43 insns per cycle   
     1228059232 branches     # 183,134 M/sec     
      64491733 branch-misses    # 5,25% of all branches   

     6,709414218 seconds time elapsed 

$ date; cpupower -c all frequency-info -f; perf stat -B ./cudd-example-8queens 
pon jun 20 12:39:30 CEST 2016 
analyzing CPU 0: 
1300000 
analyzing CPU 1: 
1300000 
analyzing CPU 2: 
1300000 
analyzing CPU 3: 
1300000 
clock() TIME = 8.43 
clock_gettime() TIME = 8.43 

Performance counter stats for './cudd-example-8queens': 

     8441,824238 task-clock (msec)   # 0,999 CPUs utilized   
       145 context-switches   # 0,017 K/sec     
       3 cpu-migrations   # 0,000 K/sec     
      30863 page-faults    # 0,004 M/sec     
     13958245339 cycles     # 1,653 GHz      
    <not supported> stalled-cycles-frontend 
    <not supported> stalled-cycles-backend 
     7360082448 instructions    # 0,53 insns per cycle   
     1227803521 branches     # 145,443 M/sec     
      64517871 branch-misses    # 5,25% of all branches   

     8,446645648 seconds time elapsed 

EDIT2:My Intel NUCにIntel Core i5-4250U CPUが搭載されています。したがって、 "cpupower frequency-set"を使用するアドバイスは有望でしたが、残念ながらそれは何の助けにもなりません。さらに、 "clock()"と "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)"を使って正確に同じ結果が得られ、それらの結果はperfの "task-clock(msec)"でも確認されます。

+3

'perf 'のようなまともなプロファイリングツールを使用しないと、全体的な話が得られません。 –

+1

あなたは何を言っているのですか?あなたはマルチユーザ、マルチタスク環境にいます。個々のタスクのタイミングは無意味なものの隣にある可能性があります。 ..そして、それがあります。物事の状態/ dev/urandomを使用するのであれば... – tink

+2

プログラムの速度を測定するとき、 '経過時間'は他のプロセスが実行されている時間を含んでいるのでほとんど役に立たない。より良い方法は、現在のプロセスの処理時間を取得する 'CLOCK_PROCESS_CPUTIME_ID'パラメータでclock_gettime()を呼び出すことです。注:呼び出しが失敗したことを示すので、常に戻り値の '-1'を確認してください。 '#define _POSIX_C_SOURCE(199309L)' – user3629249

答えて

1

現代のCPUの周波数は動的に変化しますので、壁の時間(天文学的時間)だけでなく、CPUのサイクル数も常に測定する必要があります。 perf stat(実際にはperf stat -e task-clock,cycles,instructionsで十分です)は、プログラムがcyclesの行で実行されている間に、CPU時間を測定するCPUクロック/タスククロックイベント(GHzを得るために時間を分けたサイクル)があった場合、CPUコア周波数を意味します:

#### cycles     # 1,653 GHz  

#### cycles     # 2,579 GHz 

これは、インテル®ターボ・ブースト(2)、https://en.wikipedia.org/wiki/Intel_Turbo_Boost(AMDはhttps://en.wikipedia.org/wiki/AMD_Turbo_Coreを持っている)です。どちらも非常に高速ですので、cpupower -c all frequency-infoが実行されている場合、実際の周波数は低くなります(1.3)。あなたのプログラムからの負荷が高い場合、CPUは数マイクロ秒の間にその周波数をより高いレベルに調整します

時にはより均一な測定結果を得るために、BIOSでそれをオフにすることが可能である:http://www.intel.com/content/www/us/en/support/processors/000005641.html

インテル®ターボ・ブースト・テクノロジーを有効にするか無効にする方法は? - インテル®ターボ・ブースト・テクノロジーは、通常、デフォルトで有効になっています。この技術を無効にするには、BIOSのスイッチを使用する必要があります。他にユーザーが制御できる設定はありません。

それとも、いくつかの魔法のMSRの書き込み(ランダムMSR REGSにランダムな値を書き込まないでください、それが何かを壊し、またはPCをハングアップすることがあります)してみてください可能性がありますMaythuxによってhttps://askubuntu.com/questions/619875/disabling-intel-turbo-boost-in-ubuntu答え:「wrmsr -pC 0x1a0 0x4000850089

他の行をperf statから:7361-7360 mln命令、1228-1227 mlブランチ64 mlnブランチ誤予測は、プログラムが同じであり、同じコードが実行された(外部ランダムではない)ことを示します。perf stat -dを試すこともできます(実行中のハードウェアイベントをstat -dから選択し、perf stat -e cpu-clock,....に手動でリストすることをお勧めします)。

+0

BIOSでターボが有効になっていると、MSRライティングマジックでLinuxから電源をオフにすることができます - http://askubuntu.com/questions/619875/disabling-intel-turbo-boost-in-ubuntu – osgx

+1

これはおそらく私の答えです探していた! ターボブースト( 'wrmsr'を使用)と周波数スケーリング ( 'cpupower'を使用)の両方を無効にすることで、今より信頼性の高い結果が得られます。 多くのテストプログラムの中で最も優れたテストプログラムは9.81s で、最悪のテストプログラムは10.74sでした。両方のケースで、 私はサイクル= 1,293ギガヘルツを持っています。最も速い実行のために私は ブランチ= 124,906 M /秒とL1-dcache-負荷= 214,174 M /秒 を持っていますが、最も遅い実行のために私はブランチ= 114,328 M /秒と L1-dcache-loads = 194,013 M /秒。私はこの違いをプログラム自体(例えばハッシュテーブル)に帰属させており、システムには帰属させていません。 – meolic

+0

私のシステムの周波数スケーリングドライバがacpi-cpufreqなので、コマンド 'echo "0">/sys/devices/system/cpu/cpufreq/boost'を使ってTurbo Boostを無効にしようとしました。失敗しました。 – meolic

0

オペレーティングシステムは、複数のタスクを同時に実行し、それを管理するために、あるタスクから別のタスクへのコンテキスト切り替えを行います。したがって、毎回変更されるのはあなたのコードの時間ではなく、プログラムの実行の間にオペレーティングシステムによって呼び出されている他のプログラムです。

+1

私はそのような主張の証拠が必要です。そして、私はperfから得られた結果がこれをサポートしていないと思います。私が間違っている? – meolic

関連する問題