* Read dotnet memory counter to know if the current memory consumptions goes above the specified threshold
* Generate the actual core dump
-Let's start with the first requirement, reading dotnet counters. As explained earlier, we can use the EventPipe mechanism to read counters from the runtime. In this case, the provider that writes counter events is System.Runtime. Below is the code that
-sets up the System.Runtime provider for use in our tool (for brevity, error checking has been excluded):
+Let's start with the first requirement, reading dotnet counters. As explained earlier, we can use the EventPipe mechanism to read counters from the runtime. In this case, the provider that writes counter events is System.Runtime.
-```csharp
-CounterProvider provider=null;
-KnownData.TryGetProvider("System.Runtime", out provider);
-string prov = provider.ToProviderString(1);
-```
-The above code attempts to get the System.Runtime provider which we will need in the next section of code that configures and starts the counter collection:
+[Full code](src/triggerdump/Program.cs)
+
+Below is the releveant code snippet that is required to consume the counters:
```csharp
Task monitorTask = new Task(() =>
{
- var configuration = new SessionConfiguration(circularBufferSizeMB: 1000, outputPath: "", providers: Trace.Extensions.ToProviders(prov.ToString()));
-
+ var prov = new List<Provider>();
+ prov.Add(new Provider("System.Runtime", filterData:"EventCounterIntervalSec=1"));
+
+ var configuration = new SessionConfiguration(
+ circularBufferSizeMB: 1000,
+ outputPath: "",
+ providers: prov);
+
var binaryReader = EventPipeClient.CollectTracing(Int32.Parse(args[0]), configuration, out _sessionId);
EventPipeEventSource source = new EventPipeEventSource(binaryReader);
source.Dynamic.All += Dynamic_All;
source.Process();
-});
+});
```
+
The above code first creates the configuration and specifying the buffer size, output path and finally the System.Runtime provider that we are interested in. Next, it calls the CollectTracing method specifying the process identifier we are interested in tracing, the configuration and an out session ID. Once that is completed, we create an EventPipeSource from the reader created in the previous step and attach a callback that will be invoked as the events are delivered over EventPipe. Last, we call the Process method to start processing the events. At this point, the Dynamic_All method will be invoked anytime an event comes through from the System.Runtime provider.
Now that we have the events flowing through out callback, let's turn our attention to the callback itself and how we can get the counter information:
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Microsoft.Diagnostics.Tools.Counters
-{
- public class CounterProvider
- {
- public string Name { get; }
- public string Description { get; }
- public string Keywords { get; }
- public string Level { get; }
- public Dictionary<string, CounterProfile> Counters { get; }
-
- public CounterProvider(string name, string description, string keywords, string level, IEnumerable<CounterProfile> counters)
- {
- Name = name;
- Description = description;
- Keywords = keywords;
- Level = level;
- Counters = new Dictionary<string, CounterProfile>();
- foreach (CounterProfile counter in counters)
- {
- Counters.Add(counter.Name, counter);
- }
- }
-
- public string TryGetDisplayName(string counterName)
- {
- if (Counters.ContainsKey(counterName))
- return Counters[counterName].DisplayName;
- return null;
- }
-
- public string ToProviderString(int interval)
- {
- return $"{Name}:{Keywords}:{Level}:EventCounterIntervalSec={interval}";
- }
-
- public static string SerializeUnknownProviderName(string unknownCounterProviderName, int interval)
- {
- return $"{unknownCounterProviderName}:ffffffff:4:EventCounterIntervalSec={interval}";
- }
-
- public IReadOnlyList<CounterProfile> GetAllCounters() => Counters.Values.ToList();
-
- }
-
- public class CounterProfile
- {
- public string Name { get; set; }
- public string DisplayName { get; set; }
- public string Description { get; set; }
- }
-}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.Tracing;
-using System.Linq;
-using Microsoft.Diagnostics.Tracing.Parsers;
-
-namespace Microsoft.Diagnostics.Tools.Counters
-{
- internal static class KnownData
- {
- private static readonly IReadOnlyDictionary<string, CounterProvider> _knownProviders =
- CreateKnownProviders().ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
-
-
- private static IEnumerable<CounterProvider> CreateKnownProviders()
- {
- yield return new CounterProvider(
- "System.Runtime", // Name
- "A default set of performance counters provided by the .NET runtime.", // Description
- "0xffffffff", // Keywords
- "5", // Level
- new[] { // Counters
- new CounterProfile{ Name="cpu-usage", Description="Amount of time the process has utilized the CPU (ms)", DisplayName="CPU Usage (%)" },
- new CounterProfile{ Name="working-set", Description="Amount of working set used by the process (MB)", DisplayName="Working Set (MB)" },
- new CounterProfile{ Name="gc-heap-size", Description="Total heap size reported by the GC (MB)", DisplayName="GC Heap Size (MB)" },
- new CounterProfile{ Name="gen-0-gc-count", Description="Number of Gen 0 GCs / sec", DisplayName="Gen 0 GC / sec" },
- new CounterProfile{ Name="gen-1-gc-count", Description="Number of Gen 1 GCs / sec", DisplayName="Gen 1 GC / sec" },
- new CounterProfile{ Name="gen-2-gc-count", Description="Number of Gen 2 GCs / sec", DisplayName="Gen 2 GC / sec" },
- new CounterProfile{ Name="exception-count", Description="Number of Exceptions / sec", DisplayName="Exceptions / sec" },
- });
- // TODO: Add more providers (ex. ASP.NET ones)
- }
-
- public static IReadOnlyList<CounterProvider> GetAllProviders() => _knownProviders.Values.ToList();
-
- public static bool TryGetProvider(string providerName, out CounterProvider provider) => _knownProviders.TryGetValue(providerName, out provider);
- }
-}
// See the LICENSE file in the project root for more information.
using System;
-using System.CommandLine;
-using System.CommandLine.Builder;
-using System.CommandLine.Invocation;
using System.Diagnostics;
using System.Linq;
using System.Threading;
{
pid = Convert.ToInt32(args[0]);
threshold = Convert.ToInt32(args[1]);
- CounterProvider provider=null;
- StringBuilder sb = new StringBuilder("");
- KnownData.TryGetProvider("System.Runtime", out provider);
- string prov=provider.ToProviderString(1);
Task monitorTask = new Task(() =>
{
+ var prov = new List<Provider>();
+ prov.Add(new Provider("System.Runtime", filterData:"EventCounterIntervalSec=1"));
+
var configuration = new SessionConfiguration(
circularBufferSizeMB: 1000,
outputPath: "",
- providers: Trace.Extensions.ToProviders(prov));
-
+ providers: prov);
var binaryReader = EventPipeClient.CollectTracing(Int32.Parse(args[0]), configuration, out _sessionId);
EventPipeEventSource source = new EventPipeEventSource(binaryReader);
<TargetFramework>netcoreapp2.1</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ToolCommandName>triggerdump</ToolCommandName>
- <RootNamespace>Diagnostics.TriggerDump</RootNamespace>
+ <RootNamespace>Diagnosticv.TriggerDump</RootNamespace>
<Description>Trigger dump</Description>
<PackageTags>Diagnostic</PackageTags>
<PackageReleaseNotes>$(Description)</PackageReleaseNotes>
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="$(MSBuildThisFileDirectory)..\..\..\..\src\Microsoft.Diagnostic.Repl\Microsoft.Diagnostic.Repl.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)..\..\..\..\src\Microsoft.Diagnostics.Tools.RuntimeClient\Microsoft.Diagnostics.Tools.RuntimeClient.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.41" />
</ItemGroup>
-
</Project>