2

ECLiPSe CLP でメソッドの実行時間を測定するにはどうすればよいですか? 現在、私はこれを持っています:

measure_traditional(Difficulty,Selection,Choice):-
  statistics(runtime, _),
  time(solve_traditional(Difficulty,Selection,Choice,_)),
  time(solve_traditional(Difficulty,Selection,Choice,_)),
  time(solve_traditional(Difficulty,Selection,Choice,_)),
  time(solve_traditional(Difficulty,Selection,Choice,_)),
  time(solve_traditional(Difficulty,Selection,Choice,_)),
  time(solve_traditional(Difficulty,Selection,Choice,_)),
  time(solve_traditional(Difficulty,Selection,Choice,_)),
  time(solve_traditional(Difficulty,Selection,Choice,_)),
  statistics(runtime,[_|T]), % T 
  write(T).

メソッドsolve_traditional(...)の実行にかかった時間を書き込んで、テキスト ファイルに書き出す必要があります。しかし、それは十分に正確ではありません。指定されたメソッドの時間が 0.015 または 0.016 秒と表示されることもありますが、通常は 0.0 秒と表示されます。

メソッドの完了が速すぎると判断したため、2 つのランタイム呼び出しの間にかかる時間を測定するために統計 (ランタイムなど)を使用することにしました。次に、たとえば、20 回のメソッド呼び出しを完了するのにかかる時間を測定し、測定した時間 T を 20 で割ることができます。

唯一の問題は、20 回の呼び出しで T が 0、16、32、または 48 ミリ秒のいずれかに等しいことです。どうやら、各メソッド呼び出しの時間を個別に測定し、実行時間の合計を見つけます (多くの場合、わずか 0.0 秒です)。これは、N 個のメソッド呼び出しの実行時間を測定し、時間 T を N で割るという目的全体を打ち負かします。

要するに、私が実行時間の測定に使用している現在の方法は不十分です。より正確にする方法はありますか (たとえば、小数点以下 9 桁)。

4

1 に答える 1

4

ベンチマークは、どのプログラミング言語でも難しい作業であり、CLP では特にそうです。特に、結果を公開する予定がある場合は、徹底的に調べ、測定しようとしているものを測定していることを完全に確認する必要があります。

タイマー:リアルタイム、プロセス CPU 時間、スレッド CPU 時間を測定していますか? システムコールに費やされた時間を含めますか? ガベージ コレクションを含めますか、除外しますか? ...

statistics/2プリミティブによって提供されるさまざまなタイマーを参照してください。statistics(hr_time,T)を介してアクセスできるリアルタイムの高解像度タイマーがあります。

タイマーの解像度:あなたの例では、タイマーの解像度は 1/60 秒のようです。つまり、時間測定で 3 桁の有効数字を取得するには、少なくとも 1000*1/60 = 16.7 秒のランタイムを測定する必要があります。

ベンチマークの実行時間が短すぎる場合は、複数回実行する必要があります。

ランタイムの差異:最新のマシンでは、再現可能なタイミングを取得することがますます難しくなっています。これは、キャッシュ動作、ページング、コンテキスト スイッチ、電源管理ハードウェア、メモリ アラインメントなど、測定しているプログラムとは関係のない影響によるものです。

十分に繰り返し実行し、静かなマシンで実行して、結果が再現可能であることを確認してください。

ベンチマークの繰り返し: ECLiPSe のようなシステムでは、ベンチマークを繰り返し実行して、連続する実行が実際に同じ計算を実行し、理想的にはキャッシュとガベージ コレクションの動作が同じか類似していることを確認する必要があります。

コードでは、ベンチマークを組み合わせて連続して実行します。変数のインスタンス化、遅延したゴール、またはガベージが以前の実行から生き残り、後続の実行が遅くなったり速くなったりする可能性があるため、これはお勧めできません。上記で提案したように、パターンを使用できます

run_n_times(N,Goal) :- \+ ( between(1,N,1,_), \+ Goal ).

これは本質的にシーケンスを N 回繰り返す方法です

once(Goal), fail

once/1これのポイントは、との組み合わせが のfailすべてGoalの計算を元に戻すため、次の反復が可能な限り同様のマシン状態から開始されることです。残念ながら、この元に戻すプロセス自体が余分な実行時間を追加し、測定を歪めます...

テストのオーバーヘッド:ベンチマークを数回実行する場合は、それを実行するテスト フレームワークが必要です。これは、測定するランタイムに貢献します。

オーバーヘッドが無視できることを確認するか、オーバーヘッドを測定して (たとえば、ダミーのベンチマークでテスト フレームワークを実行することによって)、それを差し引く必要があります。次に例を示します。

benchmark(N, DummyGoal, Goal, Time) :-
    cputime(T1),
    run_n_times(N, DummyGoal),
    cputime(T2),
    run_n_times(N, Goal),
    cputime(T3),
    Time is (T3-T2)-(T2-T1).

CLP の詳細: CLP ソルバーで発生するデータ駆動型操作の種類に固有の考慮事項が他にも多数あり、CLP ランタイムを比較するのが非常に難しくなっています。これらのソルバーには、プロパゲーターのスケジューリング、枝刈りの程度、検索制御におけるタイ ブレーク ルールなどに関して、多くの内部自由度があります。

これらのことを具体的に説明している論文は 、Mark Wallace、Joachim Schimpf、Kish Shen、および Warwick Harvey による On Benchmarking Constraint Logic Programming Platforms です。CONSTRAINTSジャーナルで、編。EC Freuder,9(1), pp 5-34, Kluwer, 2004 .

于 2016-03-16T02:44:16.333 に答える