[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:
Benedikt Meurer 2019-03-25 15:14:25 +01:00 committed by Commit Bot
parent 24038b9357
commit a2af7e1101
14 changed files with 325 additions and 50 deletions

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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();

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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";