WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
235581
Add support for WASM branch hinting proposal
https://bugs.webkit.org/show_bug.cgi?id=235581
Summary
Add support for WASM branch hinting proposal
Tom Tartarin
Reported
2022-01-25 05:42:04 PST
See the proposal for a more detailed description:
https://github.com/WebAssembly/branch-hinting
. This allows parsing a "code_annotation.branch_hint" custom section, as per the code annotation proposal:
https://github.com/WebAssembly/annotations
. This section provides per function information about how likely a branch at a given offset is to be taken. It is similar to branch weight metadata in LLVM. For B3 and AIR this implies generating "hinted" blocks, whose frequencies are already set. The provided test is inspired by how the name section is tested: a wasm file containing the encoded custom section is read, compiled and run. It only tests the integration of the WasmBranchHintsSectionParser in the parsing pipeline, since more accurate testing would require inspecting the internal state of the VM.
Attachments
Patch
(47.22 KB, patch)
2022-01-25 05:50 PST
,
Tom Tartarin
saam
: review-
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
bug-235581: add support for WASM branch hinting proposal
(42.37 KB, patch)
2022-01-25 06:14 PST
,
Tom Tartarin
no flags
Details
Formatted Diff
Diff
Updated patch after review
(30.21 KB, patch)
2022-01-26 17:20 PST
,
Tom Tartarin
ysuzuki
: review+
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
Use switch instead of if else. Add ASSERT for branch hint validation
(30.71 KB, patch)
2022-01-28 06:31 PST
,
Tom Tartarin
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
Show Obsolete
(3)
View All
Add attachment
proposed patch, testcase, etc.
Tom Tartarin
Comment 1
2022-01-25 05:50:05 PST
Created
attachment 449921
[details]
Patch
Tom Tartarin
Comment 2
2022-01-25 06:14:37 PST
Created
attachment 449923
[details]
bug-235581: add support for WASM branch hinting proposal
Yusuke Suzuki
Comment 3
2022-01-25 09:48:49 PST
Comment on
attachment 449921
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=449921&action=review
Nice!
> Source/JavaScriptCore/b3/B3EstimateStaticExecutionCounts.cpp:45 > constexpr double base = 10.0; > + if (block->isHinted()) > + continue; > block->setFrequency(pow(base, naturalLoops.loopDepth(block)));
Should we treat the hint as a coefficient to this calculated count? Let's consider that here is a block in the deep loop (4-depth). Then, the frequency becomes 10e4. It is much higher than the hint's value (0 or 1.0). So, currently, if we use hint, it lowers the value compared to the value offered by static-execution-counts. Background: In Wasm B3 IR generator, except for FrequencyClass::Rare, we are not attaching frequency and calculating it in this pass. In JS, we are using execution counter to profile block's frequency and reflect it at runtime.
Yusuke Suzuki
Comment 4
2022-01-25 10:11:02 PST
Comment on
attachment 449921
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=449921&action=review
>> Source/JavaScriptCore/b3/B3EstimateStaticExecutionCounts.cpp:45 >> block->setFrequency(pow(base, naturalLoops.loopDepth(block))); > > Should we treat the hint as a coefficient to this calculated count? > Let's consider that here is a block in the deep loop (4-depth). Then, the frequency becomes 10e4. > It is much higher than the hint's value (0 or 1.0). So, currently, if we use hint, it lowers the value compared to the value offered by static-execution-counts. > > Background: In Wasm B3 IR generator, except for FrequencyClass::Rare, we are not attaching frequency and calculating it in this pass. > In JS, we are using execution counter to profile block's frequency and reflect it at runtime.
Ah, let me wait. I'm currently discussing with Saam about the way to use branch hinting. It would be much simpler.
Saam Barati
Comment 5
2022-01-25 10:39:27 PST
Comment on
attachment 449921
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=449921&action=review
Your implementation in B3/Air is more complicated than it needs to be. All you need to do is set the FrequencyClass based on the hint. If the hint is Likely, set the taken side "Normal" and not taken side "Rare". If the hint is Unlikely, set it the taken side to "Rare" and the not taken sideT "Normal". That'll get you the behavior you want. No need to change static execution count estimate, no need to add the "isHinted" stuff to any of the basic block classes.
> Source/JavaScriptCore/b3/B3BasicBlock.h:150 > + void setHinted(bool hinted) { m_hinted = hinted; }
none of this is necessary. See my suggestion on how to implement this patch.
> Source/JavaScriptCore/b3/air/AirBasicBlock.h:137 > + void setHinted(bool hinted) { m_hinted = hinted; } > + bool isHinted() const { return m_hinted; }
none of this is necessary. See my suggestion on how to implement this patch.
> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:2498 > +auto B3IRGenerator::addIfWithHint(ExpressionType condition, BlockSignature signature, Stack& enclosingStack, ControlType& result, Stack& newStack, const BranchHint& hint) -> PartialResult
ditto to what I wrote about the AirIRGenerator having two versions of this function.
> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:2755 > + if (Options::useWebAssemblyBranchHints()) { > + const BranchHint& hint = m_info.getBranchHint(m_functionIndex, m_parser->currentOpcodeStartingOffset()); > + if (hint != BranchHint::Invalid) > + return addBranchWithHint(data, condition, returnValues, hint); > + }
Instead of the second "addBranchWithHint" function, just define default values for FrequencyClass for taken/not taken. Then if we find a branch hint inside the map, you can change the values of those frequency classes. Also, no need for "const BranchHint&". Just "BranchHint hint = m_info.get(...);"
> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:2775 > +auto B3IRGenerator::addBranchWithHint(ControlData& data, ExpressionType condition, const Stack& returnValues, const BranchHint& hint) -> PartialResult
You shouldn't use two versions of essentially an identical function. Just have default values for the FrequencyClass used and augment them when we have hint data.
> Source/JavaScriptCore/wasm/WasmBranchHints.h:59 > + StdUnorderedMap<uint32_t, BranchHint> m_map;
you should use HashMap here (and with UnsignedWithZeroKeyHashTraits if the branch offset can be zero)
> Source/JavaScriptCore/wasm/WasmBranchHints.h:62 > +
all functions below here can be constexpr. Also, no need to really take in this enum as "const BranchHint&"
> Source/JavaScriptCore/wasm/WasmBranchHints.h:70 > +inline BranchHint branchHintToInverse(const BranchHint& hint)
branchHintToInverse => "invertBranchHint"
> Source/JavaScriptCore/wasm/WasmBranchHints.h:84 > + break;
maybe just return false here?
> Source/JavaScriptCore/wasm/WasmBranchHintsSectionParser.cpp:39 > + int64_t lastFunctionIndex = -1;
name nit: "lastFunctionIndex" => "previousFunctionIndex"
> Source/JavaScriptCore/wasm/WasmBranchHintsSectionParser.cpp:46 > + WASM_PARSER_FAIL_IF(int64_t(functionIndex) <= lastFunctionIndex, "invalid function index ", functionIndex, " for function ", i);
webkit style guide uses static_cast<int64_t>, not C style casts. Also, is this really "<="? Why not strictly "<"? The spec says we can keep having functions of the same index? That has consequences on your algorithm below using "emplace"
> Source/JavaScriptCore/wasm/WasmBranchHintsSectionParser.cpp:60 > + WASM_PARSER_FAIL_IF(int64_t(branchOffset) <= lastBranchOffset, "invalid branch offset ", branchOffset, " for hint ", j);
same nit regarding c style casts Also, when using HashMap, we should fail if the branchOffset is either the empty or deleted value in the hash map. See the hash trait I was talking about: template<typename T> struct UnsignedWithZeroKeyHashTraits : GenericHashTraits<T> { static constexpr bool emptyValueIsZero = false; static T emptyValue() { return std::numeric_limits<T>::max(); } static void constructDeletedValue(T& slot) { slot = std::numeric_limits<T>::max() - 1; } static bool isDeletedValue(T value) { return value == std::numeric_limits<T>::max() - 1; } }; Which in general should be fine. Nobody should be using such a large offset anyways. Also, same question regarding "<=" instead of "<"
> Source/JavaScriptCore/wasm/WasmBranchHintsSectionParser.cpp:71 > + BranchHint branchHint = static_cast<BranchHint>(int32_t(parsedBranchHint));
don't use C style cast here. But also, I don't see why it's necessary at all. Shouldn't static_cast<BranchHint>(parsedBranchHint) work?
> Source/JavaScriptCore/wasm/WasmBranchHintsSectionParser.cpp:72 > + WASM_PARSER_FAIL_IF(!isValidBranchHint(branchHint), "invalid branch hint value ", parsedBranchHint, " for hint ", j);
how is this possible if we're parsing a VarUint1? The value has to be zero or one, right? Should this be an assert?
> Source/JavaScriptCore/wasm/WasmBranchHintsSectionParser.cpp:74 > + branchHintsForFunction.insert(branchOffset, branchHint);
related question regarding the "<=" above. If functionIndex already exists, what semantics do we want? Merge? Overwrite? Skip?
> Source/JavaScriptCore/wasm/WasmBranchHintsSectionParser.cpp:76 > + m_info->branchHints.emplace(functionIndex, WTFMove(branchHintsForFunction));
related question regarding the "<=" above. If functionIndex already exists, what semantics do we want? Merge? Overwrite? Skip?
> Source/JavaScriptCore/wasm/WasmModuleInformation.h:40 > + using BranchHints = StdUnorderedMap<uint32_t, BranchHintMap>;
you should use HashMap here with UnsignedWithZeroKeyHashTraits
Tom Tartarin
Comment 6
2022-01-26 01:23:33 PST
Thank you for the detailed review. I will rework the patch and submit soon.
Tom Tartarin
Comment 7
2022-01-26 17:20:24 PST
Created
attachment 450087
[details]
Updated patch after review
Yusuke Suzuki
Comment 8
2022-01-28 04:14:15 PST
Comment on
attachment 450087
[details]
Updated patch after review View in context:
https://bugs.webkit.org/attachment.cgi?id=450087&action=review
r=me
> Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp:3186 > + if (hint == BranchHint::Unlikely) > + takenFrequency = B3::FrequencyClass::Rare; > + else if (hint == BranchHint::Likely) > + notTakenFrequency = B3::FrequencyClass::Rare;
Let's use switch.
> Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp:3439 > + if (hint == BranchHint::Unlikely) > + targetFrequency = B3::FrequencyClass::Rare; > + else if (hint == BranchHint::Likely) > + continuationFrequency = B3::FrequencyClass::Rare;
Ditto.
> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:2486 > + if (hint == BranchHint::Unlikely) > + takenFrequency = FrequencyClass::Rare; > + else if (hint == BranchHint::Likely) > + notTakenFrequency = FrequencyClass::Rare;
Let's use switch, which can ensure that all enums are handled. switch (hint) { case BranchHint::Unlikely: takenFrequency = FrequencyClass::Rare; break; case BranchHint::Likely: notTakenFrequency = FrequencyClass::Rare; break; }
> Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:2742 > + if (hint == BranchHint::Unlikely) > + targetFrequency = FrequencyClass::Rare; > + else if (hint == BranchHint::Likely) > + continuationFrequency = FrequencyClass::Rare;
Ditto.
> Source/JavaScriptCore/wasm/WasmBranchHintsSectionParser.cpp:70 > + BranchHint branchHint = static_cast<BranchHint>(parsedBranchHint);
Let's add ASSERT(isValidBranchHint(branchHint)); It should be due to parseVarUInt1. But such an ASSERT is helpful if this branch hint is extended to have more values (then, assert hits and we can fix the issue :)).
Tom Tartarin
Comment 9
2022-01-28 06:31:10 PST
Created
attachment 450230
[details]
Use switch instead of if else. Add ASSERT for branch hint validation
Tom Tartarin
Comment 10
2022-01-28 06:38:37 PST
Thanks for the review!
EWS
Comment 11
2022-01-28 12:49:23 PST
Committed
r288758
(
246546@main
): <
https://commits.webkit.org/246546@main
> All reviewed patches have been landed. Closing bug and clearing flags on
attachment 450230
[details]
.
Radar WebKit Bug Importer
Comment 12
2022-01-28 12:50:18 PST
<
rdar://problem/88199746
>
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug