//------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #pragma once #ifdef PROFILE_STRINGS namespace Js { enum ConcatType { ConcatType_Unknown, ConcatType_CompoundString, ConcatType_ConcatTree, ConcatType_BufferString }; class StringProfiler { private: ArenaAllocator allocator; ThreadContextId mainThreadId; uint discardedWrongThread; // If called on the wrong thread, then statistics are inaccurate // Profiling strings records the frequency of each length of string. // It also records whether the characters in the string may be encoded // as 7-bit ASCII, 8-bit ASCII or if they really require 16bit encoding enum RequiredEncoding { ASCII7bit, ASCII8bit, Unicode16bit }; struct StringMetrics { uint count7BitASCII; uint count8BitASCII; uint countUnicode; void Accumulate( RequiredEncoding encoding ) { switch(encoding) { case ASCII7bit: this->count7BitASCII++; break; case ASCII8bit: this->count8BitASCII++; break; case Unicode16bit: this->countUnicode++; break; } } uint Total() const { return this->count7BitASCII + this->count8BitASCII + this->countUnicode; } void Accumulate(StringMetrics& rhs) { this->count7BitASCII += rhs.count7BitASCII; this->count8BitASCII += rhs.count8BitASCII; this->countUnicode += rhs.countUnicode; } }; struct ConcatMetrics { uint compoundStringCount; uint concatTreeCount; uint bufferStringBuilderCount; uint unknownCount; ConcatMetrics() {} ConcatMetrics(ConcatType concatType) : compoundStringCount(0), concatTreeCount(0), bufferStringBuilderCount(0), unknownCount(0) { this->Accumulate(concatType); } void Accumulate(ConcatType concatType) { switch(concatType) { case ConcatType_CompoundString: this->compoundStringCount++; break; case ConcatType_ConcatTree: this->concatTreeCount++; break; case ConcatType_BufferString: this->bufferStringBuilderCount++; break; case ConcatType_Unknown: this->unknownCount++; break; } } uint Total() const { return this->compoundStringCount + this->concatTreeCount + this->bufferStringBuilderCount + this->unknownCount; } }; uint embeddedNULChars; // Total number of embedded NUL chars in all strings uint embeddedNULStrings; // Number of strings with at least one embedded NUL char uint emptyStrings; // # of requests for zero-length strings (literals or BufferStrings) uint singleCharStrings; // # of requests for single-char strings (literals of BufferStrings) JsUtil::BaseDictionary stringLengthMetrics; struct UintUintPair { uint first; uint second; bool operator==(UintUintPair const& other) const { return this->first == other.first && this->second == other.second; } operator uint() const { return this->first | (this->second << 16); } }; JsUtil::BaseDictionary< UintUintPair, ConcatMetrics, ArenaAllocator, PrimeSizePolicy > stringConcatMetrics; bool IsOnWrongThread() const; static RequiredEncoding GetRequiredEncoding( const char16* sz, uint length ); static uint CountEmbeddedNULs( const char16* sz, uint length ); class HistogramIndex { UintUintPair* index; // index of "length" and "frequency" uint count; public: HistogramIndex( ArenaAllocator* allocator, uint size ); void Add( uint len, uint freq ); void SortDescending(); uint Get( uint i ) const; uint Count() const; private: static int __cdecl CompareDescending( const void* lhs, const void* rhs ); }; static void BuildIndex( unsigned int len, StringMetrics metrics, HistogramIndex* histogram, uint* total ); static void PrintOne( unsigned int len, StringMetrics metrics, uint totalCount ); static void PrintUintOrLarge( uint val ); static void PrintOneConcat( UintUintPair const& key, const ConcatMetrics& metrics); void RecordNewString( const char16* sz, uint length ); void RecordConcatenation( uint lenLeft, uint lenRight, ConcatType type); static const uint k_MaxConcatLength = 20; // Strings longer than this are just "large" public: StringProfiler(PageAllocator * pageAllocator); void PrintAll(); static void RecordNewString( ScriptContext* scriptContext, const char16* sz, uint length ); static void RecordConcatenation( ScriptContext* scriptContext, uint lenLeft, uint lenRight, ConcatType type = ConcatType_Unknown); static void RecordEmptyStringRequest( ScriptContext* scriptContext ); static void RecordSingleCharStringRequest( ScriptContext* scriptContext ); }; } // namespace Js #endif