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
+ };
0 commit comments