[tracing] Improve tracing signals for compilation/optimization.
This adds OBJECT/SNAPSHOT trace events for Script and SharedFunctionInfo objects, logging their creation with appropriate information to make sense of them. Based on that we introduces five flow events to model the optimized compilation via tracing in the "disabled-by-default-v8.compile" category: - "v8.optimizingCompile.start" logs the creation of the PipelineCompilationJob (for TurboFan JavaScript optimization) with the "function" argument referring to the trace event object created for the SharedFunctionInfo. - "v8.optimzingCompile.prepare" logs the preparation of the PipelineCompilationJob on the main thread, also carrying the "function" argument. This connects the flow event to the actual tracing duration event associated with the preparation phases. - "v8.optimizingCompile.execute" logs the (usually concurrent) optimization of the TurboFan graph (again with "function"). - "v8.optimizingCompile.finalize" logs the main thread phase which finalizes the optimized code and eventually installs it (in case of success). - "v8.optimizingCompile.end" signals the end of the PipelineCompilationJob, which carries the "compilationInfo", that contains the interesting bits of the OptimizedCompilationInfo, specifically whether the compile was successfull and which functions were inlined for example. This also adds two instant events "V8.AbortOptimization" and "V8.RetryOptimization" in "disabled-by-default-v8.compile" category that are emitted when TurboFan cannot optimize a certain function. In case of "V8.RetryOptimization", TurboFan might be able to optimize it later, whereas "V8.AbortOptimization" permanently disables the optimization of a given function. The JSON representation of this is ```js { "pid": 256639, "tid": 256639, "ts": 6935411377801, "tts": 159116, "ph": "I", "cat": "disabled-by-default-v8.compile", "name": "V8.AbortOptimization", "dur": 0, "tdur": 0, "args": { "reason": "Function is too big to be optimized", "function": { "id_ref": "0x600000001", "scope": "v8::internal::SharedFunctionInfo" } } }, ``` where the "function" refers to a previously emitted SNAPSHOT for the function in question. In the trace viewer it will show up as instant event under "v8.optimizingCompile.prepare" in case of the relevant example where optimization is disabled due to reaching the bytecode limit (as in the JSON above), i.e. it'll look something like this https://i.paste.pics/aafc2de9df10ea8f5acc1a761d80f07b.png for the example highlighted in the recent blog post https://ponyfoo.com/articles/javascript-performance-pitfalls-v8 that describes the optimization limit. The "v8.optimizingCompile.end" duration event will also carry this information as part of the "compilationInfo" object, but specifically for CI tools, etc. it might be a whole lot easier to just look for the "V8.AbortOptimization" instant event. Bug: v8:8598, v8:9039 Tbr: ulan@chromium.org Doc: bit.ly/v8-tracing-signals Change-Id: Ic87ac336004690c65b6b15ad73bc6fbd4b5f12c4 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1511483 Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Peter Marshall <petermarshall@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#60448}
This commit is contained in:
parent
24038b9357
commit
a2af7e1101
@ -1472,6 +1472,10 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
|
||||
}
|
||||
}
|
||||
script->set_eval_from_position(eval_position);
|
||||
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "Script",
|
||||
TRACE_ID_WITH_SCOPE(Script::kTraceScope, script->id()),
|
||||
script->ToTracedValue());
|
||||
|
||||
parse_info.set_eval();
|
||||
parse_info.set_language_mode(language_mode);
|
||||
@ -1795,6 +1799,10 @@ Handle<Script> NewScript(Isolate* isolate, ParseInfo* parse_info,
|
||||
script->set_host_defined_options(*host_defined_options);
|
||||
}
|
||||
LOG(isolate, ScriptDetails(*script));
|
||||
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "Script",
|
||||
TRACE_ID_WITH_SCOPE(Script::kTraceScope, script->id()),
|
||||
script->ToTracedValue());
|
||||
return script;
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,7 @@
|
||||
#include "src/parsing/parse-info.h"
|
||||
#include "src/register-configuration.h"
|
||||
#include "src/tracing/trace-event.h"
|
||||
#include "src/tracing/traced-value.h"
|
||||
#include "src/utils.h"
|
||||
#include "src/wasm/function-body-decoder.h"
|
||||
#include "src/wasm/function-compiler.h"
|
||||
@ -862,24 +863,8 @@ class PipelineCompilationJob final : public OptimizedCompilationJob {
|
||||
public:
|
||||
PipelineCompilationJob(Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared_info,
|
||||
Handle<JSFunction> function)
|
||||
// Note that the OptimizedCompilationInfo is not initialized at the time
|
||||
// we pass it to the CompilationJob constructor, but it is not
|
||||
// dereferenced there.
|
||||
: OptimizedCompilationJob(
|
||||
function->GetIsolate()->stack_guard()->real_climit(),
|
||||
&compilation_info_, "TurboFan"),
|
||||
zone_(function->GetIsolate()->allocator(), ZONE_NAME),
|
||||
zone_stats_(function->GetIsolate()->allocator()),
|
||||
compilation_info_(&zone_, function->GetIsolate(), shared_info,
|
||||
function),
|
||||
pipeline_statistics_(CreatePipelineStatistics(
|
||||
handle(Script::cast(shared_info->script()), isolate),
|
||||
compilation_info(), function->GetIsolate(), &zone_stats_)),
|
||||
data_(&zone_stats_, function->GetIsolate(), compilation_info(),
|
||||
pipeline_statistics_.get()),
|
||||
pipeline_(&data_),
|
||||
linkage_(nullptr) {}
|
||||
Handle<JSFunction> function);
|
||||
~PipelineCompilationJob();
|
||||
|
||||
protected:
|
||||
Status PrepareJobImpl(Isolate* isolate) final;
|
||||
@ -901,8 +886,43 @@ class PipelineCompilationJob final : public OptimizedCompilationJob {
|
||||
DISALLOW_COPY_AND_ASSIGN(PipelineCompilationJob);
|
||||
};
|
||||
|
||||
PipelineCompilationJob::PipelineCompilationJob(
|
||||
Isolate* isolate, Handle<SharedFunctionInfo> shared_info,
|
||||
Handle<JSFunction> function)
|
||||
// Note that the OptimizedCompilationInfo is not initialized at the time
|
||||
// we pass it to the CompilationJob constructor, but it is not
|
||||
// dereferenced there.
|
||||
: OptimizedCompilationJob(
|
||||
function->GetIsolate()->stack_guard()->real_climit(),
|
||||
&compilation_info_, "TurboFan"),
|
||||
zone_(function->GetIsolate()->allocator(), ZONE_NAME),
|
||||
zone_stats_(function->GetIsolate()->allocator()),
|
||||
compilation_info_(&zone_, function->GetIsolate(), shared_info, function),
|
||||
pipeline_statistics_(CreatePipelineStatistics(
|
||||
handle(Script::cast(shared_info->script()), isolate),
|
||||
compilation_info(), function->GetIsolate(), &zone_stats_)),
|
||||
data_(&zone_stats_, function->GetIsolate(), compilation_info(),
|
||||
pipeline_statistics_.get()),
|
||||
pipeline_(&data_),
|
||||
linkage_(nullptr) {
|
||||
TRACE_EVENT_WITH_FLOW1(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "v8.optimizingCompile.start",
|
||||
this, TRACE_EVENT_FLAG_FLOW_OUT, "function", shared_info->TraceIDRef());
|
||||
}
|
||||
|
||||
PipelineCompilationJob::~PipelineCompilationJob() {
|
||||
TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
"v8.optimizingCompile.end", this,
|
||||
TRACE_EVENT_FLAG_FLOW_IN, "compilationInfo",
|
||||
compilation_info()->ToTracedValue());
|
||||
}
|
||||
|
||||
PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
|
||||
Isolate* isolate) {
|
||||
TRACE_EVENT_WITH_FLOW1(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "v8.optimizingCompile.prepare",
|
||||
this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "function",
|
||||
compilation_info()->shared_info()->TraceIDRef());
|
||||
if (compilation_info()->bytecode_array()->length() >
|
||||
kMaxBytecodeSizeForTurbofan) {
|
||||
return AbortOptimization(BailoutReason::kFunctionTooBig);
|
||||
@ -968,6 +988,10 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
|
||||
}
|
||||
|
||||
PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() {
|
||||
TRACE_EVENT_WITH_FLOW1(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "v8.optimizingCompile.execute",
|
||||
this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "function",
|
||||
compilation_info()->shared_info()->TraceIDRef());
|
||||
if (!pipeline_.OptimizeGraph(linkage_)) return FAILED;
|
||||
pipeline_.AssembleCode(linkage_);
|
||||
return SUCCEEDED;
|
||||
@ -975,6 +999,10 @@ PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() {
|
||||
|
||||
PipelineCompilationJob::Status PipelineCompilationJob::FinalizeJobImpl(
|
||||
Isolate* isolate) {
|
||||
TRACE_EVENT_WITH_FLOW1(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "v8.optimizingCompile.finalize",
|
||||
this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "function",
|
||||
compilation_info()->shared_info()->TraceIDRef());
|
||||
MaybeHandle<Code> maybe_code = pipeline_.FinalizeCode();
|
||||
Handle<Code> code;
|
||||
if (!maybe_code.ToHandle(&code)) {
|
||||
|
@ -142,48 +142,52 @@ inline bool IsConstructable(FunctionKind kind) {
|
||||
FunctionKind::kDerivedConstructor);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, FunctionKind kind) {
|
||||
inline const char* FunctionKind2String(FunctionKind kind) {
|
||||
switch (kind) {
|
||||
case FunctionKind::kNormalFunction:
|
||||
return os << "NormalFunction";
|
||||
return "NormalFunction";
|
||||
case FunctionKind::kArrowFunction:
|
||||
return os << "ArrowFunction";
|
||||
return "ArrowFunction";
|
||||
case FunctionKind::kGeneratorFunction:
|
||||
return os << "GeneratorFunction";
|
||||
return "GeneratorFunction";
|
||||
case FunctionKind::kConciseMethod:
|
||||
return os << "ConciseMethod";
|
||||
return "ConciseMethod";
|
||||
case FunctionKind::kDerivedConstructor:
|
||||
return os << "DerivedConstructor";
|
||||
return "DerivedConstructor";
|
||||
case FunctionKind::kBaseConstructor:
|
||||
return os << "BaseConstructor";
|
||||
return "BaseConstructor";
|
||||
case FunctionKind::kGetterFunction:
|
||||
return os << "GetterFunction";
|
||||
return "GetterFunction";
|
||||
case FunctionKind::kSetterFunction:
|
||||
return os << "SetterFunction";
|
||||
return "SetterFunction";
|
||||
case FunctionKind::kAsyncFunction:
|
||||
return os << "AsyncFunction";
|
||||
return "AsyncFunction";
|
||||
case FunctionKind::kModule:
|
||||
return os << "Module";
|
||||
return "Module";
|
||||
case FunctionKind::kClassMembersInitializerFunction:
|
||||
return os << "ClassMembersInitializerFunction";
|
||||
return "ClassMembersInitializerFunction";
|
||||
case FunctionKind::kDefaultBaseConstructor:
|
||||
return os << "DefaultBaseConstructor";
|
||||
return "DefaultBaseConstructor";
|
||||
case FunctionKind::kDefaultDerivedConstructor:
|
||||
return os << "DefaultDerivedConstructor";
|
||||
return "DefaultDerivedConstructor";
|
||||
case FunctionKind::kAsyncArrowFunction:
|
||||
return os << "AsyncArrowFunction";
|
||||
return "AsyncArrowFunction";
|
||||
case FunctionKind::kAsyncConciseMethod:
|
||||
return os << "AsyncConciseMethod";
|
||||
return "AsyncConciseMethod";
|
||||
case FunctionKind::kConciseGeneratorMethod:
|
||||
return os << "ConciseGeneratorMethod";
|
||||
return "ConciseGeneratorMethod";
|
||||
case FunctionKind::kAsyncConciseGeneratorMethod:
|
||||
return os << "AsyncConciseGeneratorMethod";
|
||||
return "AsyncConciseGeneratorMethod";
|
||||
case FunctionKind::kAsyncGeneratorFunction:
|
||||
return os << "AsyncGeneratorFunction";
|
||||
return "AsyncGeneratorFunction";
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, FunctionKind kind) {
|
||||
return os << FunctionKind2String(kind);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -334,16 +334,20 @@ inline size_t hash_value(LanguageMode mode) {
|
||||
return static_cast<size_t>(mode);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const LanguageMode& mode) {
|
||||
inline const char* LanguageMode2String(LanguageMode mode) {
|
||||
switch (mode) {
|
||||
case LanguageMode::kSloppy:
|
||||
return os << "sloppy";
|
||||
return "sloppy";
|
||||
case LanguageMode::kStrict:
|
||||
return os << "strict";
|
||||
return "strict";
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, LanguageMode mode) {
|
||||
return os << LanguageMode2String(mode);
|
||||
}
|
||||
|
||||
inline bool is_sloppy(LanguageMode language_mode) {
|
||||
return language_mode == LanguageMode::kSloppy;
|
||||
}
|
||||
|
@ -1683,6 +1683,9 @@ Handle<Script> Factory::NewScriptWithId(Handle<String> source, int script_id,
|
||||
MaybeObjectHandle::Weak(script));
|
||||
heap->set_script_list(*scripts);
|
||||
LOG(isolate(), ScriptEvent(Logger::ScriptEventType::kCreate, script_id));
|
||||
TRACE_EVENT_OBJECT_CREATED_WITH_ID(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "Script",
|
||||
TRACE_ID_WITH_SCOPE(Script::kTraceScope, script_id));
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -3590,6 +3593,13 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForLiteral(
|
||||
SharedFunctionInfo::InitFromFunctionLiteral(shared, literal, is_toplevel);
|
||||
SharedFunctionInfo::SetScript(shared, script, literal->function_literal_id(),
|
||||
false);
|
||||
TRACE_EVENT_OBJECT_CREATED_WITH_ID(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "SharedFunctionInfo",
|
||||
TRACE_ID_WITH_SCOPE(SharedFunctionInfo::kTraceScope, shared->TraceID()));
|
||||
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "SharedFunctionInfo",
|
||||
TRACE_ID_WITH_SCOPE(SharedFunctionInfo::kTraceScope, shared->TraceID()),
|
||||
shared->ToTracedValue());
|
||||
return shared;
|
||||
}
|
||||
|
||||
|
@ -4878,6 +4878,37 @@ MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
|
||||
return handle(SharedFunctionInfo::cast(heap_object), isolate);
|
||||
}
|
||||
|
||||
std::unique_ptr<v8::tracing::TracedValue> Script::ToTracedValue() {
|
||||
auto value = v8::tracing::TracedValue::Create();
|
||||
if (name()->IsString()) {
|
||||
value->SetString("name", String::cast(name())->ToCString());
|
||||
}
|
||||
value->SetInteger("lineOffset", line_offset());
|
||||
value->SetInteger("columnOffset", column_offset());
|
||||
if (source_mapping_url()->IsString()) {
|
||||
value->SetString("sourceMappingURL",
|
||||
String::cast(source_mapping_url())->ToCString());
|
||||
}
|
||||
if (source()->IsString()) {
|
||||
value->SetString("source", String::cast(source())->ToCString());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// static
|
||||
const char* Script::kTraceScope = "v8::internal::Script";
|
||||
|
||||
uint64_t Script::TraceID() const { return id(); }
|
||||
|
||||
std::unique_ptr<v8::tracing::TracedValue> Script::TraceIDRef() const {
|
||||
auto value = v8::tracing::TracedValue::Create();
|
||||
std::ostringstream ost;
|
||||
ost << "0x" << std::hex << TraceID();
|
||||
value->SetString("id_ref", ost.str());
|
||||
value->SetString("scope", kTraceScope);
|
||||
return value;
|
||||
}
|
||||
|
||||
Script::Iterator::Iterator(Isolate* isolate)
|
||||
: iterator_(isolate->heap()->script_list()) {}
|
||||
|
||||
@ -4898,6 +4929,66 @@ uint32_t SharedFunctionInfo::Hash() {
|
||||
return static_cast<uint32_t>(base::hash_combine(start_pos, script_id));
|
||||
}
|
||||
|
||||
std::unique_ptr<v8::tracing::TracedValue> SharedFunctionInfo::ToTracedValue() {
|
||||
auto value = v8::tracing::TracedValue::Create();
|
||||
if (HasSharedName()) {
|
||||
value->SetString("name", Name()->ToCString());
|
||||
}
|
||||
if (HasInferredName()) {
|
||||
value->SetString("inferredName", inferred_name()->ToCString());
|
||||
}
|
||||
if (is_toplevel()) {
|
||||
value->SetBoolean("isToplevel", true);
|
||||
}
|
||||
value->SetInteger("formalParameterCount", internal_formal_parameter_count());
|
||||
value->SetString("languageMode", LanguageMode2String(language_mode()));
|
||||
value->SetString("kind", FunctionKind2String(kind()));
|
||||
if (script()->IsScript()) {
|
||||
value->SetValue("script", Script::cast(script())->TraceIDRef());
|
||||
value->BeginDictionary("sourcePosition");
|
||||
Script::PositionInfo info;
|
||||
if (Script::cast(script())->GetPositionInfo(StartPosition(), &info,
|
||||
Script::WITH_OFFSET)) {
|
||||
value->SetInteger("line", info.line + 1);
|
||||
value->SetInteger("column", info.column + 1);
|
||||
}
|
||||
value->EndDictionary();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// static
|
||||
const char* SharedFunctionInfo::kTraceScope =
|
||||
"v8::internal::SharedFunctionInfo";
|
||||
|
||||
uint64_t SharedFunctionInfo::TraceID() const {
|
||||
// TODO(bmeurer): We use a combination of Script ID and function literal
|
||||
// ID (within the Script) to uniquely identify SharedFunctionInfos. This
|
||||
// can add significant overhead, and we should probably find a better way
|
||||
// to uniquely identify SharedFunctionInfos over time.
|
||||
Script script = Script::cast(this->script());
|
||||
WeakFixedArray script_functions = script->shared_function_infos();
|
||||
for (int i = 0; i < script_functions->length(); ++i) {
|
||||
HeapObject script_function;
|
||||
if (script_functions->Get(i).GetHeapObjectIfWeak(&script_function) &&
|
||||
script_function->address() == address()) {
|
||||
return (static_cast<uint64_t>(script->id() + 1) << 32) |
|
||||
(static_cast<uint64_t>(i));
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
std::unique_ptr<v8::tracing::TracedValue> SharedFunctionInfo::TraceIDRef()
|
||||
const {
|
||||
auto value = v8::tracing::TracedValue::Create();
|
||||
std::ostringstream ost;
|
||||
ost << "0x" << std::hex << TraceID();
|
||||
value->SetString("id_ref", ost.str());
|
||||
value->SetString("scope", kTraceScope);
|
||||
return value;
|
||||
}
|
||||
|
||||
Code SharedFunctionInfo::GetCode() const {
|
||||
// ======
|
||||
// NOTE: This chain of checks MUST be kept in sync with the equivalent CSA
|
||||
|
@ -13,6 +13,11 @@
|
||||
#include "src/objects/object-macros.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
namespace tracing {
|
||||
class TracedValue;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Script describes a script which has been added to the VM.
|
||||
@ -174,6 +179,18 @@ class Script : public Struct {
|
||||
MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo(
|
||||
Isolate* isolate, const FunctionLiteral* fun);
|
||||
|
||||
// Returns the Script in a format tracing can support.
|
||||
std::unique_ptr<v8::tracing::TracedValue> ToTracedValue();
|
||||
|
||||
// The tracing scope for Script objects.
|
||||
static const char* kTraceScope;
|
||||
|
||||
// Returns the unique TraceID for this Script (within the kTraceScope).
|
||||
uint64_t TraceID() const;
|
||||
|
||||
// Returns the unique trace ID reference for this Script.
|
||||
std::unique_ptr<v8::tracing::TracedValue> TraceIDRef() const;
|
||||
|
||||
// Iterate over all script objects on the heap.
|
||||
class Iterator {
|
||||
public:
|
||||
|
@ -20,6 +20,11 @@
|
||||
#include "src/objects/object-macros.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
namespace tracing {
|
||||
class TracedValue;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
class AsmWasmData;
|
||||
@ -596,6 +601,21 @@ class SharedFunctionInfo : public HeapObject {
|
||||
void PrintSourceCode(std::ostream& os);
|
||||
#endif
|
||||
|
||||
// Returns the SharedFunctionInfo in a format tracing can support.
|
||||
std::unique_ptr<v8::tracing::TracedValue> ToTracedValue();
|
||||
|
||||
// The tracing scope for SharedFunctionInfo objects.
|
||||
static const char* kTraceScope;
|
||||
|
||||
// Returns the unique TraceID for this SharedFunctionInfo (within the
|
||||
// kTraceScope, works only for functions that have a Script and start/end
|
||||
// position).
|
||||
uint64_t TraceID() const;
|
||||
|
||||
// Returns the unique trace ID reference for this SharedFunctionInfo
|
||||
// (based on the |TraceID()| above).
|
||||
std::unique_ptr<v8::tracing::TracedValue> TraceIDRef() const;
|
||||
|
||||
// Iterate over all shared function infos in a given script.
|
||||
class ScriptIterator {
|
||||
public:
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects/shared-function-info.h"
|
||||
#include "src/source-position.h"
|
||||
#include "src/tracing/trace-event.h"
|
||||
#include "src/tracing/traced-value.h"
|
||||
#include "src/wasm/function-compiler.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -125,6 +127,28 @@ void OptimizedCompilationInfo::ReopenHandlesInNewHandleScope(Isolate* isolate) {
|
||||
}
|
||||
}
|
||||
|
||||
void OptimizedCompilationInfo::AbortOptimization(BailoutReason reason) {
|
||||
DCHECK_NE(reason, BailoutReason::kNoReason);
|
||||
if (bailout_reason_ == BailoutReason::kNoReason) {
|
||||
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
"V8.AbortOptimization", TRACE_EVENT_SCOPE_THREAD,
|
||||
"reason", GetBailoutReason(reason), "function",
|
||||
shared_info()->TraceIDRef());
|
||||
bailout_reason_ = reason;
|
||||
}
|
||||
SetFlag(kDisableFutureOptimization);
|
||||
}
|
||||
|
||||
void OptimizedCompilationInfo::RetryOptimization(BailoutReason reason) {
|
||||
DCHECK_NE(reason, BailoutReason::kNoReason);
|
||||
if (GetFlag(kDisableFutureOptimization)) return;
|
||||
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
|
||||
"V8.RetryOptimization", TRACE_EVENT_SCOPE_THREAD,
|
||||
"reason", GetBailoutReason(reason), "function",
|
||||
shared_info()->TraceIDRef());
|
||||
bailout_reason_ = reason;
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> OptimizedCompilationInfo::GetDebugName() const {
|
||||
if (!shared_info().is_null()) {
|
||||
return shared_info()->DebugName()->ToCString();
|
||||
@ -220,5 +244,33 @@ OptimizedCompilationInfo::InlinedFunctionHolder::InlinedFunctionHolder(
|
||||
position.inlined_function_id = DeoptimizationData::kNotInlinedIndex;
|
||||
}
|
||||
|
||||
std::unique_ptr<v8::tracing::TracedValue>
|
||||
OptimizedCompilationInfo::ToTracedValue() {
|
||||
auto value = v8::tracing::TracedValue::Create();
|
||||
value->SetBoolean("osr", is_osr());
|
||||
value->SetBoolean("functionContextSpecialized",
|
||||
is_function_context_specializing());
|
||||
if (has_shared_info()) {
|
||||
value->SetValue("function", shared_info()->TraceIDRef());
|
||||
}
|
||||
if (bailout_reason() != BailoutReason::kNoReason) {
|
||||
value->SetString("bailoutReason", GetBailoutReason(bailout_reason()));
|
||||
value->SetBoolean("disableFutureOptimization",
|
||||
is_disable_future_optimization());
|
||||
} else {
|
||||
value->SetInteger("optimizationId", optimization_id());
|
||||
value->BeginArray("inlinedFunctions");
|
||||
for (auto const& inlined_function : inlined_functions()) {
|
||||
value->BeginDictionary();
|
||||
value->SetValue("function", inlined_function.shared_info->TraceIDRef());
|
||||
// TODO(bmeurer): Also include the source position from the
|
||||
// {inlined_function} here as dedicated "sourcePosition" field.
|
||||
value->EndDictionary();
|
||||
}
|
||||
value->EndArray();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -17,6 +17,11 @@
|
||||
#include "src/vector.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
namespace tracing {
|
||||
class TracedValue;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
class DeferredHandles;
|
||||
@ -225,20 +230,16 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
|
||||
|
||||
void ReopenHandlesInNewHandleScope(Isolate* isolate);
|
||||
|
||||
void AbortOptimization(BailoutReason reason) {
|
||||
DCHECK_NE(reason, BailoutReason::kNoReason);
|
||||
if (bailout_reason_ == BailoutReason::kNoReason) bailout_reason_ = reason;
|
||||
SetFlag(kDisableFutureOptimization);
|
||||
}
|
||||
void AbortOptimization(BailoutReason reason);
|
||||
|
||||
void RetryOptimization(BailoutReason reason) {
|
||||
DCHECK_NE(reason, BailoutReason::kNoReason);
|
||||
if (GetFlag(kDisableFutureOptimization)) return;
|
||||
bailout_reason_ = reason;
|
||||
}
|
||||
void RetryOptimization(BailoutReason reason);
|
||||
|
||||
BailoutReason bailout_reason() const { return bailout_reason_; }
|
||||
|
||||
bool is_disable_future_optimization() const {
|
||||
return GetFlag(kDisableFutureOptimization);
|
||||
}
|
||||
|
||||
int optimization_id() const {
|
||||
DCHECK(IsOptimizing());
|
||||
return optimization_id_;
|
||||
@ -278,6 +279,8 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
|
||||
trace_turbo_filename_ = std::move(filename);
|
||||
}
|
||||
|
||||
std::unique_ptr<v8::tracing::TracedValue> ToTracedValue();
|
||||
|
||||
private:
|
||||
OptimizedCompilationInfo(Code::Kind code_kind, Zone* zone);
|
||||
void ConfigureFlags();
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "src/roots.h"
|
||||
#include "src/snapshot/natives.h"
|
||||
#include "src/snapshot/snapshot.h"
|
||||
#include "src/tracing/trace-event.h"
|
||||
#include "src/tracing/traced-value.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -154,6 +156,13 @@ void Deserializer::LogScriptEvents(Script script) {
|
||||
LOG(isolate_,
|
||||
ScriptEvent(Logger::ScriptEventType::kDeserialize, script->id()));
|
||||
LOG(isolate_, ScriptDetails(script));
|
||||
TRACE_EVENT_OBJECT_CREATED_WITH_ID(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "Script",
|
||||
TRACE_ID_WITH_SCOPE("v8::internal::Script", script->id()));
|
||||
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
|
||||
TRACE_DISABLED_BY_DEFAULT("v8.compile"), "Script",
|
||||
TRACE_ID_WITH_SCOPE("v8::internal::Script", script->id()),
|
||||
script->ToTracedValue());
|
||||
}
|
||||
|
||||
StringTableInsertionKey::StringTableInsertionKey(String string)
|
||||
|
@ -67,6 +67,7 @@ void EscapeAndAppendString(const char* value, std::string* result) {
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::unique_ptr<TracedValue> TracedValue::Create() {
|
||||
return std::unique_ptr<TracedValue>(new TracedValue());
|
||||
}
|
||||
@ -106,6 +107,14 @@ void TracedValue::SetString(const char* name, const char* value) {
|
||||
EscapeAndAppendString(value, &data_);
|
||||
}
|
||||
|
||||
void TracedValue::SetValue(const char* name, TracedValue* value) {
|
||||
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
|
||||
WriteName(name);
|
||||
std::string tmp;
|
||||
value->AppendAsTraceFormat(&tmp);
|
||||
data_ += tmp;
|
||||
}
|
||||
|
||||
void TracedValue::BeginDictionary(const char* name) {
|
||||
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
|
||||
DEBUG_PUSH_CONTAINER(kStackTypeDict);
|
||||
|
@ -33,6 +33,13 @@ class TracedValue : public ConvertableToTraceFormat {
|
||||
void SetString(const char* name, const std::string& value) {
|
||||
SetString(name, value.c_str());
|
||||
}
|
||||
void SetString(const char* name, std::unique_ptr<char[]> value) {
|
||||
SetString(name, value.get());
|
||||
}
|
||||
void SetValue(const char* name, TracedValue* value);
|
||||
void SetValue(const char* name, std::unique_ptr<TracedValue> value) {
|
||||
SetValue(name, value.get());
|
||||
}
|
||||
void BeginDictionary(const char* name);
|
||||
void BeginArray(const char* name);
|
||||
|
||||
|
@ -75,6 +75,19 @@ TEST(Hierarchy) {
|
||||
json);
|
||||
}
|
||||
|
||||
TEST(Nesting) {
|
||||
auto value = TracedValue::Create();
|
||||
auto v0 = TracedValue::Create();
|
||||
auto v2 = TracedValue::Create();
|
||||
v0->SetString("s1", std::string("Hello World!"));
|
||||
v2->SetValue("v0", v0.get());
|
||||
value->SetValue("v2", v2.get());
|
||||
|
||||
std::string json;
|
||||
value->AppendAsTraceFormat(&json);
|
||||
CHECK_EQ("{\"v2\":{\"v0\":{\"s1\":\"Hello World!\"}}}", json);
|
||||
}
|
||||
|
||||
TEST(LongStrings) {
|
||||
std::string long_string = "supercalifragilisticexpialidocious";
|
||||
std::string long_string2 = "0123456789012345678901234567890123456789";
|
||||
|
Loading…
Reference in New Issue
Block a user