Skip to content

Commit 5f87c67

Browse files
committed
HeapInfo and RecyclerSweep refactoring.
1 parent 9ef05c7 commit 5f87c67

28 files changed

+1807
-1081
lines changed

lib/Common/CommonMinMemory.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ class FinalizableObject;
3333
#include "Memory/SmallFinalizableHeapBucket.h"
3434
#include "Memory/LargeHeapBucket.h"
3535
#include "Memory/HeapInfo.h"
36+
#include "Memory/HeapInfoManager.h"
3637

3738
#include "Memory/HeapBlockMap.h"
3839
#include "Memory/RecyclerObjectDumper.h"
3940
#include "Memory/RecyclerWeakReference.h"
4041
#include "Memory/RecyclerSweep.h"
42+
#include "Memory/RecyclerSweepManager.h"
4143
#include "Memory/RecyclerHeuristic.h"
4244
#include "Memory/MarkContext.h"
4345
#include "Memory/MarkContextWrapper.h"

lib/Common/ConfigFlagsList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,7 @@ FLAGNR(Number, MinBailOutsBeforeRejit, "Minimum number of bailouts for a single
13771377
FLAGNR(Number, MinBailOutsBeforeRejitForLoops, "Minimum number of bailouts for a single bailout record after which a rejit is considered", DEFAULT_CONFIG_MinBailOutsBeforeRejitForLoops)
13781378
FLAGNR(Boolean, LibraryStackFrame , "Display library stack frame", DEFAULT_CONFIG_LibraryStackFrame)
13791379
FLAGNR(Boolean, LibraryStackFrameDebugger , "Assume debugger support for library stack frame", DEFAULT_CONFIG_LibraryStackFrameDebugger)
1380+
FLAGNR(Number, RecyclerIsolatedHeapStress, "Stress allocation on isolated heap", 2)
13801381
#ifdef RECYCLER_STRESS
13811382
FLAGNR(Boolean, RecyclerStress , "Stress the recycler by collect on every allocation call", false)
13821383
#if ENABLE_CONCURRENT_GC
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
namespace Memory
6+
{
7+
8+
#ifdef DUMP_FRAGMENTATION_STATS
9+
template <ObjectInfoBits TBucketType>
10+
struct DumpBucketTypeName { static char16 name[]; };
11+
template<> char16 DumpBucketTypeName<NoBit>::name[] = _u("Normal ");
12+
template<> char16 DumpBucketTypeName<LeafBit>::name[] = _u("Leaf ");
13+
template<> char16 DumpBucketTypeName<FinalizeBit>::name[] = _u("Fin ");
14+
#ifdef RECYCLER_WRITE_BARRIER
15+
template<> char16 DumpBucketTypeName<WithBarrierBit>::name[] = _u("NormWB ");
16+
template<> char16 DumpBucketTypeName<FinalizableWithBarrierBit>::name[] = _u("FinWB ");
17+
#endif
18+
#ifdef RECYCLER_VISITED_HOST
19+
template<> char16 DumpBucketTypeName<RecyclerVisitedHostBit>::name[] = _u("Visited");
20+
#endif
21+
template <typename TBlockType>
22+
struct DumpBlockTypeName { static char16 name[]; };
23+
template<> char16 DumpBlockTypeName<SmallAllocationBlockAttributes>::name[] = _u("(S)");
24+
template<> char16 DumpBlockTypeName<MediumAllocationBlockAttributes>::name[] = _u("(M)");
25+
#endif // DUMP_FRAGMENTATION_STATS
26+
27+
template <ObjectInfoBits TBucketType>
28+
struct EtwBucketTypeEnum { static uint16 code; };
29+
template<> uint16 EtwBucketTypeEnum<NoBit>::code = 0;
30+
template<> uint16 EtwBucketTypeEnum<LeafBit>::code = 1;
31+
template<> uint16 EtwBucketTypeEnum<FinalizeBit>::code = 2;
32+
#ifdef RECYCLER_WRITE_BARRIER
33+
template<> uint16 EtwBucketTypeEnum<WithBarrierBit>::code = 3;
34+
template<> uint16 EtwBucketTypeEnum<FinalizableWithBarrierBit>::code = 4;
35+
#endif
36+
#ifdef RECYCLER_VISITED_HOST
37+
template<> uint16 EtwBucketTypeEnum<RecyclerVisitedHostBit>::code = 5;
38+
#endif
39+
template <typename TBlockType>
40+
struct EtwBlockTypeEnum { static uint16 code; };
41+
template<> uint16 EtwBlockTypeEnum<SmallAllocationBlockAttributes>::code = 0;
42+
template<> uint16 EtwBlockTypeEnum<MediumAllocationBlockAttributes>::code = 1;
43+
44+
class BucketStatsReporter
45+
{
46+
private:
47+
static const uint16 LargeBucketNameCode = 2 << 8;
48+
static const uint16 TotalBucketNameCode = 3 << 8;
49+
50+
Recycler* recycler;
51+
HeapBucketStats total;
52+
53+
template <class TBlockAttributes, ObjectInfoBits TBucketType>
54+
uint16 BucketNameCode() const
55+
{
56+
return EtwBucketTypeEnum<TBucketType>::code + (EtwBlockTypeEnum<TBlockAttributes>::code << 8);
57+
}
58+
59+
bool IsMemProtectMode() const
60+
{
61+
return recycler->IsMemProtectMode();
62+
}
63+
64+
public:
65+
BucketStatsReporter(Recycler* recycler)
66+
: recycler(recycler)
67+
{
68+
DUMP_FRAGMENTATION_STATS_ONLY(DumpHeader());
69+
}
70+
71+
bool IsEtwEnabled() const
72+
{
73+
return IS_GCETW_Enabled(GC_BUCKET_STATS);
74+
}
75+
76+
bool IsDumpEnabled() const
77+
{
78+
return DUMP_FRAGMENTATION_STATS_IS(!!recycler->GetRecyclerFlagsTable().DumpFragmentationStats);
79+
}
80+
81+
bool IsEnabled() const
82+
{
83+
return IsEtwEnabled() || IsDumpEnabled();
84+
}
85+
86+
template <class TBlockType>
87+
void PreAggregateBucketStats(TBlockType* list)
88+
{
89+
HeapBlockList::ForEach(list, [](TBlockType* heapBlock)
90+
{
91+
// Process blocks not in allocator in pre-pass. They are not put into buckets yet.
92+
if (!heapBlock->IsInAllocator())
93+
{
94+
heapBlock->heapBucket->PreAggregateBucketStats(heapBlock);
95+
}
96+
});
97+
}
98+
99+
template <class TBlockAttributes, ObjectInfoBits TBucketType>
100+
void GetBucketStats(HeapBucketGroup<TBlockAttributes>& group)
101+
{
102+
auto& bucket = group.template GetBucket<TBucketType>();
103+
bucket.AggregateBucketStats();
104+
105+
const auto& stats = bucket.GetMemStats();
106+
total.Aggregate(stats);
107+
108+
if (stats.totalByteCount > 0)
109+
{
110+
const uint16 bucketNameCode = BucketNameCode<TBlockAttributes, TBucketType>();
111+
const uint16 sizeCat = static_cast<uint16>(bucket.GetSizeCat());
112+
GCETW(GC_BUCKET_STATS, (recycler, bucketNameCode, sizeCat, stats.objectByteCount, stats.totalByteCount));
113+
#ifdef DUMP_FRAGMENTATION_STATS
114+
DumpStats<TBlockAttributes, TBucketType>(sizeCat, stats);
115+
#endif
116+
}
117+
}
118+
119+
void GetBucketStats(LargeHeapBucket& bucket)
120+
{
121+
bucket.AggregateBucketStats();
122+
123+
const auto& stats = bucket.GetMemStats();
124+
total.Aggregate(stats);
125+
126+
if (stats.totalByteCount > 0)
127+
{
128+
const uint16 sizeCat = static_cast<uint16>(bucket.GetSizeCat());
129+
GCETW(GC_BUCKET_STATS, (recycler, LargeBucketNameCode, sizeCat, stats.objectByteCount, stats.totalByteCount));
130+
DUMP_FRAGMENTATION_STATS_ONLY(DumpLarge(stats));
131+
}
132+
}
133+
134+
void Report()
135+
{
136+
GCETW(GC_BUCKET_STATS, (recycler, TotalBucketNameCode, 0, total.objectByteCount, total.totalByteCount));
137+
DUMP_FRAGMENTATION_STATS_ONLY(DumpFooter());
138+
}
139+
140+
#ifdef DUMP_FRAGMENTATION_STATS
141+
void DumpHeader()
142+
{
143+
if (IsDumpEnabled())
144+
{
145+
Output::Print(_u("[FRAG %d] Post-Collection State\n"), ::GetTickCount());
146+
Output::Print(_u("---------------------------------------------------------------------------------------\n"));
147+
Output::Print(_u(" #Blk #Objs #Fin ObjBytes FreeBytes TotalBytes UsedPercent\n"));
148+
Output::Print(_u("---------------------------------------------------------------------------------------\n"));
149+
}
150+
}
151+
152+
template <class TBlockAttributes, ObjectInfoBits TBucketType>
153+
void DumpStats(uint sizeCat, const HeapBucketStats& stats)
154+
{
155+
if (IsDumpEnabled())
156+
{
157+
Output::Print(_u("%-7s%s %4d : "),
158+
DumpBucketTypeName<TBucketType>::name, DumpBlockTypeName<TBlockAttributes>::name, sizeCat);
159+
stats.Dump();
160+
}
161+
}
162+
163+
void DumpLarge(const HeapBucketStats& stats)
164+
{
165+
if (IsDumpEnabled())
166+
{
167+
Output::Print(_u("Large : "));
168+
stats.Dump();
169+
}
170+
}
171+
172+
void DumpFooter()
173+
{
174+
if (IsDumpEnabled())
175+
{
176+
Output::Print(_u("---------------------------------------------------------------------------------------\n"));
177+
Output::Print(_u("Total : "));
178+
total.Dump();
179+
}
180+
}
181+
#endif
182+
};
183+
184+
};

lib/Common/Memory/Chakra.Common.Memory.vcxproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@
9090
<PrecompiledHeader>Create</PrecompiledHeader>
9191
</ClCompile>
9292
<ClCompile Include="$(MSBuildThisFileDirectory)SectionAllocWrapper.cpp" />
93-
<ClCompile Include="DelayDeletingFunctionTable.cpp" />
93+
<ClCompile Include="$(MSBuildThisFileDirectory)HeapInfoManager.cpp" />
94+
<ClCompile Include="$(MSBuildThisFileDirectory)RecyclerSweepManager.cpp" />
95+
<ClCompile Include="$(MSBuildThisFileDirectory)DelayDeletingFunctionTable.cpp" />
9496
</ItemGroup>
9597
<ItemGroup>
9698
<ClInclude Include="AllocationPolicyManager.h" />
@@ -107,6 +109,7 @@
107109
</ClInclude>
108110
<ClInclude Include="AutoAllocatorObjectPtr.h" />
109111
<ClInclude Include="AutoPtr.h" />
112+
<ClInclude Include="BucketStatsReporter.h" />
110113
<ClInclude Include="CollectionState.h" />
111114
<ClInclude Include="CommonMemoryPch.h" />
112115
<ClInclude Include="CustomHeap.h" />
@@ -118,6 +121,7 @@
118121
<ClInclude Include="HeapBucket.h" />
119122
<ClInclude Include="HeapConstants.h" />
120123
<ClInclude Include="HeapInfo.h" />
124+
<ClInclude Include="HeapInfoManager.h" />
121125
<ClInclude Include="IdleDecommitPageAllocator.h" />
122126
<ClInclude Include="LargeHeapBlock.h" />
123127
<ClInclude Include="LeakReport.h" />
@@ -137,6 +141,7 @@
137141
<ClInclude Include="RecyclerPointers.h" />
138142
<ClInclude Include="RecyclerRootPtr.h" />
139143
<ClInclude Include="RecyclerSweep.h" />
144+
<ClInclude Include="RecyclerSweepManager.h" />
140145
<ClInclude Include="RecyclerWeakReference.h" />
141146
<ClInclude Include="RecyclerWriteBarrierManager.h" />
142147
<ClInclude Include="SectionAllocWrapper.h" />

lib/Common/Memory/Chakra.Common.Memory.vcxproj.filters

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@
5555
<Filter>arm64</Filter>
5656
</ClCompile>
5757
<ClCompile Include="$(MSBuildThisFileDirectory)SectionAllocWrapper.cpp" />
58-
<ClCompile Include="DelayDeletingFunctionTable.cpp" />
58+
<ClCompile Include="$(MSBuildThisFileDirectory)HeapInfoManager.cpp" />
59+
<ClCompile Include="$(MSBuildThisFileDirectory)RecyclerSweepManager.cpp" />
60+
<ClCompile Include="$(MSBuildThisFileDirectory)DelayDeletingFunctionTable.cpp" />
5961
</ItemGroup>
6062
<ItemGroup>
6163
<ClInclude Include="Allocator.h" />
@@ -117,6 +119,9 @@
117119
<Filter>arm64</Filter>
118120
</ClInclude>
119121
<ClInclude Include="SectionAllocWrapper.h" />
122+
<ClInclude Include="HeapInfoManager.h" />
123+
<ClInclude Include="BucketStatsReporter.h" />
124+
<ClInclude Include="RecyclerSweepManager.h" />
120125
</ItemGroup>
121126
<ItemGroup>
122127
<None Include="HeapBlock.inl" />

lib/Common/Memory/HeapBlock.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,13 @@ SmallHeapBlockT<TBlockAttributes>::GetRecycler() const
807807
}
808808

