[vm/snapshot] Name Code and Function objects in V8 snapshot profiles

Issue https://github.com/dart-lang/sdk/issues/41249

Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-try,pkg-win-release-try,pkg-mac-release-try,vm-kernel-precomp-linux-product-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-release-x64-try
Change-Id: Idd7644714884e4ea1461718285c1b01f12d811e7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151225
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Vyacheslav Egorov 2020-06-17 20:57:01 +00:00 committed by commit-bot@chromium.org
parent 5944ff823f
commit 572aa45c21
4 changed files with 109 additions and 31 deletions

View file

@ -27,6 +27,7 @@
#include "vm/symbols.h"
#include "vm/timeline.h"
#include "vm/version.h"
#include "vm/zone_text_buffer.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/backend/code_statistics.h"
@ -602,7 +603,7 @@ class FunctionSerializationCluster : public SerializationCluster {
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
FunctionPtr func = objects_[i];
AutoTraceObjectName(func, func->ptr()->name_);
AutoTraceObjectName(func, MakeDisambiguatedFunctionName(s, func));
WriteFromTo(func);
if (kind == Snapshot::kFull) {
NOT_IN_PRECOMPILED(WriteField(func, bytecode_));
@ -626,6 +627,22 @@ class FunctionSerializationCluster : public SerializationCluster {
}
}
static const char* MakeDisambiguatedFunctionName(Serializer* s,
FunctionPtr f) {
if (s->profile_writer() == nullptr) {
return nullptr;
}
REUSABLE_FUNCTION_HANDLESCOPE(s->thread());
Function& fun = reused_function_handle.Handle();
fun = f;
ZoneTextBuffer printer(s->thread()->zone());
fun.PrintName(NameFormattingParams::DisambiguatedUnqualified(
Object::NameVisibility::kInternalName),
&printer);
return printer.buffer();
}
private:
GrowableArray<FunctionPtr> objects_;
};
@ -1561,7 +1578,7 @@ class CodeSerializationCluster : public SerializationCluster {
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
CodePtr code = objects_[i];
AutoTraceObject(code);
AutoTraceObjectName(code, MakeDisambiguatedCodeName(s, code));
intptr_t pointer_offsets_length =
Code::PtrOffBits::decode(code->ptr()->state_bits_);
@ -1652,6 +1669,19 @@ class CodeSerializationCluster : public SerializationCluster {
}
private:
static const char* MakeDisambiguatedCodeName(Serializer* s, CodePtr c) {
if (s->profile_writer() == nullptr) {
return nullptr;
}
REUSABLE_CODE_HANDLESCOPE(s->thread());
Code& code = reused_code_handle.Handle();
code = c;
return code.QualifiedName(
NameFormattingParams::DisambiguatedWithoutClassName(
Object::NameVisibility::kInternalName));
}
GrowableArray<CodePtr> objects_;
};
#endif // !DART_PRECOMPILED_RUNTIME
@ -4812,6 +4842,22 @@ void Serializer::TraceStartWritingObject(const char* type,
StringPtr name) {
if (profile_writer_ == nullptr) return;
const char* name_str = nullptr;
if (name != nullptr) {
REUSABLE_STRING_HANDLESCOPE(thread());
String& str = reused_string_handle.Handle();
str = name;
name_str = str.ToCString();
}
TraceStartWritingObject(type, obj, name_str);
}
void Serializer::TraceStartWritingObject(const char* type,
ObjectPtr obj,
const char* name) {
if (profile_writer_ == nullptr) return;
intptr_t cid = -1;
intptr_t id = 0;
if (obj->IsHeapObject()) {
@ -4826,20 +4872,13 @@ void Serializer::TraceStartWritingObject(const char* type,
}
ASSERT(IsAllocatedReference(id));
const char* name_str = nullptr;
if (name != nullptr) {
String& str = thread()->StringHandle();
str = name;
name_str = str.ToCString();
}
FlushBytesWrittenToRoot();
object_currently_writing_.object_ = obj;
object_currently_writing_.id_ = id;
object_currently_writing_.stream_start_ = stream_.Position();
object_currently_writing_.cid_ = cid;
profile_writer_->SetObjectTypeAndName(
{V8SnapshotProfileWriter::kSnapshot, id}, type, name_str);
{V8SnapshotProfileWriter::kSnapshot, id}, type, name);
}
void Serializer::TraceEndWritingObject() {
@ -4853,6 +4892,7 @@ void Serializer::TraceEndWritingObject() {
}
}
#if !defined(DART_PRECOMPILED_RUNTIME)
bool Serializer::CreateArtificalNodeIfNeeded(ObjectPtr obj) {
ASSERT(profile_writer() != nullptr);
@ -4867,14 +4907,16 @@ bool Serializer::CreateArtificalNodeIfNeeded(ObjectPtr obj) {
id = AssignArtificialRef(obj);
const char* type = nullptr;
StringPtr name = nullptr;
StringPtr name_string = nullptr;
const char* name = nullptr;
ObjectPtr owner = nullptr;
const char* owner_ref_name = nullptr;
switch (obj->GetClassId()) {
case kFunctionCid: {
FunctionPtr func = static_cast<FunctionPtr>(obj);
type = "Function";
name = func->ptr()->name_;
name = FunctionSerializationCluster::MakeDisambiguatedFunctionName(this,
func);
owner_ref_name = "owner_";
owner = func->ptr()->owner_;
break;
@ -4882,7 +4924,7 @@ bool Serializer::CreateArtificalNodeIfNeeded(ObjectPtr obj) {
case kClassCid: {
ClassPtr cls = static_cast<ClassPtr>(obj);
type = "Class";
name = cls->ptr()->name_;
name_string = cls->ptr()->name_;
owner_ref_name = "library_";
owner = cls->ptr()->library_;
break;
@ -4897,13 +4939,20 @@ bool Serializer::CreateArtificalNodeIfNeeded(ObjectPtr obj) {
case kLibraryCid: {
LibraryPtr lib = static_cast<LibraryPtr>(obj);
type = "Library";
name = lib->ptr()->url_;
name_string = lib->ptr()->url_;
break;
}
default:
UNREACHABLE();
}
if (name_string != nullptr) {
REUSABLE_STRING_HANDLESCOPE(thread());
String& str = reused_string_handle.Handle();
str = name_string;
name = str.ToCString();
}
TraceStartWritingObject(type, obj, name);
if (owner != nullptr) {
CreateArtificalNodeIfNeeded(owner);
@ -4913,6 +4962,7 @@ bool Serializer::CreateArtificalNodeIfNeeded(ObjectPtr obj) {
TraceEndWritingObject();
return true;
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
const char* Serializer::ReadOnlyObjectType(intptr_t cid) {
switch (cid) {

View file

@ -255,6 +255,9 @@ class Serializer : public ThreadStackResource {
void FlushBytesWrittenToRoot();
void TraceStartWritingObject(const char* type, ObjectPtr obj, StringPtr name);
void TraceStartWritingObject(const char* type,
ObjectPtr obj,
const char* name);
void TraceEndWritingObject();
// Writes raw data to the stream (basic type).
@ -494,7 +497,8 @@ class Serializer : public ThreadStackResource {
#define WriteField(obj, field) s->WritePropertyRef(obj->ptr()->field, #field)
struct SerializerWritingObjectScope {
class SerializerWritingObjectScope {
public:
SerializerWritingObjectScope(Serializer* serializer,
const char* type,
ObjectPtr object,
@ -503,6 +507,14 @@ struct SerializerWritingObjectScope {
serializer_->TraceStartWritingObject(type, object, name);
}
SerializerWritingObjectScope(Serializer* serializer,
const char* type,
ObjectPtr object,
const char* name)
: serializer_(serializer) {
serializer_->TraceStartWritingObject(type, object, name);
}
~SerializerWritingObjectScope() { serializer_->TraceEndWritingObject(); }
private:

View file

@ -8853,19 +8853,19 @@ StringPtr Function::UserVisibleName() const {
StringPtr Function::QualifiedScrubbedName() const {
Thread* thread = Thread::Current();
ZoneTextBuffer printer(thread->zone());
PrintQualifiedName(NameFormattingParams(kScrubbedName), &printer);
PrintName(NameFormattingParams(kScrubbedName), &printer);
return Symbols::New(thread, printer.buffer());
}
StringPtr Function::QualifiedUserVisibleName() const {
Thread* thread = Thread::Current();
ZoneTextBuffer printer(thread->zone());
PrintQualifiedName(NameFormattingParams(kUserVisibleName), &printer);
PrintName(NameFormattingParams(kUserVisibleName), &printer);
return Symbols::New(thread, printer.buffer());
}
void Function::PrintQualifiedName(const NameFormattingParams& params,
ZoneTextBuffer* printer) const {
void Function::PrintName(const NameFormattingParams& params,
ZoneTextBuffer* printer) const {
// If |this| is the generated asynchronous body closure, use the
// name of the parent function.
Function& fun = Function::Handle(raw());
@ -8902,9 +8902,11 @@ void Function::PrintQualifiedName(const NameFormattingParams& params,
// the parent.
parent = parent.parent_function();
}
parent.PrintQualifiedName(params, printer);
// A function's scrubbed name and its user visible name are identical.
printer->AddString(".");
if (params.include_parent_name) {
parent.PrintName(params, printer);
// A function's scrubbed name and its user visible name are identical.
printer->AddString(".");
}
if (params.disambiguate_names &&
fun.name() == Symbols::AnonymousClosure().raw()) {
printer->Printf("<anonymous closure @%" Pd ">", fun.token_pos().Pos());
@ -16240,9 +16242,8 @@ const char* Code::Name() const {
Object::Handle(zone, WeakSerializationReference::UnwrapIfTarget(owner()));
if (obj.IsClass()) {
// Allocation stub.
String& cls_name = String::Handle(zone, Class::Cast(obj).ScrubbedName());
ASSERT(!cls_name.IsNull());
return OS::SCreate(zone, "[Stub] Allocate %s", cls_name.ToCString());
return OS::SCreate(zone, "[Stub] Allocate %s",
Class::Cast(obj).ScrubbedNameCString());
} else if (obj.IsAbstractType()) {
// Type test stub.
return OS::SCreate(zone, "[Stub] Type Test %s",
@ -16267,7 +16268,7 @@ const char* Code::QualifiedName(const NameFormattingParams& params) const {
if (obj.IsFunction()) {
ZoneTextBuffer printer(zone);
printer.AddString(is_optimized() ? "[Optimized] " : "[Unoptimized] ");
Function::Cast(obj).PrintQualifiedName(params, &printer);
Function::Cast(obj).PrintName(params, &printer);
return printer.buffer();
}
return Name();
@ -18737,7 +18738,7 @@ void AbstractType::PrintName(
} else if (param.parameterized_function() != Function::null()) {
const Function& func =
Function::Handle(zone, param.parameterized_function());
func.PrintQualifiedName(
func.PrintName(
NameFormattingParams(name_visibility, name_disambiguation),
printer);
printer->AddString("::");

View file

@ -2424,17 +2424,24 @@ enum {
kAllFree = kMaxInt32,
};
// Formatting configuration for Function::PrintQualifiedName.
// Formatting configuration for Function::PrintName.
struct NameFormattingParams {
Object::NameVisibility name_visibility;
bool disambiguate_names;
// By default function name includes the name of the enclosing class if any.
// However in some context this information is redundant and class name
// However in some contexts this information is redundant and class name
// is already known. In this case setting |include_class_name| to false
// allows you to exclude this information from the formatted name.
bool include_class_name = true;
// By default function name includes the name of the enclosing function if
// any. However in some contexts this information is redundant and
// the name of the enclosing function is already known. In this case
// setting |include_parent_name| to false allows to exclude this information
// from the formatted name.
bool include_parent_name = true;
NameFormattingParams(Object::NameVisibility visibility,
Object::NameDisambiguation name_disambiguation =
Object::NameDisambiguation::kNo)
@ -2448,6 +2455,14 @@ struct NameFormattingParams {
params.include_class_name = false;
return params;
}
static NameFormattingParams DisambiguatedUnqualified(
Object::NameVisibility visibility) {
NameFormattingParams params(visibility, Object::NameDisambiguation::kYes);
params.include_class_name = false;
params.include_parent_name = false;
return params;
}
};
class Function : public Object {
@ -2458,8 +2473,8 @@ class Function : public Object {
const char* NameCString(NameVisibility name_visibility) const;
void PrintQualifiedName(const NameFormattingParams& params,
ZoneTextBuffer* printer) const;
void PrintName(const NameFormattingParams& params,
ZoneTextBuffer* printer) const;
StringPtr QualifiedScrubbedName() const;
StringPtr QualifiedUserVisibleName() const;