DictionaryStats.cpp 9.3 KB

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