CPUProfiler: propagate scriptId to the front-end
authorloislo@chromium.org <loislo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 1 Jul 2013 15:15:57 +0000 (15:15 +0000)
committerloislo@chromium.org <loislo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 1 Jul 2013 15:15:57 +0000 (15:15 +0000)
Each CpuProfileNode has resource_name string property.
It cost us N * strlen(resource_name) where N is number of functions in the collected profile.
We could transfer script_id instead of resource_name so it would reduce transfer
size and help us to solve the problem with evals and sourceURL.

BUG=none
TEST=test-cpu-profiler/CollectCpuProfile
R=jkummerow@chromium.org, yurys@chromium.org

Review URL: https://codereview.chromium.org/17642009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15429 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8-profiler.h
src/api.cc
src/cpu-profiler.cc
src/profile-generator-inl.h
src/profile-generator.cc
src/profile-generator.h
test/cctest/test-profile-generator.cc

index 5338fcd..8e6251a 100644 (file)
@@ -75,6 +75,9 @@ class V8EXPORT CpuProfileNode {
   /** Returns function name (empty string for anonymous functions.) */
   Handle<String> GetFunctionName() const;
 
+  /** Returns id of the script where function is located. */
+  int GetScriptId() const;
+
   /** Returns resource name for script from where the function originates. */
   Handle<String> GetScriptResourceName() const;
 
index 4a24f4b..ee80579 100644 (file)
@@ -7326,6 +7326,15 @@ Handle<String> CpuProfileNode::GetFunctionName() const {
 }
 
 
+int CpuProfileNode::GetScriptId() const {
+  i::Isolate* isolate = i::Isolate::Current();
+  IsDeadCheck(isolate, "v8::CpuProfileNode::GetScriptId");
+  const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
+  const i::CodeEntry* entry = node->entry();
+  return entry->script_id();
+}
+
+
 Handle<String> CpuProfileNode::GetScriptResourceName() const {
   i::Isolate* isolate = i::Isolate::Current();
   IsDeadCheck(isolate, "v8::CpuProfileNode::GetScriptResourceName");
index 270da8f..55d8121 100644 (file)
@@ -255,9 +255,12 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->start = code->address();
   rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
-  rec->entry->set_no_frame_ranges(info ?
-                                  info->ReleaseNoFrameRanges() :
-                                  NULL);
+  if (info) {
+    rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
+  }
+  ASSERT(Script::cast(shared->script()));
+  Script* script = Script::cast(shared->script());
+  rec->entry->set_script_id(script->id()->value());
   rec->size = code->ExecutableSize();
   rec->shared = shared->address();
   processor_->Enqueue(evt_rec);
@@ -280,9 +283,12 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
       CodeEntry::kEmptyNamePrefix,
       profiles_->GetName(source),
       line);
-  rec->entry->set_no_frame_ranges(info ?
-                                  info->ReleaseNoFrameRanges() :
-                                  NULL);
+  if (info) {
+    rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
+  }
+  ASSERT(Script::cast(shared->script()));
+  Script* script = Script::cast(shared->script());
+  rec->entry->set_script_id(script->id()->value());
   rec->size = code->ExecutableSize();
   rec->shared = shared->address();
   processor_->Enqueue(evt_rec);
index 115e813..20c1aec 100644 (file)
@@ -56,6 +56,7 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
       resource_name_(resource_name),
       line_number_(line_number),
       shared_id_(0),
+      script_id_(v8::Script::kNoScriptId),
       security_token_id_(security_token_id),
       no_frame_ranges_(NULL) {
 }
index 1354487..aeb80a3 100644 (file)
@@ -273,12 +273,13 @@ double ProfileNode::GetTotalMillis() const {
 
 
 void ProfileNode::Print(int indent) {
-  OS::Print("%5u %5u %*c %s%s [%d] #%d",
+  OS::Print("%5u %5u %*c %s%s [%d] #%d %d",
             total_ticks_, self_ticks_,
             indent, ' ',
             entry_->name_prefix(),
             entry_->name(),
             entry_->security_token_id(),
+            entry_->script_id(),
             id());
   if (entry_->resource_name()[0] != '\0')
     OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
index 2783a08..411cbdb 100644 (file)
@@ -111,6 +111,8 @@ class CodeEntry {
   INLINE(const char* resource_name() const) { return resource_name_; }
   INLINE(int line_number() const) { return line_number_; }
   INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
+  INLINE(int script_id() const) { return script_id_; }
+  INLINE(void set_script_id(int script_id)) { script_id_ = script_id; }
   INLINE(int security_token_id() const) { return security_token_id_; }
 
   INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
@@ -138,6 +140,7 @@ class CodeEntry {
   const char* resource_name_;
   int line_number_;
   int shared_id_;
+  int script_id_;
   int security_token_id_;
   List<OffsetRange>* no_frame_ranges_;
 
index e919789..dfcc75c 100644 (file)
@@ -905,3 +905,62 @@ TEST(Issue51919) {
   for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
     i::DeleteArray(titles[i]);
 }
+
+
+static const v8::CpuProfileNode* PickChild(const v8::CpuProfileNode* parent,
+                                           const char* name) {
+  for (int i = 0; i < parent->GetChildrenCount(); ++i) {
+    const v8::CpuProfileNode* child = parent->GetChild(i);
+    v8::String::AsciiValue function_name(child->GetFunctionName());
+    if (strcmp(*function_name, name) == 0) return child;
+  }
+  return NULL;
+}
+
+
+TEST(ProfileNodeScriptId) {
+  // This test does not pass with inlining enabled since inlined functions
+  // don't appear in the stack trace.
+  i::FLAG_use_inlining = false;
+
+  const char* extensions[] = { "v8/profiler" };
+  v8::ExtensionConfiguration config(1, extensions);
+  LocalContext env(&config);
+  v8::HandleScope hs(env->GetIsolate());
+
+  v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
+  CHECK_EQ(0, profiler->GetProfileCount());
+  v8::Handle<v8::Script> script_a = v8::Script::Compile(v8::String::New(
+      "function a() { startProfiling(); }\n"));
+  script_a->Run();
+  v8::Handle<v8::Script> script_b = v8::Script::Compile(v8::String::New(
+      "function b() { a(); }\n"
+      "b();\n"
+      "stopProfiling();\n"));
+  script_b->Run();
+  CHECK_EQ(1, profiler->GetProfileCount());
+  const v8::CpuProfile* profile = profiler->GetCpuProfile(0);
+  const v8::CpuProfileNode* current = profile->GetTopDownRoot();
+  reinterpret_cast<ProfileNode*>(
+      const_cast<v8::CpuProfileNode*>(current))->Print(0);
+  // The tree should look like this:
+  //  (root)
+  //   (anonymous function)
+  //     b
+  //       a
+  // There can also be:
+  //         startProfiling
+  // if the sampler managed to get a tick.
+  current = PickChild(current, i::ProfileGenerator::kAnonymousFunctionName);
+  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
+
+  current = PickChild(current, "b");
+  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
+  CHECK_EQ(script_b->GetId(), current->GetScriptId());
+
+  current = PickChild(current, "a");
+  CHECK_NE(NULL, const_cast<v8::CpuProfileNode*>(current));
+  CHECK_EQ(script_a->GetId(), current->GetScriptId());
+}
+
+