809809
#if DBG
810+
template <class TBlockAttributes>
811+
HeapInfo *
812+
SmallHeapBlockT<TBlockAttributes>::GetHeapInfo() const
813+
{
814+
return this->heapBucket->heapInfo;
815+
}
816+
810817
template <class TBlockAttributes>
811818
BOOL
812819
SmallHeapBlockT<TBlockAttributes>::IsFreeObject(void * objectAddress)
@@ -1219,7 +1226,7 @@ SmallHeapBlockT<TBlockAttributes>::DoPartialReusePage(RecyclerSweep const& recyc
12191226
// could increase in thread sweep time.
12201227
// OTOH, if the object size is really large, the calculation below will reduce the chance for a page to be
12211228
// partial. we might need to watch out for that.
1222-
return (expectFreeByteCount + objectSize >= recyclerSweep.GetPartialCollectSmallHeapBlockReuseMinFreeBytes());
1229+
return (expectFreeByteCount + objectSize >= recyclerSweep.GetManager()->GetPartialCollectSmallHeapBlockReuseMinFreeBytes());
12231230
}
12241231

12251232
#if DBG
@@ -1287,7 +1294,7 @@ SmallHeapBlockT<TBlockAttributes>::AdjustPartialUncollectedAllocBytes(RecyclerSw
12871294
Assert(newAllocatedCount >= newObjectExpectSweepCount);
12881295
Assert(this->lastUncollectedAllocBytes >= newObjectExpectSweepCount * this->objectSize);
12891296

1290-
recyclerSweep.SubtractSweepNewObjectAllocBytes(newObjectExpectSweepCount * this->objectSize);
1297+
recyclerSweep.GetManager()->SubtractSweepNewObjectAllocBytes(newObjectExpectSweepCount * this->objectSize);
12911298
}
12921299
#endif // RECYCLER_VERIFY_MARK
12931300

@@ -1351,7 +1358,7 @@ SmallHeapBlockT<TBlockAttributes>::Sweep(RecyclerSweep& recyclerSweep, bool queu
13511358

13521359
#if ENABLE_PARTIAL_GC
13531360
// Accounting for partial heuristics
1354-
recyclerSweep.AddUnaccountedNewObjectAllocBytes(this);
1361+
recyclerSweep.GetManager()->AddUnaccountedNewObjectAllocBytes(this);
13551362
#endif
13561363
}
13571364

@@ -1373,7 +1380,7 @@ SmallHeapBlockT<TBlockAttributes>::Sweep(RecyclerSweep& recyclerSweep, bool queu
13731380
RECYCLER_STATS_INC(recycler, heapBlockCount[this->GetHeapBlockType()]);
13741381

13751382
#if ENABLE_PARTIAL_GC
1376-
if (recyclerSweep.DoAdjustPartialHeuristics() && allocable)
1383+
if (recyclerSweep.GetManager()->DoAdjustPartialHeuristics() && allocable)
13771384
{
13781385
this->AdjustPartialUncollectedAllocBytes(recyclerSweep, expectSweepCount);
13791386
}

lib/Common/Memory/HeapBlock.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ if (flags.Trace.IsEnabled(Js::PageHeapPhase)) \
3333

3434
class Recycler;
3535
class HeapBucket;
36+
class HeapInfo;
3637
template <typename TBlockType> class HeapBucketT;
3738
class RecyclerSweep;
3839
class MarkContext;
@@ -130,6 +131,8 @@ enum ObjectInfoBits : unsigned short
130131
ClientTrackedBit = 0x0400, // This allocation is client tracked
131132
TraceBit = 0x0800,
132133

134+
IsolatedBit = 0x1000,
135+
133136
// Additional definitions based on above
134137

135138
#ifdef RECYCLER_STATS
@@ -445,6 +448,7 @@ class HeapBlock
445448

446449

447450
#if DBG
451+
virtual HeapInfo * GetHeapInfo() const = 0;
448452
virtual BOOL IsFreeObject(void* objectAddress) = 0;
449453
#endif
450454
virtual BOOL IsValidObject(void* objectAddress) = 0;
@@ -752,6 +756,7 @@ class SmallHeapBlockT : public HeapBlock
752756
SmallHeapBlockBitVector * GetDebugFreeBitVector() { return &debugFreeBits; }
753757
#endif
754758
#if DBG
759+
virtual HeapInfo * GetHeapInfo() const override;
755760
virtual BOOL IsFreeObject(void* objectAddress) override;
756761
#endif
757762
virtual BOOL IsValidObject(void* objectAddress) override;

0 commit comments

Comments
 (0)