mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
Bug 1209515 part 1 - IonBuilder: Attach hit counts on the MIRGraph. r=bhackett
This commit is contained in:
parent
b0da2d5086
commit
ba054b65a3
@ -7280,6 +7280,8 @@ IonBuilder::addBlock(MBasicBlock* block, uint32_t loopDepth)
|
|||||||
{
|
{
|
||||||
if (!block)
|
if (!block)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
if (block->pc() && script()->hasScriptCounts())
|
||||||
|
block->setHitCount(script()->getHitCount(block->pc()));
|
||||||
graph().addBlock(block);
|
graph().addBlock(block);
|
||||||
block->setLoopDepth(loopDepth);
|
block->setLoopDepth(loopDepth);
|
||||||
return block;
|
return block;
|
||||||
@ -7316,6 +7318,7 @@ IonBuilder::newBlockAfter(MBasicBlock* at, MBasicBlock* predecessor, jsbytecode*
|
|||||||
bytecodeSite(pc), MBasicBlock::NORMAL);
|
bytecodeSite(pc), MBasicBlock::NORMAL);
|
||||||
if (!block)
|
if (!block)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
block->setHitCount(0); // osr block
|
||||||
graph().insertBlockAfter(at, block);
|
graph().insertBlockAfter(at, block);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
@ -259,6 +259,8 @@ JSONSpewer::spewMIR(MIRGraph* mir)
|
|||||||
beginObject();
|
beginObject();
|
||||||
|
|
||||||
integerProperty("number", block->id());
|
integerProperty("number", block->id());
|
||||||
|
if (block->getHitState() == MBasicBlock::HitState::Count)
|
||||||
|
integerProperty("count", block->getHitCount());
|
||||||
|
|
||||||
beginListProperty("attributes");
|
beginListProperty("attributes");
|
||||||
if (block->isLoopBackedge())
|
if (block->isLoopBackedge())
|
||||||
|
@ -98,6 +98,9 @@ JitOptions::JitOptions()
|
|||||||
// Toggles whether Loop Unrolling is globally disabled.
|
// Toggles whether Loop Unrolling is globally disabled.
|
||||||
SET_DEFAULT(disableLoopUnrolling, true);
|
SET_DEFAULT(disableLoopUnrolling, true);
|
||||||
|
|
||||||
|
// Toggle whether Profile Guided Optimization is globally disabled.
|
||||||
|
SET_DEFAULT(disablePgo, true);
|
||||||
|
|
||||||
// Toggles whether instruction reordering is globally disabled.
|
// Toggles whether instruction reordering is globally disabled.
|
||||||
SET_DEFAULT(disableInstructionReordering, false);
|
SET_DEFAULT(disableInstructionReordering, false);
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ struct JitOptions
|
|||||||
bool disableInlining;
|
bool disableInlining;
|
||||||
bool disableLicm;
|
bool disableLicm;
|
||||||
bool disableLoopUnrolling;
|
bool disableLoopUnrolling;
|
||||||
|
bool disablePgo;
|
||||||
bool disableInstructionReordering;
|
bool disableInstructionReordering;
|
||||||
bool disableRangeAnalysis;
|
bool disableRangeAnalysis;
|
||||||
bool disableScalarReplacement;
|
bool disableScalarReplacement;
|
||||||
|
@ -404,7 +404,9 @@ MBasicBlock::MBasicBlock(MIRGraph& graph, CompileInfo& info, BytecodeSite* site,
|
|||||||
mark_(false),
|
mark_(false),
|
||||||
immediatelyDominated_(graph.alloc()),
|
immediatelyDominated_(graph.alloc()),
|
||||||
immediateDominator_(nullptr),
|
immediateDominator_(nullptr),
|
||||||
trackedSite_(site)
|
trackedSite_(site),
|
||||||
|
hitCount_(0),
|
||||||
|
hitState_(HitState::NotDefined)
|
||||||
#if defined (JS_ION_PERF)
|
#if defined (JS_ION_PERF)
|
||||||
, lineno_(0u),
|
, lineno_(0u),
|
||||||
columnIndex_(0u)
|
columnIndex_(0u)
|
||||||
|
@ -603,6 +603,32 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
|||||||
void dump(GenericPrinter& out);
|
void dump(GenericPrinter& out);
|
||||||
void dump();
|
void dump();
|
||||||
|
|
||||||
|
// Hit count
|
||||||
|
enum class HitState {
|
||||||
|
// Not hit information is attached to this basic block.
|
||||||
|
NotDefined,
|
||||||
|
|
||||||
|
// The hit information is a raw counter. Note that due to inlining this
|
||||||
|
// counter is not guaranteed to be consistent over the graph.
|
||||||
|
Count,
|
||||||
|
|
||||||
|
// The hit information is a frequency, which is a form of normalized
|
||||||
|
// counter, where a hit-count can be compared against any previous block
|
||||||
|
// in the graph.
|
||||||
|
Frequency
|
||||||
|
};
|
||||||
|
HitState getHitState() const {
|
||||||
|
return hitState_;
|
||||||
|
}
|
||||||
|
void setHitCount(uint64_t count) {
|
||||||
|
hitCount_ = count;
|
||||||
|
hitState_ = HitState::Count;
|
||||||
|
}
|
||||||
|
uint64_t getHitCount() const {
|
||||||
|
MOZ_ASSERT(hitState_ == HitState::Count);
|
||||||
|
return hitCount_;
|
||||||
|
}
|
||||||
|
|
||||||
// Track bailouts by storing the current pc in MIR instruction added at
|
// Track bailouts by storing the current pc in MIR instruction added at
|
||||||
// this cycle. This is also used for tracking calls and optimizations when
|
// this cycle. This is also used for tracking calls and optimizations when
|
||||||
// profiling.
|
// profiling.
|
||||||
@ -666,6 +692,11 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
|||||||
|
|
||||||
BytecodeSite* trackedSite_;
|
BytecodeSite* trackedSite_;
|
||||||
|
|
||||||
|
// Record the number of times a block got visited. Note, due to inlined
|
||||||
|
// scripts these numbers might not be continuous.
|
||||||
|
uint64_t hitCount_;
|
||||||
|
HitState hitState_;
|
||||||
|
|
||||||
#if defined(JS_ION_PERF) || defined(DEBUG)
|
#if defined(JS_ION_PERF) || defined(DEBUG)
|
||||||
unsigned lineno_;
|
unsigned lineno_;
|
||||||
unsigned columnIndex_;
|
unsigned columnIndex_;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "gc/Marking.h"
|
#include "gc/Marking.h"
|
||||||
#include "jit/JitCompartment.h"
|
#include "jit/JitCompartment.h"
|
||||||
|
#include "jit/JitOptions.h"
|
||||||
#include "js/Date.h"
|
#include "js/Date.h"
|
||||||
#include "js/Proxy.h"
|
#include "js/Proxy.h"
|
||||||
#include "js/RootingAPI.h"
|
#include "js/RootingAPI.h"
|
||||||
@ -1075,6 +1076,15 @@ JSCompartment::updateDebuggerObservesCoverage()
|
|||||||
clearScriptCounts();
|
clearScriptCounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
JSCompartment::collectCoverage() const
|
||||||
|
{
|
||||||
|
return !js_JitOptions.disablePgo ||
|
||||||
|
debuggerObservesCoverage() ||
|
||||||
|
runtimeFromAnyThread()->profilingScripts ||
|
||||||
|
runtimeFromAnyThread()->lcovOutput.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSCompartment::clearScriptCounts()
|
JSCompartment::clearScriptCounts()
|
||||||
{
|
{
|
||||||
|
@ -680,11 +680,7 @@ struct JSCompartment
|
|||||||
|
|
||||||
// The code coverage can be enabled either for each compartment, with the
|
// The code coverage can be enabled either for each compartment, with the
|
||||||
// Debugger API, or for the entire runtime.
|
// Debugger API, or for the entire runtime.
|
||||||
bool collectCoverage() const {
|
bool collectCoverage() const;
|
||||||
return debuggerObservesCoverage() ||
|
|
||||||
runtimeFromAnyThread()->profilingScripts ||
|
|
||||||
runtimeFromAnyThread()->lcovOutput.isEnabled();
|
|
||||||
}
|
|
||||||
void clearScriptCounts();
|
void clearScriptCounts();
|
||||||
|
|
||||||
bool needsDelazificationForDebugger() const {
|
bool needsDelazificationForDebugger() const {
|
||||||
|
@ -1415,6 +1415,20 @@ ScriptCounts::maybeGetPCCounts(size_t offset) const {
|
|||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const js::PCCounts*
|
||||||
|
ScriptCounts::getImmediatePrecedingPCCounts(size_t offset) const
|
||||||
|
{
|
||||||
|
PCCounts searched = PCCounts(offset);
|
||||||
|
const PCCounts* elem = std::lower_bound(pcCounts_.begin(), pcCounts_.end(), searched);
|
||||||
|
if (elem == pcCounts_.end())
|
||||||
|
return &pcCounts_.back();
|
||||||
|
if (elem->pcOffset() == offset)
|
||||||
|
return elem;
|
||||||
|
if (elem != pcCounts_.begin())
|
||||||
|
return elem - 1;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
const js::PCCounts*
|
const js::PCCounts*
|
||||||
ScriptCounts::maybeGetThrowCounts(size_t offset) const {
|
ScriptCounts::maybeGetThrowCounts(size_t offset) const {
|
||||||
PCCounts searched = PCCounts(offset);
|
PCCounts searched = PCCounts(offset);
|
||||||
@ -1424,6 +1438,23 @@ ScriptCounts::maybeGetThrowCounts(size_t offset) const {
|
|||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const js::PCCounts*
|
||||||
|
ScriptCounts::getImmediatePrecedingThrowCounts(size_t offset) const
|
||||||
|
{
|
||||||
|
PCCounts searched = PCCounts(offset);
|
||||||
|
const PCCounts* elem = std::lower_bound(throwCounts_.begin(), throwCounts_.end(), searched);
|
||||||
|
if (elem == throwCounts_.end()) {
|
||||||
|
if (throwCounts_.begin() == throwCounts_.end())
|
||||||
|
return nullptr;
|
||||||
|
return &throwCounts_.back();
|
||||||
|
}
|
||||||
|
if (elem->pcOffset() == offset)
|
||||||
|
return elem;
|
||||||
|
if (elem != throwCounts_.begin())
|
||||||
|
return elem - 1;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
js::PCCounts*
|
js::PCCounts*
|
||||||
ScriptCounts::getThrowCounts(size_t offset) {
|
ScriptCounts::getThrowCounts(size_t offset) {
|
||||||
PCCounts searched = PCCounts(offset);
|
PCCounts searched = PCCounts(offset);
|
||||||
@ -1462,6 +1493,33 @@ JSScript::getThrowCounts(jsbytecode* pc) {
|
|||||||
return getScriptCounts().getThrowCounts(pcToOffset(pc));
|
return getScriptCounts().getThrowCounts(pcToOffset(pc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
JSScript::getHitCount(jsbytecode* pc)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(containsPC(pc));
|
||||||
|
if (pc < main())
|
||||||
|
pc = main();
|
||||||
|
|
||||||
|
ScriptCounts& sc = getScriptCounts();
|
||||||
|
size_t targetOffset = pcToOffset(pc);
|
||||||
|
const js::PCCounts* baseCount = sc.getImmediatePrecedingPCCounts(targetOffset);
|
||||||
|
if (!baseCount)
|
||||||
|
return 0;
|
||||||
|
if (baseCount->pcOffset() == targetOffset)
|
||||||
|
return baseCount->numExec();
|
||||||
|
MOZ_ASSERT(baseCount->pcOffset() < targetOffset);
|
||||||
|
uint64_t count = baseCount->numExec();
|
||||||
|
do {
|
||||||
|
const js::PCCounts* throwCount = sc.getImmediatePrecedingThrowCounts(targetOffset);
|
||||||
|
if (!throwCount)
|
||||||
|
return count;
|
||||||
|
if (throwCount->pcOffset() <= baseCount->pcOffset())
|
||||||
|
return count;
|
||||||
|
count -= throwCount->numExec();
|
||||||
|
targetOffset = throwCount->pcOffset() - 1;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSScript::addIonCounts(jit::IonScriptCounts* ionCounts)
|
JSScript::addIonCounts(jit::IonScriptCounts* ionCounts)
|
||||||
{
|
{
|
||||||
|
@ -468,10 +468,22 @@ class ScriptCounts
|
|||||||
PCCounts* maybeGetPCCounts(size_t offset);
|
PCCounts* maybeGetPCCounts(size_t offset);
|
||||||
const PCCounts* maybeGetPCCounts(size_t offset) const;
|
const PCCounts* maybeGetPCCounts(size_t offset) const;
|
||||||
|
|
||||||
|
// PCCounts are stored at jump-target offsets. This function looks for the
|
||||||
|
// previous PCCount which is in the same basic block as the current offset.
|
||||||
|
const PCCounts* getImmediatePrecedingPCCounts(size_t offset) const;
|
||||||
|
|
||||||
// Return the counter used to count the number of throws. Returns null if
|
// Return the counter used to count the number of throws. Returns null if
|
||||||
// the element is not found.
|
// the element is not found.
|
||||||
const PCCounts* maybeGetThrowCounts(size_t offset) const;
|
const PCCounts* maybeGetThrowCounts(size_t offset) const;
|
||||||
|
|
||||||
|
// Throw counts are stored at the location of each throwing
|
||||||
|
// instruction. This function looks for the previous throw count.
|
||||||
|
//
|
||||||
|
// Note: if the offset of the returned count is higher than the offset of
|
||||||
|
// the immediate preceding PCCount, then this throw happened in the same
|
||||||
|
// basic block.
|
||||||
|
const PCCounts* getImmediatePrecedingThrowCounts(size_t offset) const;
|
||||||
|
|
||||||
// Return the counter used to count the number of throws. Allocate it if
|
// Return the counter used to count the number of throws. Allocate it if
|
||||||
// none exists yet. Returns null if the allocation failed.
|
// none exists yet. Returns null if the allocation failed.
|
||||||
PCCounts* getThrowCounts(size_t offset);
|
PCCounts* getThrowCounts(size_t offset);
|
||||||
@ -1671,6 +1683,7 @@ class JSScript : public js::gc::TenuredCell
|
|||||||
js::PCCounts* maybeGetPCCounts(jsbytecode* pc);
|
js::PCCounts* maybeGetPCCounts(jsbytecode* pc);
|
||||||
const js::PCCounts* maybeGetThrowCounts(jsbytecode* pc);
|
const js::PCCounts* maybeGetThrowCounts(jsbytecode* pc);
|
||||||
js::PCCounts* getThrowCounts(jsbytecode* pc);
|
js::PCCounts* getThrowCounts(jsbytecode* pc);
|
||||||
|
uint64_t getHitCount(jsbytecode* pc);
|
||||||
void addIonCounts(js::jit::IonScriptCounts* ionCounts);
|
void addIonCounts(js::jit::IonScriptCounts* ionCounts);
|
||||||
js::jit::IonScriptCounts* getIonCounts();
|
js::jit::IonScriptCounts* getIonCounts();
|
||||||
void releaseScriptCounts(js::ScriptCounts* counts);
|
void releaseScriptCounts(js::ScriptCounts* counts);
|
||||||
|
@ -6245,6 +6245,15 @@ SetRuntimeOptions(JSRuntime* rt, const OptionParser& op)
|
|||||||
return OptionFailure("ion-edgecase-analysis", str);
|
return OptionFailure("ion-edgecase-analysis", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const char* str = op.getStringOption("ion-pgo")) {
|
||||||
|
if (strcmp(str, "on") == 0)
|
||||||
|
jit::js_JitOptions.disablePgo = false;
|
||||||
|
else if (strcmp(str, "off") == 0)
|
||||||
|
jit::js_JitOptions.disablePgo = true;
|
||||||
|
else
|
||||||
|
return OptionFailure("ion-pgo", str);
|
||||||
|
}
|
||||||
|
|
||||||
if (const char* str = op.getStringOption("ion-range-analysis")) {
|
if (const char* str = op.getStringOption("ion-range-analysis")) {
|
||||||
if (strcmp(str, "on") == 0)
|
if (strcmp(str, "on") == 0)
|
||||||
jit::js_JitOptions.disableRangeAnalysis = false;
|
jit::js_JitOptions.disableRangeAnalysis = false;
|
||||||
@ -6599,6 +6608,8 @@ main(int argc, char** argv, char** envp)
|
|||||||
"Loop invariant code motion (default: on, off to disable)")
|
"Loop invariant code motion (default: on, off to disable)")
|
||||||
|| !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
|
|| !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
|
||||||
"Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
|
"Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
|
||||||
|
|| !op.addStringOption('\0', "ion-pgo", "on/off",
|
||||||
|
"Profile guided optimization (default: off, on to enable)")
|
||||||
|| !op.addStringOption('\0', "ion-range-analysis", "on/off",
|
|| !op.addStringOption('\0', "ion-range-analysis", "on/off",
|
||||||
"Range analysis (default: on, off to disable)")
|
"Range analysis (default: on, off to disable)")
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
|
Loading…
Reference in New Issue
Block a user