Commit a2af7e11 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[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: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60448}
parent 24038b93
...@@ -1472,6 +1472,10 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval( ...@@ -1472,6 +1472,10 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval(
} }
} }
script->set_eval_from_position(eval_position); 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_eval();
parse_info.set_language_mode(language_mode); parse_info.set_language_mode(language_mode);
...@@ -1795,6 +1799,10 @@ Handle<Script> NewScript(Isolate* isolate, ParseInfo* parse_info, ...@@ -1795,6 +1799,10 @@ Handle<Script> NewScript(Isolate* isolate, ParseInfo* parse_info,
script->set_host_defined_options(*host_defined_options); script->set_host_defined_options(*host_defined_options);
} }
LOG(isolate, ScriptDetails(*script)); 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; return script;
} }
......
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
#include "src/parsing/parse-info.h" #include "src/parsing/parse-info.h"
#include "src/register-configuration.h" #include "src/register-configuration.h"
#include "src/tracing/trace-event.h" #include "src/tracing/trace-event.h"
#include "src/tracing/traced-value.h"
#include "src/utils.h" #include "src/utils.h"
#include "src/wasm/function-body-decoder.h" #include "src/wasm/function-body-decoder.h"
#include "src/wasm/function-compiler.h" #include "src/wasm/function-compiler.h"
...@@ -862,24 +863,8 @@ class PipelineCompilationJob final : public OptimizedCompilationJob { ...@@ -862,24 +863,8 @@ class PipelineCompilationJob final : public OptimizedCompilationJob {
public: public:
PipelineCompilationJob(Isolate* isolate, PipelineCompilationJob(Isolate* isolate,
Handle<SharedFunctionInfo> shared_info, Handle<SharedFunctionInfo> shared_info,
Handle<JSFunction> function) Handle<JSFunction> function);
// Note that the OptimizedCompilationInfo is not initialized at the time ~PipelineCompilationJob();
// 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) {}
protected: protected:
Status PrepareJobImpl(Isolate* isolate) final; Status PrepareJobImpl(Isolate* isolate) final;
...@@ -901,8 +886,43 @@ class PipelineCompilationJob final : public OptimizedCompilationJob { ...@@ -901,8 +886,43 @@ class PipelineCompilationJob final : public OptimizedCompilationJob {
DISALLOW_COPY_AND_ASSIGN(PipelineCompilationJob); 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( PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
Isolate* isolate) { 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() > if (compilation_info()->bytecode_array()->length() >
kMaxBytecodeSizeForTurbofan) { kMaxBytecodeSizeForTurbofan) {
return AbortOptimization(BailoutReason::kFunctionTooBig); return AbortOptimization(BailoutReason::kFunctionTooBig);
...@@ -968,6 +988,10 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl( ...@@ -968,6 +988,10 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(
} }
PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() { 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; if (!pipeline_.OptimizeGraph(linkage_)) return FAILED;
pipeline_.AssembleCode(linkage_); pipeline_.AssembleCode(linkage_);
return SUCCEEDED; return SUCCEEDED;
...@@ -975,6 +999,10 @@ PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() { ...@@ -975,6 +999,10 @@ PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl() {
PipelineCompilationJob::Status PipelineCompilationJob::FinalizeJobImpl( PipelineCompilationJob::Status PipelineCompilationJob::FinalizeJobImpl(
Isolate* isolate) { 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(); MaybeHandle<Code> maybe_code = pipeline_.FinalizeCode();
Handle<Code> code; Handle<Code> code;
if (!maybe_code.ToHandle(&code)) { if (!maybe_code.ToHandle(&code)) {
......
...@@ -142,48 +142,52 @@ inline bool IsConstructable(FunctionKind kind) { ...@@ -142,48 +142,52 @@ inline bool IsConstructable(FunctionKind kind) {
FunctionKind::kDerivedConstructor); FunctionKind::kDerivedConstructor);
} }
inline std::ostream& operator<<(std::ostream& os, FunctionKind kind) { inline const char* FunctionKind2String(FunctionKind kind) {
switch (kind) { switch (kind) {
case FunctionKind::kNormalFunction: case FunctionKind::kNormalFunction:
return os << "NormalFunction"; return "NormalFunction";
case FunctionKind::kArrowFunction: case FunctionKind::kArrowFunction:
return os << "ArrowFunction"; return "ArrowFunction";
case FunctionKind::kGeneratorFunction: case FunctionKind::kGeneratorFunction:
return os << "GeneratorFunction"; return "GeneratorFunction";
case FunctionKind::kConciseMethod: case FunctionKind::kConciseMethod:
return os << "ConciseMethod"; return "ConciseMethod";
case FunctionKind::kDerivedConstructor: case FunctionKind::kDerivedConstructor:
return os << "DerivedConstructor"; return "DerivedConstructor";
case FunctionKind::kBaseConstructor: case FunctionKind::kBaseConstructor:
return os << "BaseConstructor"; return "BaseConstructor";
case FunctionKind::kGetterFunction: case FunctionKind::kGetterFunction:
return os << "GetterFunction"; return "GetterFunction";
case FunctionKind::kSetterFunction: case FunctionKind::kSetterFunction:
return os << "SetterFunction"; return "SetterFunction";
case FunctionKind::kAsyncFunction: case FunctionKind::kAsyncFunction:
return os << "AsyncFunction"; return "AsyncFunction";
case FunctionKind::kModule: case FunctionKind::kModule:
return os << "Module"; return "Module";
case FunctionKind::kClassMembersInitializerFunction: case FunctionKind::kClassMembersInitializerFunction:
return os << "ClassMembersInitializerFunction"; return "ClassMembersInitializerFunction";
case FunctionKind::kDefaultBaseConstructor: case FunctionKind::kDefaultBaseConstructor:
return os << "DefaultBaseConstructor"; return "DefaultBaseConstructor";
case FunctionKind::kDefaultDerivedConstructor: case FunctionKind::kDefaultDerivedConstructor:
return os << "DefaultDerivedConstructor"; return "DefaultDerivedConstructor";
case FunctionKind::kAsyncArrowFunction: case FunctionKind::kAsyncArrowFunction:
return os << "AsyncArrowFunction"; return "AsyncArrowFunction";
case FunctionKind::kAsyncConciseMethod: case FunctionKind::kAsyncConciseMethod:
return os << "AsyncConciseMethod"; return "AsyncConciseMethod";
case FunctionKind::kConciseGeneratorMethod: case FunctionKind::kConciseGeneratorMethod:
return os << "ConciseGeneratorMethod"; return "ConciseGeneratorMethod";
case FunctionKind::kAsyncConciseGeneratorMethod: case FunctionKind::kAsyncConciseGeneratorMethod:
return os << "AsyncConciseGeneratorMethod"; return "AsyncConciseGeneratorMethod";
case FunctionKind::kAsyncGeneratorFunction: case FunctionKind::kAsyncGeneratorFunction:
return os << "AsyncGeneratorFunction"; return "AsyncGeneratorFunction";
} }
UNREACHABLE(); UNREACHABLE();
} }
inline std::ostream& operator<<(std::ostream& os, FunctionKind kind) {
return os << FunctionKind2String(kind);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -334,16 +334,20 @@ inline size_t hash_value(LanguageMode mode) { ...@@ -334,16 +334,20 @@ inline size_t hash_value(LanguageMode mode) {
return static_cast<size_t>(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) { switch (mode) {
case LanguageMode::kSloppy: case LanguageMode::kSloppy:
return os << "sloppy"; return "sloppy";
case LanguageMode::kStrict: case LanguageMode::kStrict:
return os << "strict"; return "strict";
} }
UNREACHABLE(); UNREACHABLE();
} }
inline std::ostream& operator<<(std::ostream& os, LanguageMode mode) {
return os << LanguageMode2String(mode);
}
inline bool is_sloppy(LanguageMode language_mode) { inline bool is_sloppy(LanguageMode language_mode) {
return language_mode == LanguageMode::kSloppy; return language_mode == LanguageMode::kSloppy;
} }
......
...@@ -1683,6 +1683,9 @@ Handle<Script> Factory::NewScriptWithId(Handle<String> source, int script_id, ...@@ -1683,6 +1683,9 @@ Handle<Script> Factory::NewScriptWithId(Handle<String> source, int script_id,
MaybeObjectHandle::Weak(script)); MaybeObjectHandle::Weak(script));
heap->set_script_list(*scripts); heap->set_script_list(*scripts);
LOG(isolate(), ScriptEvent(Logger::ScriptEventType::kCreate, script_id)); 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; return script;
} }
...@@ -3590,6 +3593,13 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForLiteral( ...@@ -3590,6 +3593,13 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForLiteral(
SharedFunctionInfo::InitFromFunctionLiteral(shared, literal, is_toplevel); SharedFunctionInfo::InitFromFunctionLiteral(shared, literal, is_toplevel);
SharedFunctionInfo::SetScript(shared, script, literal->function_literal_id(), SharedFunctionInfo::SetScript(shared, script, literal->function_literal_id(),
false); 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; return shared;
} }
......
...@@ -4878,6 +4878,37 @@ MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo( ...@@ -4878,6 +4878,37 @@ MaybeHandle<SharedFunctionInfo> Script::FindSharedFunctionInfo(
return handle(SharedFunctionInfo::cast(heap_object), isolate); 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) Script::Iterator::Iterator(Isolate* isolate)
: iterator_(isolate->heap()->script_list()) {} : iterator_(isolate->heap()->script_list()) {}
...@@ -4898,6 +4929,66 @@ uint32_t SharedFunctionInfo::Hash() { ...@@ -4898,6 +4929,66 @@ uint32_t SharedFunctionInfo::Hash() {
return static_cast<uint32_t>(base::hash_combine(start_pos, script_id)); 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 { Code SharedFunctionInfo::GetCode() const {
// ====== // ======
// NOTE: This chain of checks MUST be kept in sync with the equivalent CSA // NOTE: This chain of checks MUST be kept in sync with the equivalent CSA
......
...@@ -13,6 +13,11 @@ ...@@ -13,6 +13,11 @@
#include "src/objects/object-macros.h" #include "src/objects/object-macros.h"
namespace v8 { namespace v8 {
namespace tracing {
class TracedValue;
}
namespace internal { namespace internal {
// Script describes a script which has been added to the VM. // Script describes a script which has been added to the VM.
...@@ -174,6 +179,18 @@ class Script : public Struct { ...@@ -174,6 +179,18 @@ class Script : public Struct {
MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo( MaybeHandle<SharedFunctionInfo> FindSharedFunctionInfo(
Isolate* isolate, const FunctionLiteral* fun); 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. // Iterate over all script objects on the heap.
class Iterator { class Iterator {
public: public:
......
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
#include "src/objects/object-macros.h" #include "src/objects/object-macros.h"
namespace v8 { namespace v8 {
namespace tracing {
class TracedValue;
}
namespace internal { namespace internal {
class AsmWasmData; class AsmWasmData;
...@@ -596,6 +601,21 @@ class SharedFunctionInfo : public HeapObject { ...@@ -596,6 +601,21 @@ class SharedFunctionInfo : public HeapObject {
void PrintSourceCode(std::ostream& os); void PrintSourceCode(std::ostream& os);
#endif #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. // Iterate over all shared function infos in a given script.
class ScriptIterator { class ScriptIterator {
public: public:
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/shared-function-info.h" #include "src/objects/shared-function-info.h"
#include "src/source-position.h" #include "src/source-position.h"
#include "src/tracing/trace-event.h"
#include "src/tracing/traced-value.h"
#include "src/wasm/function-compiler.h" #include "src/wasm/function-compiler.h"
namespace v8 { namespace v8 {
...@@ -125,6 +127,28 @@ void OptimizedCompilationInfo::ReopenHandlesInNewHandleScope(Isolate* isolate) { ...@@ -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 { std::unique_ptr<char[]> OptimizedCompilationInfo::GetDebugName() const {
if (!shared_info().is_null()) { if (!shared_info().is_null()) {
return shared_info()->DebugName()->ToCString(); return shared_info()->DebugName()->ToCString();
...@@ -220,5 +244,33 @@ OptimizedCompilationInfo::InlinedFunctionHolder::InlinedFunctionHolder( ...@@ -220,5 +244,33 @@ OptimizedCompilationInfo::InlinedFunctionHolder::InlinedFunctionHolder(
position.inlined_function_id = DeoptimizationData::kNotInlinedIndex; 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 internal
} // namespace v8 } // namespace v8
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
#include "src/vector.h" #include "src/vector.h"
namespace v8 { namespace v8 {
namespace tracing {
class TracedValue;
}
namespace internal { namespace internal {
class DeferredHandles; class DeferredHandles;
...@@ -225,20 +230,16 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final { ...@@ -225,20 +230,16 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
void ReopenHandlesInNewHandleScope(Isolate* isolate); void ReopenHandlesInNewHandleScope(Isolate* isolate);
void AbortOptimization(BailoutReason reason) { void AbortOptimization(BailoutReason reason);
DCHECK_NE(reason, BailoutReason::kNoReason);
if (bailout_reason_ == BailoutReason::kNoReason) bailout_reason_ = reason;
SetFlag(kDisableFutureOptimization);
}
void RetryOptimization(BailoutReason reason) { void RetryOptimization(BailoutReason reason);
DCHECK_NE(reason, BailoutReason::kNoReason);
if (GetFlag(kDisableFutureOptimization)) return;
bailout_reason_ = reason;
}
BailoutReason bailout_reason() const { return bailout_reason_; } BailoutReason bailout_reason() const { return bailout_reason_; }
bool is_disable_future_optimization() const {
return GetFlag(kDisableFutureOptimization);
}
int optimization_id() const { int optimization_id() const {
DCHECK(IsOptimizing()); DCHECK(IsOptimizing());
return optimization_id_; return optimization_id_;
...@@ -278,6 +279,8 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final { ...@@ -278,6 +279,8 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
trace_turbo_filename_ = std::move(filename); trace_turbo_filename_ = std::move(filename);
} }
std::unique_ptr<v8::tracing::TracedValue> ToTracedValue();
private: private:
OptimizedCompilationInfo(Code::Kind code_kind, Zone* zone); OptimizedCompilationInfo(Code::Kind code_kind, Zone* zone);
void ConfigureFlags(); void ConfigureFlags();
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include "src/roots.h" #include "src/roots.h"
#include "src/snapshot/natives.h" #include "src/snapshot/natives.h"
#include "src/snapshot/snapshot.h" #include "src/snapshot/snapshot.h"
#include "src/tracing/trace-event.h"
#include "src/tracing/traced-value.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -154,6 +156,13 @@ void Deserializer::LogScriptEvents(Script script) { ...@@ -154,6 +156,13 @@ void Deserializer::LogScriptEvents(Script script) {
LOG(isolate_, LOG(isolate_,
ScriptEvent(Logger::ScriptEventType::kDeserialize, script->id())); ScriptEvent(Logger::ScriptEventType::kDeserialize, script->id()));
LOG(isolate_, ScriptDetails(script)); 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) StringTableInsertionKey::StringTableInsertionKey(String string)
......
...@@ -67,6 +67,7 @@ void EscapeAndAppendString(const char* value, std::string* result) { ...@@ -67,6 +67,7 @@ void EscapeAndAppendString(const char* value, std::string* result) {
} // namespace } // namespace
// static
std::unique_ptr<TracedValue> TracedValue::Create() { std::unique_ptr<TracedValue> TracedValue::Create() {
return std::unique_ptr<TracedValue>(new TracedValue()); return std::unique_ptr<TracedValue>(new TracedValue());
} }
...@@ -106,6 +107,14 @@ void TracedValue::SetString(const char* name, const char* value) { ...@@ -106,6 +107,14 @@ void TracedValue::SetString(const char* name, const char* value) {
EscapeAndAppendString(value, &data_); 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) { void TracedValue::BeginDictionary(const char* name) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
DEBUG_PUSH_CONTAINER(kStackTypeDict); DEBUG_PUSH_CONTAINER(kStackTypeDict);
......
...@@ -33,6 +33,13 @@ class TracedValue : public ConvertableToTraceFormat { ...@@ -33,6 +33,13 @@ class TracedValue : public ConvertableToTraceFormat {
void SetString(const char* name, const std::string& value) { void SetString(const char* name, const std::string& value) {
SetString(name, value.c_str()); 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 BeginDictionary(const char* name);
void BeginArray(const char* name); void BeginArray(const char* name);
......
...@@ -75,6 +75,19 @@ TEST(Hierarchy) { ...@@ -75,6 +75,19 @@ TEST(Hierarchy) {
json); 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) { TEST(LongStrings) {
std::string long_string = "supercalifragilisticexpialidocious"; std::string long_string = "supercalifragilisticexpialidocious";
std::string long_string2 = "0123456789012345678901234567890123456789"; std::string long_string2 = "0123456789012345678901234567890123456789";
......
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