Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/livecharts merged into master #10

Merged
merged 37 commits into from
Nov 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
85b6bb8
WPF app initial commit
kkokosa Oct 21, 2017
890264a
WPF app added to solution
kkokosa Oct 22, 2017
d19c000
WPF app initial commit
kkokosa Oct 21, 2017
506cac1
WPF app added to solution
kkokosa Oct 22, 2017
673a091
Merge branch 'feature/livecharts' of https://github.com/kkokosa/Tune …
kkokosa Oct 30, 2017
a51a91d
Mystical licenses changes
kkokosa Oct 30, 2017
8305215
WPF version - initial commit
kkokosa Oct 30, 2017
70d9880
WPF version - initial layout
kkokosa Oct 30, 2017
34a8066
WPF version - MVVM framework initial commit
kkokosa Oct 30, 2017
05cb46d
WPF version - AvalonEdit MVVM binding
kkokosa Oct 30, 2017
2e4af0f
WPF version - AvalonEdit MVVM binding fixes
kkokosa Oct 30, 2017
1bb7716
Build configuration cleanup
kkokosa Oct 30, 2017
d453715
WPF MVVM binding improvements
kkokosa Oct 30, 2017
96eef40
WPF MVVM simple file commands binding
kkokosa Oct 31, 2017
aff643a
WPF MVVM binding setters changed
kkokosa Nov 2, 2017
9e70671
WPF MVVM - dispatcher logic removed (WPF automatically dispatches the…
kkokosa Nov 2, 2017
9380c42
WPF MVVM messaging added
kkokosa Nov 2, 2017
73a4567
WPF MVVM project split
kkokosa Nov 2, 2017
e7e0e3d
WPF added LiveCharts
kkokosa Nov 2, 2017
b8ab0be
WPF LiveCharts - initial sample usage
kkokosa Nov 2, 2017
597d98a
WPF LiveCharts - initial ETW data graphs
kkokosa Nov 2, 2017
08b76ee
WPF LiveCharts - data graphs in progress
kkokosa Nov 2, 2017
0d50daa
WPF LiveCharts - graphs region for GC added
kkokosa Nov 2, 2017
0956c28
WPF LiveCharts - graph regions fixed
kkokosa Nov 3, 2017
3d878ad
WPF LiveCharts - ETW data filtering
kkokosa Nov 3, 2017
5d96702
WPF LiveCharts - time data changed
kkokosa Nov 3, 2017
43e9d58
WPF LiveCharts - ETW events table added
kkokosa Nov 3, 2017
bf16695
WPF LiveCharts - ETW events table small fix
kkokosa Nov 3, 2017
3be4853
ETW collector refactoring
kkokosa Nov 3, 2017
0be1603
File experiment handling - load, save, save as...
kkokosa Nov 3, 2017
eb5695f
ETW generation ranges collection
kkokosa Nov 3, 2017
d6884c1
WPF fix for read-only properties killing application
kkokosa Nov 3, 2017
680a275
ETW session changed to file-based
kkokosa Nov 3, 2017
712b55b
ETW session changed to file-based - processing
kkokosa Nov 3, 2017
e74bbba
Small UI tweaks
kkokosa Nov 3, 2017
c996020
Table with GCStarts added
kkokosa Nov 3, 2017
179df77
Documentation changes
kkokosa Nov 3, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ As you can see, it is using parts of [SharpDevelop](http://www.icsharpcode.net/)
Requirements:
* Visual Studio 2015
* [Debugging Tools for Windows](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/) installed - look at post-build event
* [DevExpress](https://www.devexpress.com/Products/NET/Controls/WinForms/) installed - trial is enough (this dependency will be removed shortly)

If you do not want to install trial of DevExpress to build Tune, you may download compiled program from:

* [Tune 0.2 (Release x64)](https://1drv.ms/u/s!ApZOZuEUCC2DjZhc0vmj9P-6JCmqOQ)

Additional info and examples:
* [The Ultimate .NET Experiment – open source project](http://tooslowexception.com/the-ultimate-net-experiment-project/)
163 changes: 163 additions & 0 deletions Tune.Core/Collectors/ClrEtwCollector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Etlx;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Parsers.Clr;
using Microsoft.Diagnostics.Tracing.Session;

namespace Tune.Core.Collectors
{
// https://github.com/Microsoft/dotnet-samples/blob/master/Microsoft.Diagnostics.Tracing/TraceEvent/TraceEvent/40_SimpleTraceLog.cs
class ClrEtwCollector : IDisposable
{
private readonly List<ClrEtwGcData> gcData = new List<ClrEtwGcData>();
private readonly List<ClrEtwHeapStatsData> heapStatsData = new List<ClrEtwHeapStatsData>();
private readonly List<ClrEtwGenerationData>[] generationsData = new List<ClrEtwGenerationData>[]
{
new List<ClrEtwGenerationData>(),
new List<ClrEtwGenerationData>(),
new List<ClrEtwGenerationData>(),
new List<ClrEtwGenerationData>()
};
private const string providerName = "Microsoft-Windows-DotNETRuntime";
private const string sessionName = "Tune-DotNetRuntimeSession";

private bool stopped;
private TraceEventSession session;
private TraceEventSession kernelSession;

public void Start()
{
RunAsync();
}

public void Stop()
{
using (var rundownSession = new TraceEventSession(sessionName + "Rundown", "data.clrRundown.etl"))
{
rundownSession.EnableProvider(ClrRundownTraceEventParser.ProviderGuid, TraceEventLevel.Verbose,
(ulong) ClrRundownTraceEventParser.Keywords.Default);
// Poll until 2 second goes by without growth.
for (var prevLength = new FileInfo("data.clrRundown.etl").Length;;)
{
Thread.Sleep(2000);
var newLength = new FileInfo("data.clrRundown.etl").Length;
if (newLength == prevLength) break;
prevLength = newLength;
}
}

// TODO: Currenty not aware of any more sophisticated control, when hosting sub-process it will wait for timeout without new events after sub-process ends
//Thread.Sleep(4000);
stopped = true;
session?.Dispose();
kernelSession?.Dispose();
TraceEventSession.MergeInPlace("data.etl", TextWriter.Null);

//var traceLog = TraceLog.OpenOrConvert("data.etl");
//var simpleTraceLogProcess = traceLog.Processes.LastProcessWithID(Process.GetCurrentProcess().Id);
//foreach (var data in simpleTraceLogProcess.EventsInProcess)
//{
//}

using (var source = new ETWTraceEventSource("data.etl"))
{
source.Clr.GCHeapStats += ClrOnGcHeapStats;
source.Clr.GCStart += ClrOnGcStart;
source.Clr.GCStop += ClrOnGcStop;
source.Clr.GCGenerationRange += ClrOnGcGenerationRange;
source.Process();
}
}

public List<ClrEtwHeapStatsData> HeapStatsData => this.heapStatsData;
public List<ClrEtwGcData> GcData => this.gcData;
public List<ClrEtwGenerationData>[] GenerationsData => this.generationsData;

private void RunAsync()
{
var elevated = TraceEventSession.IsElevated();

var eventSourceGuid = TraceEventProviders.GetProviderGuidByName(providerName);
session = new TraceEventSession(sessionName, "data.etl");
kernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName, "data.kernel.etl");

kernelSession.EnableKernelProvider(KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread);

var optionsWithStacks = new TraceEventProviderOptions() { StacksEnabled = true };
session.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)ClrTraceEventParser.Keywords.Default);
session.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)ClrTraceEventParser.Keywords.GC, optionsWithStacks);
}

private void ClrOnGcGenerationRange(GCGenerationRangeTraceData evt)
{
if (!IsTargetProcess(evt)) return;

this.generationsData[evt.Generation].Add(new ClrEtwGenerationData()
{
Index = evt.EventIndex,
TimeStamp = evt.TimeStamp,
Start = evt.RangeStart,
Used = evt.RangeUsedLength,
Reserved = evt.RangeReservedLength,
});
}

private void ClrOnGcStop(GCEndTraceData evt)
{
if (!IsTargetProcess(evt)) return;

}

private void ClrOnGcStart(GCStartTraceData evt)
{
if (!IsTargetProcess(evt)) return;

gcData.Add(new ClrEtwGcData()
{
Index = evt.EventIndex,
TimeStamp = evt.TimeStamp,
Generation = evt.Depth,
Reason = evt.Reason,
Type = evt.Type,
Description = $"Count: {evt.Count}"
});
}

private void ClrOnGcHeapStats(GCHeapStatsTraceData evt)
{
if (!IsTargetProcess(evt)) return;

heapStatsData.Add(new ClrEtwHeapStatsData()
{
Index = evt.EventIndex,
TimeStamp = evt.TimeStamp,
GenerationSize0 = evt.GenerationSize0,
GenerationSize1 = evt.GenerationSize1,
GenerationSize2 = evt.GenerationSize2,
GenerationSize3 = evt.GenerationSize3,
Description = $"TID: {evt.ThreadID}"
});
}

private bool IsTargetProcess(TraceEvent evt)
{
return Process.GetCurrentProcess().Id == evt.ProcessID;
}

public void Dispose()
{
if (!stopped)
{
Stop();
}
}
}
}
20 changes: 20 additions & 0 deletions Tune.Core/Collectors/ClrEtwGcData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Parsers.Clr;

