Skip to content

Commit

Permalink
Bug 1824772: part 4 - Cache jit hints in the process for eager baseli…
Browse files Browse the repository at this point in the history
…ne compilation r=iain,arai

Add a cache, based on a bloom filter, in the JIT Runtime that will exist for the process lifetime.  Whenever a script is baseline compiled, we add a hint to the cache based on the script filename+sourceStart values.  If we encounter this script again, during a navigation for example, then we can eagerly compile this script and skip the warmup.

Using a bloom filter does introduce false positives, so we try to maintain a false positivity rate of less than 1% and if we exceed this value we clear the cache.

Depends on D175523

Differential Revision: https://phabricator.services.mozilla.com/D175524
  • Loading branch information
dpalmeiro committed Apr 21, 2023
1 parent a1f9cb7 commit 712972e
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 3 deletions.
8 changes: 8 additions & 0 deletions js/src/jit/BaselineCodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

#include "debugger/DebugAPI-inl.h"
#include "jit/BaselineFrameInfo-inl.h"
#include "jit/JitHints-inl.h"
#include "jit/JitScript-inl.h"
#include "jit/MacroAssembler-inl.h"
#include "jit/SharedICHelpers-inl.h"
Expand Down Expand Up @@ -220,6 +221,13 @@ MethodStatus BaselineCompiler::compile() {
}
}

#ifdef NIGHTLY_BUILD
if (!JitOptions.disableJitHints) {
JitHintsMap* jitHints = cx->runtime()->jitRuntime()->getJitHintsMap();
jitHints->setEagerBaselineHint(script);
}
#endif

// Suppress GC during compilation.
gc::AutoSuppressGC suppressGC(cx);

Expand Down
21 changes: 18 additions & 3 deletions js/src/jit/BaselineJIT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include "debugger/DebugAPI-inl.h"
#include "gc/GC-inl.h"
#include "jit/JitHints-inl.h"
#include "jit/JitScript-inl.h"
#include "vm/GeckoProfiler-inl.h"
#include "vm/JSScript-inl.h"
Expand Down Expand Up @@ -290,9 +291,23 @@ static MethodStatus CanEnterBaselineJIT(JSContext* cx, HandleScript script,
return Method_Compiled;
}

