Using ETW Events within a Windows Phone 8 Application

The sample code used in this article can be found here and is based on the standard “Windows Phone Direct 3D with XAML App” project template from Visual Studio.

The Manifest

Your ETW manifest is an XML file which defines what your events look like so that event viewers can intelligently display your events once you've collected them in a log.

Windows Phone uses the same manifests as Windows, so the regular documentation applies:

The sample manifest that we'll be using can be downloaded directly.


Provider GUID

If you're developing a regular application you will want to use the developer GUID for your provider: 7A68C8E0-BE90-4039-9048-2A69F64BDF3C

If you're writing a library you're going to want to select your own GUID that doesn't clash with the standard app developer one and then publicize it so that developers can collect it when they use your library.

 

Compiling the Manifest

In order to decode your events from the ETL (Event Trace Log) the system needs to read your manifest out of a binary that has your manifest compiled into it as a resource. While you can register arbitrary providers (and their associated manifests) on your local machine, you can't do this on the Phone, so the Phone won't be able to recognize your events. To work around this we will be post-processing your events on your local machine using an x86 (or x64) resource only dll that includes your manifest.

  1. First, add a new project to your solution:

    File -> Add -> New Project -> Other Languages -> Visual C++ -> Win32 -> Win32 Project

    While the name is generally unimportant for clarity sake we’ll go with the name of the provider, In this case "Phone-Direct3DXaml-App"
  2. In the wizard select an "Application Type" of "DLL", "Empty Project" and clear any other check boxes:

    clip_image001
  3. Add the manifest to your project (so that it appears in your solution and you can edit it in VS)
  4. Add the following pre-build command (substitute your manifest name:

    mc -um Phone-Direct3DXaml-App.man

    clip_image002
  5. Specify the "No Entry Point" option in the linker (since this will be a resource only dll):

    clip_image003
  6. Make sure the project is set to build with everything else by going to Build -> Configuration Manager and selecting "Build" next to your project:
clip_image004

 

Registering Your Manifest

Registering your manifest on your local machine allows you to decode your events so that they don't show up as "unknown". If you run VS as admin you can have you can do this as part of the compile step, otherwise you can do it manually using the same commands as below (just expand the paths): 

  1. Right click your project -> Properties -> Config… -> Build Events -> Post-Build Events -> Command Line (hit the little down arrow and click <edit>)
  2. Paste in the follow lines:

    wevtutil um "$(ProjectDir)Phone-Direct3DXaml-App.man"
    wevtutil im $(ProjectDir)Phone-Direct3DXaml-App.man /mf:"$(TargetPath)" /rf:"$(TargetPath)"


    clip_image005

    The above lines unregister your provider (which may, or may not already be registered) and then reregister it providing full paths to your resource dll. Unregistering is required to update your provider with any new changes you may have made.
  3. Next, make sure that the resource project is set to build first in your solution (so that it generates it's files before anyone can use them) by right clicking on your solution -> Project Build Order -> Dependencies. Under your native project select the manifest project and then verify in the "Build Order" tab that it will build first.
clip_image006

clip_image007

 

Finally

So we have our resource events, now, let's use them!

  1. Optional Step - easy header access:
    1. Add the header file generated from your manfiest to your project. If you are using the above steps to compile your manifest then you should find the header in the root of your manifest project. The file will be added with a small link icon to indicate that the file is in a different location to the rest of your project files

      clip_image008
    2. In case you ever change anything, and so that you don't have to #include the full path to the header file every time create a EtwEvents.h file that includes your generated header file:

      #pragma once 
      #include "..\..\Phone-Direct3DXaml-App\Phone-Direct3DXaml-App.h"
  2. Add a call to the EventRegister* macro before using any of the marker macros for the first time
  3. Add a call to the EventUnregister* macro during your shutdown code
  4. You can now include "EtwEvents.h" wherever needed and simply call EventWrite<func> (you can find the names in your ETW header).

 

Writing Events from Managed Code

Our first order of business will be creating a WinRT class to expose the events to Managed code:

  1. Right click on your existing Native WinRT project (or, if you don't have one, add a new one) -> Add -> Class.
  2. In the wizard give your class whatever name you like (we'll be using Etw)
  3. Since we need this to be a WinRT class you'll need to sprinkle some WinRT sugar around your class definition (Etw.h) to make it visible to managed code. At the same time we're going to make the constructor private and remove the destructor since the Etw class won't maintain any state and all of its members will be static.

    #pragma once

    #include "EtwEvents.h"

    namespace PhoneDirect3DXamlAppComponent
    {

    public ref class Etw sealed
    {

    private:

      Etw() {};

    public:

    };

    }

    Don’t forget to add the namespace declaration to Etw.cpp as well.

  4. Now add functions for provider registration and deregistration and a function that represents each event macro in your header (search for "EventWrite").

    Recommendation: make your functions static (which matches the private constructor above) so that you don't have to instantiate the Etw object everywhere.

    Etw.h

    #pragma once

    #include "EtwEvents.h"

    namespace PhoneDirect3DXamlAppComponent
    {

    public ref class Etw sealed
    {
    private:
      Etw() {};

    public:
      static void
    RegisterProvider();
      static void UnregisterProvider();
      static void WriteInitialized();
      static void WriteFramerate(float fps);
      static void WriteFrameStart();
      static void WriteFrameEnd();

    };

    }

    Etw.cpp:

    #include "pch.h"

    #include "Etw.h"

    namespace PhoneDirect3DXamlAppComponent
    {

    void Etw::RegisterProvider()
    {
      EventRegisterPhone_Direct3DXaml_App();
    }

    void Etw::UnregisterProvider() |
    {
      EventUnregisterPhone_Direct3DXaml_App();
    }

    void Etw::WriteInitialized()
    {
      EventWriteInitialized();
    }

    void Etw::WriteFramerate(float fps)
    {
      EventWriteFramerate(fps);
    }

    void Etw::WriteFrameStart()
    {
      EventWriteFrameStart();
    }

    void Etw::WriteFrameEnd()
    {
      EventWriteFrameEnd();
    }

    }


    Word to the wise: your function names cannot match your task names. In the example above you cannot have a function named simply "Initialized" since that is the same name as one of my tasks (you'll know you've done this when you get Template cast errors).
  5. Now, in your app constructor / initializer code you can run Etw.RegisterProvider() and in your shutdown code you can call Etw.UnregisterProvider().

And we’re done!

Last edited May 20, 2013 at 8:48 AM by nachmore, version 9

Comments

No comments yet.