Commit 15281893 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[Liftoff] Compute a better initial assembler buffer size

Instead of always using {AssemblerBase::kMinimalBufferSize}, this CL
computes the expected code size per function compiled with Liftoff, and
uses that size to allocate the initial assembler buffer. This saves
reallocations especially for big functions.

R=jkummerow@chromium.org

Change-Id: I0031033c6be986f9d0d7bb10db0d213669044603
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1910951Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64938}
parent 2c661e44
......@@ -477,8 +477,6 @@ constexpr AssemblerOptions DefaultLiftoffOptions() {
} // namespace
// TODO(clemensb): Provide a reasonably sized buffer, based on wasm function
// size.
LiftoffAssembler::LiftoffAssembler(std::unique_ptr<AssemblerBuffer> buffer)
: TurboAssembler(nullptr, DefaultLiftoffOptions(), CodeObjectRequired::kNo,
std::move(buffer)) {
......
......@@ -2159,17 +2159,22 @@ WasmCompilationResult ExecuteLiftoffCompilation(AccountingAllocator* allocator,
int func_index,
Counters* counters,
WasmFeatures* detected) {
int func_body_size = static_cast<int>(func_body.end - func_body.start);
TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
"ExecuteLiftoffCompilation", "func_index", func_index,
"body_size", func_body.end - func_body.start);
"body_size", func_body_size);
Zone zone(allocator, "LiftoffCompilationZone");
const WasmModule* module = env ? env->module : nullptr;
auto call_descriptor = compiler::GetWasmCallDescriptor(&zone, func_body.sig);
base::Optional<TimedHistogramScope> liftoff_compile_time_scope(
base::in_place, counters->liftoff_compile_time());
size_t code_size_estimate =
WasmCodeManager::EstimateLiftoffCodeSize(func_body_size);
// Allocate the initial buffer a bit bigger to avoid reallocation during code
// generation.
std::unique_ptr<wasm::WasmInstructionBuffer> instruction_buffer =
wasm::WasmInstructionBuffer::New();
wasm::WasmInstructionBuffer::New(128 + code_size_estimate * 4 / 3);
WasmFullDecoder<Decoder::kValidate, LiftoffCompiler> decoder(
&zone, module, env->enabled_features, detected, func_body,
call_descriptor, env, &zone, instruction_buffer->CreateView());
......
......@@ -57,6 +57,9 @@ class WasmInstructionBufferImpl {
WasmInstructionBufferImpl* const holder_;
};
explicit WasmInstructionBufferImpl(size_t size)
: buffer_(OwnedVector<uint8_t>::New(size)) {}
std::unique_ptr<AssemblerBuffer> CreateView() {
DCHECK_NOT_NULL(buffer_);
return std::make_unique<View>(buffer_.as_vector(), this);
......@@ -72,8 +75,7 @@ class WasmInstructionBufferImpl {
private:
// The current buffer used to emit code.
OwnedVector<uint8_t> buffer_ =
OwnedVector<uint8_t>::New(AssemblerBase::kMinimalBufferSize);
OwnedVector<uint8_t> buffer_;
// While the buffer is grown, we need to temporarily also keep the old buffer
// alive.
......@@ -100,10 +102,10 @@ std::unique_ptr<uint8_t[]> WasmInstructionBuffer::ReleaseBuffer() {
}
// static
std::unique_ptr<WasmInstructionBuffer> WasmInstructionBuffer::New() {
std::unique_ptr<WasmInstructionBuffer> WasmInstructionBuffer::New(size_t size) {
return std::unique_ptr<WasmInstructionBuffer>{
reinterpret_cast<WasmInstructionBuffer*>(
new WasmInstructionBufferImpl())};
reinterpret_cast<WasmInstructionBuffer*>(new WasmInstructionBufferImpl(
std::max(size_t{AssemblerBase::kMinimalBufferSize}, size)))};
}
// End of PIMPL interface WasmInstructionBuffer for WasmInstBufferImpl
......
......@@ -35,7 +35,9 @@ class WasmInstructionBuffer final {
std::unique_ptr<AssemblerBuffer> CreateView();
std::unique_ptr<uint8_t[]> ReleaseBuffer();
static std::unique_ptr<WasmInstructionBuffer> New();
// Allocate a new {WasmInstructionBuffer}. The size is the maximum of {size}
// and {AssemblerBase::kMinimalSize}.
static std::unique_ptr<WasmInstructionBuffer> New(size_t size = 0);
// Override {operator delete} to avoid implicit instantiation of {operator
// delete} with {size_t} argument. The {size_t} argument would be incorrect.
......
......@@ -1539,6 +1539,64 @@ VirtualMemory WasmCodeManager::TryAllocate(size_t size, void* hint) {
return mem;
}
namespace {
// The numbers here are rough estimates, used to calculate the size of the
// initial code reservation and for estimating the amount of external memory
// reported to the GC.
// They do not need to be accurate. Choosing them too small will result in
// separate code spaces being allocated (compile time and runtime overhead),
// choosing them too large results in over-reservation (virtual address space
// only).
// The current numbers have been determined on 2019-11-11 by clemensb@, based
// on one small and one large module compiled from C++ by Emscripten. If in
// doubt, they where chosen slightly larger than required, as over-reservation
// is not a big issue currently.
// Numbers will change when Liftoff or TurboFan evolve, other toolchains are
// used to produce the wasm code, or characteristics of wasm modules on the
// web change. They might require occasional tuning.
// This patch might help to find reasonable numbers for any future adaptation:
// https://crrev.com/c/1910945
#if V8_TARGET_ARCH_X64
constexpr size_t kTurbofanFunctionOverhead = 20;
constexpr size_t kTurbofanCodeSizeMultiplier = 3;
constexpr size_t kLiftoffFunctionOverhead = 60;
constexpr size_t kLiftoffCodeSizeMultiplier = 4;
constexpr size_t kImportSize = 350;
#elif V8_TARGET_ARCH_IA32
constexpr size_t kTurbofanFunctionOverhead = 20;
constexpr size_t kTurbofanCodeSizeMultiplier = 4;
constexpr size_t kLiftoffFunctionOverhead = 60;
constexpr size_t kLiftoffCodeSizeMultiplier = 5;
constexpr size_t kImportSize = 480;
#elif V8_TARGET_ARCH_ARM
constexpr size_t kTurbofanFunctionOverhead = 40;
constexpr size_t kTurbofanCodeSizeMultiplier = 4;
constexpr size_t kLiftoffFunctionOverhead = 108;
constexpr size_t kLiftoffCodeSizeMultiplier = 7;
constexpr size_t kImportSize = 750;
#elif V8_TARGET_ARCH_ARM64
constexpr size_t kTurbofanFunctionOverhead = 60;
constexpr size_t kTurbofanCodeSizeMultiplier = 4;
constexpr size_t kLiftoffFunctionOverhead = 80;
constexpr size_t kLiftoffCodeSizeMultiplier = 7;
constexpr size_t kImportSize = 750;
#else
// Other platforms should add their own estimates if needed. Numbers below are
// the minimum of other architectures.
constexpr size_t kTurbofanFunctionOverhead = 20;
constexpr size_t kTurbofanCodeSizeMultiplier = 3;
constexpr size_t kLiftoffFunctionOverhead = 60;
constexpr size_t kLiftoffCodeSizeMultiplier = 4;
constexpr size_t kImportSize = 350;
#endif
} // namespace
// static
size_t WasmCodeManager::EstimateLiftoffCodeSize(int body_size) {
return kLiftoffFunctionOverhead + kCodeAlignment / 2 +
body_size * kLiftoffCodeSizeMultiplier;
}
// static
size_t WasmCodeManager::EstimateNativeModuleCodeSize(const WasmModule* module,
bool include_liftoff) {
......@@ -1561,56 +1619,6 @@ size_t WasmCodeManager::EstimateNativeModuleCodeSize(int num_functions,
int num_imported_functions,
int code_section_length,
bool include_liftoff) {
// The numbers here are rough estimates, used to calculate the size of the
// initial code reservation and for estimating the amount of external memory
// reported to the GC.
// They do not need to be accurate. Choosing them too small will result in
// separate code spaces being allocated (compile time and runtime overhead),
// choosing them too large results in over-reservation (virtual address space
// only).
// The current numbers have been determined on 2019-11-11 by clemensb@, based
// on one small and one large module compiled from C++ by Emscripten. If in
// doubt, they where chosen slightly larger than required, as over-reservation
// is not a big issue currently.
// Numbers will change when Liftoff or TurboFan evolve, other toolchains are
// used to produce the wasm code, or characteristics of wasm modules on the
// web change. They might require occasional tuning.
// This patch might help to find reasonable numbers for any future adaptation:
// https://crrev.com/c/1910945
#if V8_TARGET_ARCH_X64
constexpr size_t kTurbofanFunctionOverhead = 20;
constexpr size_t kTurbofanCodeSizeMultiplier = 3;
constexpr size_t kLiftoffFunctionOverhead = 60;
constexpr size_t kLiftoffCodeSizeMultiplier = 4;
constexpr size_t kImportSize = 350;
#elif V8_TARGET_ARCH_IA32
constexpr size_t kTurbofanFunctionOverhead = 20;
constexpr size_t kTurbofanCodeSizeMultiplier = 4;
constexpr size_t kLiftoffFunctionOverhead = 60;
constexpr size_t kLiftoffCodeSizeMultiplier = 5;
constexpr size_t kImportSize = 480;
#elif V8_TARGET_ARCH_ARM
constexpr size_t kTurbofanFunctionOverhead = 40;
constexpr size_t kTurbofanCodeSizeMultiplier = 4;
constexpr size_t kLiftoffFunctionOverhead = 108;
constexpr size_t kLiftoffCodeSizeMultiplier = 7;
constexpr size_t kImportSize = 750;
#elif V8_TARGET_ARCH_ARM64
constexpr size_t kTurbofanFunctionOverhead = 60;
constexpr size_t kTurbofanCodeSizeMultiplier = 4;
constexpr size_t kLiftoffFunctionOverhead = 80;
constexpr size_t kLiftoffCodeSizeMultiplier = 7;
constexpr size_t kImportSize = 750;
#else
// Other platforms should add their own estimates if needed. Numbers below are
// the minimum of other architectures.
constexpr size_t kTurbofanFunctionOverhead = 20;
constexpr size_t kTurbofanCodeSizeMultiplier = 3;
constexpr size_t kLiftoffFunctionOverhead = 60;
constexpr size_t kLiftoffCodeSizeMultiplier = 4;
constexpr size_t kImportSize = 350;
#endif
const size_t overhead_per_function =
kTurbofanFunctionOverhead + kCodeAlignment / 2 +
(include_liftoff ? kLiftoffFunctionOverhead + kCodeAlignment / 2 : 0);
......
......@@ -692,6 +692,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final {
return total_committed_code_space_.load();
}
// Estimate the needed code space for a Liftoff function based on the size of
// the function body (wasm byte code).
static size_t EstimateLiftoffCodeSize(int body_size);
// Estimate the needed code space from a completely decoded module.
static size_t EstimateNativeModuleCodeSize(const WasmModule* module,
bool include_liftoff);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment