Skip to content

Latest commit

 

History

History
150 lines (102 loc) · 5.88 KB

README.md

File metadata and controls

150 lines (102 loc) · 5.88 KB

NuGet package

WPP Tracing for C++ Universal Store apps

The Windows trace PreProcessor (WPP) provides high-performance tracing for C++ apps. It has low impact on binary size and CPU usage -- even when tracing is turned on -- which makes it suitable for both Debug and Release builds. It is however difficult to set up, especially in Universal Windows/Windows Phone Store apps. This project tries to address that issue.

Initial setup

Start by installing the WPP Tracing NuGet package. The package adds a header to the VS project (TraceWpp\TraceWpp.h) and an MSBuild target generating .tmh trace headers during the build. Also install the WDK to get required WPP config files.

If using GIT, add '*.tmh' to .gitignore to avoid checking-in generated headers.

Then create a GUID to identify the trace provider via the 'Tools > Create GUID' menu in Visual Studio. In the following {B5DBB673-AB73-48A3-B004-B8902FA191C3} is used as provider GUID.

In the pch.h precompiled header define the trace provider:

// {B5DBB673-AB73-48A3-B004-B8902FA191C3}
#define TraceWpp_Guid (B5DBB673,AB73,48A3,B004,B8902FA191C3)

#define WPP_CONTROL_GUIDS \
    WPP_DEFINE_CONTROL_GUID(TraceWpp_CtrlGuid, TraceWpp_Guid, \
    WPP_DEFINE_BIT(TF_Default) \
    WPP_DEFINE_BIT(TF_EntryExit))

#include "TraceWpp\TraceWpp.h"

TraceWpp.h defines a set of tracing macros:

  • Trace
  • TraceFlag
  • TraceLevel
  • TraceHr
  • TraceScope
  • TraceScopeCx
  • TraceScopeHr

The first four provide printf-style traces with various parameters. The last three trace function calls.

In each cpp file add as last include the trace header generated by the preprocessor. Its filename is the cpp file name with a '.tmh' extension appended to it.

#include "TraceWpp\foo.cpp.tmh"   

When creating a Store app, add the following code to initialize and shut down the trace provider (replacing 'AppName' with some appropriate value):

App::App()
{
    WPP_INIT_TRACING(L"AppName");
    Trace(L"@%p Starting", (void*)this);
}

void App::OnSuspending(Object^ /*sender*/, SuspendingEventArgs^ /*e*/)
{
    Trace(L"@%p Stopping", (void*)this);
    WPP_CLEANUP();
}

When creating a Windows Runtime Component DLL, add a file called module.cpp to the VS project with the following content (replacing 'DllName' with some appropriate value):

#include "pch.h"
#include "TraceWpp\module.cpp.tmh"

BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
{
    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(instance);
        WPP_INIT_TRACING(L"DllName");
        Trace(L"@ DLL_PROCESS_ATTACH");
        break;

    case DLL_PROCESS_DETACH:
        Trace(L"@ DLL_PROCESS_DETACH");
        WPP_CLEANUP();
        break;
    }

    return TRUE;
}

In VS projects targetting Windows, add advapi32.lib as imported static lib under 'Configuration Properties > Linker > Input > Additional Dependencies'. In Windows Phone VS projects the required static libs are already properly imported.

Disable 'Edit and Continue' used in Debug builds as this breaks WPP trace macro generation: under 'Configuration Properties > C/C++ > General > Debug Information Format' replace 'Program Database for Edit And Continue (/ZI)' by 'Program Database (/Zi)'.

Adding traces

Trace macros use format strings similar to printf():

Trace(L"@%p Starting", this);

One caveat: for C++/CX objects the this pointer needs to be cast to void* in trace calls.

Recording traces

Windows

The logman.exe tool under %windir%\system32 turns trace providers on and off. To start tracing run the following command in an elevated command prompt:

logman.exe create trace mytrace -p {B5DBB673-AB73-48A3-B004-B8902FA191C3} 0xff 5 -ets -o trace.etl

Replacing the '-p' option by '-pf' allows controlling more than one provider. The list of providers is stored in a config file with one set of 'GUID flags level' per line.

To stop tracing run

logman.exe stop mytrace -ets

Windows Phone

Field Medic records traces on Windows Phone. For more details see this blog. A WPRP profile controlling the trace provider defined above is available here.

Formatting traces

Once recorded, traces need to be converted from binary trace files (.etl) to text files (.log). The process is the same whether traces were recorded on Windows or Windows Phone.

Two tools are needed from the Windows SDK: tracepdb.exe and tracefmt.exe. They are located in '%ProgramFiles%\Windows Kits\8.1\bin\x86' on 32b machines and in '%ProgramFiles(x86)%\Windows Kits\8.1\bin\x64' on 64b machines.

First extract .tmf trace format files from .pdb symbol files:

tracepdb.exe -f *.pdb -p c:\Symbols\TraceFormat

Then format the .etl binary traces into text traces:

set TRACE_FORMAT_SEARCH_PATH=c:\Symbols\TraceFormat
set TRACE_FORMAT_PREFIX=[%9!d!]%8!04X!.%3!04X! %4!s! %!FUNC!
tracefmt.exe -f trace.etl -o trace.log

The TRACE_FORMAT_PREFIX environment variable can be customized using the format specifiers documented here. The format used above is '[CpuNumber]ProcessID.ThreadID Time FunctionName'.

Analysing traces

TextAnalysisTool.NET can quickly filter and color traces using string patterns. See this blog for more details.