[log] Support logging basic function events
This CL contains the base implementation for logging function events. Currently only compiler events are support (compile, compile-lazy...), future CLs will enable log events for parsing and first-time exeuction of functions. Bug: chromium:757467 Change-Id: Ia705979190a3ebc1009989610483a7a141bc504b Reviewed-on: https://chromium-review.googlesource.com/743921 Reviewed-by: Igor Sheludko <ishell@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#49040}
This commit is contained in:
parent
ef45d789d2
commit
949734f73a
103
src/compiler.cc
103
src/compiler.cc
@ -179,43 +179,74 @@ void CompilationJob::RecordOptimizedCompilationStats() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilationJob::RecordFunctionCompilation(
|
||||||
|
CodeEventListener::LogEventsAndTags tag) const {
|
||||||
|
// Log the code generation. If source information is available include
|
||||||
|
// script name and line number. Check explicitly whether logging is
|
||||||
|
// enabled as finding the line number is not free.
|
||||||
|
CompilationInfo* compilation_info = this->compilation_info();
|
||||||
|
Isolate* isolate = compilation_info->isolate();
|
||||||
|
if (!isolate->logger()->is_logging_code_events() &&
|
||||||
|
!isolate->is_profiling() && !FLAG_log_function_events) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SharedFunctionInfo> shared = compilation_info->shared_info();
|
||||||
|
Handle<Script> script = parse_info()->script();
|
||||||
|
Handle<AbstractCode> abstract_code =
|
||||||
|
compilation_info->has_bytecode_array()
|
||||||
|
? Handle<AbstractCode>::cast(compilation_info->bytecode_array())
|
||||||
|
: Handle<AbstractCode>::cast(compilation_info->code());
|
||||||
|
|
||||||
|
if (abstract_code.is_identical_to(
|
||||||
|
BUILTIN_CODE(compilation_info->isolate(), CompileLazy))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
|
||||||
|
int column_num =
|
||||||
|
Script::GetColumnNumber(script, shared->start_position()) + 1;
|
||||||
|
String* script_name = script->name()->IsString()
|
||||||
|
? String::cast(script->name())
|
||||||
|
: isolate->heap()->empty_string();
|
||||||
|
CodeEventListener::LogEventsAndTags log_tag =
|
||||||
|
Logger::ToNativeByScript(tag, *script);
|
||||||
|
PROFILE(isolate, CodeCreateEvent(log_tag, *abstract_code, *shared,
|
||||||
|
script_name, line_num, column_num));
|
||||||
|
if (!FLAG_log_function_events) return;
|
||||||
|
|
||||||
|
DisallowHeapAllocation no_gc;
|
||||||
|
|
||||||
|
double ms = time_taken_to_prepare_.InMillisecondsF();
|
||||||
|
ms += time_taken_to_execute_.InMillisecondsF();
|
||||||
|
ms += time_taken_to_finalize_.InMillisecondsF();
|
||||||
|
|
||||||
|
std::string name = compilation_info->IsOptimizing() ? "optimize" : "compile";
|
||||||
|
switch (tag) {
|
||||||
|
case CodeEventListener::EVAL_TAG:
|
||||||
|
name += "-eval";
|
||||||
|
break;
|
||||||
|
case CodeEventListener::SCRIPT_TAG:
|
||||||
|
break;
|
||||||
|
case CodeEventListener::LAZY_COMPILE_TAG:
|
||||||
|
name += "-lazy";
|
||||||
|
break;
|
||||||
|
case CodeEventListener::FUNCTION_TAG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(isolate, FunctionEvent(name.c_str(), nullptr, script->id(), ms,
|
||||||
|
shared->start_position(), shared->end_position(),
|
||||||
|
shared->name()));
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Local helper methods that make up the compilation pipeline.
|
// Local helper methods that make up the compilation pipeline.
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
|
|
||||||
Handle<Script> script,
|
|
||||||
CompilationInfo* compilation_info) {
|
|
||||||
// Log the code generation. If source information is available include
|
|
||||||
// script name and line number. Check explicitly whether logging is
|
|
||||||
// enabled as finding the line number is not free.
|
|
||||||
if (compilation_info->isolate()->logger()->is_logging_code_events() ||
|
|
||||||
compilation_info->isolate()->is_profiling()) {
|
|
||||||
Handle<SharedFunctionInfo> shared = compilation_info->shared_info();
|
|
||||||
Handle<AbstractCode> abstract_code =
|
|
||||||
compilation_info->has_bytecode_array()
|
|
||||||
? Handle<AbstractCode>::cast(compilation_info->bytecode_array())
|
|
||||||
: Handle<AbstractCode>::cast(compilation_info->code());
|
|
||||||
if (abstract_code.is_identical_to(
|
|
||||||
BUILTIN_CODE(compilation_info->isolate(), CompileLazy))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int line_num = Script::GetLineNumber(script, shared->start_position()) + 1;
|
|
||||||
int column_num =
|
|
||||||
Script::GetColumnNumber(script, shared->start_position()) + 1;
|
|
||||||
String* script_name =
|
|
||||||
script->name()->IsString()
|
|
||||||
? String::cast(script->name())
|
|
||||||
: compilation_info->isolate()->heap()->empty_string();
|
|
||||||
CodeEventListener::LogEventsAndTags log_tag =
|
|
||||||
Logger::ToNativeByScript(tag, *script);
|
|
||||||
PROFILE(compilation_info->isolate(),
|
|
||||||
CodeCreateEvent(log_tag, *abstract_code, *shared, script_name,
|
|
||||||
line_num, column_num));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnsureFeedbackMetadata(CompilationInfo* compilation_info) {
|
void EnsureFeedbackMetadata(CompilationInfo* compilation_info) {
|
||||||
DCHECK(compilation_info->has_shared_info());
|
DCHECK(compilation_info->has_shared_info());
|
||||||
|
|
||||||
@ -333,7 +364,7 @@ CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) {
|
|||||||
log_tag = parse_info->lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
|
log_tag = parse_info->lazy_compile() ? CodeEventListener::LAZY_COMPILE_TAG
|
||||||
: CodeEventListener::FUNCTION_TAG;
|
: CodeEventListener::FUNCTION_TAG;
|
||||||
}
|
}
|
||||||
RecordFunctionCompilation(log_tag, parse_info->script(), compilation_info);
|
job->RecordFunctionCompilation(log_tag);
|
||||||
job->RecordUnoptimizedCompilationStats();
|
job->RecordUnoptimizedCompilationStats();
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
@ -536,8 +567,7 @@ bool GetOptimizedCodeNow(CompilationJob* job) {
|
|||||||
job->RecordOptimizedCompilationStats();
|
job->RecordOptimizedCompilationStats();
|
||||||
DCHECK(!isolate->has_pending_exception());
|
DCHECK(!isolate->has_pending_exception());
|
||||||
InsertCodeIntoOptimizedCodeCache(compilation_info);
|
InsertCodeIntoOptimizedCodeCache(compilation_info);
|
||||||
RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG,
|
job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG);
|
||||||
job->parse_info()->script(), compilation_info);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,8 +743,7 @@ CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) {
|
|||||||
job->RetryOptimization(kBailedOutDueToDependencyChange);
|
job->RetryOptimization(kBailedOutDueToDependencyChange);
|
||||||
} else if (job->FinalizeJob() == CompilationJob::SUCCEEDED) {
|
} else if (job->FinalizeJob() == CompilationJob::SUCCEEDED) {
|
||||||
job->RecordOptimizedCompilationStats();
|
job->RecordOptimizedCompilationStats();
|
||||||
RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG,
|
job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG);
|
||||||
job->parse_info()->script(), compilation_info);
|
|
||||||
InsertCodeIntoOptimizedCodeCache(compilation_info);
|
InsertCodeIntoOptimizedCodeCache(compilation_info);
|
||||||
if (FLAG_trace_opt) {
|
if (FLAG_trace_opt) {
|
||||||
PrintF("[completed optimizing ");
|
PrintF("[completed optimizing ");
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "src/allocation.h"
|
#include "src/allocation.h"
|
||||||
#include "src/bailout-reason.h"
|
#include "src/bailout-reason.h"
|
||||||
|
#include "src/code-events.h"
|
||||||
#include "src/contexts.h"
|
#include "src/contexts.h"
|
||||||
#include "src/isolate.h"
|
#include "src/isolate.h"
|
||||||
#include "src/zone/zone.h"
|
#include "src/zone/zone.h"
|
||||||
@ -189,6 +190,7 @@ class V8_EXPORT_PRIVATE CompilationJob {
|
|||||||
|
|
||||||
void RecordOptimizedCompilationStats() const;
|
void RecordOptimizedCompilationStats() const;
|
||||||
void RecordUnoptimizedCompilationStats() const;
|
void RecordUnoptimizedCompilationStats() const;
|
||||||
|
void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag) const;
|
||||||
|
|
||||||
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
|
void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; }
|
||||||
uintptr_t stack_limit() const { return stack_limit_; }
|
uintptr_t stack_limit() const { return stack_limit_; }
|
||||||
|
@ -1097,6 +1097,9 @@ DEFINE_BOOL(log_gc, false,
|
|||||||
DEFINE_BOOL(log_handles, false, "Log global handle events.")
|
DEFINE_BOOL(log_handles, false, "Log global handle events.")
|
||||||
DEFINE_BOOL(log_suspect, false, "Log suspect operations.")
|
DEFINE_BOOL(log_suspect, false, "Log suspect operations.")
|
||||||
DEFINE_BOOL(log_source_code, false, "Log source code.")
|
DEFINE_BOOL(log_source_code, false, "Log source code.")
|
||||||
|
DEFINE_BOOL(log_function_events, false,
|
||||||
|
"Log function events "
|
||||||
|
"(parse, compile, execute) separately.")
|
||||||
DEFINE_BOOL(prof, false,
|
DEFINE_BOOL(prof, false,
|
||||||
"Log statistical profiling information (implies --log-code).")
|
"Log statistical profiling information (implies --log-code).")
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ Log::Log(Logger* logger, const char* file_name)
|
|||||||
FLAG_log_suspect = true;
|
FLAG_log_suspect = true;
|
||||||
FLAG_log_handles = true;
|
FLAG_log_handles = true;
|
||||||
FLAG_log_internal_timer_events = true;
|
FLAG_log_internal_timer_events = true;
|
||||||
|
FLAG_log_function_events = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --prof implies --log-code.
|
// --prof implies --log-code.
|
||||||
|
@ -33,7 +33,8 @@ class Log {
|
|||||||
return FLAG_log || FLAG_log_api || FLAG_log_code || FLAG_log_gc ||
|
return FLAG_log || FLAG_log_api || FLAG_log_code || FLAG_log_gc ||
|
||||||
FLAG_log_handles || FLAG_log_suspect || FLAG_ll_prof ||
|
FLAG_log_handles || FLAG_log_suspect || FLAG_ll_prof ||
|
||||||
FLAG_perf_basic_prof || FLAG_perf_prof || FLAG_log_source_code ||
|
FLAG_perf_basic_prof || FLAG_perf_prof || FLAG_log_source_code ||
|
||||||
FLAG_log_internal_timer_events || FLAG_prof_cpp || FLAG_trace_ic;
|
FLAG_log_internal_timer_events || FLAG_prof_cpp || FLAG_trace_ic ||
|
||||||
|
FLAG_log_function_events;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frees all resources acquired in Initialize and Open... functions.
|
// Frees all resources acquired in Initialize and Open... functions.
|
||||||
|
44
src/log.cc
44
src/log.cc
@ -1264,6 +1264,50 @@ void Logger::SuspectReadEvent(Name* name, Object* obj) {
|
|||||||
msg.WriteToLogFile();
|
msg.WriteToLogFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void AppendFunctionMessage(Log::MessageBuilder& msg, const char* reason,
|
||||||
|
Script* script, int script_id, double time_delta,
|
||||||
|
int start_position, int end_position,
|
||||||
|
base::ElapsedTimer* timer) {
|
||||||
|
msg << "function" << Logger::kNext << reason << Logger::kNext;
|
||||||
|
if (script) {
|
||||||
|
if (script->name()->IsString()) {
|
||||||
|
msg << String::cast(script->name());
|
||||||
|
}
|
||||||
|
msg << Logger::kNext << script->id();
|
||||||
|
} else {
|
||||||
|
msg << Logger::kNext << script_id;
|
||||||
|
}
|
||||||
|
msg << Logger::kNext << start_position << Logger::kNext << end_position
|
||||||
|
<< Logger::kNext << time_delta << Logger::kNext
|
||||||
|
<< timer->Elapsed().InMicroseconds() << Logger::kNext;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Logger::FunctionEvent(const char* reason, Script* script, int script_id,
|
||||||
|
double time_delta, int start_position,
|
||||||
|
int end_position, String* function_name) {
|
||||||
|
if (!log_->IsEnabled() || !FLAG_log_function_events) return;
|
||||||
|
Log::MessageBuilder msg(log_);
|
||||||
|
AppendFunctionMessage(msg, reason, script, script_id, time_delta,
|
||||||
|
start_position, end_position, &timer_);
|
||||||
|
if (function_name) msg << function_name;
|
||||||
|
msg.WriteToLogFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::FunctionEvent(const char* reason, Script* script, int script_id,
|
||||||
|
double time_delta, int start_position,
|
||||||
|
int end_position, const char* function_name,
|
||||||
|
int function_name_length) {
|
||||||
|
if (!log_->IsEnabled() || !FLAG_log_function_events) return;
|
||||||
|
Log::MessageBuilder msg(log_);
|
||||||
|
AppendFunctionMessage(msg, reason, script, script_id, time_delta,
|
||||||
|
start_position, end_position, &timer_);
|
||||||
|
if (function_name_length > 0) {
|
||||||
|
msg.AppendStringPart(function_name, function_name_length);
|
||||||
|
}
|
||||||
|
msg.WriteToLogFile();
|
||||||
|
}
|
||||||
|
|
||||||
void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
|
void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
|
||||||
if (!log_->IsEnabled() || !FLAG_log_gc) return;
|
if (!log_->IsEnabled() || !FLAG_log_gc) return;
|
||||||
|
@ -145,6 +145,14 @@ class Logger : public CodeEventListener {
|
|||||||
// object.
|
// object.
|
||||||
void SuspectReadEvent(Name* name, Object* obj);
|
void SuspectReadEvent(Name* name, Object* obj);
|
||||||
|
|
||||||
|
void FunctionEvent(const char* reason, Script* script, int script_id,
|
||||||
|
double time_delta_ms, int start_position = -1,
|
||||||
|
int end_position = -1, String* function_name = nullptr);
|
||||||
|
void FunctionEvent(const char* reason, Script* script, int script_id,
|
||||||
|
double time_delta_ms, int start_position, int end_position,
|
||||||
|
const char* function_name = nullptr,
|
||||||
|
int function_name_length = 0);
|
||||||
|
|
||||||
// ==== Events logged by --log-api. ====
|
// ==== Events logged by --log-api. ====
|
||||||
void ApiSecurityCheck();
|
void ApiSecurityCheck();
|
||||||
void ApiNamedPropertyAccess(const char* tag, JSObject* holder, Object* name);
|
void ApiNamedPropertyAccess(const char* tag, JSObject* holder, Object* name);
|
||||||
|
@ -776,3 +776,32 @@ TEST(ConsoleTimeEvents) {
|
|||||||
|
|
||||||
isolate->Dispose();
|
isolate->Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(LogFunctionEvents) {
|
||||||
|
SETUP_FLAGS();
|
||||||
|
i::FLAG_log_function_events = true;
|
||||||
|
v8::Isolate::CreateParams create_params;
|
||||||
|
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||||
|
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||||
|
{
|
||||||
|
ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
|
||||||
|
// Try to create many different kind of maps to make sure the logging won't
|
||||||
|
// crash. More detailed tests are implemented separately.
|
||||||
|
const char* source_text =
|
||||||
|
"function lazyNotExecutedFunction() { return 'lazy' };"
|
||||||
|
"function lazyFunction() { return 'lazy' };"
|
||||||
|
"lazyFunction();"
|
||||||
|
"(function eagerFunction(){ return 'eager' })();";
|
||||||
|
CompileRun(source_text);
|
||||||
|
|
||||||
|
logger.StopLogging();
|
||||||
|
|
||||||
|
// TODO(cbruni): Extend with parsing/first-execution log statements.
|
||||||
|
CHECK_NULL(
|
||||||
|
logger.FindLine("function,compile-lazy,", ",lazyNotExecutedFunction"));
|
||||||
|
CHECK(logger.FindLine("function,compile-lazy,", ",lazyFunction"));
|
||||||
|
CHECK(logger.FindLine("function,compile,", ",eagerFunction"));
|
||||||
|
}
|
||||||
|
i::FLAG_log_function_events = false;
|
||||||
|
isolate->Dispose();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user