Microsoft ソリューション専用サイト TOP  >  Microsoft MVP's コラム  >  Silverlightのテツジん  >  第36回「Windows ストア アプリケーションでタイマーを使った性能測定の話」

Microsoft® Most Valuable Professional MVP's コラム

日立ソリューションズ在籍、各専門分野で”日本有数”のMVPによる連載コラムです。

[Sliverlightのテツジん] Silverlight: Development Microsoft MVPアワード受賞 <Silverlightコミュニティ「Silverlightを囲む会in名古屋」リーダー> 加藤 哲司 Tetsuji Kato 株式会社 日立ソリューションズ プラットフォームソリューション事業部

2014年2月26日
第36回

Windows ストア アプリケーションでタイマーを使った性能測定の話

みなさん、こんにちは。
日立ソリューションズ 加藤です。

今年のインフルエンザですが、非常に強力ですね・・・
2月の上旬頃から私の周りの人たちが怖いくらいの勢いでインフルエンザにかかっていき、お見舞いをお伝えする機会が多くありました。
本当に一斉だったのでそろそろ自分も・・・と思っていたのですが、今のところ私への影響はありません。
このまま乗り切っていきたいと思います!

さて、私がかかわっているWindows ストア アプリケーションの開発プロジェクトが終盤に差し掛かって来ているのですが、品質も上がり不具合が減ってきたところで、気になり始めるのが性能です。
規模が大きいプロジェクトの場合、複数の組織が一緒になって物を作ることになりますが、そのようなプロジェクトで性能の問題が出ると、担当範囲の性能を保証するためAPI単位で性能を明確にすることを求められることがあります。
このプロジェクトでもAPIの実行時間を明確にして性能を示す必要に迫られたのですが、担当者からうまく測れないと質問をうけました。
調べたところ、原因がWindowsのアプリケーション開発でありがちなことでしたので、今回はWindows ストア アプリケーションでAPI単位の実行時間の計測方法について書きたいと思います。


・APIの処理時間を証明する

API単位で性能の証明を求められた場合、呼び出すAPIの前と後に時間値をとるコードを入れることがあります。今回はWindows ストア アプリケーションのC#ですが、こんなコードが書かれていました。

private void Button_Click(object sender, RoutedEventArgs e)
{
     var StartTime = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
     *** API Call***
     var EndTime = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
               ・
               ・
               ・
}

コード 1 質問されたときの計測方法

性能を測る話になると、よく見かける方法です。
しかし、実際に計ってみると、計測対象のAPIの処理が軽量なものほど予想以上に処理時間がかかっている印象だったようで、質問に来られたようです。
試しに10msほど処理にかかるAPIの実行時間を計測するコードを私も書いて測ってみたところ、下記のような結果になりました。
表 1 計測結果
計測回数

TimeSpan.FromTicks(DateTime.Now.Ticks).

TotalMillisecondsで測った経過時間(ms)

1
0
2
15.6015625
3
0
4
15.6015625
5
15.6015625
6
0
7
15.6015625
8
0
9
15.6015625
10
0

計測結果にばらつきがあることと、0msという超高速な結果が出ていること。あと、15ms以下の計測結果が出てきていないので、確かに計測結果が正確ではない感じがします。
実は計測に使っているDateTime構造体を用いた計測方法には、ハードウェアも絡んだ罠があり、注意が必要です。


・DateTime構造体の分解能の罠
アナログである時間をコンピュータ上で量として扱うためには、一定のタイミングで区切って数値化する必要があります。
この区切る幅のことを「分解能」と言います。
下記の図の場合、PCは1秒ごとに時間を区切ってカウントアップしているので、このPCの時間の分解能は「1秒」となります。(実際のPCはもっと細かいですけどね。)

図 1  分解能

図 1 分解能

 


分解能という表現は、PCの時間値のような場合だけではなく、たとえば1mm間隔でメモリが刻まれた定規は「1mmの分解能を持つ定規」となります。(あまり言いませんけど)

