Skip to content

Commit

Permalink
-Extract/Dump ObjectRef Improvements (#89)
Browse files Browse the repository at this point in the history
* Fix: -Extract ObjectRef does not keep names of leaked handles which were never closed.
* Added -MinMaxTime filter for -dump ObjectRef
* Updated to v3.0.0.9
  • Loading branch information
Alois-xx authored Jun 24, 2024
1 parent 4208e91 commit 7863343
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 4 deletions.
12 changes: 11 additions & 1 deletion ETWAnalyzer/Commands/DumpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,13 +397,14 @@ class DumpCommand : ArgParser
" ObjectRef -filedir/fd Extract\\ or xx.json7z" + Environment.NewLine +
" [-TimeFmt s,Local,LocalTime,UTC,UTCTime,Here,HereTime] [-csv xx.csv] [-NoCSVSeparator] [-NoCmdLine] [-Clip] [-TestsPerRun dd -SkipNTests dd] [-TestRunIndex dd -TestRunCount dd] [-MinMaxMsTestTimes xx-yy ...] [-ProcessName/pn xx.exe(pid)] " + Environment.NewLine +
" [-RelatedProcess xx.exe(pid)] [-MinMaxDuration minS [maxS]] [-MinMaxId min [max]] [-CreateStack filter] [-DestroyStack filter] [-StackFilter filter] [-Object filter] [-ObjectName filter] [-Handle filter] [-ShowRef]" + Environment.NewLine +
" [-ShowStack] [-Type filter] [-Leak] [-MultiProcess] [-Map [0,1]] [-PtrInMap 0x...] [-MinMaxMapSize min [max]] [-Overlapped] [-Showtotal Total,File,None]" + Environment.NewLine +
" [-ShowStack] [-Type filter] [-Leak] [-MultiProcess] [-Map [0,1]] [-PtrInMap 0x...] [-MinMaxMapSize min [max]] [-MinMaxTime min [max]] [-Overlapped] [-Showtotal Total,File,None]" + Environment.NewLine +
" [-NewProcess 0/1/-1/-2/2] [-PlainProcessNames] [-CmdLine substring]" + Environment.NewLine;
static readonly string ObjectRefHelpString = ObjectRefHelpStringHeader +
" -ProcessName/pn xx.exe(pid) Filter for processes which did create the object." + Environment.NewLine +
" -RelatedProcess xx.exe(pid) Filter in all events for this process. You can also use a negative filter to exclude specific processes like -pn *creator.exe -realatedprocess !other.exe" + Environment.NewLine +
" -MinMaxDuration minS [maxS] Filter for handle lifetime. Never closed handles get a lifetime of 9999 s which serves as magic marker value." + Environment.NewLine +
" -MinMaxId min [max] Filter for one or a range of objects. E.g. -MinMaxId 500 600 to filter for all object events with id 500-600. The ids are sorted by object creation time." + Environment.NewLine +
" -MinMaxTime min [max] Remove all events which are not within time filter. Time is specified in ETW session time in seconds." +Environment.NewLine +
" -CreateStack filter Keep all object events (create/objRef/duplicate...) where the create stack matches." + Environment.NewLine +
" -DestroyStack filter Keep all object events (create/objRef/duplicate...) where the destroy stack matches." + Environment.NewLine +
" -StackFilter filter Keep only the events where the stack matches and throw away all other events. To keep all events which have e.g. CreateWebRequest in their stack use -StackFilter *CreateWebRequest*" + Environment.NewLine +
Expand Down Expand Up @@ -883,6 +884,8 @@ internal enum ZeroTimeModes
public KeyValuePair<string, Func<string, bool>> StackFilter { get; private set; } = new(null, _ => true);
public KeyValuePair<string, Func<string, bool>> TypeFilter { get; private set; } = new(null, _ => true);

public MinMaxRange<double> MinMaxTime { get; private set; } = new();

// Dump Exception specific Flags
public bool FilterExceptions { get; private set; }

Expand Down Expand Up @@ -1562,6 +1565,12 @@ public override void Parse()
Tuple<double, double> minMaxTimeMsDouble = minTimeMs.GetMinMaxDouble(maxTimeMs, MSUnit);
MinMaxTimeMs = new MinMaxRange<double>(minMaxTimeMsDouble.Item1, minMaxTimeMsDouble.Item2);
break;
case "-minmaxtime":
string minTime = GetNextNonArg("-minmaxtime");
string maxTime = GetNextNonArg("-minmaxtime", false); // optional
Tuple<double, double> minMaxTimeDouble = minTime.GetMinMaxDouble(maxTime, 1);
MinMaxTime = new MinMaxRange<double>(minMaxTimeDouble.Item1, minMaxTimeDouble.Item2);
break;
case "-minmaxtotaltimems":
string minTotalTimeMs = GetNextNonArg("-minmaxtimems");
string maxTotalTimeMs = GetNextNonArg("-minmaxtimems", false); // optional
Expand Down Expand Up @@ -2474,6 +2483,7 @@ public override void Run()
ViewBaseFilter = ViewBaseFilter,
HandleFilter = HandleFilter,
MinMaxDurationS = MinMaxDurationS,
MinMaxTime = MinMaxTime,
ShowStack = ShowStack,
ShowRef = ShowRef,
Leak = Leak,
Expand Down
4 changes: 3 additions & 1 deletion ETWAnalyzer/Documentation/DumpObjectRefCommand.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ reason we have 108 Create handle calls which is disturbing because this means th

Before diving deeper lets explain what data is shown:

The Id is a unique number which can be used with ```-MinMaxId``` filter to select a specific object instance or a range of them. The kernel object pointer is printed, but
The Id is a unique number which can be used with ```-MinMaxId``` filter to select a specific object instance or a range of them. You can also filter by time with ```-MinMaxTime min max``` which
will throw away all events not passing the time filter. Time is entered in ETW session time in seconds since trace start (use ```-Timefmt s``` to display instead of local time).
The kernel object pointer is printed, but
this value can be reused so it is not always unique (can be filtered with ```-Object``` filter). After the kernel pointer the object name (can be filtered with ```-ObjectName``` filter) is printed, if present. Then the object
lifetime is printed or 9999s is used to mark objects which were never closed (can be filtered with ```-MinMaxDuration```).
Then the individual events grouped by type sorted by time are printed. Each line contains
Expand Down
2 changes: 1 addition & 1 deletion ETWAnalyzer/ETWAnalyzer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<PackageProjectUrl>https://github.com/Siemens-Healthineers/ETWAnalyzer</PackageProjectUrl>
<PackageReadmeFile>ProgramaticAccess.md</PackageReadmeFile>
<Version>3.0.0.8</Version>
<Version>3.0.0.9</Version>
<Platforms>x64</Platforms>
<ServerGarbageCollection>true</ServerGarbageCollection>
<GarbageCollectionAdaptationMode>1</GarbageCollectionAdaptationMode>
Expand Down
34 changes: 34 additions & 0 deletions ETWAnalyzer/EventDump/DumpObjectRef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public string HandleType
public bool Inherit { get; internal set; }
public KeyValuePair<string, Func<string, bool>> TypeFilter { get; internal set; }
public SkipTakeRange TopN { get; internal set; } = new();
public MinMaxRange<double> MinMaxTime { get; internal set; }

Dictionary<StackIdx, bool> myStackFilterResult = new();

Expand Down Expand Up @@ -312,6 +313,16 @@ private List<MatchData> ReadFileData()
}
}


