Skip to content

Commit

Permalink
improvements for usage in PowerShell
Browse files Browse the repository at this point in the history
  • Loading branch information
lowleveldesign committed Mar 12, 2017
1 parent 2526353 commit 1a6f99a
Show file tree
Hide file tree
Showing 9 changed files with 25 additions and 79 deletions.
34 changes: 5 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@

# wtrace

This application will trace in real-time all File I/O, TCP IP, ALPC and RPC operations performed by a given process. It works on Windows 7+ and requires .NET 4.5.2+. Wtrace stops when the traced process exits, or if you issue Ctrl+C (Ctrl+Break in Powershell, when pipes are used) in its command line.
This application will trace in real-time all File I/O, TCP IP, ALPC and RPC operations performed by a given process. It works on Windows 7+ and requires .NET 4.5.2+. Wtrace stops when the traced process exits, or if you issue Ctrl+C in its command line.

Use pipeline to filter the events, e.g.: `wtrace notepad | findstr "FileIO/Write"`

It is possible to use wtrace as a **PowerShell cmdlet**. Please check the [wiki](https://github.com/lowleveldesign/wtrace/wiki/PowerShell-support) for more details.

The available options are:

Expand All @@ -10,7 +14,6 @@ Usage: wtrace [OPTIONS] pid|imagename args
Options:
--newconsole Start the process in a new console window.
--summary Prints only a summary of the collected trace.
--nosummary Prints only ETW events - no summary at the end.
-h, --help Show this message and exit
-? Show this message and exit
Expand Down Expand Up @@ -44,33 +47,6 @@ PS temp> wtrace mspaint
1385,3323 (1072) FileIO/Read '' (0xFFFFFA801FDBFCD0) 0x5C200 16384b
2318,6876 (1072) FileIO/Read '' (0xFFFFFA80230F5970) 0x209400 32768b
2319,3279 (1072) FileIO/Read '' (0xFFFFFA80230F5970) 0x213400 32768b
### Stopping ETW session...
======= ETW session =======
### ETW session stopped. Number of lost events: 0
======= System Configuration =======
Host: TEST (test.example.com)
CPU: 2793MHz 8cores 32382MB
LOGICAL DISK: 0 C: NTFS 238GB
NIC: VirtualBox Host-Only Ethernet Adapter fe80::9d86:1063:fe66:ef0b;169.254.239.11
NIC: Software Loopback Interface 1 ::1;127.0.0.1
======= File I/O =======
File name Writes / Reads (bytes)
C:\Windows\SysWOW64\mspaint.exe 0 / 12 759 040
0 / 1 905 760
C:\Windows\SysWOW64\MFC42u.dll 0 / 455 728
C:\Windows\SysWOW64\sti.dll 0 / 431 472
C:\Windows\SysWOW64\UIRibbon.dll 0 / 412 016
C:\Windows\SysWOW64\UIRibbonRes.dll 0 / 255 088
C:\Windows\SysWOW64\en-US\UIRibbon.dll.mui 0 / 179 312
C:\Windows\win.ini 0 / 516
C:\Windows\Fonts\staticcache.dat 0 / 60
C:\ProgramData\NVIDIA Corporation\Drs\nvdrssel.bin 0 / 1
======= Process/Thread =======
Number of child processes started: 0
Number of threads started: 7
```

**Please visit the project [wiki](https://github.com/lowleveldesign/wtrace/wiki) to learn more**
Expand Down
9 changes: 2 additions & 7 deletions wtrace/Handlers/AlpcTraceEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ class AlpcTraceEventHandler : ITraceEventHandler
private readonly Dictionary<int, Tuple<int, string, int>> sentMessages = new Dictionary<int, Tuple<int, string, int>>();
private readonly HashSet<string> connectedProcesses = new HashSet<string>();

private TraceEventSource traceEventSource;

public AlpcTraceEventHandler(int pid, ITraceOutput output)
{
traceOutput = output;
Expand All @@ -30,8 +28,6 @@ public void SubscribeToEvents(TraceEventParser parser)
//kernel.ALPCUnwait += HandleALPCUnwait;
//kernel.ALPCWaitForNewMessage += HandleALPCWaitForNewMessage;
kernel.ALPCWaitForReply += HandleALPCWaitForReply;

traceEventSource = parser.Source;
}

private void HandleALPCWaitForReply(ALPCWaitForReplyTraceData data)
Expand Down Expand Up @@ -73,14 +69,13 @@ private void UpdateCache(int processId, string processName, int threadId, int me
}
}

public void PrintStatistics()
public void PrintStatistics(double sessionEndTimeInMs)
{
if (connectedProcesses.Count == 0) {
return;
}
Debug.Assert(traceEventSource != null);
foreach (var process in connectedProcesses) {
traceOutput.Write(traceEventSource.SessionEndTimeRelativeMSec, pid, 0, "Summary/ALPC", $"endpoint: {process}");
traceOutput.Write(sessionEndTimeInMs, pid, 0, "Summary/ALPC", $"endpoint: {process}");
}
}
}
Expand Down
9 changes: 2 additions & 7 deletions wtrace/Handlers/FileIOTraceEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ class FileIoSummary
private readonly Dictionary<ulong, string> fileObjectToFileNameMap = new Dictionary<ulong, string>();
private readonly Dictionary<string, FileIoSummary> fileIoSummary = new Dictionary<string, FileIoSummary>();

private TraceEventSource traceEventSource;

public FileIOTraceEventHandler(int pid, ITraceOutput output)
{
traceOutput = output;
Expand All @@ -49,18 +47,15 @@ public void SubscribeToEvents(TraceEventParser parser)
kernel.FileIORead += HandleFileIoReadWrite;
kernel.FileIOWrite += HandleFileIoReadWrite;
kernel.FileIOMapFile += HandleFileIoMapFile;

traceEventSource = parser.Source;
}

public void PrintStatistics()
public void PrintStatistics(double sessionEndTimeInMs)
{
if (fileIoSummary.Count == 0) {
return;
}
Debug.Assert(traceEventSource != null);
foreach (var summary in fileIoSummary.OrderByDescending(kv => kv.Value.Total)) {
traceOutput.Write(traceEventSource.SessionEndTimeRelativeMSec, pid, 0,
traceOutput.Write(sessionEndTimeInMs, pid, 0,
"Summary/FileIO", $"{summary.Key} W: {summary.Value.Write:#,0} b / R: {summary.Value.Read:#,0} b");
}
}
Expand Down
2 changes: 1 addition & 1 deletion wtrace/Handlers/ITraceEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ public interface ITraceEventHandler
{
void SubscribeToEvents(TraceEventParser parser);

void PrintStatistics();
void PrintStatistics(double sessionEndTimeInMs);
}
}
9 changes: 2 additions & 7 deletions wtrace/Handlers/NetworkTraceEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ class NetworkIoSummary
private readonly int pid;
private readonly Dictionary<string, NetworkIoSummary> networkIoSummary = new Dictionary<string, NetworkIoSummary>();

private TraceEventSource traceEventSource;

public NetworkTraceEventHandler(int pid, ITraceOutput output)
{
traceOutput = output;
Expand Down Expand Up @@ -58,18 +56,15 @@ public void SubscribeToEvents(TraceEventParser parser)
kernel.TcpIpSendIPV6 += HandleTcpIpV6Send;
kernel.TcpIpTCPCopy += HandleTcpIp;
kernel.TcpIpTCPCopyIPV6 += HandleTcpIpV6;

traceEventSource = parser.Source;
}

public void PrintStatistics()
public void PrintStatistics(double sessionEndTimeInMs)
{
if (networkIoSummary.Count == 0) {
return;
}
Debug.Assert(traceEventSource != null);
foreach (var summary in networkIoSummary.OrderByDescending(kv => kv.Value.Total)) {
traceOutput.Write(traceEventSource.SessionEndTimeRelativeMSec, pid, 0, "Summary/Network",
traceOutput.Write(sessionEndTimeInMs, pid, 0, "Summary/Network",
$"{summary.Key} --> S: {summary.Value.Send:#,0} b / R: {summary.Value.Recv:#,0} b");
}
}
Expand Down
11 changes: 3 additions & 8 deletions wtrace/Handlers/ProcessThreadsTraceEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,17 @@ sealed class ProcessThreadsTraceEventHandler : ITraceEventHandler
private int noOfChildProcessesStarted = 0;
private int noOfThreadStarted = 0;

private TraceEventSource traceEventSource;

public ProcessThreadsTraceEventHandler(int pid, ITraceOutput output)
{
traceOutput = output;
this.pid = pid;
}

public void PrintStatistics()
public void PrintStatistics(double sessionEndTimeInMs)
{
Debug.Assert(traceEventSource != null);
traceOutput.Write(traceEventSource.SessionEndTimeRelativeMSec, pid, 0, "Summary/Process",
traceOutput.Write(sessionEndTimeInMs, pid, 0, "Summary/Process",
$"Number of child processes started: {noOfChildProcessesStarted}");
traceOutput.Write(traceEventSource.SessionEndTimeRelativeMSec, pid, 0, "Summary/Thread",
traceOutput.Write(sessionEndTimeInMs, pid, 0, "Summary/Thread",
$"Number of threads started: {noOfThreadStarted}");
}

Expand All @@ -36,8 +33,6 @@ public void SubscribeToEvents(TraceEventParser parser)
var kernel = (KernelTraceEventParser)parser;
kernel.ProcessStart += HandleProcessStart;
kernel.ThreadStart += HandleThreadStart;

traceEventSource = parser.Source;
}

private void HandleThreadStart(ThreadTraceData data)
Expand Down
14 changes: 3 additions & 11 deletions wtrace/Handlers/RpcTraceEventHandler.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
using LowLevelDesign.WinTrace.Tracing;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Parsers.MicrosoftWindowsRPC;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

namespace LowLevelDesign.WinTrace.Handlers
Expand All @@ -18,22 +15,19 @@ sealed class RpcTraceEventHandler : ITraceEventHandler
private readonly Dictionary<Tuple<Guid, string, int>, Tuple<int, int>> awaitingClientCalls = new Dictionary<Tuple<Guid, string, int>, Tuple<int, int>>();
private readonly Dictionary<Guid, string> rpcActivity = new Dictionary<Guid, string>();

private TraceEventSource traceEventSource;

public RpcTraceEventHandler(int pid, ITraceOutput output)
{
traceOutput = output;
this.pid = pid;
}

public void PrintStatistics()
public void PrintStatistics(double sessionEndTimeInMs)
{
if (rpcSummary.Count == 0) {
return;
}
Debug.Assert(traceEventSource != null);
foreach (var summary in rpcSummary.AsEnumerable().OrderByDescending(kv => kv.Value)) {
traceOutput.Write(traceEventSource.SessionEndTimeRelativeMSec, pid, 0, "Summary/RPC",
traceOutput.Write(sessionEndTimeInMs, pid, 0, "Summary/RPC",
$"endpoint: {summary.Key}, connections: {summary.Value}");
}
}
Expand All @@ -45,8 +39,6 @@ public void SubscribeToEvents(TraceEventParser parser)
rpcParser.RpcClientCallStop += RpcClientCallStop;
rpcParser.RpcServerCallStart += RpcServerCallStart;
rpcParser.RpcServerCallStop += RpcServerCallStop;

traceEventSource = parser.Source;
}

private void RpcServerCallStop(RpcServerCallStopArgs data)
Expand Down
9 changes: 2 additions & 7 deletions wtrace/Handlers/SystemConfigTraceEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ class SystemConfigTraceEventHandler : ITraceEventHandler
private readonly ITraceOutput output;
private readonly List<string> buffer = new List<string>();

private TraceEventSource traceEventSource;

public SystemConfigTraceEventHandler(int pid, ITraceOutput output)
{
this.pid = pid;
Expand All @@ -26,15 +24,12 @@ public void SubscribeToEvents(TraceEventParser parser)
kernel.SystemConfigCPU += Kernel_SystemConfigCPU;
kernel.SystemConfigNIC += HandleConfigNIC;
kernel.SystemConfigLogDisk += Kernel_SystemConfigLogDisk;

traceEventSource = parser.Source;
}

public void PrintStatistics()
public void PrintStatistics(double sessionEndTimeInMs)
{
Debug.Assert(traceEventSource != null);
foreach (var ev in buffer) {
output.Write(traceEventSource.SessionEndTimeRelativeMSec, pid, 0, "Summary/SysConfig", ev);
output.Write(sessionEndTimeInMs, pid, 0, "Summary/SysConfig", ev);
}
}

Expand Down
7 changes: 5 additions & 2 deletions wtrace/Tracing/TraceCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace LowLevelDesign.WinTrace.Tracing
Expand All @@ -14,6 +13,7 @@ abstract class TraceCollector : IDisposable

protected readonly TraceEventSession traceSession;
protected readonly List<ITraceEventHandler> eventHandlers;
protected readonly Stopwatch sw = new Stopwatch();

public TraceCollector(TraceEventSession session)
{
Expand All @@ -23,6 +23,7 @@ public TraceCollector(TraceEventSession session)

public void Start()
{
sw.Start();
traceSession.Source.Process();
}

Expand All @@ -34,6 +35,8 @@ public void Stop(bool printSummary)
Trace.WriteLine($"### Stopping {traceSession.SessionName} session...");
traceSession.Stop();

sw.Stop();

// This timeout is needed to handle all the DCStop events
// (in case we ever are going to do anything about them)
Thread.Sleep(1500);
Expand All @@ -42,7 +45,7 @@ public void Stop(bool printSummary)

if (printSummary) {
foreach (var handler in eventHandlers) {
handler.PrintStatistics();
handler.PrintStatistics(sw.Elapsed.TotalMilliseconds);
}
}
}
Expand Down

0 comments on commit 1a6f99a

Please sign in to comment.