Skip to content

Commit

Permalink
Make trace starting more robust
Browse files Browse the repository at this point in the history
Starting of ETW tracing will fail if there is another trace running with
the same kernel logger (and there are only two), with the same name for
a user logger sesion, or if the file names being used for tracing to a
file are in use. This means that starting tracing will fail if it wasn't
stopped for some reason (UIforETW crash perhaps) and tracing may fail
if some other program happens to be using the same file or session
names. These start failures are not self healing - repeated attempts to
start tracing will repeatedly fail. Previously UIforETW dealt with this
by printing a message suggesting that you stop tracing. This didn't
always work.

This change makes trace starting far more robust by unilaterally
stopping all trace sessions that UIforETW might use. This change also
changes the session names and file names to make them less likely to
collide.

If this doesn't work then changing the kernel logger using the checkbox
added in the previous change may help.
  • Loading branch information
Bruce Dawson committed Nov 20, 2016
1 parent 6368343 commit 092fa4d
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 10 deletions.
7 changes: 4 additions & 3 deletions UIforETW/ChildProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ limitations under the License.

static const wchar_t* kPipeName = L"\\\\.\\PIPE\\UIforETWPipe";

ChildProcess::ChildProcess(std::wstring exePath)
: exePath_(std::move(exePath))
ChildProcess::ChildProcess(std::wstring exePath, bool printFailedExitCodes)
: exePath_(std::move(exePath)), printFailedExitCodes_(printFailedExitCodes)
{
// Create the pipe here so that it is guaranteed to be created before
// we try starting the process.
Expand All @@ -44,8 +44,9 @@ ChildProcess::~ChildProcess()
{
if (hProcess_)
{
// Always get the exit code since this also waits for the process to exit.
DWORD exitCode = GetExitCode();
if (exitCode)
if (printFailedExitCodes_ && exitCode)
outputPrintf(L"Process exit code was %08x (%lu)\n", exitCode, exitCode);
CloseHandle(hProcess_);
}
Expand Down
5 changes: 4 additions & 1 deletion UIforETW/ChildProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ limitations under the License.
class ChildProcess
{
public:
ChildProcess(std::wstring exePath);
ChildProcess(std::wstring exePath, bool printFailedExitCodes = true);
// This waits for the child process to terminate, and prints
// output with outputPrintf as it arrives.
~ChildProcess();
Expand All @@ -56,6 +56,9 @@ class ChildProcess
private:
// Path to the executable to be run, and its process handle.
std::wstring exePath_;

bool printFailedExitCodes_ = true;

// Process, thread, and event handles have an uninitialized state
// of zero. Pipes and files have an uninitialized state of
// INVALID_HANDLE_VALUE. Yay Windows!
Expand Down
15 changes: 12 additions & 3 deletions UIforETW/UIforETWDlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,15 @@ void CUIforETWDlg::OnBnClickedStarttracing()
else
UIETWASSERT(0);

{
// Force any existing sessions to stop. This makes starting tracing much more robust.
// Never show the commands executing, and never print the exit code.
ChildProcess child(GetXperfPath(), false);
child.Run(false, L"xperf.exe -stop UIforETWHeapSession -stop UIforETWSession -stop " + GetKernelLogger());
// Swallow all of the output so that the normal failures will be silent.
child.GetOutput();
}

std::wstring kernelProviders = L" Latency+POWER+DISPATCHER+DISK_IO_INIT+FILE_IO+FILE_IO_INIT+VIRT_ALLOC+MEMINFO";
if (!extraKernelFlags_.empty())
kernelProviders += L"+" + extraKernelFlags_;
Expand Down Expand Up @@ -1030,7 +1039,7 @@ void CUIforETWDlg::OnBnClickedStarttracing()
std::wstring heapStackWalk;
if (bHeapStacks_)
heapStackWalk = L" -stackwalk HeapCreate+HeapDestroy+HeapAlloc+HeapRealloc";
std::wstring heapArgs = L" -start xperfHeapSession -heap -Pids 0" + heapStackWalk + heapBuffers + heapFile;
std::wstring heapArgs = L" -start UIforETWHeapSession -heap -Pids 0" + heapStackWalk + heapBuffers + heapFile;

DWORD exitCode = 0;
bool started = true;
Expand Down Expand Up @@ -1158,7 +1167,7 @@ void CUIforETWDlg::StopTracingAndMaybeRecord(bool bSaveTrace)
if (tracingMode_ == kHeapTracingToFile)
{
ETWMark("Tracing type was heap tracing to file.");
child.Run(bShowCommands_, L"xperf.exe -stop xperfHeapSession -stop UIforETWSession -stop " + GetKernelLogger());
child.Run(bShowCommands_, L"xperf.exe -stop UIforETWHeapSession -stop UIforETWSession -stop " + GetKernelLogger());
}
else
{
Expand Down Expand Up @@ -1430,7 +1439,7 @@ void CUIforETWDlg::UpdateTraceList()
tempTraces.insert(tempTraces.end(), tempZips.begin(), tempZips.end());
std::sort(tempTraces.begin(), tempTraces.end());
// Function to stop the temporary traces from showing up.
auto ifInvalid = [](const std::wstring& name) { return name == L"kernel.etl" || name == L"user.etl" || name == L"heap.etl"; };
auto ifInvalid = [](const std::wstring& name) { return name == L"UIForETWkernel.etl" || name == L"UIForETWuser.etl" || name == L"UIForETWheap.etl"; };
tempTraces.erase(std::remove_if(tempTraces.begin(), tempTraces.end(), ifInvalid), tempTraces.end());
for (auto& name : tempTraces)
{
Expand Down
6 changes: 3 additions & 3 deletions UIforETW/UIforETWDlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,9 @@ class CUIforETWDlg : public CDialog
// the same result across multiple calls!
std::wstring GenerateResultFilename() const;
std::wstring GetTempTraceDir() const { return tempTraceDir_; }
std::wstring GetKernelFile() const { return CUIforETWDlg::GetTempTraceDir() + L"kernel.etl"; }
std::wstring GetUserFile() const { return GetTempTraceDir() + L"user.etl"; }
std::wstring GetHeapFile() const { return GetTempTraceDir() + L"heap.etl"; }
std::wstring GetKernelFile() const { return CUIforETWDlg::GetTempTraceDir() + L"UIForETWkernel.etl"; }
std::wstring GetUserFile() const { return GetTempTraceDir() + L"UIForETWuser.etl"; }
std::wstring GetHeapFile() const { return GetTempTraceDir() + L"UIForETWheap.etl"; }

// Get session name for kernel logger
const std::wstring NTKernelLogger_ = L"\"NT Kernel Logger\"";
Expand Down

0 comments on commit 092fa4d

Please sign in to comment.