| //------------------------------------------------------------------------------------------------------- |
| // Copyright (C) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. |
| //------------------------------------------------------------------------------------------------------- |
| #include "ParserPch.h" |
| |
| #if ENABLE_REGEX_CONFIG_OPTIONS |
| |
| namespace UnifiedRegex |
| { |
| const char16* RegexStats::PhaseNames[RegexStats::NumPhases] = { _u("parse"), _u("compile"), _u("execute") }; |
| const char16* RegexStats::UseNames[RegexStats::NumUses] = { _u("match"), _u("exec"), _u("test"), _u("replace"), _u("split"), _u("search") }; |
| |
| RegexStats::RegexStats(RegexPattern* pattern) |
| : pattern(pattern) |
| , inputLength(0) |
| , numCompares(0) |
| , numPushes(0) |
| , numPops(0) |
| , stackHWM(0) |
| , numInsts(0) |
| { |
| for (int i = 0; i < NumPhases; i++) |
| phaseTicks[i] = 0; |
| for (int i = 0; i < NumUses; i++) |
| useCounts[i] = 0; |
| } |
| |
| void RegexStats::Print(DebugWriter* w, RegexStats* totals, Ticks ticksPerMillisecond) |
| { |
| if (pattern == 0) |
| w->PrintEOL(_u("TOTAL")); |
| else |
| pattern->Print(w); |
| w->EOL(); |
| w->Indent(); |
| |
| for (int i = 0; i < NumPhases; i++) |
| { |
| double ms = (double)phaseTicks[i] / (double)ticksPerMillisecond; |
| if (totals == 0 || totals->phaseTicks[i] == 0) |
| w->PrintEOL(_u("%-12s: %10.4fms"), PhaseNames[i], ms); |
| else |
| { |
| double pc = (double)phaseTicks[i] * 100.0 / (double)totals->phaseTicks[i]; |
| w->PrintEOL(_u("%-12s: %10.4fms (%10.4f%%)"), PhaseNames[i], ms, pc); |
| } |
| } |
| |
| for (int i = 0; i < NumUses; i++) |
| { |
| if (useCounts[i] > 0) |
| { |
| if (totals == 0 || totals->useCounts[i] == 0) |
| w->PrintEOL(_u("#%-11s: %10I64u"), UseNames[i], useCounts[i]); |
| else |
| { |
| double pc = (double)useCounts[i] * 100.0 / (double)totals->useCounts[i]; |
| w->PrintEOL(_u("#%-11s: %10I64u (%10.4f%%)"), UseNames[i], useCounts[i], pc); |
| } |
| } |
| } |
| |
| if (inputLength > 0) |
| { |
| double r = (double)numCompares * 100.0 / (double)inputLength; |
| if (totals == 0 || totals->numCompares == 0) |
| w->PrintEOL(_u("numCompares : %10.4f%%"), r); |
| else |
| { |
| double pc = (double)numCompares * 100.0 / (double)totals->numCompares; |
| w->PrintEOL(_u("numCompares : %10.4f%% (%10.4f%%)"), r, pc); |
| } |
| } |
| |
| if (totals == 0 || totals->inputLength == 0) |
| w->PrintEOL(_u("inputLength : %10I64u"), inputLength); |
| else |
| { |
| double pc = (double)inputLength * 100.0 / (double)totals->inputLength; |
| w->PrintEOL(_u("inputLength : %10I64u (%10.4f%%)"), inputLength, pc); |
| } |
| |
| if (totals == 0 || totals->numPushes == 0) |
| w->PrintEOL(_u("numPushes : %10I64u"), numPushes); |
| else |
| { |
| double pc = (double)numPushes * 100.0 / (double)totals->numPushes; |
| w->PrintEOL(_u("numPushes : %10I64u (%10.4f%%)"), numPushes, pc); |
| } |
| |
| if (totals == 0 || totals->numPops == 0) |
| w->PrintEOL(_u("numPops : %10I64u"), numPops); |
| else |
| { |
| double pc = (double)numPops * 100.0 / (double)totals->numPops; |
| w->PrintEOL(_u("numPops : %10I64u (%10.4f%%)"), numPops, pc); |
| } |
| |
| if (totals == 0 || totals->stackHWM == 0) |
| w->PrintEOL(_u("stackHWM : %10I64u"), stackHWM); |
| else |
| { |
| double pc = (double)stackHWM * 100.0 / (double)totals->stackHWM; |
| w->PrintEOL(_u("stackHWM : %10I64u (%10.4f%%)"), stackHWM, pc); |
| } |
| |
| if (totals == 0 || totals->numInsts == 0) |
| w->PrintEOL(_u("numInsts : %10I64u"), numInsts); |
| else |
| { |
| double pc = (double)numInsts * 100.0 / (double)totals->numInsts; |
| w->PrintEOL(_u("numInsts : %10I64u (%10.4f%%)"), numInsts, pc); |
| } |
| |
| w->Unindent(); |
| } |
| |
| void RegexStats::Add(RegexStats* other) |
| { |
| for (int i = 0; i < NumPhases; i++) |
| phaseTicks[i] += other->phaseTicks[i]; |
| for (int i = 0; i < NumUses; i++) |
| useCounts[i] += other->useCounts[i]; |
| inputLength += other->inputLength; |
| numCompares += other->numCompares; |
| numPushes += other->numPushes; |
| numPops += other->numPops; |
| if (other->stackHWM > stackHWM) |
| stackHWM = other->stackHWM; |
| numInsts += other->numInsts; |
| } |
| |
| RegexStats::Ticks RegexStatsDatabase::Now() |
| { |
| LARGE_INTEGER tmp; |
| if (QueryPerformanceCounter(&tmp)) |
| return tmp.QuadPart; |
| else |
| { |
| Assert(false); |
| return 0; |
| } |
| } |
| |
| RegexStats::Ticks RegexStatsDatabase::Freq() |
| { |
| LARGE_INTEGER tmp; |
| if (QueryPerformanceFrequency(&tmp)) |
| { |
| return tmp.QuadPart / 1000; |
| } |
| else |
| { |
| Assert(false); |
| return 1; |
| } |
| } |
| |
| RegexStatsDatabase::RegexStatsDatabase(ArenaAllocator* allocator) |
| : start(0), allocator(allocator) |
| { |
| ticksPerMillisecond = Freq(); |
| map = Anew(allocator, RegexStatsMap, allocator, 17); |
| } |
| |
| RegexStats* RegexStatsDatabase::GetRegexStats(RegexPattern* pattern) |
| { |
| Js::InternalString str = pattern->GetSource(); |
| RegexStats *res; |
| if (!map->TryGetValue(str, &res)) |
| { |
| res = Anew(allocator, RegexStats, pattern); |
| map->Add(str, res); |
| } |
| return res; |
| } |
| |
| void RegexStatsDatabase::BeginProfile() |
| { |
| start = Now(); |
| } |
| |
| void RegexStatsDatabase::EndProfile(RegexStats* stats, RegexStats::Phase phase) |
| { |
| stats->phaseTicks[phase] += Now() - start; |
| } |
| |
| void RegexStatsDatabase::Print(DebugWriter* w) |
| { |
| RegexStats totals(0); |
| |
| Output::Print(_u("Regular Expression Statistics\n")); |
| Output::Print(_u("=============================\n")); |
| |
| for (int i = 0; i < map->Count(); i++) |
| totals.Add(map->GetValueAt(i)); |
| |
| for (int i = 0; i < map->Count(); i++) |
| map->GetValueAt(i)->Print(w, &totals, ticksPerMillisecond); |
| |
| totals.Print(w, 0, ticksPerMillisecond); |
| |
| allocator->Free(w, sizeof(DebugWriter)); |
| } |
| } |
| |
| #endif |