BucketStatsReporter.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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. #pragma once
  6. #include "HeapBucketStats.h"
  7. namespace Memory
  8. {
  9. #ifdef DUMP_FRAGMENTATION_STATS
  10. template <ObjectInfoBits TBucketType>
  11. struct DumpBucketTypeName { static char16 name[]; };
  12. template<> char16 DumpBucketTypeName<NoBit>::name[] = _u("Normal ");
  13. template<> char16 DumpBucketTypeName<LeafBit>::name[] = _u("Leaf ");
  14. template<> char16 DumpBucketTypeName<FinalizeBit>::name[] = _u("Fin ");
  15. #ifdef RECYCLER_WRITE_BARRIER
  16. template<> char16 DumpBucketTypeName<WithBarrierBit>::name[] = _u("NormWB ");
  17. template<> char16 DumpBucketTypeName<FinalizableWithBarrierBit>::name[] = _u("FinWB ");
  18. #endif
  19. #ifdef RECYCLER_VISITED_HOST
  20. template<> char16 DumpBucketTypeName<RecyclerVisitedHostBit>::name[] = _u("Visited");
  21. #endif
  22. template <typename TBlockType>
  23. struct DumpBlockTypeName { static char16 name[]; };
  24. template<> char16 DumpBlockTypeName<SmallAllocationBlockAttributes>::name[] = _u("(S)");
  25. template<> char16 DumpBlockTypeName<MediumAllocationBlockAttributes>::name[] = _u("(M)");
  26. #endif // DUMP_FRAGMENTATION_STATS
  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. class BucketStatsReporter
  44. {
  45. private:
  46. static const uint16 LargeBucketNameCode = 2 << 8;
  47. static const uint16 TotalBucketNameCode = 3 << 8;
  48. Recycler* recycler;
  49. HeapBucketStats total;
  50. template <class TBlockAttributes, ObjectInfoBits TBucketType>
  51. uint16 BucketNameCode() const
  52. {
  53. return EtwBucketTypeEnum<TBucketType>::code + (EtwBlockTypeEnum<TBlockAttributes>::code << 8);
  54. }
  55. bool IsMemProtectMode() const
  56. {
  57. return recycler->IsMemProtectMode();
  58. }
  59. public:
  60. BucketStatsReporter(Recycler* recycler)
  61. : recycler(recycler)
  62. {
  63. DUMP_FRAGMENTATION_STATS_ONLY(DumpHeader());
  64. }
  65. HeapBucketStats* GetTotalStats() { return &total; }
  66. bool IsEtwEnabled() const
  67. {
  68. return IS_GCETW_Enabled(GC_BUCKET_STATS);
  69. }
  70. bool IsDumpEnabled() const
  71. {
  72. return DUMP_FRAGMENTATION_STATS_IS(!!recycler->GetRecyclerFlagsTable().DumpFragmentationStats);
  73. }
  74. bool IsEnabled() const
  75. {
  76. return IsEtwEnabled() || IsDumpEnabled();
  77. }
  78. template <class TBlockType>
  79. void PreAggregateBucketStats(TBlockType* list)
  80. {
  81. HeapBlockList::ForEach(list, [](TBlockType* heapBlock)
  82. {
  83. // Process blocks not in allocator in pre-pass. They are not put into buckets yet.
  84. if (!heapBlock->IsInAllocator())
  85. {
  86. heapBlock->heapBucket->PreAggregateBucketStats(heapBlock);
  87. }
  88. });
  89. }
  90. template <class TBlockAttributes, ObjectInfoBits TBucketType>
  91. void GetBucketStats(HeapBucketGroup<TBlockAttributes>& group)
  92. {
  93. auto& bucket = group.template GetBucket<TBucketType>();
  94. bucket.AggregateBucketStats();
  95. const auto& stats = bucket.GetMemStats();
  96. total.Aggregate(stats);
  97. if (stats.totalByteCount > 0)
  98. {
  99. const uint16 bucketNameCode = BucketNameCode<TBlockAttributes, TBucketType>();
  100. const uint16 sizeCat = static_cast<uint16>(bucket.GetSizeCat());
  101. GCETW(GC_BUCKET_STATS, (recycler, bucketNameCode, sizeCat, stats.objectByteCount, stats.totalByteCount));
  102. #ifdef DUMP_FRAGMENTATION_STATS
  103. DumpStats<TBlockAttributes, TBucketType>(sizeCat, stats);
  104. #endif
  105. }
  106. }
  107. void GetBucketStats(LargeHeapBucket& bucket)
  108. {
  109. bucket.AggregateBucketStats();
  110. const auto& stats = bucket.GetMemStats();
  111. total.Aggregate(stats);
  112. if (stats.totalByteCount > 0)
  113. {
  114. const uint16 sizeCat = static_cast<uint16>(bucket.GetSizeCat());
  115. GCETW(GC_BUCKET_STATS, (recycler, LargeBucketNameCode, sizeCat, stats.objectByteCount, stats.totalByteCount));
  116. DUMP_FRAGMENTATION_STATS_ONLY(DumpLarge(stats));
  117. }
  118. }
  119. void Report()
  120. {
  121. GCETW(GC_BUCKET_STATS, (recycler, TotalBucketNameCode, 0, total.objectByteCount, total.totalByteCount));
  122. DUMP_FRAGMENTATION_STATS_ONLY(DumpFooter());
  123. }
  124. #ifdef DUMP_FRAGMENTATION_STATS
  125. void DumpHeader()
  126. {
  127. if (IsDumpEnabled())
  128. {
  129. Output::Print(_u("[FRAG %d] Post-Collection State\n"), ::GetTickCount());
  130. Output::Print(_u("---------------------------------------------------------------------------------------\n"));
  131. Output::Print(_u(" #Blk #Objs #Fin ObjBytes FreeBytes TotalBytes UsedPercent\n"));
  132. Output::Print(_u("---------------------------------------------------------------------------------------\n"));
  133. }
  134. }
  135. template <class TBlockAttributes, ObjectInfoBits TBucketType>
  136. void DumpStats(uint sizeCat, const HeapBucketStats& stats)
  137. {
  138. if (IsDumpEnabled())
  139. {
  140. Output::Print(_u("%-7s%s %4d : "),
  141. DumpBucketTypeName<TBucketType>::name, DumpBlockTypeName<TBlockAttributes>::name, sizeCat);
  142. stats.Dump();
  143. }
  144. }
  145. void DumpLarge(const HeapBucketStats& stats)
  146. {
  147. if (IsDumpEnabled())
  148. {
  149. Output::Print(_u("Large : "));
  150. stats.Dump();
  151. }
  152. }
  153. void DumpFooter()
  154. {
  155. if (IsDumpEnabled())
  156. {
  157. Output::Print(_u("---------------------------------------------------------------------------------------\n"));
  158. Output::Print(_u("Total : "));
  159. total.Dump();
  160. }
  161. }
  162. #endif
  163. };
  164. };