if( !MinMaxTime.IsDefault )
{
ThrowAwayAllEventsNotMatchingTimeFilter(MinMaxTime, handle);
if( handle.IsEmpty )
{
continue;
}
}

if( StackFilter.Key != null)
{
ThrowAwayAllEventsWithNotMatchingStacks(stacks, handle);
Expand Down Expand Up @@ -434,6 +445,7 @@ private List<MatchData> ReadFileData()
}



private void HarmonizeFilterSettings()
{
if (HandleFilter.Key != null || ObjectNameFilter.Key != null) // disable map events when handle specific filters are enabled
Expand Down Expand Up @@ -583,6 +595,28 @@ private void ThrowAwayAllEventsWithNotMatchingStacks(IStackCollection stacks, Ob
handle.FileUnmapEvents = handle.FileUnmapEvents.Where(x => CachingStackFilter(stacks, x.StackIdx)).ToList();
}

private void ThrowAwayAllEventsNotMatchingTimeFilter(MinMaxRange<double> minMaxTime, ObjectRefTrace handle)
{
const double Giga = 1_000_000_000.0d;
if ( handle.CreateEvent != null && !minMaxTime.IsWithin(handle.CreateEvent.TimeNs/Giga) )
{
handle.CreateEvent = null;
}

if( handle.DestroyEvent != null && !minMaxTime.IsWithin(handle.DestroyEvent.TimeNs/Giga) )
{
handle.DestroyEvent = null;
}

Func<StackEventBase, bool> timeFilter = x => minMaxTime.IsWithin(x.TimeNs / Giga);
handle.HandleCreateEvents = handle.HandleCreateEvents.Where(timeFilter).Cast<HandleCreateEvent>().ToList();
handle.HandleCloseEvents = handle.HandleCloseEvents.Where(timeFilter).Cast<HandleCloseEvent>().ToList();
handle.HandleDuplicateEvents = handle.HandleDuplicateEvents.Where(timeFilter).Cast<HandleDuplicateEvent>().ToList();
handle.RefChanges = handle.RefChanges.Where(timeFilter).Cast<RefCountChangeEvent>().ToList();
handle.FileMapEvents = handle.FileMapEvents.Where(timeFilter).Cast<FileMapEvent>().ToList();
handle.FileUnmapEvents = handle.FileUnmapEvents.Where(timeFilter).Cast<FileUnmapEvent>().ToList();
}

class Totals
{
public int ObjectCreateCount { get; internal set; }
Expand Down
4 changes: 4 additions & 0 deletions ETWAnalyzer/Extractors/Handle/ObjectRefExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,10 @@ public override void Extract(ITraceProcessor processor, ETWExtract results)
};
OpenHandles.Add(hTrace.ObjectPtr, hTrace);
}
else
{
hTrace.Name = dcEnd.Name; // when no handle close handle was called add object name form DCEndEvent
}

if( hTrace.Existing == null )
{
Expand Down
2 changes: 1 addition & 1 deletion ETWAnalyzer/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("3.0.0.8")]
[assembly: AssemblyFileVersion("3.0.0.9")]

0 comments on commit 7863343

Please sign in to comment.