namespace Tune.Core.Collectors
{
public class ClrEtwGcData
{
public DateTime TimeStamp { get; set; }
public string Description { get; set; }
public EventIndex Index { get; set; }
public int Generation { get; set; }
public GCReason Reason { get; set; }
public GCType Type { get; set; }
}
}
18 changes: 18 additions & 0 deletions Tune.Core/Collectors/ClrEtwGenerationData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing;

namespace Tune.Core.Collectors
{
public class ClrEtwGenerationData
{
public DateTime TimeStamp { get; set; }
public ulong Start { get; set; }
public ulong Used { get; set; }
public ulong Reserved { get; set; }
public EventIndex Index { get; set; }
}
}
20 changes: 20 additions & 0 deletions Tune.Core/Collectors/ClrEtwHeapStatsData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing;

namespace Tune.Core.Collectors
{
public class ClrEtwHeapStatsData
{
public DateTime TimeStamp { get; set; }
public long GenerationSize0 { get; set; }
public long GenerationSize1 { get; set; }
public long GenerationSize2 { get; set; }
public long GenerationSize3 { get; set; }
public string Description { get; set; }
public EventIndex Index { get; set; }
}
}
18 changes: 17 additions & 1 deletion Tune.Core/DiagnosticAssembly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tune.Core.Collectors;