// Check script warm-up counter.
if (script->getWarmUpCount() <= JitOptions.baselineJitWarmUpThreshold) {
return Method_Skipped;
// If a hint is available, skip the warmup count threshold.
bool mightHaveEagerBaselineHint = false;
#ifdef NIGHTLY_BUILD
if (!JitOptions.disableJitHints && !script->noEagerBaselineHint()) {
JitHintsMap* jitHints = cx->runtime()->jitRuntime()->getJitHintsMap();
// If this lookup fails, the NoEagerBaselineHint script flag is set
// to true to prevent any further lookups for this script.
if (jitHints->mightHaveEagerBaselineHint(script)) {
mightHaveEagerBaselineHint = true;
}
}
#endif
// Check script warm-up counter if no hint.
if (!mightHaveEagerBaselineHint) {
if (script->getWarmUpCount() <= JitOptions.baselineJitWarmUpThreshold) {
return Method_Skipped;
}
}

// Check this before calling ensureJitRealmExists, so we're less
Expand Down
13 changes: 13 additions & 0 deletions js/src/jit/Ion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ JitRuntime::~JitRuntime() {
// interpreterEntryMap should be cleared out during finishRoots()
MOZ_ASSERT_IF(interpreterEntryMap_, interpreterEntryMap_->empty());
js_delete(interpreterEntryMap_.ref());

#ifdef NIGHTLY_BUILD
js_delete(jitHintsMap_.ref());
#endif
}

uint32_t JitRuntime::startTrampolineCode(MacroAssembler& masm) {
Expand Down Expand Up @@ -124,6 +128,15 @@ bool JitRuntime::initialize(JSContext* cx) {
return false;
}

#ifdef NIGHTLY_BUILD
if (!JitOptions.disableJitHints) {
jitHintsMap_ = cx->new_<JitHintsMap>();
if (!jitHintsMap_) {
return false;
}
}
#endif

if (JitOptions.emitInterpreterEntryTrampoline) {
interpreterEntryMap_ = cx->new_<EntryTrampolineMap>();
if (!interpreterEntryMap_) {
Expand Down
60 changes: 60 additions & 0 deletions js/src/jit/JitHints-inl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef jit_JitHints_inl_h
#define jit_JitHints_inl_h

#include "jit/JitHints.h"
#include "mozilla/HashFunctions.h"

namespace js::jit {

inline JitHintsMap::ScriptKey JitHintsMap::getScriptKey(
JSScript* script) const {
if (ScriptKey key = script->filenameHash()) {
return mozilla::AddToHash(key, script->sourceStart());
}
return 0;
}

inline void JitHintsMap::incrementEntryCount() {
// Clear the cache if we've exceeded the false positivity rate
// calculated by MaxEntries.
if (++entryCount_ > MaxEntries_) {
map_.clear();
entryCount_ = 0;
}
}

inline void JitHintsMap::setEagerBaselineHint(JSScript* script) {
ScriptKey key = getScriptKey(script);
if (!key) {
return;
}

// If the entry already exists, don't increment entryCount.
if (map_.mightContain(key)) {
return;
}

// Increment entry count, and possibly clear the cache.
incrementEntryCount();

script->setNoEagerBaselineHint(false);
map_.add(key);
}

inline bool JitHintsMap::mightHaveEagerBaselineHint(JSScript* script) const {
if (ScriptKey key = getScriptKey(script)) {
return map_.mightContain(key);
}
script->setNoEagerBaselineHint(true);
return false;
}

} // namespace js::jit

#endif /* jit_JitHints_inl_h */
56 changes: 56 additions & 0 deletions js/src/jit/JitHints.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef jit_JitHints_h
#define jit_JitHints_h

#include "mozilla/BloomFilter.h"
#include "vm/JSScript.h"

namespace js::jit {

/*
* The JitHintsMap implements a BitBloomFilter to track whether or not a script,
* identified by filename+sourceStart, has been baseline compiled before in the
* same process. This can occur frequently during navigations.
*
* The bloom filter allows us to have very efficient storage and lookup costs,
* at the expense of occasional false positives. The number of entries added
* to the bloom filter is monitored in order to try and keep the false
* positivity rate below 1%. If the entry count exceeds MaxEntries_, which
* indicates the false positivity rate may exceed 1.5%, then the filter is
* completely cleared to reset the cache.
*/

class JitHintsMap {
// ScriptKey is a hash on the filename+sourceStart.
using ScriptKey = HashNumber;

static constexpr uint32_t CacheSize_ = 16;
mozilla::BitBloomFilter<CacheSize_, ScriptKey> map_;

/*
* MaxEntries_ is the approximate entry count for which the
* false positivity rate will exceed p=0.015 using k=2 and m=2**CacheSize.
* Formula is as follows:
* MaxEntries_ = floor(m / (-k / ln(1-exp(ln(p) / k))))
*/
static constexpr uint32_t MaxEntries_ = 4281;
static_assert(CacheSize_ == 16 && MaxEntries_ == 4281,
"MaxEntries should be recalculated for given CacheSize.");

uint32_t entryCount_ = 0;

ScriptKey getScriptKey(JSScript* script) const;
void incrementEntryCount();

public:
void setEagerBaselineHint(JSScript* script);
bool mightHaveEagerBaselineHint(JSScript* script) const;
};

} // namespace js::jit
#endif /* jit_JitHints_h */
11 changes: 11 additions & 0 deletions js/src/jit/JitRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "jit/IonCompileTask.h"
#include "jit/IonTypes.h"
#include "jit/JitCode.h"
#include "jit/JitHints.h"
#include "jit/shared/Assembler-shared.h"
#include "js/AllocPolicy.h"
#include "js/ProfilingFrameIterator.h"
Expand Down Expand Up @@ -196,6 +197,9 @@ class JitRuntime {
// Global table of jitcode native address => bytecode address mappings.
UnprotectedData<JitcodeGlobalTable*> jitcodeGlobalTable_{nullptr};

// Map that stores Jit Hints for each script.
MainThreadData<JitHintsMap*> jitHintsMap_{nullptr};

// Map used to collect entry trampolines for the Interpreters which is used
// for external profiling to identify which functions are being interpreted.
MainThreadData<EntryTrampolineMap*> interpreterEntryMap_{nullptr};
Expand Down Expand Up @@ -391,6 +395,13 @@ class JitRuntime {
return jitcodeGlobalTable_;
}

bool hasJitHintsMap() const { return jitHintsMap_ != nullptr; }

JitHintsMap* getJitHintsMap() {
MOZ_ASSERT(hasJitHintsMap());
return jitHintsMap_;
}

bool hasInterpreterEntryMap() const {
return interpreterEntryMap_ != nullptr;
}
Expand Down

0 comments on commit 712972e

Please sign in to comment.