27

私が構築しているいくつかの検索コードでは、レーベンシュタインのアルゴリズムの最適化されたバージョンを使用しています。アルゴリズムが正しい結果を返すことを検証する機能ユニット テストがありますが、このコンテキストでは、アルゴリズムのパフォーマンスも非常に重要です。

プロジェクトにいくつかのテスト カバレッジを追加して、将来の変更が最適化に影響を与えた場合に失敗したテストとして表示されるようにすることを検討しています。アルゴリズムは決定論的であり、既知のテスト データに対して実行されているため、これはカウントと同じくらい詳細になる可能性があります。特定のテスト入力セットに対して実行された命令の数。つまり、タイマーを使用してアルゴリズムのパフォーマンスを測定するつもりはありません。出力だけでなく、アルゴリズムの内部動作を実際にテストすることに興味があります。

C#/.NET 4 でこれにアプローチする方法はありますか?

編集:実時間だけを使用したくない理由は、テストの制御外の CPU 負荷やその他の要因によって変化するためです。これにより、たとえば、ビルド サーバーに負荷がかかっているときにテストが失敗する可能性があります。展開されたシステムの一部として、壁時計の監視があります。

EDIT 2: このように考えてください...パフォーマンスが重要な要件である場合、どのように赤→緑→リファクタリングを適用しますか?

4

1 に答える 1

34

私はこれを何度か成功させてきたので、あなたの質問の3番目の部分に答えるつもりです。

パフォーマンスが重要な要件である場合、赤->緑->リファクタリングをどのように適用しますか?

  1. 変更する予定の内容や、変更の結果として速度が低下する可能性のあるその他の方法について、リグレッションをキャッチするためのピン留めテストを作成します。
  2. 失敗するパフォーマンステストを作成します。
  3. すべてのテストを頻繁に実行して、パフォーマンスを向上させます。
  4. 固定テストを更新して、パフォーマンスをより厳密に固定します。

固定テストを作成する

このようなヘルパーメソッドを作成して、ピン留めしたいものの時間を計ります。

private TimeSpan Time(Action toTime)
{
    var timer = Stopwatch.StartNew();
    toTime();
    timer.Stop();
    return timer.Elapsed;
}

次に、メソッドに時間がかからないことを確認するテストを作成します。

[Test]
public void FooPerformance_Pin()
{
    Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0));
}

失敗した場合(失敗メッセージに実際の経過時間が表示されている場合)、実際の時間より少し長い時間で時間を更新します。再実行すると合格します。変更によってパフォーマンスに影響を与える可能性のある他の関数についてもこれを繰り返し、最終的には次のようになります。

[Test]
public void FooPerformance_Pin()
{
    Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0.8));
}
[Test]
public void BarPerformance_Pin()
{
    Assert.That(Time(()=>fooer.Bar()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(6));
}

失敗したパフォーマンステストを書く

私はこの種のテストを「ベイティングテスト」と呼んでいます。これは、ピン留めテストの最初のステップにすぎません。

[Test]
public void FooPerformance_Bait()
{
    Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0));
}

次に、パフォーマンスの向上に取り組みます。暫定的な改善を行うたびに、すべてのテスト(ピン留めとベイト)を実行します。成功すると、ベイティングテストの失敗出力で時間が減少し、ピン留めテストが失敗することはありません。

改善に満足したら、変更したコードのピン留めテストを更新し、ベイティングテストを削除します。

あなたは今これらのテストで何をしますか?

最も気になることは、これらのテストにExplicit属性のマークを付けて、次にパフォーマンスをチェックするときのためにそれらを保持することです。

作業範囲の反対側では、これらの種類のテストを実行するためにCIで適切に制御されたサブシステムを作成することは、パフォーマンスの低下を監視するための非常に優れた方法です。私の経験では、実際の障害よりも「他の何かからのCPU負荷が原因でランダムに障害が発生する」という心配がたくさんあります。この種の取り組みの成功は、環境を管理する能力よりもチームの文化に依存します。

于 2013-03-03T03:15:38.223 に答える