Skip to content

Commit

Permalink
[JSC] Make profiling check-pointing longer for mega functions
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=260010
rdar://113668308

Reviewed by Justin Michaud.

While we designed our profiling collection with "they are cheap" assumption, this is not true for some mega-sized functions.
There are some mega-sized functions, which can be generated by toolings etc., has massive amount of ValueProfiles, and causing
very long stop for profile update.

In this patch, we attempt to avoid this pathological case. When function size exceeds the threshold, we categorize it as mega-sized,
and we relax maximumExecutionCountsBetweenCheckpoints more larger. Because we do profiling update on each checkpoint, making it longer
means less frequent profiling update.

* Source/JavaScriptCore/bytecode/CodeBlock.cpp:
(JSC::CodeBlock::optimizationThresholdScalingFactor const):
(JSC::CodeBlock::optimizationThresholdScalingFactor): Deleted.
* Source/JavaScriptCore/bytecode/CodeBlock.h:
* Source/JavaScriptCore/bytecode/ExecutionCounter.cpp:
(JSC::maximumExecutionCountsBetweenCheckpoints):
(JSC::ExecutionCounter<countingVariant>::hasCrossedThreshold const):
(JSC::ExecutionCounter<countingVariant>::setThreshold):
* Source/JavaScriptCore/bytecode/ExecutionCounter.h:
(JSC::ExecutionCounter::clippedThreshold):
(JSC::ExecutionCounter::maximumExecutionCountsBetweenCheckpoints): Deleted.
* Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp:
(JSC::DFG::handleExitCounts):
* Source/JavaScriptCore/runtime/OptionsList.h:

Canonical link: https://commits.webkit.org/266819@main
  • Loading branch information
Constellation committed Aug 11, 2023
1 parent 11dd1ef commit c323bd2
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/bytecode/CodeBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2488,7 +2488,7 @@ int32_t CodeBlock::codeTypeThresholdMultiplier() const
return 1;
}

double CodeBlock::optimizationThresholdScalingFactor()
double CodeBlock::optimizationThresholdScalingFactor() const
{
// This expression arises from doing a least-squares fit of
//
Expand Down
4 changes: 2 additions & 2 deletions Source/JavaScriptCore/bytecode/CodeBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,8 @@ class CodeBlock : public JSCell {

bool loopHintsAreEligibleForFuzzingEarlyReturn() { return m_unlinkedCode->loopHintsAreEligibleForFuzzingEarlyReturn(); }

double optimizationThresholdScalingFactor() const;

protected:
void finalizeLLIntInlineCaches();
#if ENABLE(JIT)
Expand All @@ -879,8 +881,6 @@ class CodeBlock : public JSCell {
CodeBlock* specialOSREntryBlockOrNull();

void noticeIncomingCall(CallFrame* callerFrame);

double optimizationThresholdScalingFactor();

void updateAllNonLazyValueProfilePredictionsAndCountLiveness(const ConcurrentJSLocker&, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);

Expand Down
31 changes: 29 additions & 2 deletions Source/JavaScriptCore/bytecode/ExecutionCounter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,33 @@ int32_t applyMemoryUsageHeuristicsAndConvertToInt(int32_t value, CodeBlock* code
return static_cast<int32_t>(doubleResult);
}

int32_t maximumExecutionCountsBetweenCheckpoints(CountingVariant countingVariant, CodeBlock* codeBlock)
{
switch (countingVariant) {
case CountingForBaseline: {
int32_t threshold = Options::maximumExecutionCountsBetweenCheckpointsForBaseline();
UNUSED_PARAM(codeBlock);
#if ENABLE(JIT)
if (codeBlock) {
// If the CodeBlock becomes particularly mega sized, then updating profiles become huge cost.
// We would like to avoid updating profiles repeatedly for that function, so we relax checkpoint period longer.
// We do not need to make checkpoint period longer for CountingForUpperTiers since they do not update profiles.
if (static_cast<int32_t>(codeBlock->bytecodeCost()) >= Options::highCostBaselineProfilingFunctionBytecodeCost()) {
double factor = std::max(std::sqrt(codeBlock->optimizationThresholdScalingFactor()), 1.0);
return toInt32(threshold * factor);
}
}
#endif
return threshold;
}
case CountingForUpperTiers:
return Options::maximumExecutionCountsBetweenCheckpointsForUpperTiers();
default:
RELEASE_ASSERT_NOT_REACHED();
return 0;
}
}

template<CountingVariant countingVariant>
bool ExecutionCounter<countingVariant>::hasCrossedThreshold(CodeBlock* codeBlock) const
{
Expand All @@ -123,7 +150,7 @@ bool ExecutionCounter<countingVariant>::hasCrossedThreshold(CodeBlock* codeBlock

double actualCount = static_cast<double>(m_totalCount) + m_counter;
double desiredCount = modifiedThreshold - static_cast<double>(
std::min(m_activeThreshold, maximumExecutionCountsBetweenCheckpoints())) / 2;
std::min(m_activeThreshold, maximumExecutionCountsBetweenCheckpoints(countingVariant, codeBlock))) / 2;

bool result = actualCount >= desiredCount;

Expand Down Expand Up @@ -159,7 +186,7 @@ bool ExecutionCounter<countingVariant>::setThreshold(CodeBlock* codeBlock)
return true;
}

threshold = clippedThreshold(threshold);
threshold = clippedThreshold(codeBlock, threshold);

m_counter = static_cast<int32_t>(-threshold);

Expand Down
18 changes: 3 additions & 15 deletions Source/JavaScriptCore/bytecode/ExecutionCounter.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum CountingVariant {

double applyMemoryUsageHeuristics(int32_t value, CodeBlock*);
int32_t applyMemoryUsageHeuristicsAndConvertToInt(int32_t value, CodeBlock*);
int32_t maximumExecutionCountsBetweenCheckpoints(CountingVariant, CodeBlock*);

inline int32_t formattedTotalExecutionCount(float value)
{
Expand Down Expand Up @@ -72,23 +73,10 @@ class ExecutionCounter {
m_totalCount = memoryUsageAdjustedThreshold;
}

static int32_t maximumExecutionCountsBetweenCheckpoints()
{
switch (countingVariant) {
case CountingForBaseline:
return Options::maximumExecutionCountsBetweenCheckpointsForBaseline();
case CountingForUpperTiers:
return Options::maximumExecutionCountsBetweenCheckpointsForUpperTiers();
default:
RELEASE_ASSERT_NOT_REACHED();
return 0;
}
}

template<typename T>
static T clippedThreshold(T threshold)
static T clippedThreshold(CodeBlock* codeBlock, T threshold)
{
int32_t maxThreshold = maximumExecutionCountsBetweenCheckpoints();
int32_t maxThreshold = maximumExecutionCountsBetweenCheckpoints(countingVariant, codeBlock);
if (threshold > maxThreshold)
threshold = maxThreshold;
return threshold;
Expand Down
4 changes: 2 additions & 2 deletions Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ void handleExitCounts(VM& vm, CCallHelpers& jit, const OSRExitBase& exit)
int32_t clippedValue;
switch (jit.codeBlock()->jitType()) {
case JITType::DFGJIT:
clippedValue = BaselineExecutionCounter::clippedThreshold(targetValue);
clippedValue = BaselineExecutionCounter::clippedThreshold(jit.codeBlock(), targetValue);
break;
case JITType::FTLJIT:
clippedValue = UpperTierExecutionCounter::clippedThreshold(targetValue);
clippedValue = UpperTierExecutionCounter::clippedThreshold(jit.codeBlock(), targetValue);
break;
default:
RELEASE_ASSERT_NOT_REACHED();
Expand Down
1 change: 1 addition & 0 deletions Source/JavaScriptCore/runtime/OptionsList.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ bool canUseWebAssemblyFastMemory();
\
v(Int32, maximumExecutionCountsBetweenCheckpointsForBaseline, 1000, Normal, nullptr) \
v(Int32, maximumExecutionCountsBetweenCheckpointsForUpperTiers, 50000, Normal, nullptr) \
v(Int32, highCostBaselineProfilingFunctionBytecodeCost, 10000, Normal, nullptr) \
\
v(Unsigned, likelyToTakeSlowCaseMinimumCount, 20, Normal, nullptr) \
v(Unsigned, couldTakeSlowCaseMinimumCount, 10, Normal, nullptr) \
Expand Down

0 comments on commit c323bd2

Please sign in to comment.