Commit 53bc649e authored by bradnelson's avatar bradnelson Committed by Commit bot

[wasm] Adding metrics for Asm/Wasm.

Collecting:
Time histograms for: instantiate, decode module, decode function, compile, compile function.
Memory histograms for: decode peak, instantiate peak, compile function peak, min mem pages, max mem pages, function bytes, module bytes.
Range histograms of: functions per module.

BUG= https://code.google.com/p/v8/issues/detail?id=4203
BUG= https://bugs.chromium.org/p/chromium/issues/detail?id=575167
TEST=None
R=ahaas@chromium.org,bmeurer@chromium.org
LOG=N

Review URL: https://codereview.chromium.org/1866873002

Cr-Commit-Position: refs/heads/master@{#35467}
parent 6f8630ed
......@@ -2677,6 +2677,8 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction& function) {
HistogramTimerScope wasm_compile_function_time_scope(
isolate->counters()->wasm_compile_function_time());
if (FLAG_trace_wasm_compiler) {
OFStream os(stdout);
os << "Compiling WASM function "
......@@ -2780,6 +2782,9 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
static_cast<int>(function.code_end_offset - function.code_start_offset),
decode_ms, static_cast<int>(graph.NodeCount()), compile_ms);
}
// TODO(bradnelson): Improve histogram handling of size_t.
isolate->counters()->wasm_compile_function_peak_memory_bytes()->AddSample(
static_cast<int>(zone.allocation_size()));
return code;
}
......
......@@ -588,7 +588,9 @@ class RuntimeCallTimerScope {
101) \
HR(code_cache_reject_reason, V8.CodeCacheRejectReason, 1, 6, 6) \
HR(errors_thrown_per_context, V8.ErrorsThrownPerContext, 0, 200, 20) \
HR(debug_feature_usage, V8.DebugFeatureUsage, 1, 7, 7)
HR(debug_feature_usage, V8.DebugFeatureUsage, 1, 7, 7) \
/* Asm/Wasm. */ \
HR(wasm_functions_per_module, V8.WasmFunctionsPerModule, 0, 10000, 101)
#define HISTOGRAM_TIMER_LIST(HT) \
/* Garbage collection timers. */ \
......@@ -619,8 +621,17 @@ class RuntimeCallTimerScope {
HT(compile_deserialize, V8.CompileDeserializeMicroSeconds, 1000000, \
MICROSECOND) \
/* Total compilation time incl. caching/parsing */ \
HT(compile_script, V8.CompileScriptMicroSeconds, 1000000, MICROSECOND)
HT(compile_script, V8.CompileScriptMicroSeconds, 1000000, MICROSECOND) \
/* Asm/Wasm */ \
HT(wasm_instantiate_time, V8.WasmInstantiateMicroSeconds, 1000000, \
MICROSECOND) \
HT(wasm_decode_module_time, V8.WasmDecodeModuleMicroSeconds, 1000000, \
MICROSECOND) \
HT(wasm_decode_function_time, V8.WasmDecodeFunctionMicroSeconds, 1000000, \
MICROSECOND) \
HT(wasm_compile_time, V8.WasmCompileMicroSeconds, 1000000, MICROSECOND) \
HT(wasm_compile_function_time, V8.WasmCompileFunctionMicroSeconds, 1000000, \
MICROSECOND)
#define AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT) \
AHT(compile_lazy, V8.CompileLazyMicroSeconds)
......@@ -651,10 +662,17 @@ class RuntimeCallTimerScope {
HM(heap_sample_code_space_committed, V8.MemoryHeapSampleCodeSpaceCommitted) \
HM(heap_sample_maximum_committed, V8.MemoryHeapSampleMaximumCommitted)
#define HISTOGRAM_MEMORY_LIST(HM) \
HM(memory_heap_committed, V8.MemoryHeapCommitted) \
HM(memory_heap_used, V8.MemoryHeapUsed)
#define HISTOGRAM_MEMORY_LIST(HM) \
HM(memory_heap_committed, V8.MemoryHeapCommitted) \
HM(memory_heap_used, V8.MemoryHeapUsed) \
/* Asm/Wasm */ \
HM(wasm_decode_peak_memory_bytes, V8.WasmDecodePeakMemoryBytes) \
HM(wasm_compile_function_peak_memory_bytes, \
V8.WasmCompileFunctionPeakMemoryBytes) \
HM(wasm_min_mem_pages_count, V8.WasmMinMemPagesCount) \
HM(wasm_max_mem_pages_count, V8.WasmMaxMemPagesCount) \
HM(wasm_function_size_bytes, V8.WasmFunctionSizeBytes) \
HM(wasm_module_size_bytes, V8.WasmModuleSizeBytes)
// WARNING: STATS_COUNTER_LIST_* is a very large macro that is causing MSVC
// Intellisense to crash. It was broken into two macros (each of length 40
......@@ -703,7 +721,6 @@ class RuntimeCallTimerScope {
/* The store-buffer implementation of the write barrier. */ \
SC(store_buffer_overflows, V8.StoreBufferOverflows)
#define STATS_COUNTER_LIST_2(SC) \
/* Number of code stubs. */ \
SC(code_stubs, V8.CodeStubs) \
......@@ -763,7 +780,7 @@ class RuntimeCallTimerScope {
SC(math_pow_runtime, V8.MathPowRuntime) \
SC(stack_interrupts, V8.StackInterrupts) \
SC(runtime_profiler_ticks, V8.RuntimeProfilerTicks) \
SC(runtime_calls, V8.RuntimeCalls) \
SC(runtime_calls, V8.RuntimeCalls) \
SC(bounds_checks_eliminated, V8.BoundsChecksEliminated) \
SC(bounds_checks_hoisted, V8.BoundsChecksHoisted) \
SC(soft_deopts_requested, V8.SoftDeoptsRequested) \
......
......@@ -767,15 +767,24 @@ class FunctionError : public FunctionResult {
ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
const byte* module_start, const byte* module_end,
bool verify_functions, ModuleOrigin origin) {
size_t decode_memory_start = zone->allocation_size();
HistogramTimerScope wasm_decode_module_time_scope(
isolate->counters()->wasm_decode_module_time());
size_t size = module_end - module_start;
if (module_start > module_end) return ModuleError("start > end");
if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
// TODO(bradnelson): Improve histogram handling of size_t.
isolate->counters()->wasm_module_size_bytes()->AddSample(
static_cast<int>(size));
WasmModule* module = new WasmModule();
ModuleDecoder decoder(zone, module_start, module_end, origin);
return decoder.DecodeModule(module, verify_functions);
ModuleResult result = decoder.DecodeModule(module, verify_functions);
// TODO(bradnelson): Improve histogram handling of size_t.
isolate->counters()->wasm_decode_peak_memory_bytes()->AddSample(
static_cast<int>(zone->allocation_size() - decode_memory_start));
return result;
}
FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
const byte* end) {
ModuleDecoder decoder(zone, start, end, kWasmOrigin);
......@@ -787,10 +796,14 @@ FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
ModuleEnv* module_env,
const byte* function_start,
const byte* function_end) {
HistogramTimerScope wasm_decode_function_time_scope(
isolate->counters()->wasm_decode_function_time());
size_t size = function_end - function_start;
if (function_start > function_end) return FunctionError("start > end");
if (size > kMaxFunctionSize)
return FunctionError("size > maximum function size");
isolate->counters()->wasm_function_size_bytes()->AddSample(
static_cast<int>(size));
WasmFunction* function = new WasmFunction();
ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin);
return decoder.DecodeSingleFunction(module_env, function);
......
......@@ -382,6 +382,8 @@ static MaybeHandle<JSFunction> LookupFunction(
MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
Handle<JSObject> ffi,
Handle<JSArrayBuffer> memory) {
HistogramTimerScope wasm_instantiate_time_scope(
isolate->counters()->wasm_instantiate_time());
this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate.
ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
Factory* factory = isolate->factory();
......@@ -402,6 +404,10 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
//-------------------------------------------------------------------------
// Allocate and initialize the linear memory.
//-------------------------------------------------------------------------
isolate->counters()->wasm_min_mem_pages_count()->AddSample(
instance.module->min_mem_pages);
isolate->counters()->wasm_max_mem_pages_count()->AddSample(
instance.module->max_mem_pages);
if (memory.is_null()) {
if (!AllocateMemory(&thrower, isolate, &instance)) {
return MaybeHandle<JSObject>();
......@@ -424,6 +430,9 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
*instance.globals_buffer);
}
HistogramTimerScope wasm_compile_time_scope(
isolate->counters()->wasm_compile_time());
//-------------------------------------------------------------------------
// Compile wrappers to imported functions.
//-------------------------------------------------------------------------
......@@ -457,89 +466,96 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
//-------------------------------------------------------------------------
// Compile all functions in the module.
//-------------------------------------------------------------------------
{
isolate->counters()->wasm_functions_per_module()->AddSample(
static_cast<int>(functions.size()));
// First pass: compile each function and initialize the code table.
index = FLAG_skip_compiling_wasm_funcs;
while (index < functions.size()) {
const WasmFunction& func = functions[index];
if (thrower.error()) break;
DCHECK_EQ(index, func.func_index);
// First pass: compile each function and initialize the code table.
index = FLAG_skip_compiling_wasm_funcs;
while (index < functions.size()) {
const WasmFunction& func = functions[index];
if (thrower.error()) break;
DCHECK_EQ(index, func.func_index);
WasmName str = GetName(func.name_offset, func.name_length);
WasmName str_null = {nullptr, 0};
Handle<String> name = factory->InternalizeUtf8String(
Vector<const char>(str.name, str.length));
Handle<Code> code = Handle<Code>::null();
Handle<JSFunction> function = Handle<JSFunction>::null();
if (func.external) {
// Lookup external function in FFI object.
MaybeHandle<JSFunction> function =
LookupFunction(thrower, factory, ffi, index, str, str_null);
if (function.is_null()) return MaybeHandle<JSObject>();
code = compiler::CompileWasmToJSWrapper(isolate, &module_env,
function.ToHandleChecked(),
func.sig, str, str_null);
} else {
// Compile the function.
code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
if (code.is_null()) {
thrower.Error("Compilation of #%d:%.*s failed.", index, str.length,
str.name);
return MaybeHandle<JSObject>();
WasmName str = GetName(func.name_offset, func.name_length);
WasmName str_null = {nullptr, 0};
Handle<String> name = factory->InternalizeUtf8String(
Vector<const char>(str.name, str.length));
Handle<Code> code = Handle<Code>::null();
Handle<JSFunction> function = Handle<JSFunction>::null();
if (func.external) {
// Lookup external function in FFI object.
MaybeHandle<JSFunction> function =
LookupFunction(thrower, factory, ffi, index, str, str_null);
if (function.is_null()) return MaybeHandle<JSObject>();
code = compiler::CompileWasmToJSWrapper(isolate, &module_env,
function.ToHandleChecked(),
func.sig, str, str_null);
} else {
// Compile the function.
code =
compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
if (code.is_null()) {
thrower.Error("Compilation of #%d:%.*s failed.", index, str.length,
str.name);
return MaybeHandle<JSObject>();
}
if (func.exported) {
function = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object, index);
}
}
if (!code.is_null()) {
// Install the code into the linker table.
linker.Finish(index, code);
code_table->set(index, *code);
}
if (func.exported) {
function = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object, index);
// Exported functions are installed as read-only properties on the
// module.
JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
}
index++;
}
if (!code.is_null()) {
// Install the code into the linker table.
linker.Finish(index, code);
code_table->set(index, *code);
}
if (func.exported) {
// Exported functions are installed as read-only properties on the module.
JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
}
index++;
}
// Second pass: patch all direct call sites.
linker.Link(instance.function_table, this->function_table);
instance.js_object->SetInternalField(kWasmModuleFunctionTable,
Smi::FromInt(0));
// Second pass: patch all direct call sites.
linker.Link(instance.function_table, this->function_table);
instance.js_object->SetInternalField(kWasmModuleFunctionTable,
Smi::FromInt(0));
//-------------------------------------------------------------------------
// Create and populate the exports object.
//-------------------------------------------------------------------------
if (export_table.size() > 0 || mem_export) {
index = 0;
// Create the "exports" object.
Handle<JSFunction> object_function = Handle<JSFunction>(
isolate->native_context()->object_function(), isolate);
Handle<JSObject> exports_object =
factory->NewJSObject(object_function, TENURED);
Handle<String> exports_name = factory->InternalizeUtf8String("exports");
JSObject::AddProperty(instance.js_object, exports_name, exports_object,
READ_ONLY);
//-------------------------------------------------------------------------
// Create and populate the exports object.
//-------------------------------------------------------------------------
if (export_table.size() > 0 || mem_export) {
index = 0;
// Create the "exports" object.
Handle<JSFunction> object_function = Handle<JSFunction>(
isolate->native_context()->object_function(), isolate);
Handle<JSObject> exports_object =
factory->NewJSObject(object_function, TENURED);
Handle<String> exports_name = factory->InternalizeUtf8String("exports");
JSObject::AddProperty(instance.js_object, exports_name, exports_object,
READ_ONLY);
// Compile wrappers and add them to the exports object.
for (const WasmExport& exp : export_table) {
if (thrower.error()) break;
WasmName str = GetName(exp.name_offset, exp.name_length);
Handle<String> name = factory->InternalizeUtf8String(
Vector<const char>(str.name, str.length));
Handle<Code> code = linker.GetFunctionCode(exp.func_index);
Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object, exp.func_index);
JSObject::AddProperty(exports_object, name, function, READ_ONLY);
}
// Compile wrappers and add them to the exports object.
for (const WasmExport& exp : export_table) {
if (thrower.error()) break;
WasmName str = GetName(exp.name_offset, exp.name_length);
Handle<String> name = factory->InternalizeUtf8String(
Vector<const char>(str.name, str.length));
Handle<Code> code = linker.GetFunctionCode(exp.func_index);
Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object,
exp.func_index);
JSObject::AddProperty(exports_object, name, function, READ_ONLY);
}
if (mem_export) {
// Export the memory as a named property.
Handle<String> name = factory->InternalizeUtf8String("memory");
JSObject::AddProperty(exports_object, name, instance.mem_buffer,
READ_ONLY);
if (mem_export) {
// Export the memory as a named property.
Handle<String> name = factory->InternalizeUtf8String("memory");
JSObject::AddProperty(exports_object, name, instance.mem_buffer,
READ_ONLY);
}
}
}
......
......@@ -66,7 +66,7 @@ struct LocalTypePair {
{kLocalF32, kAstF32},
{kLocalF64, kAstF64}};
class WasmModuleVerifyTest : public TestWithZone {
class WasmModuleVerifyTest : public TestWithIsolateAndZone {
public:
ModuleResult DecodeModule(const byte* module_start, const byte* module_end) {
// Add the WASM magic and version number automatically.
......@@ -76,14 +76,14 @@ class WasmModuleVerifyTest : public TestWithZone {
auto temp = new byte[total];
memcpy(temp, header, sizeof(header));
memcpy(temp + sizeof(header), module_start, size);
ModuleResult result = DecodeWasmModule(nullptr, zone(), temp, temp + total,
false, kWasmOrigin);
ModuleResult result = DecodeWasmModule(isolate(), zone(), temp,
temp + total, false, kWasmOrigin);
delete[] temp;
return result;
}
ModuleResult DecodeModuleNoHeader(const byte* module_start,
const byte* module_end) {
return DecodeWasmModule(nullptr, zone(), module_start, module_end, false,
return DecodeWasmModule(isolate(), zone(), module_start, module_end, false,
kWasmOrigin);
}
};
......@@ -901,9 +901,7 @@ TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type) {
}
}
class WasmFunctionVerifyTest : public TestWithZone {};
class WasmFunctionVerifyTest : public TestWithIsolateAndZone {};
TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
static const byte data[] = {
......@@ -916,7 +914,7 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
kExprNop // body
};
FunctionResult result = DecodeWasmFunction(nullptr, zone(), nullptr, data,
FunctionResult result = DecodeWasmFunction(isolate(), zone(), nullptr, data,
data + arraysize(data));
EXPECT_TRUE(result.ok());
......
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