Windows Phone 7 エミュレーターには、レジストリ設定 (EnableConsole) または XDE.exe の decfg パラメーターを介して有効にできる優れたコンソール ウィンドウ機能がありました。
デバッガを付けなくても動作しました。ランタイム バインディングの問題や例外を見つけるのに役立ちました。
Windows 8 Phone エミュレーターでコンソール ウィンドウを有効にする方法はありますか?
Windows Phone 7 エミュレーターには、レジストリ設定 (EnableConsole) または XDE.exe の decfg パラメーターを介して有効にできる優れたコンソール ウィンドウ機能がありました。
デバッガを付けなくても動作しました。ランタイム バインディングの問題や例外を見つけるのに役立ちました。
Windows 8 Phone エミュレーターでコンソール ウィンドウを有効にする方法はありますか?
WP8 エミュレーターは WP7 エミュレーターを完全に書き直したものであるため、文書化されていない同じデバッグ メッセージをサポートする可能性は低いです。結局のところ、質問は次のとおりです。何をログに記録しようとしていますか?
アプリ固有のメッセージのロギング
重要なボタンのクリックなど、何か興味深いことがアプリで発生したとします。それをアプリに記録し、そのメッセージを IsoStore に書き込む (またはカスタム Web サービスに送信する) 必要があります。私は WP8 と Win8 のログ記録に MetroLog を使用していますが、ファイルが IsoStore に書き込まれる限り、何でも使用できます。MetroLog @ https://github.com/mbrit/MetroLogをチェックしてください
その後、CoreCon APIを使用してファイルを読み取ることができます。WP8 @ https://stackoverflow.com/a/13429709/81687のこれらの API のコード サンプルをアップロードしました。
エミュレーター固有のメッセージのロギング
エミュレーターがアクティブ化されたとき、ズームが設定されたとき、スクリーンショットが失敗した場合、またはタッチイベントが発生した場合に関心があるとします。WP8 エミュレーターは、ETW プロバイダーff86852d-541c-4f7e-98c5-5761e8cb7074を使用して、これらの他のイベントをログに記録します。ETW の詳細については、http://msdn.microsoft.com/en-us/magazine/cc163437.aspx を参照してください。
まず、PerfViewをダウンロードして XDE.exe エミュレーターを起動し、ETW 出力のキャプチャを開始します。
次に、PerfView からエミュレーターを実行し、いくつかのことを行い、エミュレーターをシャットダウンして、情報の収集を停止します。これを行うと、エミュレーターで行われたすべてのログを確認できます。興味深い内容は、プロバイダー ID でフィルター処理すると、「イベント」ログの下にあります。
上記の印刷画面では、イベントと、それらがエミュレーターでいつ発生したかを確認できます。たとえば、イベント 76 はエミュレーターの MicrophoneCaptureThreadStarted であり、プロファイリング セッションの 27 秒後に発生しました。イベント コードの完全なリストについては、XDE.exe アセンブリの Microsoft.Xde.Etw.WindowsPhoneEmulatorProvider c'tor を参照してください。納得させるためにここにコピーを貼り付けます:
public WindowsPhoneEmulatorProvider()
{
this.m_provider = new EventProviderVersionTwo(new Guid("ff86852d-541c-4f7e-98c5-5761e8cb7074"));
this.XdeStarted = new EventDescriptor(0, 0, 9, 4, 0, 0, -9223372036854775808L);
this.XdeStopped = new EventDescriptor(1, 0, 0, 4, 0, 0, 0L);
this.DesktopResolutionChanged = new EventDescriptor(2, 0, 0, 4, 0, 0, 0L);
this.InvalidLanguageSpecified = new EventDescriptor(3, 0, 0, 2, 0, 0, 0L);
this.CantFindVhd = new EventDescriptor(5, 0, 0, 2, 0, 0, 0L);
this.DiffDiskVhdRequiresVhdPath = new EventDescriptor(6, 0, 0, 2, 0, 0, 0L);
this.InvalidVideoParam = new EventDescriptor(7, 0, 0, 2, 0, 0, 0L);
this.InvalidMemorySize = new EventDescriptor(8, 0, 0, 2, 0, 0, 0L);
this.CantFindVM = new EventDescriptor(9, 0, 0, 2, 0, 0, 0L);
this.UnableToSendKeyToVM = new EventDescriptor(10, 0, 0, 2, 0, 0, 0L);
this.FailedToCreateDiffVhd = new EventDescriptor(11, 0, 0, 2, 0, 0, 0L);
this.FailedToCreateVM = new EventDescriptor(12, 0, 0, 2, 0, 0, 0L);
this.FailedVMStop = new EventDescriptor(13, 0, 0, 2, 0, 0, 0L);
this.FailedStartVM = new EventDescriptor(14, 0, 0, 2, 0, 0, 0L);
this.UnableToConnectToGuest = new EventDescriptor(15, 0, 0, 2, 0, 0, 0L);
this.ConnectedToGuest = new EventDescriptor(0x10, 0, 0, 4, 0, 0, 0L);
this.GuestIndicatedResolution = new EventDescriptor(0x11, 0, 0, 4, 0, 0, 0L);
this.LoadedSkin = new EventDescriptor(0x12, 0, 0, 4, 0, 0, 0L);
this.ButtonPressed = new EventDescriptor(0x13, 0, 0, 4, 0, 0, 0L);
this.VirtualMachineStateChanged = new EventDescriptor(20, 0, 0, 4, 0, 0, 0L);
this.ProxyInitialized = new EventDescriptor(4, 0, 0, 4, 0, 0, 0L);
this.UsageShown = new EventDescriptor(0x16, 0, 0, 4, 0, 0, 0L);
this.DisplayOrientationSet = new EventDescriptor(0x17, 0, 0, 4, 0, 0, 0L);
this.ZoomSet = new EventDescriptor(0x18, 0, 0, 4, 0, 0, 0L);
this.ScreenshotSavedToFile = new EventDescriptor(0x19, 0, 0, 4, 0, 0, 0L);
this.KeySentToVM = new EventDescriptor(0x1a, 0, 0, 4, 0, 0, 0L);
this.MouseEventSentToVM = new EventDescriptor(0x1b, 0, 0, 4, 0, 0, 0L);
this.UnableToSendMouseEventToVM = new EventDescriptor(0x1c, 0, 0, 0, 0, 0, 0L);
this.BringToFrontExecuted = new EventDescriptor(0x1d, 0, 0, 4, 0, 0, 0L);
this.ConnectedToAccelerometer = new EventDescriptor(30, 0, 0, 4, 0, 0, 0L);
this.UnableToConnectToAccelermometer = new EventDescriptor(0x1f, 0, 0, 0, 0, 0, 0L);
this.InvalidWindowsDetected = new EventDescriptor(0x20, 0, 0, 2, 0, 0, 0L);
this.HyperVNotEnabled = new EventDescriptor(0x21, 0, 0, 2, 0, 0, 0L);
this.AskedToConnectExternalSwitches = new EventDescriptor(0x22, 0, 0, 4, 0, 0, 0L);
this.ConnectedToGuestNotifications = new EventDescriptor(0x23, 0, 0, 4, 0, 0, 0L);
this.UnableToConnectToGuestNotifications = new EventDescriptor(0x24, 0, 0, 2, 0, 0, 0L);
this.FailedToSetVmProperties = new EventDescriptor(0x25, 0, 0, 2, 0, 0, 0L);
this.FailedToInitializeSnapshots = new EventDescriptor(0x26, 0, 0, 2, 0, 0, 0L);
this.FailedToSetVhd = new EventDescriptor(0x27, 0, 0, 2, 0, 0, 0L);
this.RdpServerDisconnected = new EventDescriptor(40, 0, 0, 4, 0, 0, 0L);
this.ScreenshotFailed = new EventDescriptor(0x29, 0, 0, 2, 0, 0, 0L);
this.AccelerometerSendFailed = new EventDescriptor(0x2a, 0, 0, 2, 0, 0, 0L);
this.LocationSendFailed = new EventDescriptor(0x2b, 0, 0, 2, 0, 0, 0L);
this.SnapshotStarted = new EventDescriptor(0x2c, 0, 0, 0, 0, 0, 0L);
this.SnapshotSucceeded = new EventDescriptor(0x2d, 0, 0, 0, 0, 0, 0L);
this.SnapshotFailed = new EventDescriptor(0x2e, 0, 0, 2, 0, 0, 0L);
this.CloseAfterSilentSnapshot = new EventDescriptor(0x2f, 0, 0, 0, 0, 0, 0L);
this.ApplySnapshotFailed = new EventDescriptor(0x30, 0, 0, 2, 0, 0, 0L);
this.RemovingSnapshotAfterFailedConnect = new EventDescriptor(50, 0, 0, 0, 0, 0, 0L);
this.RemovingSnapshotAfterSettingsDidntMatch = new EventDescriptor(0x33, 0, 0, 0, 0, 0, 0L);
this.ConnectedToShellReadyPipe = new EventDescriptor(0x34, 0, 0, 4, 0, 0, 0L);
this.UnableToConnectToShellReadyPipe = new EventDescriptor(0x35, 0, 0, 2, 0, 0, 0L);
this.ConnectedToTouch = new EventDescriptor(0x36, 0, 0, 4, 0, 0, 0L);
this.UnableToConnectToTouch = new EventDescriptor(0x37, 0, 0, 2, 0, 0, 0L);
this.TouchSendFailed = new EventDescriptor(0x38, 0, 0, 2, 0, 0, 0L);
this.SendTextFailed = new EventDescriptor(0x39, 0, 0, 2, 0, 0, 0L);
this.ReceiveAudioFromGuestWithSpinFailed = new EventDescriptor(0x3a, 0, 0, 2, 0, 0, 0L);
this.SendMicrophoneDataToGuestFailed = new EventDescriptor(0x3b, 0, 0, 2, 0, 0, 0L);
this.LoadUserSettingsFailed = new EventDescriptor(60, 0, 0, 0, 0, 0, 0L);
this.SetGuestSystemTimeAndZoneFailed = new EventDescriptor(0x3d, 0, 0, 2, 0, 0, 0L);
this.HypervisorNotRunning = new EventDescriptor(0x3e, 0, 0, 2, 0, 0, 0L);
this.HyperVManagementServiceNotRunning = new EventDescriptor(0x3f, 0, 0, 2, 0, 0, 0L);
this.UserAlreadyInHyperVAdmin = new EventDescriptor(0x40, 0, 0, 4, 0, 0, 0L);
this.UserAddedToHyperVAdmins = new EventDescriptor(0x41, 0, 0, 4, 0, 0, 0L);
this.FailedToAddUserToHyperVAdmins = new EventDescriptor(0x42, 0, 0, 0, 0, 0, 0L);
this.SendKeyboardEvent = new EventDescriptor(0x43, 0, 0, 4, 0, 0, 0L);
this.SendKeyboardEventFailed = new EventDescriptor(0x44, 0, 0, 2, 0, 0, 0L);
this.AudioPlayThreadStarted = new EventDescriptor(0x45, 0, 0, 0, 0, 0, 0L);
this.AudioPlayThreadExited = new EventDescriptor(70, 0, 0, 0, 0, 0, 0L);
this.AudioDataReceivedFromGuest = new EventDescriptor(0x47, 0, 0, 0, 0, 0, 0L);
this.AudioGlitch = new EventDescriptor(0x48, 0, 0, 0, 0, 0, 0L);
this.AudioPaused = new EventDescriptor(0x49, 0, 0, 0, 0, 0, 0L);
this.AudioResumed = new EventDescriptor(0x4a, 0, 0, 0, 0, 0, 0L);
this.AudioDeviceChange = new EventDescriptor(0x4b, 0, 0, 0, 0, 0, 0L);
this.MicrophoneCaptureThreadStarted = new EventDescriptor(0x4c, 0, 0, 0, 0, 0, 0L);
this.MicrophoneCaptureThreadExited = new EventDescriptor(0x4d, 0, 0, 0, 0, 0, 0L);
this.MicrophoneDataSentToGuest = new EventDescriptor(0x4e, 0, 0, 0, 0, 0, 0L);
this.MicrophoneDeviceChange = new EventDescriptor(0x4f, 0, 0, 0, 0, 0, 0L);
this.GetNetworkInfoFailed = new EventDescriptor(90, 0, 0, 2, 0, 0, 0L);
this.IPRenewalInitiated = new EventDescriptor(0x5b, 0, 0, 4, 0, 0, 0L);
}
Hyper-V ホスト OS からのイベントのログ記録
WP8 JIT がどのようにアセンブリするか、またはいつガベージ コレクションを行うかについて詳しく知りたいとしましょう。VS2012 には、その情報をプロファイリング、保存、表示する分析ツールが付属しています。たとえば、プロファイリング セッションを開始する方法は次のとおりです。
プロファイリング セッションが完了すると、アプリの下の "PerfLogs" フォルダーにプロファイリング セッションのデータがあることがわかります。CPU/Execution をプロファイリングした場合、そのフォルダーに VSPX ファイルが表示されます。VSPX ファイルの名前を ZIP に変更し、含まれているファイルを抽出します。その ZIP に ETL ファイルがあります。その ETL ファイルは、PerfView で調べることができるもう 1 つの ETW ログです。
このような ETL ファイルを PerfView で開くと、各クラスが JITTed された時期、所要時間、IL とネイティブのサイズを確認できます。たとえば、アプリの App クラスは 123.461 ミリ秒で JITT され、1.2 ミリ秒で IL サイズが 105 でネイティブ サイズが 289 でした。
VS2012 を使用してそのデータをキャプチャする代わりに、プロファイリング API を直接使用することもできます。それをやりたい場合は、VS2012 の SilverlightProfiler.*.dll アセンブリをリバース エンジニアリングして、何を行っているかを確認し、VS2012 の外部で再作成する必要があります。
私は、しばらくの間、デバッガーを接続せずに WP8 エミュレーターでアプリの実行を追跡するコンソールまたはその他の方法を探していました。Hyper-V VM で実行されているため、コンソールが使用できなくなったようです。
しかし、私は少し回避策を見つけました。メッセージをアプリの分離ストレージに記録する単純なクラスを作成できます (分離ストレージの詳細はこちら)。アプリを実行した後、Windows Phone Power Toolsを使用して分離ストレージのコンテンツを調べることができます(幸いなことに、「更新」オプションがあるため、エミュレーターでいくつかのアクションを実行してから、分離ストレージを修正することができます)。