I moved the the "Generation" enum to ClrMD itself. It's far more useful (and accurate) to talk about an object's generation as a member of an enum which describes it rather than a simple integer. This change flowed through the SOS commands which used ClrSegment.GetGeneration.
I manually tested all commands affected.
<Uri>https://github.com/dotnet/symstore</Uri>
<Sha>e09f81a0b38786cb20f66b589a8b88b6997a62da</Sha>
</Dependency>
- <Dependency Name="Microsoft.Diagnostics.Runtime" Version="3.0.0-beta.23177.1">
+ <Dependency Name="Microsoft.Diagnostics.Runtime" Version="3.0.0-beta.23205.1">
<Uri>https://github.com/microsoft/clrmd</Uri>
- <Sha>e61e6bdb23739ad2c59616b6c8d6659f4558c88d</Sha>
+ <Sha>3368bf4451a9441076595022fdff0f2bbea57b1b</Sha>
</Dependency>
- <Dependency Name="Microsoft.Diagnostics.Runtime.Utilities" Version="3.0.0-beta.23177.1">
+ <Dependency Name="Microsoft.Diagnostics.Runtime.Utilities" Version="3.0.0-beta.23205.1">
<Uri>https://github.com/microsoft/clrmd</Uri>
- <Sha>e61e6bdb23739ad2c59616b6c8d6659f4558c88d</Sha>
+ <Sha>3368bf4451a9441076595022fdff0f2bbea57b1b</Sha>
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
<SystemReflectionMetadataVersion>5.0.0</SystemReflectionMetadataVersion>
<!-- Other libs -->
<MicrosoftBclAsyncInterfacesVersion>1.1.0</MicrosoftBclAsyncInterfacesVersion>
- <MicrosoftDiagnosticsRuntimeVersion>3.0.0-beta.23177.1</MicrosoftDiagnosticsRuntimeVersion>
+ <MicrosoftDiagnosticsRuntimeVersion>3.0.0-beta.23205.1</MicrosoftDiagnosticsRuntimeVersion>
<MicrosoftDiaSymReaderNativePackageVersion>16.9.0-beta1.21055.5</MicrosoftDiaSymReaderNativePackageVersion>
<MicrosoftDiagnosticsTracingTraceEventVersion>3.0.7</MicrosoftDiagnosticsTracingTraceEventVersion>
<!-- Use pinned version to avoid picking up latest (which doesn't support netcoreapp3.1) during source-build -->
group ptr by ptr into g
orderby g.Count() descending
select g.First()).First();
-
- internal static Generation GetGeneration(this ClrObject obj, ClrSegment knownSegment)
- {
- if (knownSegment is null)
- {
- knownSegment = obj.Type.Heap.GetSegmentByAddress(obj);
- if (knownSegment is null)
- {
- return Generation.Error;
- }
- }
-
- if (knownSegment.Kind == GCSegmentKind.Ephemeral)
- {
- return knownSegment.GetGeneration(obj) switch
- {
- 0 => Generation.Gen0,
- 1 => Generation.Gen1,
- 2 => Generation.Gen2,
- _ => Generation.Error
- };
- }
-
- return knownSegment.Kind switch
- {
- GCSegmentKind.Generation0 => Generation.Gen0,
- GCSegmentKind.Generation1 => Generation.Gen1,
- GCSegmentKind.Generation2 => Generation.Gen2,
- GCSegmentKind.Large => Generation.Large,
- GCSegmentKind.Pinned => Generation.Pinned,
- GCSegmentKind.Frozen => Generation.Frozen,
- _ => Generation.Error
- };
- }
}
}
Console.CancellationToken.ThrowIfCancellationRequested();
// This handles both regions and segments
- Generation gen = obj.GetGeneration(seg);
- if (gen is not Generation.Gen0 or Generation.Gen1)
+ Generation gen = seg.GetGeneration(obj);
+ if (gen is not Generation.Generation0 or Generation.Generation1)
{
continue;
}
continue;
}
- Generation refGen = objRef.GetGeneration(null);
- if (refGen == Generation.Large)
+ if (GetGenerationWithoutSegment(objRef) == Generation.Large)
{
yield return (obj, objRef);
}
continue;
}
- Generation refGen = objRef.GetGeneration(null);
- if (refGen is Generation.Gen0 or Generation.Gen1)
+ if (GetGenerationWithoutSegment(objRef) is Generation.Generation0 or Generation.Generation1)
{
yield return (obj, objRef);
}
}
}
}
+
+ private Generation GetGenerationWithoutSegment(ClrObject obj)
+ {
+ ClrSegment seg = Runtime.Heap.GetSegmentByAddress(obj);
+ if (seg is not null)
+ {
+ return seg.GetGeneration(obj);
+ }
+
+ return Generation.Unknown;
+ }
}
}
Console.CancellationToken.ThrowIfCancellationRequested();
// Skip this object if it's gen0 or we hit an error
- Generation objGen = obj.GetGeneration(seg);
- if (objGen is Generation.Gen0 or Generation.Error)
+ Generation objGen = seg.GetGeneration(obj);
+ if (objGen is Generation.Generation0 or Generation.Unknown)
{
continue;
}
ulong refObjSize = objRef.Size;
- Generation refGen = objRef.GetGeneration(null);
+ ClrSegment refSeg = Runtime.Heap.GetSegmentByAddress(objRef);
+ Generation refGen = refSeg?.GetGeneration(objRef) ?? Generation.Unknown;
switch (refGen)
{
- case Generation.Gen0:
+ case Generation.Generation0:
gen0 ??= new EphemeralRefCount()
{
Object = obj,
break;
- case Generation.Gen1:
- if (objGen > Generation.Gen1)
+ case Generation.Generation1:
+ if (objGen > Generation.Generation1)
{
gen1 ??= new EphemeralRefCount()
{
continue;
}
- GenerationInfo gen = seg.GetGeneration(obj) switch
+ GenerationInfo genInfo = result.GetInfoByGeneration(seg.GetGeneration(obj));
+ if (genInfo is not null)
{
- 0 => result.Gen0,
- 1 => result.Gen1,
- _ => result.Gen2,
- };
-
- if (obj.IsFree)
- {
- result.Ephemeral.Free += obj.Size;
- gen.Free += obj.Size;
- }
- else
- {
- gen.Allocated += obj.Size;
-
- if (IncludeUnreachable && !LiveObjects.IsLive(obj))
+ if (obj.IsFree)
+ {
+ result.Ephemeral.Free += obj.Size;
+ genInfo.Free += obj.Size;
+ }
+ else
{
- gen.Unrooted += obj.Size;
+ genInfo.Allocated += obj.Size;
+
+ if (IncludeUnreachable && !LiveObjects.IsLive(obj))
+ {
+ genInfo.Unrooted += obj.Size;
+ }
}
}
}
Frozen = left.Frozen + right.Frozen,
};
}
+
+ public GenerationInfo GetInfoByGeneration(Generation gen)
+ {
+ return gen switch
+ {
+ Generation.Generation0 => Gen0,
+ Generation.Generation1 => Gen1,
+ Generation.Generation2 => Gen2,
+ Generation.Large => LoH,
+ Generation.Pinned => PoH,
+ Generation.Frozen => Frozen,
+ _ => null
+ };
+ }
}
private sealed class GenerationInfo
{
generation = "reserve";
}
- else if (segment.Kind == GCSegmentKind.Frozen)
- {
- generation = "frozen";
- }
- else if (segment.Kind == GCSegmentKind.Pinned)
- {
- generation = "pinned";
- }
- else if (segment.Kind == GCSegmentKind.Large)
- {
- generation = "large";
- }
else
{
- int gen = segment.GetGeneration(address);
- generation = gen != -1 ? gen.ToString() : "???";
+ generation = segment.GetGeneration(address) switch
+ {
+ Generation.Generation0 => "0",
+ Generation.Generation1 => "1",
+ Generation.Generation2 => "2",
+ Generation.Frozen => "frozen",
+ Generation.Pinned => "pinned",
+ Generation.Large => "large",
+ _ => "???",
+ };
}
object addressColumn = segment.ObjectRange.Contains(address) ? new DmlListNearObj(address) : address;
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.Diagnostics.ExtensionCommands
-{
- internal enum Generation
- {
- Gen0,
- Gen1,
- Gen2,
- Large,
- Pinned,
- Frozen,
- Error,
- }
-}
public override void Invoke()
{
- SizeStats(Generation.Gen0, isFree: false);
- SizeStats(Generation.Gen1, isFree: false);
- SizeStats(Generation.Gen2, isFree: false);
+ SizeStats(Generation.Generation0, isFree: false);
+ SizeStats(Generation.Generation1, isFree: false);
+ SizeStats(Generation.Generation2, isFree: false);
SizeStats(Generation.Large, isFree: false);
bool hasPinned = Runtime.Heap.Segments.Any(seg => seg.Kind == GCSegmentKind.Pinned);
SizeStats(Generation.Frozen, isFree: false);
}
- SizeStats(Generation.Gen0, isFree: true);
- SizeStats(Generation.Gen1, isFree: true);
- SizeStats(Generation.Gen2, isFree: true);
+ SizeStats(Generation.Generation0, isFree: true);
+ SizeStats(Generation.Generation1, isFree: true);
+ SizeStats(Generation.Generation2, isFree: true);
SizeStats(Generation.Large, isFree: true);
if (hasPinned)
// If Kind == Ephemeral, we have to further filter by object generation
if (seg.Kind == GCSegmentKind.Ephemeral)
{
- if (obj.GetGeneration(seg) != requestedGen)
+ if (seg.GetGeneration(obj) != requestedGen)
{
continue;
}
{
return seg.Kind switch
{
- GCSegmentKind.Ephemeral => gen <= Generation.Gen2,
- GCSegmentKind.Generation0 => gen == Generation.Gen0,
- GCSegmentKind.Generation1 => gen == Generation.Gen1,
- GCSegmentKind.Generation2 => gen == Generation.Gen2,
+ GCSegmentKind.Ephemeral => gen <= Generation.Generation2,
+ GCSegmentKind.Generation0 => gen == Generation.Generation0,
+ GCSegmentKind.Generation1 => gen == Generation.Generation1,
+ GCSegmentKind.Generation2 => gen == Generation.Generation2,
GCSegmentKind.Frozen => gen == Generation.Frozen,
GCSegmentKind.Pinned => gen == Generation.Pinned,
GCSegmentKind.Large => gen == Generation.Large,