DictionaryStats.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. #include "CommonDataStructuresPch.h"
  6. #if PROFILE_DICTIONARY
  7. #include "DictionaryStats.h"
  8. DictionaryType* DictionaryStats::dictionaryTypes = NULL;
  9. CriticalSection DictionaryStats::dictionaryTypesCriticalSection;
  10. DictionaryStats* DictionaryStats::Create(const char* name, uint bucketCount)
  11. {
  12. if (!Js::Configuration::Global.flags.IsEnabled(Js::ProfileDictionaryFlag) ||
  13. Js::Configuration::Global.flags.ProfileDictionary < 0)
  14. return NULL;
  15. return NoCheckHeapNew(DictionaryStats, name, bucketCount);
  16. }
  17. DictionaryStats* DictionaryStats::Clone()
  18. {
  19. DictionaryStats* cloned = NoCheckHeapNew(DictionaryStats, pName, initialSize);
  20. cloned->finalSize = finalSize;
  21. cloned->countOfEmptyBuckets = countOfEmptyBuckets;
  22. cloned->countOfResize = countOfResize;
  23. cloned->itemCount = itemCount;
  24. cloned->maxDepth = maxDepth;
  25. cloned->lookupCount = lookupCount;
  26. cloned->collisionCount = collisionCount;
  27. cloned->lookupDepthTotal = lookupDepthTotal;
  28. cloned->maxLookupDepth = maxLookupDepth;
  29. cloned->pName = pName;
  30. return cloned;
  31. }
  32. DictionaryStats::DictionaryStats(const char* name, uint bucketCount)
  33. :
  34. initialSize(bucketCount),
  35. finalSize(bucketCount),
  36. countOfEmptyBuckets(bucketCount),
  37. countOfResize(0),
  38. itemCount(0),
  39. maxDepth(0),
  40. lookupCount(0),
  41. collisionCount(0),
  42. lookupDepthTotal(0),
  43. maxLookupDepth(0),
  44. pNext(NULL),
  45. pName(NULL)
  46. {
  47. DictionaryStats::dictionaryTypesCriticalSection.Enter();
  48. DictionaryType* type = NULL;
  49. // See if we already created instance(s) of this type
  50. DictionaryType* current = dictionaryTypes;
  51. while(current)
  52. {
  53. if (strncmp(name, current->name, _countof(current->name)-1) == 0)
  54. {
  55. type = current;
  56. break;
  57. }
  58. current = current->pNext;
  59. }
  60. if (!type)
  61. {
  62. // We haven't seen this type before so add a new entry for it
  63. type = NoCheckHeapNew(DictionaryType);
  64. type->pNext = dictionaryTypes;
  65. dictionaryTypes = type;
  66. type->instancesCount = 0;
  67. strncpy_s(type->name, name, _countof(type->name)-1);
  68. type->name[sizeof(type->name)-1]='\0';
  69. }
  70. dictionaryTypesCriticalSection.Leave();
  71. // keep a pointer to the name in case we are asked to clone ourselves
  72. pName = type->name;
  73. // Add ourself in the list
  74. pNext = type->instances;
  75. type->instances = this;
  76. ++(type->instancesCount);
  77. }
  78. void DictionaryStats::Resize(uint newSize, uint emptyBucketCount)
  79. {
  80. finalSize = newSize;
  81. countOfEmptyBuckets = emptyBucketCount;
  82. ++countOfResize;
  83. }
  84. void DictionaryStats::Insert(uint depth)
  85. {
  86. ++itemCount;
  87. if (maxDepth < depth)
  88. maxDepth = depth;
  89. if (depth == 1 && countOfEmptyBuckets > 0)
  90. --countOfEmptyBuckets;
  91. }
  92. void DictionaryStats::Remove(bool isBucketEmpty)
  93. {
  94. if (itemCount > 0)
  95. --itemCount;
  96. if (isBucketEmpty)
  97. ++countOfEmptyBuckets;
  98. }
  99. void DictionaryStats::Lookup(uint depth)
  100. {
  101. // Note, lookup and collision math only works out if depth is 0-based.
  102. // I.e., depth of 1 means there was 1 collision and the lookup found key at second item in the bucket
  103. lookupCount += 1;
  104. lookupDepthTotal += depth;
  105. if (depth > 0)
  106. collisionCount += 1;
  107. if (maxLookupDepth < depth)
  108. maxLookupDepth = depth;
  109. }
  110. void DictionaryStats::OutputStats()
  111. {
  112. if (!dictionaryTypes)
  113. return;
  114. DictionaryStats::dictionaryTypesCriticalSection.Enter();
  115. DictionaryType* current = dictionaryTypes;
  116. Output::Print(_u("PROFILE DICTIONARY\n"));
  117. Output::Print(_u("%8s %13s %13s %13s %13s %13s %13s %13s %14s %14s %13s %13s %13s %s\n"), _u("Metric"),_u("StartSize"), _u("EndSize"), _u("Resizes"), _u("Items"), _u("MaxDepth"), _u("EmptyBuckets"), _u("Lookups"), _u("Collisions"), _u("AvgLookupDepth"), _u("AvgCollDepth"), _u("MaxLookupDepth"), _u("Instances"), _u("Type"));
  118. while(current)
  119. {
  120. DictionaryType *type = current;
  121. DictionaryStats *instance = type->instances;
  122. double size = 0, max_size = 0;
  123. double endSize = 0, max_endSize = 0;
  124. double resizes = 0, max_resizes = 0;
  125. double items = 0, max_items = 0;
  126. double depth = 0, max_depth = 0;
  127. double empty = 0, max_empty = 0;
  128. double lookups = 0, max_lookups = 0;
  129. double collisions = 0, max_collisions = 0;
  130. double avglookupdepth = 0, max_avglookupdepth = 0;
  131. double avgcollisiondepth = 0, max_avgcollisiondepth = 0;
  132. double maxlookupdepth = 0, max_maxlookupdepth = 0;
  133. bool dumpInstances = false;
  134. //if(strstr(type->name, "SimpleDictionaryPropertyDescriptor") != nullptr)
  135. //{
  136. // dumpInstances = true;
  137. //}
  138. while(instance)
  139. {
  140. ComputeStats(instance->initialSize, size, max_size);
  141. ComputeStats(instance->finalSize, endSize, max_endSize);
  142. ComputeStats(instance->countOfResize, resizes, max_resizes);
  143. ComputeStats(instance->itemCount, items, max_items);
  144. ComputeStats(instance->maxDepth, depth, max_depth);
  145. ComputeStats(instance->countOfEmptyBuckets, empty, max_empty);
  146. ComputeStats(instance->lookupCount, lookups, max_lookups);
  147. ComputeStats(instance->collisionCount, collisions, max_collisions);
  148. if (instance->lookupCount > 0)
  149. {
  150. ComputeStats((double)instance->lookupDepthTotal / (double)instance->lookupCount, avglookupdepth, max_avglookupdepth);
  151. }
  152. if (instance->collisionCount > 0)
  153. {
  154. ComputeStats((double)instance->lookupDepthTotal / (double)instance->collisionCount, avgcollisiondepth, max_avgcollisiondepth);
  155. }
  156. ComputeStats(instance->maxLookupDepth, maxlookupdepth, max_maxlookupdepth);
  157. if(dumpInstances)
  158. {
  159. double avgld = 0.0;
  160. double avgcd = 0.0;
  161. if (instance->lookupCount > 0)
  162. {
  163. avgld = (double)instance->lookupDepthTotal / (double)instance->lookupCount;
  164. avgcd = (double)instance->lookupDepthTotal / (double)instance->collisionCount;
  165. }
  166. Output::Print(_u("%8s %13d %13d %13d %13d %13d %13d %13d %14d %14.2f %13.2f %13d \n"),
  167. _u("INS:"),
  168. instance->initialSize, instance->finalSize, instance->countOfResize,
  169. instance->itemCount, instance->maxDepth, instance->countOfEmptyBuckets,
  170. instance->lookupCount, instance->collisionCount, avgld, avgcd,
  171. instance->maxLookupDepth);
  172. }
  173. instance = instance->pNext;
  174. }
  175. if (max_depth >= Js::Configuration::Global.flags.ProfileDictionary)
  176. {
  177. Output::Print(_u("%8s %13.0f %13.0f %13.2f %13.0f %13.2f %13.0f %13.0f %14.0f %14.2f %13.2f %13.2f %13d %S\n"), _u("AVG:"),
  178. size/type->instancesCount, endSize/type->instancesCount, resizes/type->instancesCount, items/type->instancesCount,
  179. depth/type->instancesCount, empty/type->instancesCount, lookups/type->instancesCount, collisions/type->instancesCount,
  180. avglookupdepth/type->instancesCount, avgcollisiondepth/type->instancesCount, maxlookupdepth/type->instancesCount, type->instancesCount, type->name);
  181. Output::Print(_u("%8s %13.0f %13.0f %13.2f %13.0f %13.2f %13.0f %13.0f %14.0f %14.2f %13.2f %13.2f %13d %S\n\n"), _u("MAX:"),
  182. max_size, max_endSize, max_resizes, max_items, max_depth, max_empty, max_lookups, max_collisions, max_avglookupdepth,
  183. max_avgcollisiondepth, max_maxlookupdepth, type->instancesCount, type->name);
  184. }
  185. current = current->pNext;
  186. }
  187. Output::Print(_u("====================================================================================\n"));
  188. ClearStats();
  189. DictionaryStats::dictionaryTypesCriticalSection.Leave();
  190. }
  191. void DictionaryStats::ComputeStats(uint input, double &total, double &max)
  192. {
  193. total += input;
  194. if (input > max)
  195. max = input;
  196. }
  197. void DictionaryStats::ComputeStats(double input, double &total, double &max)
  198. {
  199. total += input;
  200. if (input > max)
  201. max = input;
  202. }
  203. void DictionaryStats::ClearStats()
  204. {
  205. // Clear the collection since we already reported on what we already collected
  206. DictionaryType* current = dictionaryTypes;
  207. while(current)
  208. {
  209. DictionaryType *type = current;
  210. DictionaryStats *pNext = type->instances;
  211. while(pNext)
  212. {
  213. DictionaryStats *pCurrent = pNext;
  214. pNext = pNext->pNext;
  215. NoCheckHeapDelete(pCurrent);
  216. }
  217. current = current->pNext;
  218. NoCheckHeapDelete(type);
  219. }
  220. dictionaryTypes = NULL;
  221. }
  222. #endif