namespace Tune.Core
{
Expand Down Expand Up @@ -61,7 +62,18 @@ public string Execute(string argument)
TextWriter programWriter = new StringWriter();
Console.SetOut(programWriter);
this.engine.UpdateLog($"Invoking method {mi.Name} with argument {argument}");
result = mi.Invoke(obj, new object[] { argument });

using (var collector = new ClrEtwCollector())
{
collector.Start();
result = mi.Invoke(obj, new object[] {argument});
collector.Stop();

this.HeapStatsData = collector.HeapStatsData;
this.GcData = collector.GcData;
this.GenerationsData = collector.GenerationsData;
}

this.engine.UpdateLog($"Script result: {result}");
this.engine.UpdateLog("Script log:");
this.engine.UpdateLog(programWriter.ToString());
Expand All @@ -74,6 +86,10 @@ public string Execute(string argument)
}
}

public List<ClrEtwGenerationData>[] GenerationsData { get; set; } = new List<ClrEtwGenerationData>[4];

public List<ClrEtwHeapStatsData> HeapStatsData { get; private set; } = new List<ClrEtwHeapStatsData>();
public List<ClrEtwGcData> GcData { get; private set; } = new List<ClrEtwGcData>();
public string DumpIL()
{
TextWriter ilWriter = new StringWriter();
Expand Down
55 changes: 55 additions & 0 deletions Tune.Core/Tune.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand All @@ -21,6 +23,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
Expand All @@ -29,6 +32,43 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="ICSharpCode.Decompiler, Version=2.3.1.1855, Culture=neutral, PublicKeyToken=d4bfe873e7598c49, processorArchitecture=MSIL">
Expand Down Expand Up @@ -63,6 +103,10 @@
<HintPath>..\packages\Microsoft.Diagnostics.Runtime.0.9.170809.03\lib\net40\Microsoft.Diagnostics.Runtime.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Diagnostics.Tracing.TraceEvent, Version=1.0.41.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil, Version=0.9.5.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.5.4\lib\net40\Mono.Cecil.dll</HintPath>
<Private>True</Private>
Expand Down Expand Up @@ -179,6 +223,10 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Collectors\ClrEtwGenerationData.cs" />
<Compile Include="Collectors\ClrEtwHeapStatsData.cs" />
<Compile Include="Collectors\ClrEtwCollector.cs" />
<Compile Include="Collectors\ClrEtwGcData.cs" />
<Compile Include="DiagnosticAssembly.cs" />
<Compile Include="DiagnosticEngine.cs" />
<Compile Include="NativeTarget.cs" />
Expand All @@ -194,6 +242,13 @@
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.2.3.0-beta1\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets" Condition="Exists('..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
Expand Down
1 change: 1 addition & 0 deletions Tune.Core/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<package id="Microsoft.CodeAnalysis.Common" version="2.3.2" targetFramework="net46" />
<package id="Microsoft.CodeAnalysis.CSharp" version="2.3.2" targetFramework="net46" />
<package id="Microsoft.Diagnostics.Runtime" version="0.9.170809.03" targetFramework="net46" />
<package id="Microsoft.Diagnostics.Tracing.TraceEvent" version="1.0.41" targetFramework="net46" />
<package id="Mono.Cecil" version="0.9.5.4" targetFramework="net46" />
<package id="SharpDisasm" version="1.1.5" targetFramework="net46" />
<package id="System.AppContext" version="4.3.0" targetFramework="net46" />
Expand Down
Loading