High-performance tracing for C++ Windows/Windows Phone 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.
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:
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)'.
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.
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
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.
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'.
TextAnalysisTool.NET can quickly filter and color traces using string patterns. See this blog for more details.