在ASP.NET Core MVC之外使用MiniProfiler

首先

注意: 間違ったプロファイラの使い方をしていたので、初版と比べてベンチマーク結果が大幅に変わりました。

ASP.NETでリクエストの応答速度等を測りたい場合に使えるプロファイラとして、MiniProfilerというものがある。
ASP.NET Coreに対応したバージョンはまだalpha版だが、使用は可能。
しかし、ドキュメントを見るだけでは不明な点がいくつかあったので、調べてわかったことを記事に書く。

这里将写一个将其嵌入控制台项目的方法作为示例。在一开始阶段,我参考了官方文档。

なお、プロファイラと言えば、ものによってはメモリ使用量等も計測できる場合もあるが、MiniProfilerではそのような機能は存在せず、あくまで速度の計測のみができることに注意。

前提条件

dotnet sdk 2.0以降 をインストールしている
“dotnet”コマンドにパスが通っている

准备控制台项目

用以下命令创建一个新项目。

dotnet new console --name [プロジェクト名]

在成功后,将在[项目名称]指定的文件夹中创建csproj文件。

包的安装

将当前目录切换至创建的项目,并执行以下命令。

dotnet add package MiniProfiler.AspNetCore --version [パッケージバージョン]

由于在文章撰写时,尚未有正式发布阶段的软件包,因此需要参考MiniProfiler的nuget页面并指定版本。

如果成功的话,csproj将添加以下项目。

实施个人信息分类

除非另有特别注明,否则在StackExchange.Profiling命名空间中存在该类。

准备配置选项实例

首先要创建MiniProfilerOptions的实例。Profiler似乎是设计成从这个实例中重复使用配置的,所以如果将其全局保存或通过DI注入,将来会更加方便。如果所有的设置都可以使用默认配置,则可以直接使用无参数的new方法。

开始建立个人档案

从生成的选项中执行StartProfiler(“[Profiler name]”),以创建MiniProfiler实例。
在此处创建的实例将在一个度量区间(例如,一个请求)中共享。
在指定名称时,请确保它能够清楚地表示使用了哪个度量区间,以备后续显示使用。

层级化

通常情况下,处理过程一般都以层次结构的形式存在。

A-+-B
  +-C-D

在MiniProfiler中,通过Timing对象来控制并以以下方式表示层次结构。

// using StackExchange.Profiling;
MiniProfiler mp = new MiniProfilerOptions().StartProfiler("my_profile");
using(mp.Step("step_a"))
{
    // 処理A
    using(mp.Step("step_b"))
    {
        // 処理B
    }
    using(mp.Step("step_c"))
    {
        // 処理C
        using(mp.Step("step_d"))
        {
            // 処理D
        }
    }
}
// 計測を終了したい時は、Stop()を実行する
// 実行しないと、処理時間が大幅に変わってしまうので注意
mp.Stop()

在Step()函数的参数中,指定了时间间隔名称。该名称将在之后用于显示。

如果您想在运行时决定是否执行配置文件,只需将MiniProfiler实例设置为null即可,这样Step就不会生成任何内容,几乎没有额外开销。(由于Step是扩展方法,所以即使实例为空也没有问题)

获取结果

可以从MiniProfiler实例的Timing MiniProfiler.Root属性中递归地获取结果。
Timing类主要使用以下内容。

Name: Step()等で付けた名前

Children: 子区間のリスト

DurationMilliseconds: 子も含めた経過時間

DurationWithoutChildrenMilliseconds: 子を含まない経過時間

Depth: ルートから数えた深さ(数字が大きいほど深い階層)

HasChildren: 子を持っているかどうか

因此,对于一个个人资料,基本上会按照以下方式处理结果。

// MiniProfiler mp;
// 計測終了

void ProcessTiming(Timing t)
{
    // tに対して何らかの処理
    if(t.HasChildren)
    {
        foreach(var child in t.Children)
        {
            // 再帰的に処理する
            ProcessTiming(child);
        }
    }
}

ProcessTiming(mp.Root);

保存和获取结果

如果需要即時处理分析结果,上述内容就足够了。但如果想要将每个分析结果汇总并后续查看,可以使用MiniProfiler的IAsyncStorage。
大致使用步骤如下:

MiniProfilerOptions.StorageにIAsyncStorageのインスタンスをセット(以後、このインスタンスを使い回す)

MiniProfiler.Storage.Save(MiniProfiler)で、プロファイル結果を保存

MiniProfilerOptions.Storage.List()で、保存したプロファイル結果を列挙(GUID)

MiniProfilerOptions.Storage.Load(guid)で、列挙したGUIDを指定して、プロファイル結果を取り出す
列挙したプロファイル結果それぞれに対して処理を行う

IAsyncStorageの実装については、基本的なものはStackExchange.Profiling.Storage.MemoryCacheStorageとなる。(MiniProfiler.AspNetCore.Mvcでデフォルトで使われるのもこれ)
ただし、このMemoryCacheStorageの生成が柔軟な分若干回りくどいので、後述する。
なお、他のIAsyncStorageの実装は、NugetでMiniProfiler.Providersで検索すると出てくる(RedisやSqlServer実装が存在する)

MemoryCacheStorageの生成方法

このMemoryCacheStorage、newの引数は(IMemoryCache cache, TimeSpan cacheDuration)になっている。
IMemoryCacheがどこにあるかというと、Microsoft.Extensions.Caching.Memory以下に存在する。

なので、このIMemoryCacheを実装したインスタンスを生成すればいいわけだけど、デフォルト実装(MemoryCache)を使用するには、Microsoft.Extensions.Caching.Memoryパッケージを追加する必要がある。
パッケージの追加は以下のコマンドで可能。

dotnet add package Microsoft.Extensions.Caching.Memory

パッケージを追加すれば、Microsoft.Extensions.Caching.Memory.MemoryCacheが使用できるようになる。
更にこのMemoryCacheを生成するには、IOptionがnew引数に必要になる。
これは、作成するだけならMicrosoft.Extensions.Options.Options.Create(new MemoryCacheOptions())でOK。
応用すれば、設定ファイルからメモリキャッシュオプションを生成することも可能らしいが、ここでは省略する。

总结起来,会得到以下的代码。

// using Microsoft.Extensions.Options;
// using Microsoft.Extensions.Caching.Memory;
// using StackExchange.Profiling.Storage;
var memcacheopt = Options.Create(new MemoryCacheOptions());
var memcache = new MemoryCache(memcacheopt);
var memstorage = new MemoryCacheStorage(memcache, TimeSpan.FromMinutes(60));

请注意

在中文中,只需要一种选项进行改写:
由于自身的配置文件增加了一些开销,所以最好在开始时的设置中决定是否使用,以便可以上传实际测试结果到Gist。

bannerAds