Skip to content

Commit

Permalink
Reusable TC
Browse files Browse the repository at this point in the history
Summary: Add an option to enable relocating new translations and prologues into dead
regions in the TC. The recycle-tc interface handles tracking and updating TC
meta-data when recycling old translations, and a new ReusableCodeBlock class
allows free/allocInner to track free ranges within the TC. For the most part
code has to be written at the frontier and relocated into a free region.

The allocator is currently pretty dumb, it can coalesce adjacent blocks, and
adjust the frontier of the code-block. I didn't group free regions into size
classes, or do much other than favoring low addresses to prevent fragmentation.

At some point it may be worth exploring TC compaction by relocating live
translations to fill free code-blocks. Tests with sandcastle have shown that
the current method is a noticable improvement.

For now the option is defaulted to off (unless built with HHVM_REUSE_TC), it
may be worth having it on in non-repo mode by default.

Reviewed By: @markw65

Differential Revision: D1989755
  • Loading branch information
paulbiss authored and hhvm-bot committed Jun 26, 2015
1 parent 07b2ff9 commit 75632c1
Show file tree
Hide file tree
Showing 25 changed files with 1,257 additions and 80 deletions.
4 changes: 4 additions & 0 deletions hphp/runtime/base/runtime-option.cpp
Expand Up @@ -476,6 +476,10 @@ static inline bool jitLLVMSLPVectorizeDefault() {
RuntimeOption::EvalJitLLVMSizeLevel < 2;
}

static inline bool reuseTCDefault() {
return hhvm_reuse_tc && !RuntimeOption::RepoAuthoritative;
}

