blob: 55150486c33ae03e2e6907f96896d98ffc744c43 [file]
//-------------------------------------------------------------------------------------------------------
// 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<uint, StringMetrics, ArenaAllocator> 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