本題となりますが、計測時に使用していたDateTime構造体のNowプロパティは、Windowsが持つシステムタイマーを元に値を生成しています。
(MSDNのDateTime.Now プロパティ:
http://msdn.microsoft.com/ja-jp/library/windows/apps/system.datetime.now.aspx


システムタイマーの分解能は10ms~16msであり、先ほどの計測結果で出てきた15msとほぼ等しいので、分解能の面では正しく計測できていたということになります。
また0msが出たり値がばらついたりしたのは、分解能が15msシステムタイマーを使って、分解能以下である10msの処理を計測したため、実行時の状態により0msと扱われたり15msと扱われたためです。

ちなみに・・・
このシステムタイマーの分解能は、OSによるものなので言語に依存しません。
システムタイマーについてはMSDNにあるC++用のAPIの説明にも出てきます。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724408(v=vs.85).aspx

システムタイマーの分解能には幅ありますが、10msに近いのか?16msに近いのか?についてはPCの構成に依存します。
ただ、最近のPCの場合は16msのほうになると思います。
なぜ「最近のPCのほうが劣化するのか?」については、ハードウェア周りの話になるので割愛しますが、ご興味がありましたら、「APIC 16ms」で検索するか、下記を読んでみるとよいと思います。
(ユニプロセッサ PC における APIC の重要性について:
http://msdn.microsoft.com/ja-jp/library/windows/hardware/gg462964.aspx




・もっと高分解能なヤツを求む。
時間幅としての15msはそこまで長くはありませんが、1秒でも性能を求めるような状況であれば、誤差で処理時間が大きく見えることは都合が悪いと思います。
15msより細かく測れないのか?と要求されることもあるでしょう。
Windows ストア アプリケーションのC#の場合、Stopwatchクラスを使うとシステムタイマーより精度のよい高解像度タイマーを使って時間を計ることができます。
Stopwatchクラスを使ったコードはこのようになります。

private void Button_Click(object sender, RoutedEventArgs e)
{
     var stopwatch = System.Diagnostics.Stopwatch.StartNew();
     var StartTime = stopwatch.ElapsedMilliseconds;
     *** API Call***
     var EndTime = stopwatch.ElapsedMilliseconds;
     stopwatch.Stop();                ・
               ・
               ・
}

コード 2 Stopwatchクラスを使った測定

Stopwatchクラスが時間値として扱っている最小単位はElapsedMilliseconds プロパティで扱えるmsです。
Stopwatchクラスはどの環境でも正しく動くと思いますが、実際に計測する前にはStopwatchクラスのIsHighResolutionフィールドを確認しておいてください。
もし、IsHighResolutionフィールドがfalseの場合、高解像度タイマーが使用できない環境のため、Stopwatchはシステムタイマーを元に動きます。
この場合、計測結果に誤差が出ることになります。


・限界はどこだ!?
よほどのことでない限り、Stopwatchクラスが提供するms単位の計測結果で事足りると思いますが、状況によっては事足りないこともあるでしょう。
では、Stopwatchクラスで測れる最も高い分解能はどうなのか?と言うと、これはPCの環境に依存しますがElapsedTicksプロパティとFrequencyフィールドを使うと一番高い分解能を使用できます。
FrequencyフィールドはそのPCが1秒間でカウントできる数なので、分解能を求めるには1秒をFrequencyフィールドの値で割れば求めることができます。
また、ElapsedTicksプロパティはStopwatchクラスで計測をスタートしてからカウントされた数になるので、1秒をFrequencyフィールドの値で割って求めた分解能とElapsedTicksプロパティを積算すれば、Windows ストア アプリケーションで知ることのできるもっとも細かい精度で、実行時間を測定できます。
もっとも、上記の手法で求めた細かい時間値は、細かすぎてノイズが入りやすくなるため性能を示すためにここまでやるべきか?と個人的には思います。


システムタイマーの面白い動き
今回ご紹介したようにDateTime構造体を使ったシステムタイマーでの計測はそれなりの誤差がでますが、実はシステムタイマーを使っていても誤差がなくなることがあります。
それは、そのOS上で動いているアプリケーションのうち、どれかが高解像度タイマーを使用している場合です。
以前、C++で同じようにシステムタイマーを用いたコードを書いたことがありますが、この時にほかのアプリケーションに影響を受ける動きをしていたので、今回も試してみるとWindows 8.1とWindows ストア アプリケーションの組み合わせでも発生しました。
もし、「AのPCではシステムタイマーでも正しく計れていたのに、BのPCでは誤差が出る・・・」というような事態に直面したら、AのPCのほかのアプリケーションを疑ってみてください。
誰かが高解像度タイマーを使っているはずです。
 


(株)日立ソリューションズ
Microsoft MVP(Client Development)
加藤哲司

 

UXを実現するSilverlight/WPF/WinRTのご相談はこちらから!
http://www.hitachi-solutions.co.jp/ms-solutions/sp/solution/silverlight_wpf/index.html


 

Profile
加藤 哲司 Tetsuji Kato
1998年に日立中部ソフトウェア(現:日立ソリューションズ)入社。T-560/20オンライン端末エミュレータ「CommuniNet」シリーズなど、Windows系アプリケーションを中心に設計・開発を行ってきた。現在は、SilverlightやWPFなどのXAMLプラットフォームを駆使し、業務アプリケーションでクオリティの高いユーザーエクスペリエンスを実現することに情熱を注ぐ。2010年10月に日本で最初の Microsoft MVP for Silverlight に認定され、現在はMicrosoft MVP for Client Developmentに認定されている。
マイクロソフトの技術コミュニティ 「MiCoCi」の中心メンバーも務める。 
[MVP] Microsoft Most Valuable Professional
■受賞歴

2010/10~2013/9:Microsoft MVP for Silverlight
2013/10~現在 :Microsoft MVP for Client Development

■講演歴
【日本マイクロソフト】
Tech・ed 2009
Tech・days 2010
Tech・ed 2010
【インフラジスティックス・ジャパン】
Developer Days 7
【翔泳社】
Developers Summit 2011
など多数

PAGETOP
お問い合わせ
お電話でのお問い合わせ
0120-571-488
受付時間:月〜金(祝祭日除く)10:00〜17:30
ウェブサイトからのお問い合わせ
資料請求・お問い合わせ

カタログ・資料ダウンロード
拡張ソリューション
セミナー・展示会情報
メールマガジン
関連リンク
Microsoft MVP's コラム
Silverlight のテツジん プラットフォームソリューション事業本部 加藤 哲司
Microsoft Dynamics ソリューション 専用サイトはこちらから
2013 Microsoft Partner of the Year