[cpu-profiler] Split out debug mode for CPU profiler naming

Adds a new flag to CpuProfiler to control whether or not "debug" names
(potentially inferred from scope) are used for captured frames
associated with a SharedFunctionInfo instance.

Bug: v8:9135
Change-Id: I104f3246431dc6336de4e4688c0d98c86e0bb776
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1566169
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Alexei Filippov <alph@chromium.org>
Reviewed-by: Peter Marshall <petermarshall@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60972}
This commit is contained in:
Andrew Comminos 2019-04-17 13:08:26 -07:00 committed by Commit Bot
parent 4214933c6b
commit fa6ec3cb08
8 changed files with 121 additions and 20 deletions

View File

@ -297,6 +297,15 @@ enum CpuProfilingMode {
kCallerLineNumbers,
};
// Determines how names are derived for functions sampled.
enum CpuProfilingNamingMode {
// Use the immediate name of functions at compilation time.
kStandardNaming,
// Use more verbose naming for functions without names, inferred from scope
// where possible.
kDebugNaming,
};
/**
* Interface for controlling CPU profiling. Instance of the
* profiler can be created using v8::CpuProfiler::New method.
@ -308,7 +317,8 @@ class V8_EXPORT CpuProfiler {
* initialized. The profiler object must be disposed after use by calling
* |Dispose| method.
*/
static CpuProfiler* New(Isolate* isolate);
static CpuProfiler* New(Isolate* isolate,
CpuProfilingNamingMode = kDebugNaming);
/**
* Synchronously collect current stack sample in all profilers attached to

View File

@ -10117,9 +10117,9 @@ int CpuProfile::GetSamplesCount() const {
return reinterpret_cast<const i::CpuProfile*>(this)->samples_count();
}
CpuProfiler* CpuProfiler::New(Isolate* isolate) {
CpuProfiler* CpuProfiler::New(Isolate* isolate, CpuProfilingNamingMode mode) {
return reinterpret_cast<CpuProfiler*>(
new i::CpuProfiler(reinterpret_cast<i::Isolate*>(isolate)));
new i::CpuProfiler(reinterpret_cast<i::Isolate*>(isolate), mode));
}
void CpuProfiler::Dispose() { delete reinterpret_cast<i::CpuProfiler*>(this); }

View File

@ -310,14 +310,16 @@ DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager)
} // namespace
CpuProfiler::CpuProfiler(Isolate* isolate)
: CpuProfiler(isolate, new CpuProfilesCollection(isolate), nullptr,
nullptr) {}
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode)
: CpuProfiler(isolate, naming_mode, new CpuProfilesCollection(isolate),
nullptr, nullptr) {}
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilesCollection* test_profiles,
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilesCollection* test_profiles,
ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor)
: isolate_(isolate),
naming_mode_(naming_mode),
sampling_interval_(base::TimeDelta::FromMicroseconds(
FLAG_cpu_profiler_sampling_interval)),
profiles_(test_profiles),
@ -409,7 +411,8 @@ void CpuProfiler::StartProcessorIfNotStarted() {
if (profiler_listener_) {
profiler_listener_->set_observer(processor_.get());
} else {
profiler_listener_.reset(new ProfilerListener(isolate_, processor_.get()));
profiler_listener_.reset(
new ProfilerListener(isolate_, processor_.get(), naming_mode_));
}
logger->AddCodeEventListener(profiler_listener_.get());
is_profiling_ = true;

View File

@ -216,10 +216,10 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
class V8_EXPORT_PRIVATE CpuProfiler {
public:
explicit CpuProfiler(Isolate* isolate);
explicit CpuProfiler(Isolate* isolate, CpuProfilingNamingMode = kDebugNaming);
CpuProfiler(Isolate* isolate, CpuProfilesCollection* profiles,
ProfileGenerator* test_generator,
CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilesCollection* profiles, ProfileGenerator* test_generator,
ProfilerEventsProcessor* test_processor);
~CpuProfiler();
@ -227,6 +227,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
static void CollectSample(Isolate* isolate);
typedef v8::CpuProfilingMode ProfilingMode;
typedef v8::CpuProfilingNamingMode NamingMode;
void set_sampling_interval(base::TimeDelta value);
void set_use_precise_sampling(bool);
@ -260,6 +261,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
void CreateEntriesForRuntimeCallStats();
Isolate* const isolate_;
const NamingMode naming_mode_;
base::TimeDelta sampling_interval_;
bool use_precise_sampling_ = true;
std::unique_ptr<CpuProfilesCollection> profiles_;

View File

@ -21,8 +21,9 @@ namespace v8 {
namespace internal {
ProfilerListener::ProfilerListener(Isolate* isolate,
CodeEventObserver* observer)
: isolate_(isolate), observer_(observer) {}
CodeEventObserver* observer,
CpuProfilingNamingMode naming_mode)
: isolate_(isolate), observer_(observer), naming_mode_(naming_mode) {}
ProfilerListener::~ProfilerListener() = default;
@ -163,7 +164,7 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
std::unique_ptr<CodeEntry> inline_entry =
base::make_unique<CodeEntry>(
tag, GetName(pos_info.shared->DebugName()), resource_name,
tag, GetFunctionName(*pos_info.shared), resource_name,
start_pos_info.line + 1, start_pos_info.column + 1, nullptr,
code->InstructionStart(), inline_is_shared_cross_origin);
inline_entry->FillFunctionInfo(*pos_info.shared);
@ -182,7 +183,7 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
}
}
rec->entry =
new CodeEntry(tag, GetName(shared->DebugName()),
new CodeEntry(tag, GetFunctionName(shared),
GetName(InferScriptName(script_name, shared)), line, column,
std::move(line_table), abstract_code->InstructionStart(),
is_shared_cross_origin);
@ -283,6 +284,18 @@ Name ProfilerListener::InferScriptName(Name name, SharedFunctionInfo info) {
return source_url->IsName() ? Name::cast(source_url) : name;
}
const char* ProfilerListener::GetFunctionName(SharedFunctionInfo shared) {
DisallowHeapAllocation no_gc;
switch (naming_mode_) {
case kDebugNaming:
return GetName(shared.DebugName());
case kStandardNaming:
return GetName(shared.Name());
default:
UNREACHABLE();
}
}
void ProfilerListener::AttachDeoptInlinedFrames(Code code,
CodeDeoptEventRecord* rec) {
int deopt_id = rec->deopt_id;

View File

@ -8,6 +8,7 @@
#include <memory>
#include <vector>
#include "include/v8-profiler.h"
#include "src/code-events.h"
#include "src/profiler/profile-generator.h"
@ -25,7 +26,8 @@ class CodeEventObserver {
class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
public:
ProfilerListener(Isolate*, CodeEventObserver*);
ProfilerListener(Isolate*, CodeEventObserver*,
CpuProfilingNamingMode mode = kDebugNaming);
~ProfilerListener() override;
void CallbackEvent(Name name, Address entry_point) override;
@ -70,6 +72,8 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
void set_observer(CodeEventObserver* observer) { observer_ = observer; }
private:
const char* GetFunctionName(SharedFunctionInfo);
void AttachDeoptInlinedFrames(Code code, CodeDeoptEventRecord* rec);
Name InferScriptName(Name name, SharedFunctionInfo info);
V8_INLINE void DispatchCodeEvent(const CodeEventsContainer& evt_rec) {
@ -79,6 +83,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
Isolate* isolate_;
CodeEventObserver* observer_;
StringsStorage function_and_resource_names_;
const CpuProfilingNamingMode naming_mode_;
DISALLOW_COPY_AND_ASSIGN(ProfilerListener);
};

View File

@ -53,7 +53,7 @@ void TracingCpuProfilerImpl::StartProfiling() {
TRACE_EVENT_CATEGORY_GROUP_ENABLED(
TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler.hires"), &enabled);
int sampling_interval_us = enabled ? 100 : 1000;
profiler_.reset(new CpuProfiler(isolate_));
profiler_.reset(new CpuProfiler(isolate_, kDebugNaming));
profiler_->set_sampling_interval(
base::TimeDelta::FromMicroseconds(sampling_interval_us));
profiler_->StartProfiling("", true);

View File

@ -226,7 +226,7 @@ TEST(TickEvents) {
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
profiles->StartProfiling("", false);
processor->Start();
ProfilerListener profiler_listener(isolate, processor);
@ -295,7 +295,7 @@ TEST(Issue1398) {
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
profiles->StartProfiling("", false);
processor->Start();
ProfilerListener profiler_listener(isolate, processor);
@ -1153,7 +1153,7 @@ static void TickLines(bool optimize) {
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), generator,
v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, profiles, generator, processor);
CpuProfiler profiler(isolate, kDebugNaming, profiles, generator, processor);
profiles->StartProfiling("", false);
// TODO(delphick): Stop using the CpuProfiler internals here: This forces
// LogCompiledFunctions so that source positions are collected everywhere.
@ -2857,6 +2857,74 @@ TEST(LowPrecisionSamplingStartStopPublic) {
cpu_profiler->Dispose();
}
const char* naming_test_source = R"(
function doWork(n = 1e3) {
let x = 1;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
x += i * j;
}
}
return x;
}
(function testAssignmentPropertyNamedFunction() {
let object = {};
object.propNamed = function () {
doWork();
};
object.propNamed();
})();
)";
TEST(StandardNaming) {
LocalContext env;
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
v8::CpuProfiler* profiler =
v8::CpuProfiler::New(env->GetIsolate(), kStandardNaming);
const auto profile_name = v8_str("");
profiler->StartProfiling(profile_name);
CompileRun(naming_test_source);
auto* profile = profiler->StopProfiling(profile_name);
auto* root = profile->GetTopDownRoot();
auto* toplevel = FindChild(root, "");
DCHECK(toplevel);
auto* prop_assignment_named_test =
GetChild(env.local(), toplevel, "testAssignmentPropertyNamedFunction");
CHECK(FindChild(prop_assignment_named_test, ""));
profiler->Dispose();
}
TEST(DebugNaming) {
LocalContext env;
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
v8::CpuProfiler* profiler =
v8::CpuProfiler::New(env->GetIsolate(), kDebugNaming);
const auto profile_name = v8_str("");
profiler->StartProfiling(profile_name);
CompileRun(naming_test_source);
auto* profile = profiler->StopProfiling(profile_name);
auto* root = profile->GetTopDownRoot();
auto* toplevel = FindChild(root, "");
DCHECK(toplevel);
auto* prop_assignment_named_test =
GetChild(env.local(), toplevel, "testAssignmentPropertyNamedFunction");
CHECK(FindChild(prop_assignment_named_test, "object.propNamed"));
profiler->Dispose();
}
enum class EntryCountMode { kAll, kOnlyInlined };
// Count the number of unique source positions.