FrameDescription のプロパティの参照は負荷が大きいので注意する

マイクロソフトの許可を得て使用しています。Microsoft.com をご覧ください。

FramdeDescription からは WidthHeight などの汎用的なパラメータを取得することができます。 ところがそれらのパラメータを取得するためのプロパティは、参照時に酷く大きな負荷(オーバーヘッド・遅延)を発生させます。 ここではそれを検証して確認しておきます。

Kinect for Windows v2 Sensor と Kinect SDK 2.0 (2.0.1410.19000) 時点での検証です。 SDK のバージョンアップなどによって解決している可能性があります。 実装には C# と WPF を利用します。

サンプルプロジェクト
KinectV2Samples/Wpf_FDesc_PerformanceTest
開発環境
Kinect for Windows v2 Sensor
MS Kinect SDK 2.0.1410.19000
VisualStudio 2012

サンプルの配布方法に GitHub を採用してみることにしました。 試験的なものなので変更したり停止する場合があります。

繰り返し処理での検証

10,000 回の繰り返し処理を4つのパターンで実装して、それぞれの実行時間を計測します。 実行時間の計測は .Net の StopWatch クラスを利用します。

A : FrameDescription.Width を参照する

stopWatch.Restart();

for (int i = 0; i < 10000; i++)
{
    dummyValue = colorFrame.FrameDescription.Width;
}

B : 予め確保した FrameDescription から Width を参照する

FrameDescription colorFrameDescription
	= colorFrame.CreateFrameDescription(ColorImageFormat.Bgra);

for (int i = 0; i < 10000; i++)
{
	dummyValue = colorFrameDescription.Width;
}

C : 予め確保した colorFrameDescription.Width を参照する

int width = colorFrameDescription.Width;

for (int i = 0; i < 10000; i++)
{
	dummyValue = width;
}

実行結果

実行結果は次の表の通りです。何度か実行し数値は多少前後しますが概ねこの範囲に収まります。

計測結果の比較
パターン実行時間(msec)
A2.410 ~ 4.210
B0.040 ~ 0.070
C0.019 ~ 0.028

実行環境は KinectV2, Windows8.1Pro, Corei7-2600K 3.40GHz, Mem 16G です。

基本的にはほぼ平均数値で出るんですが、特に A の FrameDescription.Width を直接参照するパターンでは差が大きいです。 2.3 msec 程度の実行時間を前後することが多いのですが、不意に 3msec 4msec で処理されることがあります。 いずれにせよ、少なくともパターン A のような実装方法は避ける必要がありますね。

Kinect の公式サンプルでは WidthHeight は予め int 型の変数として確保していて、 オーバーヘッドが発生しないようにしてあります。発生することとプログラミング指針を示してくれても良いと思うのですが…。

新しいインスタンスが生成されている可能性?

新しインスタンスか何かが生成されているのではないかと思って、参照の等価をチェック(しようと)してみました。 とりあえず FrameDescription は等価のようです。 次のコードでは、colorFrame.FrameDescription を 2 回参照して参照の等価を比較していますが True が返ります。

Console.WriteLine(Object.Equals(colorFrame.FrameDescription, colorFrame.FrameDescription));
//結果は True です。

WidthHeight なんですが、プロパティによる実装って(確か)アドレスが取得できないんですよね。 int 型ですから等値しか比較できませんし、新しいインスタンスが生成されているかどうかを正しく確認する術が私にはありません。 (まぁ多分方法はあるんでしょうけれども私にとってそれは本題ではないのでパスします。) しかし単純に int 型のインスタンスを生成しているわけではなさそうですね、負荷の大きさからすると。

参照の類でのみ発生する負荷でもない

プロパティの参照の方が、値型変数のインスタンスを直接参照するよりも負荷がある、というのは理解できます。 しかしWidthHeight は明らかにそれ以上の負荷があるようにみえるので、 簡易的なプロパティを用意してその実行結果も計測しておきました。

用意したクラスとプロパティは次のようにシンプルなものです。

public class DummyParent
{
	public class DummyChild
	{
		public int Value { get; set; }
	}

	public DummyChild Child { get; set; }

	public DummyParent()
	{
		this.Child = new DummyChild();
	}
}

用意した DummyParent クラスのインスタンスを利用して dummyObject.Child.Value を 10,000 回参照します。

DummyParent dummyObject = new DummyParent();

for (int i = 0; i < 10000; i++)
{
	dummyValue = dummyObject.Child.Value;
}

実行時間は 0.2 ~ 0.5msec です。どんなに早くても 0.2msec 程度なので、 プロパティの参照にはどうしても一定の負荷がかかりますね。先の B, C の結果と比較すれば明らかです。 一方でどんなに遅くても 0.5msec 程度なので、先の A のパターンはどう考えても参照以上の負荷がかかっています。