3

.NET の属性を介して個々のメソッドをプロファイリングすることは可能ですか?

私は現在、静的メソッドを多用する大規模なレガシー アプリケーションのボトルネックを特定しようとしています。フレームワークを統合することは、現時点では選択肢ではありません。ほとんどの呼び出しは静的メソッドを使用するため、インターフェイスと依存性注入は利用できません。コードをハッキングして診断をログに記録することも、実行可能な解決策ではありません。

いくつかのプロファイリング ツールが市場に出回っていることは知っていますが、現在それらは予算外です。理想的には、メソッドのエントリとメソッドの終了に関する基本的な情報をログに記録する独自のカスタム属性を作成できます。私はカスタム属性を実際に扱ったことがないので、これが可能かどうかについての洞察をいただければ幸いです。

可能であれば、構成ファイルを介してプロファイリングを有効にしたいと考えています。これにより、単体テストと統合テストによるプロファイリングがサポートされます。

4

6 に答える 6

6

自分がしていることに属性を使用することはできません。ただし、いくつかの選択肢があります。

まず、そこにあるプロファイラーツールの多く(RedGate ANTSなど)は比較的安価($ 200- $ 300)で使いやすく、ほとんどの場合、数週間の無料の評価期間が提供されます-したがって、それらがあなたにリフトを与えるかどうかを確認できますあなたがそれらを購入するかどうかを決める前に、あなたは今必要です。また、.NETCLRプロファイラーは無料でダウンロードできます。

それが不可能な場合は、PostSharpがそのようなロジックをコードに組み込む最も簡単な方法です。

最後に、何らかの理由でPostSharpを使用できず、コードに属性を追加する場合は、usingブロックの形式で各メソッドに単純なインストルメンテーションブロックを追加することもできます。

public void SomeMethodToProfile()
{
    // following line collects information about current executing method
    // and logs it when the metric tracker is disposed of
    using(MetricTracker.Track(MethodBase.GetCurrentMethod()))
    { 
        // original code here...
    }
}

典型的なMetricTrackerの実装は次のようになります。

public sealed class MetricTracker : IDisposable
{
    private readonly string m_MethodName;
    private readonly Stopwatch m_Stopwatch;

    private MetricTracker( string methodName ) 
       { m_MethodName = methodName; m_Stopwatch = Stopwatch.StartNew(); }

    void IDisposable.Dispose()
       { m_Stopwatch.Stop(); LogToSomewhere(); }

    private void LogToSomewhere()
       { /* supply your own implementation here...*/ }

    public static MetricTracker Track( MethodBase mb )
       { return new MetricTracker( mb.Name ); }
}
于 2009-09-28T20:49:50.390 に答える
3

基本的に次のように、PostSharpを使用して編み込みを行うことができます。

[Profiled]
public void Foo()
{
     DoSomeStuff();
}

の中へ

public void Foo()
{
    Stopwatch sw = Stopwatch.StartNew();
    try
    {
        DoSomeStuff();
    }
    finally
    {
        sw.Stop();
        ProfileData.AddSample("Foo", sw.Elapsed);
    }
}

実際、PostSharp のドキュメントを見ると、余裕があればGibraltar (PostSharp を使用) を使用できるはずです。そうしないと、PostSharp のコツをつかむのに 1 日ほど費やすことになるかもしれませんが、それでも十分に価値があるかもしれません。

フレームワークをコードベースに統合する余裕がないと言ったことは知っていますが、PostSharp を使用してコードでコンパイル後の変換を実行するほど、実際に「統合」するわけではありません。

于 2009-09-28T20:19:17.363 に答える
1

あなたが説明したものと非常によく似たものを探していました。そのようなフレームワークが見つからなかったので、自分で作成しました。これは非常にシンプルですが、シンプルであることが良い場合もあります。

ベンチマークが単体テストに対応していると説明します。概念は、速度を測定または比較するためにコードのセクションを分離することです。

属性の使用法の典型的な例は次のようになります。

[ProfileClass]
public class ForEachLoopBenchmarks
{
    [ProfileMethod]
    public void ForLoopBenchmark()
    {
        List<int> list = GetNumberList();

        for (int i = 0; i < list.Count; i++)
        {
        }
    }

    [ProfileMethod]
    public void ForEachLoopBenchmark()
    {
        List<int> list = GetNumberList();

        foreach (int i in list)
        {
        }
    }

    private List<int> GetNumberList()
    {
        List<int> list = new List<int>();
        for (int i = 0; i < 1000; i++)
        {
            list.Add(i);
        }
        return list;
    }
}

次に、コンソール アプリを作成し、以下のコードをMainメソッドに貼り付けて、前述の属性で装飾されたクラスを含むアセンブリへの参照を追加します。各メソッドの実行時間 (1000 回実行) がコンソールに出力されます。

class Program
{
    static void Main(string[] args)
    {
        ProfileRunner rp = new ProfileRunner();
        rp.Run();
    }
}

コンソール出力は次のようになります。

コンソール出力

pUnit.dllの参照をコンソール アプリケーションと、属性でマークされたメソッドを含むクラス ライブラリに追加する必要があります。

これはNuget hereからパッケージとして入手できます。

Nuget コマンド: PM> Install-Package pUnit

完全なソース コードが必要な場合は、こちらのGithub で見つけることができます。

この質問の実行時間を実際に測定する方法に基づいています: https://stackoverflow.com/a/1048708/1139752

実装については、次のブログ投稿で詳しく説明します。

于 2012-02-18T13:29:36.923 に答える
0

一見の価値がある無料のプロファイラー ツールもいくつかあります。

于 2009-09-28T20:20:21.760 に答える
0

これを達成するためにPostSharpのようなものを介してアスペクト指向プログラミングを使用したい場合を除き、属性を介してこれを実装することはできません。

ただし、定義 (ビルド構成で設定される可能性があります) に基づいて、そこに条件付きロジックを配置することはできます。これにより、現在のコンパイル設定に応じたタイミングでロギングをオンまたはオフにすることができます。

于 2009-09-28T20:20:52.280 に答える
0

C# でパフォーマンス チューニングを行っています。必要なのはこのテクニックだけです。大したことじゃないよ。

シンプルな考え方に基づいています。必要以上に長く待機している場合、それはプログラムの一部が必要以上に長く待機していることを意味します。

そして、それはどのように待っていますか?ほとんどの場合、呼び出しサイトで、呼び出しスタックで。

したがって、待機中に一時停止してコール スタックを見ると、何が待機されているかがわかります。また、それが本当に必要でない場合 (通常はそうではありません)、その理由がすぐにわかります。

1 つのサンプルだけを信用するのではなく、数回実行してください。複数のスタック サンプルに表示されるものはすべて、それについて何かを行うことができれば、多くの時間を節約できます。

ご覧のとおり、関数のタイミングを計ったり、関数が呼び出された回数を数えたりすることではありません。それは、予告なしにプログラムに数回立ち寄って、何をしているのか、なぜそれをしているのかを尋ねることです。何かが時間の 80% (または 20% など) を無駄にしている場合、サイクルの 80% は本当に必要ではない状態になるので、それらに立ち寄って見てください。正確な測定は必要ありません。

それは大きな問題で動作します。小さな問題にも対応します。そして、すべてを複数回実行すると、プログラムが高速になるにつれて、小さな問題が比較的大きくなり、見つけやすくなります。

于 2009-09-28T23:11:08.413 に答える