ProfileString.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. #ifdef PROFILE_STRINGS
  7. namespace Js
  8. {
  9. enum ConcatType
  10. {
  11. ConcatType_Unknown,
  12. ConcatType_CompoundString,
  13. ConcatType_ConcatTree,
  14. ConcatType_BufferString
  15. };
  16. class StringProfiler
  17. {
  18. private:
  19. ArenaAllocator allocator;
  20. ThreadContextId mainThreadId;
  21. uint discardedWrongThread; // If called on the wrong thread, then statistics are inaccurate
  22. // Profiling strings records the frequency of each length of string.
  23. // It also records whether the characters in the string may be encoded
  24. // as 7-bit ASCII, 8-bit ASCII or if they really require 16bit encoding
  25. enum RequiredEncoding
  26. {
  27. ASCII7bit,
  28. ASCII8bit,
  29. Unicode16bit
  30. };
  31. struct StringMetrics
  32. {
  33. uint count7BitASCII;
  34. uint count8BitASCII;
  35. uint countUnicode;
  36. void Accumulate( RequiredEncoding encoding )
  37. {
  38. switch(encoding)
  39. {
  40. case ASCII7bit:
  41. this->count7BitASCII++;
  42. break;
  43. case ASCII8bit:
  44. this->count8BitASCII++;
  45. break;
  46. case Unicode16bit:
  47. this->countUnicode++;
  48. break;
  49. }
  50. }
  51. uint Total() const
  52. {
  53. return this->count7BitASCII +
  54. this->count8BitASCII +
  55. this->countUnicode;
  56. }
  57. void Accumulate(StringMetrics& rhs)
  58. {
  59. this->count7BitASCII += rhs.count7BitASCII;
  60. this->count8BitASCII += rhs.count8BitASCII;
  61. this->countUnicode += rhs.countUnicode;
  62. }
  63. };
  64. struct ConcatMetrics
  65. {
  66. uint compoundStringCount;
  67. uint concatTreeCount;
  68. uint bufferStringBuilderCount;
  69. uint unknownCount;
  70. ConcatMetrics() {}
  71. ConcatMetrics(ConcatType concatType)
  72. : compoundStringCount(0), concatTreeCount(0), bufferStringBuilderCount(0), unknownCount(0)
  73. {
  74. this->Accumulate(concatType);
  75. }
  76. void Accumulate(ConcatType concatType)
  77. {
  78. switch(concatType)
  79. {
  80. case ConcatType_CompoundString:
  81. this->compoundStringCount++;
  82. break;
  83. case ConcatType_ConcatTree:
  84. this->concatTreeCount++;
  85. break;
  86. case ConcatType_BufferString:
  87. this->bufferStringBuilderCount++;
  88. break;
  89. case ConcatType_Unknown:
  90. this->unknownCount++;
  91. break;
  92. }
  93. }
  94. uint Total() const
  95. {
  96. return this->compoundStringCount +
  97. this->concatTreeCount +
  98. this->bufferStringBuilderCount +
  99. this->unknownCount;
  100. }
  101. };
  102. uint embeddedNULChars; // Total number of embedded NUL chars in all strings
  103. uint embeddedNULStrings; // Number of strings with at least one embedded NUL char
  104. uint emptyStrings; // # of requests for zero-length strings (literals or BufferStrings)
  105. uint singleCharStrings; // # of requests for single-char strings (literals of BufferStrings)
  106. JsUtil::BaseDictionary<uint, StringMetrics, ArenaAllocator> stringLengthMetrics;
  107. struct UintUintPair
  108. {
  109. uint first;
  110. uint second;
  111. bool operator==(UintUintPair const& other) const
  112. {
  113. return this->first == other.first && this->second == other.second;
  114. }
  115. operator uint() const
  116. {
  117. return this->first | (this->second << 16);
  118. }
  119. };
  120. JsUtil::BaseDictionary< UintUintPair, ConcatMetrics, ArenaAllocator, PrimeSizePolicy > stringConcatMetrics;
  121. bool IsOnWrongThread() const;
  122. static RequiredEncoding GetRequiredEncoding( const char16* sz, uint length );
  123. static uint CountEmbeddedNULs( const char16* sz, uint length );
  124. class HistogramIndex
  125. {
  126. UintUintPair* index; // index of "length" and "frequency"
  127. uint count;
  128. public:
  129. HistogramIndex( ArenaAllocator* allocator, uint size );
  130. void Add( uint len, uint freq );
  131. void SortDescending();
  132. uint Get( uint i ) const;
  133. uint Count() const;
  134. private:
  135. static int __cdecl CompareDescending( const void* lhs, const void* rhs );
  136. };
  137. static void BuildIndex( unsigned int len, StringMetrics metrics, HistogramIndex* histogram, uint* total );
  138. static void PrintOne( unsigned int len, StringMetrics metrics, uint totalCount );
  139. static void PrintUintOrLarge( uint val );
  140. static void PrintOneConcat( UintUintPair const& key, const ConcatMetrics& metrics);
  141. void RecordNewString( const char16* sz, uint length );
  142. void RecordConcatenation( uint lenLeft, uint lenRight, ConcatType type);
  143. static const uint k_MaxConcatLength = 20; // Strings longer than this are just "large"
  144. public:
  145. StringProfiler(PageAllocator * pageAllocator);
  146. void PrintAll();
  147. static void RecordNewString( ScriptContext* scriptContext, const char16* sz, uint length );
  148. static void RecordConcatenation( ScriptContext* scriptContext, uint lenLeft, uint lenRight, ConcatType type = ConcatType_Unknown);
  149. static void RecordEmptyStringRequest( ScriptContext* scriptContext );
  150. static void RecordSingleCharStringRequest( ScriptContext* scriptContext );
  151. };
  152. } // namespace Js
  153. #endif