static inline bool hugePagesSoundNice() {
return RuntimeOption::ServerExecutionMode();
}
Expand Down
2 changes: 2 additions & 0 deletions hphp/runtime/base/runtime-option.h
Expand Up @@ -554,6 +554,8 @@ class RuntimeOption {
F(bool, EnableNumaLocal, ServerExecutionMode()) \
F(bool, DisableStructArray, true) \
F(bool, EnableCallBuiltin, true) \
F(bool, EnableReusableTC, reuseTCDefault()) \
F(uint32_t, ReusableTCPadding, 128) \
/* */

private:
Expand Down
15 changes: 15 additions & 0 deletions hphp/runtime/server/admin-request-handler.cpp
Expand Up @@ -28,6 +28,7 @@
#include "hphp/runtime/base/thread-hooks.h"
#include "hphp/runtime/base/unit-cache.h"
#include "hphp/runtime/vm/jit/mc-generator.h"
#include "hphp/runtime/vm/jit/recycle-tc.h"
#include "hphp/runtime/vm/jit/relocation.h"
#include "hphp/runtime/vm/repo.h"

Expand Down Expand Up @@ -758,6 +759,20 @@ bool AdminRequestHandler::handleCheckRequest(const std::string &cmd,
appendStat("rds-persistent", rds::usedPersistentBytes());
appendStat("units", numLoadedUnits());
appendStat("funcs", Func::nextFuncId());

if (RuntimeOption::EvalEnableReusableTC) {
mCGenerator->code.forEachBlock([&](const char* name, const CodeBlock& a) {
appendStat(folly::format("tc-{}-allocs", name).str(), a.numAllocs());
appendStat(folly::format("tc-{}-frees", name).str(), a.numFrees());
appendStat(folly::format("tc-{}-free-size", name).str(), a.bytesFree());
appendStat(folly::format("tc-{}-free-blocks", name).str(),
a.blocksFree());
});
appendStat("tc-recorded-funcs", jit::recordedFuncs());
appendStat("tc-smashed-calls", jit::smashedCalls());
appendStat("tc-smashed-branches", jit::smashedBranches());
}

out << "}" << endl;
transport->sendString(out.str());
return true;
Expand Down
27 changes: 20 additions & 7 deletions hphp/runtime/vm/func.cpp
Expand Up @@ -27,6 +27,7 @@
#include "hphp/runtime/base/type-string.h"
#include "hphp/runtime/vm/class.h"
#include "hphp/runtime/vm/jit/mc-generator.h"
#include "hphp/runtime/vm/jit/recycle-tc.h"
#include "hphp/runtime/vm/jit/types.h"
#include "hphp/runtime/vm/treadmill.h"
#include "hphp/runtime/vm/type-constraint.h"
Expand Down Expand Up @@ -87,13 +88,10 @@ Func::~Func() {
if (m_fullName != nullptr && m_maybeIntercepted != -1) {
unregister_intercept_flag(fullNameStr(), &m_maybeIntercepted);
}
int maxNumPrologues = getMaxNumPrologues(numParams());
int numPrologues =
maxNumPrologues > kNumFixedPrologues ? maxNumPrologues
: kNumFixedPrologues;
if (mcg != nullptr) {
mcg->smashPrologueGuards((jit::TCA*)m_prologueTable,
numPrologues, this);
if (mcg != nullptr && !RuntimeOption::EvalEnableReusableTC) {
// If Reusable TC is enabled then the prologue may have already been smashed
// and the memory may now be in use by another function.
smashPrologues();
}
#ifdef DEBUG
validate();
Expand All @@ -112,9 +110,15 @@ void* Func::allocFuncMem(int numParams) {

void Func::destroy(Func* func) {
if (func->m_funcId != InvalidFuncId) {
if (mcg && RuntimeOption::EvalEnableReusableTC) {
// Free TC-space associated with func
jit::reclaimFunction(func);
}

DEBUG_ONLY auto oldVal = s_funcVec.exchange(func->m_funcId, nullptr);
assert(oldVal == func);
func->m_funcId = InvalidFuncId;

if (s_treadmill.load(std::memory_order_acquire)) {
Treadmill::enqueue([func](){ destroy(func); });
return;
Expand All @@ -124,6 +128,15 @@ void Func::destroy(Func* func) {
low_free(func);
}

void Func::smashPrologues() {
int maxNumPrologues = getMaxNumPrologues(numParams());
int numPrologues =
maxNumPrologues > kNumFixedPrologues ? maxNumPrologues
: kNumFixedPrologues;
mcg->smashPrologueGuards((jit::TCA*)m_prologueTable,
numPrologues, this);
}

Func* Func::clone(Class* cls, const StringData* name) const {
auto numParams = this->numParams();

Expand Down
5 changes: 5 additions & 0 deletions hphp/runtime/vm/func.h
Expand Up @@ -928,6 +928,11 @@ struct Func {
void resetPrologue(int numParams);
void resetPrologues();

/*
* Smash prologue guards to prevent function from being called.
*/
void smashPrologues();


/////////////////////////////////////////////////////////////////////////////
// Pretty printer. [const]
Expand Down
1 change: 1 addition & 0 deletions hphp/runtime/vm/jit/back-end-x64.cpp
Expand Up @@ -488,6 +488,7 @@ void BackEnd::genCodeImpl(IRUnit& unit, CodeKind kind, AsmInfo* asmInfo) {
CodeBlock coldCode;
bool do_relocate = false;
if (!mcg->useLLVM() &&
!RuntimeOption::EvalEnableReusableTC &&
RuntimeOption::EvalJitRelocationSize &&
coldCodeIn.canEmit(RuntimeOption::EvalJitRelocationSize * 3)) {
/*
Expand Down
2 changes: 2 additions & 0 deletions hphp/runtime/vm/jit/code-gen.h
Expand Up @@ -28,6 +28,8 @@
namespace HPHP { namespace jit {
///////////////////////////////////////////////////////////////////////////////

struct TransLoc;

enum class SyncOptions {
kNoSyncPoint,
kSyncPoint,
Expand Down
7 changes: 6 additions & 1 deletion hphp/runtime/vm/jit/fixup.h
Expand Up @@ -149,7 +149,12 @@ struct FixupMap {
void recordFixup(CTCA tca, const Fixup& fixup) {
TRACE(3, "FixupMapImpl::recordFixup: tca %p -> (pcOff %d, spOff %d)\n",
tca, fixup.pcOffset, fixup.spOffset);
m_fixups.insert(tca, FixupEntry(fixup));

if (auto pos = m_fixups.find(tca)) {
*pos = FixupEntry(fixup);
} else {
m_fixups.insert(tca, FixupEntry(fixup));
}
}

const Fixup* findFixup(CTCA tca) const {
Expand Down

0 comments on commit 75632c1

Please sign in to comment.