Include getters and setters callbacks invocations in CPU profiler log.

Logging getters and setters from DOM API is extremely useful for web
developers as setting (and getting!) several properties can cause
page relayouts which take significant time.

Review URL: http://codereview.chromium.org/434074

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3363 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mikhail.naganov@gmail.com 2009-11-25 16:39:18 +00:00
parent 93d6199de0
commit 2af151ee63
5 changed files with 147 additions and 5 deletions

View File

@ -680,22 +680,51 @@ class CompressionHelper {
#endif // ENABLE_LOGGING_AND_PROFILING
void Logger::CallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::CallbackEventInternal(const char* prefix, const char* name,
Address entry_point) {
if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg;
msg.Append("%s,%s,",
log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]);
msg.AppendAddress(entry_point);
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append(",1,\"%s\"", *str);
msg.Append(",1,\"%s%s\"", prefix, name);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n');
msg.WriteToLogFile();
}
#endif
void Logger::CallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("", *str, entry_point);
#endif
}
void Logger::GetterCallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("get ", *str, entry_point);
#endif
}
void Logger::SetterCallbackEvent(String* name, Address entry_point) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code) return;
SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
CallbackEventInternal("set ", *str, entry_point);
#endif
}
@ -1098,6 +1127,7 @@ void Logger::ResumeProfiler(int flags) {
LOG(UncheckedStringEvent("profiler", "resume"));
FLAG_log_code = true;
LogCompiledFunctions();
LogAccessorCallbacks();
if (!FLAG_sliding_state_window) ticker_->Start();
}
profiler_->resume();
@ -1242,6 +1272,28 @@ void Logger::LogCompiledFunctions() {
DeleteArray(sfis);
}
void Logger::LogAccessorCallbacks() {
AssertNoAllocation no_alloc;
HeapIterator iterator;
while (iterator.has_next()) {
HeapObject* obj = iterator.next();
ASSERT(obj != NULL);
if (!obj->IsAccessorInfo()) continue;
AccessorInfo* ai = AccessorInfo::cast(obj);
if (!ai->name()->IsString()) continue;
String* name = String::cast(ai->name());
Address getter_entry = v8::ToCData<Address>(ai->getter());
if (getter_entry != 0) {
LOG(GetterCallbackEvent(name, getter_entry));
}
Address setter_entry = v8::ToCData<Address>(ai->setter());
if (setter_entry != 0) {
LOG(SetterCallbackEvent(name, setter_entry));
}
}
}
#endif

View File

@ -208,6 +208,8 @@ class Logger {
// ==== Events logged by --log-code. ====
// Emits a code event for a callback function.
static void CallbackEvent(String* name, Address entry_point);
static void GetterCallbackEvent(String* name, Address entry_point);
static void SetterCallbackEvent(String* name, Address entry_point);
// Emits a code create event.
static void CodeCreateEvent(LogEventsAndTags tag,
Code* code, const char* source);
@ -273,6 +275,8 @@ class Logger {
// Logs all compiled functions found in the heap.
static void LogCompiledFunctions();
// Logs all accessor callbacks found in the heap.
static void LogAccessorCallbacks();
// Used for logging stubs found in the snapshot.
static void LogCodeObject(Object* code_object);
@ -287,6 +291,11 @@ class Logger {
// Emits the profiler's first message.
static void ProfilerBeginEvent();
// Emits callback event messages.
static void CallbackEventInternal(const char* prefix,
const char* name,
Address entry_point);
// Emits aliases for compressed messages.
static void LogAliases();

View File

@ -750,6 +750,9 @@ Object* LoadCallbackProperty(Arguments args) {
{
// Leaving JavaScript.
VMState state(EXTERNAL);
#ifdef ENABLE_LOGGING_AND_PROFILING
state.set_external_callback(getter_address);
#endif
result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
}
RETURN_IF_SCHEDULED_EXCEPTION();
@ -773,6 +776,9 @@ Object* StoreCallbackProperty(Arguments args) {
{
// Leaving JavaScript.
VMState state(EXTERNAL);
#ifdef ENABLE_LOGGING_AND_PROFILING
state.set_external_callback(setter_address);
#endif
fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
}
RETURN_IF_SCHEDULED_EXCEPTION();

View File

@ -538,6 +538,81 @@ TEST(LogCallbacks) {
}
static v8::Handle<v8::Value> Prop1Getter(v8::Local<v8::String> property,
const v8::AccessorInfo& info) {
return v8::Handle<v8::Value>();
}
static void Prop1Setter(v8::Local<v8::String> property,
v8::Local<v8::Value> value,
const v8::AccessorInfo& info) {
}
static v8::Handle<v8::Value> Prop2Getter(v8::Local<v8::String> property,
const v8::AccessorInfo& info) {
return v8::Handle<v8::Value>();
}
TEST(LogAccessorCallbacks) {
const bool saved_prof_lazy = i::FLAG_prof_lazy;
const bool saved_prof = i::FLAG_prof;
const bool saved_prof_auto = i::FLAG_prof_auto;
i::FLAG_prof = true;
i::FLAG_prof_lazy = false;
i::FLAG_prof_auto = false;
i::FLAG_logfile = "*";
// If tests are being run manually, V8 will be already initialized
// by the bottom test.
const bool need_to_set_up_logger = i::V8::IsRunning();
v8::HandleScope scope;
v8::Handle<v8::Context> env = v8::Context::New();
if (need_to_set_up_logger) Logger::Setup();
env->Enter();
// Skip all initially logged stuff.
EmbeddedVector<char, 102400> buffer;
int log_pos = GetLogLines(0, &buffer);
v8::Persistent<v8::FunctionTemplate> obj =
v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
obj->SetClassName(v8::String::New("Obj"));
v8::Handle<v8::ObjectTemplate> inst = obj->InstanceTemplate();
inst->SetAccessor(v8::String::New("prop1"), Prop1Getter, Prop1Setter);
inst->SetAccessor(v8::String::New("prop2"), Prop2Getter);
i::Logger::LogAccessorCallbacks();
log_pos = GetLogLines(log_pos, &buffer);
CHECK_GT(log_pos, 0);
buffer[log_pos] = 0;
printf("%s", buffer.start());
EmbeddedVector<char, 100> prop1_getter_record;
i::OS::SNPrintF(prop1_getter_record,
"code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop1\"",
Prop1Getter);
CHECK_NE(NULL, strstr(buffer.start(), prop1_getter_record.start()));
EmbeddedVector<char, 100> prop1_setter_record;
i::OS::SNPrintF(prop1_setter_record,
"code-creation,Callback,0x%" V8PRIxPTR ",1,\"set prop1\"",
Prop1Setter);
CHECK_NE(NULL, strstr(buffer.start(), prop1_setter_record.start()));
EmbeddedVector<char, 100> prop2_getter_record;
i::OS::SNPrintF(prop2_getter_record,
"code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop2\"",
Prop2Getter);
CHECK_NE(NULL, strstr(buffer.start(), prop2_getter_record.start()));
obj.Dispose();
env->Exit();
Logger::TearDown();
i::FLAG_prof_lazy = saved_prof_lazy;
i::FLAG_prof = saved_prof;
i::FLAG_prof_auto = saved_prof_auto;
}
static inline bool IsStringEqualTo(const char* r, const char* s) {
return strncmp(r, s, strlen(r)) == 0;
}

View File

@ -244,7 +244,7 @@ devtools.profiler.CodeMap.CodeEntry.prototype.toString = function() {
devtools.profiler.CodeMap.NameGenerator = function() {
this.knownNames_ = [];
this.knownNames_ = {};
};