C++ profiles processor: align browser mode with the old implementation, sample VM...
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 7 Apr 2010 14:18:26 +0000 (14:18 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 7 Apr 2010 14:18:26 +0000 (14:18 +0000)
In browser (DevTools) mode, only non-native JS code and callbacks are reported.
Also, added "(garbage collector)" entry which accumulates samples count in GC state.
Trying to display "(compiler)" and "(external)" only brings confusion,
because it ends up in displaying scripts code under "(compiler)" node, and DOM
event handlers under "(external)" node, which looks weird.

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

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

16 files changed:
src/compiler.cc
src/cpu-profiler-inl.h
src/cpu-profiler.cc
src/cpu-profiler.h
src/globals.h
src/log-inl.h
src/log.cc
src/log.h
src/platform-linux.cc
src/platform-macos.cc
src/platform-win32.cc
src/platform.h
src/profile-generator-inl.h
src/profile-generator.cc
src/profile-generator.h
test/cctest/test-cpu-profiler.cc

index 611c0bdff332cb2f445fdaafb03825ede52e5c51..aa80a029a75f10c60ef0426ceb866e792748b817 100755 (executable)
@@ -217,14 +217,18 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
   }
 
   if (script->name()->IsString()) {
-    PROFILE(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
-                            *code, String::cast(script->name())));
+    PROFILE(CodeCreateEvent(
+        is_eval ? Logger::EVAL_TAG :
+            Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+        *code, String::cast(script->name())));
     OPROFILE(CreateNativeCodeRegion(String::cast(script->name()),
                                     code->instruction_start(),
                                     code->instruction_size()));
   } else {
-    PROFILE(CodeCreateEvent(is_eval ? Logger::EVAL_TAG : Logger::SCRIPT_TAG,
-                            *code, ""));
+    PROFILE(CodeCreateEvent(
+        is_eval ? Logger::EVAL_TAG :
+            Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+        *code, ""));
     OPROFILE(CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
                                     code->instruction_start(),
                                     code->instruction_size()));
@@ -592,7 +596,8 @@ void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
     if (script->name()->IsString()) {
       int line_num = GetScriptLineNumber(script, start_position) + 1;
       USE(line_num);
-      PROFILE(CodeCreateEvent(tag, *code, *func_name,
+      PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
+                              *code, *func_name,
                               String::cast(script->name()), line_num));
       OPROFILE(CreateNativeCodeRegion(*func_name,
                                       String::cast(script->name()),
@@ -600,7 +605,8 @@ void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
                                       code->instruction_start(),
                                       code->instruction_size()));
     } else {
-      PROFILE(CodeCreateEvent(tag, *code, *func_name));
+      PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
+                              *code, *func_name));
       OPROFILE(CreateNativeCodeRegion(*func_name,
                                       code->instruction_start(),
                                       code->instruction_size()));
index 7855aa564a55cc2a280c54e1751e39bce4d06147..0e833156caa6bb2958426664f6f1f186b0682d0f 100644 (file)
@@ -65,6 +65,20 @@ TickSample* ProfilerEventsProcessor::TickSampleEvent() {
   return &evt->sample;
 }
 
+
+bool ProfilerEventsProcessor::FilterOutCodeCreateEvent(
+    Logger::LogEventsAndTags tag) {
+  // In browser mode, leave only callbacks and non-native JS entries.
+  // We filter out regular expressions as currently we can't tell
+  // whether they origin from native scripts, so let's not confise people by
+  // showing them weird regexes they didn't wrote.
+  return FLAG_prof_browser_mode
+      && (tag != Logger::CALLBACK_TAG
+          && tag != Logger::FUNCTION_TAG
+          && tag != Logger::LAZY_COMPILE_TAG
+          && tag != Logger::SCRIPT_TAG);
+}
+
 } }  // namespace v8::internal
 
 #endif  // ENABLE_CPP_PROFILES_PROCESSOR
index fb76845c03d9e6c8c2249fd7d3096476da575946..5b862276990a91488f8f40a650a0ee872cb17fa2 100644 (file)
@@ -57,6 +57,7 @@ void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
                                                   const char* prefix,
                                                   String* name,
                                                   Address start) {
+  if (FilterOutCodeCreateEvent(tag)) return;
   CodeEventsContainer evt_rec;
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->type = CodeEventRecord::CODE_CREATION;
@@ -74,6 +75,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
                                               int line_number,
                                               Address start,
                                               unsigned size) {
+  if (FilterOutCodeCreateEvent(tag)) return;
   CodeEventsContainer evt_rec;
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->type = CodeEventRecord::CODE_CREATION;
@@ -89,6 +91,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
                                               const char* name,
                                               Address start,
                                               unsigned size) {
+  if (FilterOutCodeCreateEvent(tag)) return;
   CodeEventsContainer evt_rec;
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->type = CodeEventRecord::CODE_CREATION;
@@ -104,6 +107,7 @@ void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
                                               int args_count,
                                               Address start,
                                               unsigned size) {
+  if (FilterOutCodeCreateEvent(tag)) return;
   CodeEventsContainer evt_rec;
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->type = CodeEventRecord::CODE_CREATION;
@@ -164,6 +168,7 @@ void ProfilerEventsProcessor::RegExpCodeCreateEvent(
     String* name,
     Address start,
     unsigned size) {
+  if (FilterOutCodeCreateEvent(tag)) return;
   CodeEventsContainer evt_rec;
   CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
   rec->type = CodeEventRecord::CODE_CREATION;
index 82d8ff91cb53dc0f1ed9ecdadfb000b66b4f4203..5f263d1a9fe2b9799a20040b6249c1b38ea03299 100644 (file)
@@ -104,9 +104,10 @@ class CodeAliasEventRecord : public CodeEventRecord {
 class TickSampleEventRecord BASE_EMBEDDED {
  public:
   // In memory, the first machine word of a TickSampleEventRecord will be the
-  // first entry of TickSample, that is -- a program counter field.
+  // first entry of TickSample, that is -- the VM state field.
   // TickSample is put first, because 'order' can become equal to
-  // SamplingCircularQueue::kClear, while program counter can't.
+  // SamplingCircularQueue::kClear, while VM state can't, see
+  // the definition of 'enum StateTag'.
   TickSample sample;
   unsigned order;
 
@@ -172,6 +173,8 @@ class ProfilerEventsProcessor : public Thread {
   bool ProcessCodeEvent(unsigned* dequeue_order);
   bool ProcessTicks(unsigned dequeue_order);
 
+  INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
+
   ProfileGenerator* generator_;
   bool running_;
   CircularQueue<CodeEventsContainer> events_buffer_;
@@ -236,8 +239,7 @@ class CpuProfiler {
   static void SetterCallbackEvent(String* name, Address entry_point);
 
   static INLINE(bool is_profiling()) {
-    ASSERT(singleton_ != NULL);
-    return singleton_->processor_ != NULL;
+    return singleton_ != NULL && singleton_->processor_ != NULL;
   }
 
  private:
index ea74b5d3303029824d5e07bef591afd73f24c4de..fe08adad2c348b0d44e781bb6b4e819034d76c5a 100644 (file)
@@ -471,6 +471,11 @@ struct AccessorDescriptor {
   V(EXTERNAL)
 
 enum StateTag {
+#ifdef ENABLE_CPP_PROFILES_PROCESSOR
+  // This is to ensure that VM state field value of TickSample
+  // never gets equal to SamplingCircularQueue::kClear.
+  NULL_STATE = 0,
+#endif
 #define DEF_STATE_TAG(name) name,
   STATE_TAG_LIST(DEF_STATE_TAG)
 #undef DEF_STATE_TAG
index 1500252a5c66a09e436653a17847945a228e4c88..e71b667d16087d21d5c77f4a0140d24973cf7ff4 100644 (file)
@@ -29,6 +29,7 @@
 #define V8_LOG_INL_H_
 
 #include "log.h"
+#include "cpu-profiler.h"
 
 namespace v8 {
 namespace internal {
@@ -55,10 +56,13 @@ inline const char* StateToString(StateTag state) {
   }
 }
 
-VMState::VMState(StateTag state) : disabled_(true), external_callback_(NULL) {
-  if (!Logger::is_logging()) {
+VMState::VMState(StateTag state)
+    : disabled_(true),
+      state_(OTHER),
+      external_callback_(NULL) {
+  if (!Logger::is_logging() && !CpuProfiler::is_profiling()) {
     return;
-  }
+}
 
   disabled_ = false;
 #if !defined(ENABLE_HEAP_PROTECTION)
@@ -118,6 +122,26 @@ VMState::~VMState() {
   }
 #endif
 }
+
+Logger::LogEventsAndTags Logger::ToNativeByScript(Logger::LogEventsAndTags tag,
+                                                  Script* script) {
+#ifdef ENABLE_CPP_PROFILES_PROCESSOR
+  if ((tag == FUNCTION_TAG || tag == LAZY_COMPILE_TAG || tag == SCRIPT_TAG)
+      && script->type()->value() == Script::TYPE_NATIVE) {
+    switch (tag) {
+      case FUNCTION_TAG: return NATIVE_FUNCTION_TAG;
+      case LAZY_COMPILE_TAG: return NATIVE_LAZY_COMPILE_TAG;
+      case SCRIPT_TAG: return NATIVE_SCRIPT_TAG;
+      default: return tag;
+    }
+  } else {
+    return tag;
+  }
+#else
+  return tag;
+#endif
+}
+
 #endif
 
 
index daf078ad11c2a24719ccf45c57f0669cbe6c5dfb..2d16044e9d7156bde50ec25fa98a76d7acb4ecd8 100644 (file)
@@ -1337,17 +1337,20 @@ void Logger::LogCompiledFunctions() {
         Handle<String> script_name(String::cast(script->name()));
         int line_num = GetScriptLineNumber(script, shared->start_position());
         if (line_num > 0) {
-          PROFILE(CodeCreateEvent(Logger::LAZY_COMPILE_TAG,
-                                  shared->code(), *func_name,
-                                  *script_name, line_num + 1));
+          PROFILE(CodeCreateEvent(
+              Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+              shared->code(), *func_name,
+              *script_name, line_num + 1));
         } else {
-          // Can't distinguish enum and script here, so always use Script.
-          PROFILE(CodeCreateEvent(Logger::SCRIPT_TAG,
-                                  shared->code(), *script_name));
+          // Can't distinguish eval and script here, so always use Script.
+          PROFILE(CodeCreateEvent(
+              Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+              shared->code(), *script_name));
         }
       } else {
         PROFILE(CodeCreateEvent(
-            Logger::LAZY_COMPILE_TAG, shared->code(), *func_name));
+            Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+            shared->code(), *func_name));
       }
     } else if (shared->IsApiFunction()) {
       // API function.
index 961b100e6691d4ac8add7ae318ebcdf57061d03a..846ab67ded081c2ba4e565c7c919b3d5a5612383 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -148,6 +148,11 @@ class Logger {
   enum LogEventsAndTags {
     LOG_EVENTS_AND_TAGS_LIST(DECLARE_ENUM)
     NUMBER_OF_LOG_EVENTS
+#ifdef ENABLE_CPP_PROFILES_PROCESSOR
+    , NATIVE_FUNCTION_TAG
+    , NATIVE_LAZY_COMPILE_TAG
+    , NATIVE_SCRIPT_TAG
+#endif
   };
 #undef DECLARE_ENUM
 
@@ -287,6 +292,9 @@ class Logger {
   // Used for logging stubs found in the snapshot.
   static void LogCodeObjects();
 
+  // Converts tag to a corresponding NATIVE_... if the script is native.
+  INLINE(static LogEventsAndTags ToNativeByScript(LogEventsAndTags, Script*));
+
  private:
 
   // Profiler's sampling interval (in milliseconds).
index 03f73dd1b5e1c4d22f1b3440dc700bc11413e173..78b6eb689e4a1ba7bc40102d227f225c8485dc0f 100644 (file)
@@ -728,52 +728,47 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
   if (active_sampler_ == NULL) return;
 
 #ifdef ENABLE_CPP_PROFILES_PROCESSOR
-  if (Logger::state() == GC || !IsVmThread()) return;
-
-  TickSample* sample = NULL;
+  TickSample* sample = CpuProfiler::TickSampleEvent();
+  if (sample == NULL) return;
+  sample->pc = NULL;  // Impossible value if sampling succeeds.
+  sample->frames_count = 0;
 #else
   TickSample sample_obj;
   TickSample* sample = &sample_obj;
+#endif
 
   // We always sample the VM state.
   sample->state = Logger::state();
-#endif
-
   // If profiling, we extract the current pc and sp.
   if (active_sampler_->IsProfiling()) {
     // Extracting the sample from the context is extremely machine dependent.
     ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
     mcontext_t& mcontext = ucontext->uc_mcontext;
-#ifdef ENABLE_CPP_PROFILES_PROCESSOR
-    sample = CpuProfiler::TickSampleEvent();
-#endif
-    if (sample != NULL) {
 #if V8_HOST_ARCH_IA32
-      sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
-      sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
-      sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
+    sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
+    sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
+    sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
 #elif V8_HOST_ARCH_X64
-      sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
-      sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
-      sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
+    sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
+    sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
+    sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
 #elif V8_HOST_ARCH_ARM
 // An undefined macro evaluates to 0, so this applies to Android's Bionic also.
 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
-      sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
-      sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
-      sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
+    sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
+    sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
+    sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
 #else
-      sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
-      sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
-      sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
+    sample->pc = reinterpret_cast<Address>(mcontext.arm_pc);
+    sample->sp = reinterpret_cast<Address>(mcontext.arm_sp);
+    sample->fp = reinterpret_cast<Address>(mcontext.arm_fp);
 #endif
 #elif V8_HOST_ARCH_MIPS
     // Implement this on MIPS.
-      UNIMPLEMENTED();
+    UNIMPLEMENTED();
 #endif
-      if (IsVmThread()) {
-        active_sampler_->SampleStack(sample);
-      }
+    if (IsVmThread()) {
+      active_sampler_->SampleStack(sample);
     }
   }
 #ifndef ENABLE_CPP_PROFILES_PROCESSOR
index 7da3ccaab4faf6c88f84758a96d0b69453cf7462..75e7e830afe9f7fc6eb68c13471b1bac48268f42 100644 (file)
@@ -547,17 +547,17 @@ class Sampler::PlatformData : public Malloced {
     // Loop until the sampler is disengaged, keeping the specified samling freq.
     for ( ; sampler_->IsActive(); OS::Sleep(sampler_->interval_)) {
 #ifdef ENABLE_CPP_PROFILES_PROCESSOR
-      if (Logger::state() == GC) continue;
-
-      TickSample* sample = NULL;
+      TickSample* sample = CpuProfiler::TickSampleEvent();
+      if (sample == NULL) continue;
+      sample->pc = NULL;  // Impossible value if sampling succeeds.
+      sample->frames_count = 0;
 #else
       TickSample sample_obj;
       TickSample* sample = &sample_obj;
+#endif  // ENABLE_CPP_PROFILES_PROCESSOR
 
       // We always sample the VM state.
       sample->state = Logger::state();
-#endif  // ENABLE_CPP_PROFILES_PROCESSOR
-
       // If profiling, we record the pc and sp of the profiled thread.
       if (sampler_->IsProfiling()
           && KERN_SUCCESS == thread_suspend(profiled_thread_)) {
@@ -587,15 +587,10 @@ class Sampler::PlatformData : public Malloced {
                              flavor,
                              reinterpret_cast<natural_t*>(&state),
                              &count) == KERN_SUCCESS) {
-#ifdef ENABLE_CPP_PROFILES_PROCESSOR
-          sample = CpuProfiler::TickSampleEvent();
-#endif
-          if (sample != NULL) {
-            sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
-            sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
-            sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
-            sampler_->SampleStack(sample);
-          }
+          sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
+          sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
+          sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
+          sampler_->SampleStack(sample);
         }
         thread_resume(profiled_thread_);
       }
index 9b09aa3458f234625fbe16d1302ce164f7da7f42..54eed4a3b54a142590ddf5f06587f22de4890b7e 100644 (file)
@@ -1806,37 +1806,32 @@ class Sampler::PlatformData : public Malloced {
     // Loop until the sampler is disengaged, keeping the specified samling freq.
     for ( ; sampler_->IsActive(); Sleep(sampler_->interval_)) {
 #ifdef ENABLE_CPP_PROFILES_PROCESSOR
-      if (Logger::state() == GC) continue;
-
-      TickSample* sample = NULL;
+      TickSample* sample = CpuProfiler::TickSampleEvent();
+      if (sample == NULL) continue;
+      sample->pc = NULL;  // Impossible value if sampling succeeds.
+      sample->frames_count = 0;
 #else
       TickSample sample_obj;
       TickSample* sample = &sample_obj;
+#endif  // ENABLE_CPP_PROFILES_PROCESSOR
 
       // We always sample the VM state.
       sample->state = Logger::state();
-#endif  // ENABLE_CPP_PROFILES_PROCESSOR
-
       // If profiling, we record the pc and sp of the profiled thread.
       if (sampler_->IsProfiling()
           && SuspendThread(profiled_thread_) != (DWORD)-1) {
         context.ContextFlags = CONTEXT_FULL;
         if (GetThreadContext(profiled_thread_, &context) != 0) {
-#ifdef ENABLE_CPP_PROFILES_PROCESSOR
-          sample = CpuProfiler::TickSampleEvent();
-#endif
-          if (sample != NULL) {
 #if V8_HOST_ARCH_X64
-            sample->pc = reinterpret_cast<Address>(context.Rip);
-            sample->sp = reinterpret_cast<Address>(context.Rsp);
-            sample->fp = reinterpret_cast<Address>(context.Rbp);
+          sample->pc = reinterpret_cast<Address>(context.Rip);
+          sample->sp = reinterpret_cast<Address>(context.Rsp);
+          sample->fp = reinterpret_cast<Address>(context.Rbp);
 #else
-            sample->pc = reinterpret_cast<Address>(context.Eip);
-            sample->sp = reinterpret_cast<Address>(context.Esp);
-            sample->fp = reinterpret_cast<Address>(context.Ebp);
+          sample->pc = reinterpret_cast<Address>(context.Eip);
+          sample->sp = reinterpret_cast<Address>(context.Esp);
+          sample->fp = reinterpret_cast<Address>(context.Ebp);
 #endif
-            sampler_->SampleStack(sample);
-          }
+          sampler_->SampleStack(sample);
         }
         ResumeThread(profiled_thread_);
       }
index 85e6fd35355b7122a31a92865d4f1415cfbff864..82e2e3c06253589fb1e6c3937cc33d13776ecb0b 100644 (file)
@@ -516,17 +516,17 @@ class Socket {
 class TickSample {
  public:
   TickSample()
-      : pc(NULL),
+      : state(OTHER),
+        pc(NULL),
         sp(NULL),
         fp(NULL),
         function(NULL),
-        state(OTHER),
         frames_count(0) {}
+  StateTag state;  // The state of the VM.
   Address pc;  // Instruction pointer.
   Address sp;  // Stack pointer.
   Address fp;  // Frame pointer.
   Address function;  // The last called JS function.
-  StateTag state;  // The state of the VM.
   static const int kMaxFramesCount = 64;
   Address stack[kMaxFramesCount];  // Call stack.
   int frames_count;  // Number of captured frames.
index 5739ca76612f4784201985baa2bb97d2294ce929..b4fdfb7d78ea3e0e0ec3e9c8be11458207dbba44 100644 (file)
@@ -49,10 +49,13 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
 }
 
 
-bool CodeEntry::is_js_function() const {
-  return tag_ == Logger::FUNCTION_TAG
-      || tag_ == Logger::LAZY_COMPILE_TAG
-      || tag_ == Logger::SCRIPT_TAG;
+bool CodeEntry::is_js_function_tag(Logger::LogEventsAndTags tag) {
+  return tag == Logger::FUNCTION_TAG
+      || tag == Logger::LAZY_COMPILE_TAG
+      || tag == Logger::SCRIPT_TAG
+      || tag == Logger::NATIVE_FUNCTION_TAG
+      || tag == Logger::NATIVE_LAZY_COMPILE_TAG
+      || tag == Logger::NATIVE_SCRIPT_TAG;
 }
 
 
@@ -86,6 +89,33 @@ bool CpuProfilesCollection::is_last_profile() {
   return current_profiles_.length() == 1;
 }
 
+
+const char* CpuProfilesCollection::GetFunctionName(String* name) {
+  return GetFunctionName(GetName(name));
+}
+
+
+const char* CpuProfilesCollection::GetFunctionName(const char* name) {
+  return strlen(name) > 0 ? name : ProfileGenerator::kAnonymousFunctionName;
+}
+
+
+CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
+  switch (tag) {
+    case GC:
+      return gc_entry_;
+    case JS:
+    case COMPILER:
+    // DOM events handlers are reported as OTHER / EXTERNAL entries.
+    // To avoid confusing people, let's put all these entries into
+    // one bucket.
+    case OTHER:
+    case EXTERNAL:
+      return program_entry_;
+    default: return NULL;
+  }
+}
+
 } }  // namespace v8::internal
 
 #endif  // ENABLE_CPP_PROFILES_PROCESSOR
index 17c0835727cf5d5e353e23eb5eaaf5e62fd0f340..46e7aabcdbe5ad470490df3c340e2ea6e226aa11 100644 (file)
@@ -383,7 +383,7 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
                                                const char* name) {
   CodeEntry* entry = new CodeEntry(tag,
                                    CodeEntry::kEmptyNamePrefix,
-                                   name,
+                                   GetFunctionName(name),
                                    "",
                                    v8::CpuProfileNode::kNoLineNumberInfo);
   code_entries_.Add(entry);
@@ -416,13 +416,6 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
 }
 
 
-const char* CpuProfilesCollection::GetFunctionName(String* name) {
-  const char* maybe_empty_name = GetName(name);
-  return strlen(maybe_empty_name) > 0 ?
-      maybe_empty_name : "(anonymous function)";
-}
-
-
 const char* CpuProfilesCollection::GetName(String* name) {
   if (name->IsString()) {
     char* c_name =
@@ -473,44 +466,56 @@ void CpuProfilesCollection::AddPathToCurrentProfiles(
 }
 
 
+const char* ProfileGenerator::kAnonymousFunctionName = "(anonymous function)";
+const char* ProfileGenerator::kProgramEntryName = "(program)";
+const char* ProfileGenerator::kGarbageCollectorEntryName =
+  "(garbage collector)";
+
 
 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
     : profiles_(profiles),
       program_entry_(
-          profiles->NewCodeEntry(Logger::FUNCTION_TAG, "(program)")) {
+          profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)),
+      gc_entry_(
+          profiles->NewCodeEntry(Logger::BUILTIN_TAG,
+                                 kGarbageCollectorEntryName)) {
 }
 
 
 void ProfileGenerator::RecordTickSample(const TickSample& sample) {
-  // Allocate space for stack frames + pc + function + (program).
+  // Allocate space for stack frames + pc + function + vm-state.
   ScopedVector<CodeEntry*> entries(sample.frames_count + 3);
+  // As actual number of decoded code entries may vary, initialize
+  // entries vector with NULL values.
   CodeEntry** entry = entries.start();
-  *entry++ = code_map_.FindEntry(sample.pc);
+  memset(entry, 0, entries.length() * sizeof(*entry));
+  if (sample.pc != NULL) {
+    *entry++ = code_map_.FindEntry(sample.pc);
 
-  if (sample.function != NULL) {
-    *entry = code_map_.FindEntry(sample.function);
-    if (*entry != NULL && !(*entry)->is_js_function()) {
-      *entry = NULL;
-    } else {
-      CodeEntry* pc_entry = *entries.start();
-      if (pc_entry == NULL || pc_entry->is_js_function())
+    if (sample.function != NULL) {
+      *entry = code_map_.FindEntry(sample.function);
+      if (*entry != NULL && !(*entry)->is_js_function()) {
         *entry = NULL;
+      } else {
+        CodeEntry* pc_entry = *entries.start();
+        if (pc_entry == NULL || pc_entry->is_js_function())
+          *entry = NULL;
+      }
+      entry++;
     }
-    entry++;
-  } else {
-    *entry++ = NULL;
-  }
 
-  for (const Address *stack_pos = sample.stack,
-         *stack_end = stack_pos + sample.frames_count;
-       stack_pos != stack_end;
-       ++stack_pos) {
-    *entry++ = code_map_.FindEntry(*stack_pos);
+    for (const Address *stack_pos = sample.stack,
+           *stack_end = stack_pos + sample.frames_count;
+         stack_pos != stack_end;
+         ++stack_pos) {
+      *entry++ = code_map_.FindEntry(*stack_pos);
+    }
   }
 
-  // WebKit CPU profiles visualization requires "(program)" to be the
-  // topmost entry.
-  *entry++ = FLAG_prof_browser_mode ? program_entry_ : NULL;
+  if (FLAG_prof_browser_mode) {
+    // Put VM state as the topmost entry.
+    *entry++ = EntryForVMState(sample.state);
+  }
 
   profiles_->AddPathToCurrentProfiles(entries);
 }
index 38d1654b2a229e262d58f0c1b9142b7fc984ab2a..79bef0921dcb3ae567c96c3c06e25c6557284f1f 100644 (file)
@@ -44,7 +44,7 @@ class CodeEntry {
                    const char* resource_name,
                    int line_number));
 
-  INLINE(bool is_js_function() const);
+  INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
   INLINE(const char* name_prefix() const) { return name_prefix_; }
   INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; }
   INLINE(const char* name() const) { return name_; }
@@ -52,6 +52,8 @@ class CodeEntry {
   INLINE(int line_number() const) { return line_number_; }
   INLINE(unsigned call_uid() const) { return call_uid_; }
 
+  INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
+
   static const char* kEmptyNamePrefix;
 
  private:
@@ -223,7 +225,8 @@ class CpuProfilesCollection {
   void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
 
  private:
-  const char* GetFunctionName(String* name);
+  INLINE(const char* GetFunctionName(String* name));
+  INLINE(const char* GetFunctionName(const char* name));
   const char* GetName(String* name);
   const char* GetName(int args_count);
 
@@ -284,10 +287,17 @@ class ProfileGenerator {
 
   INLINE(CodeMap* code_map()) { return &code_map_; }
 
+  static const char* kAnonymousFunctionName;
+  static const char* kProgramEntryName;
+  static const char* kGarbageCollectorEntryName;
+
  private:
+  INLINE(CodeEntry* EntryForVMState(StateTag tag));
+
   CpuProfilesCollection* profiles_;
   CodeMap code_map_;
   CodeEntry* program_entry_;
+  CodeEntry* gc_entry_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
 };
index 5e1b9f2a7f5316850a83627631e9ba4e0f024738..a8f5b161d3d9cdaa6f22e6ae20fdf1293cfb1aab 100644 (file)
@@ -47,6 +47,7 @@ static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
                                    i::Address frame2 = NULL,
                                    i::Address frame3 = NULL) {
   i::TickSample* sample = proc->TickSampleEvent();
+  sample->state = i::OTHER;
   sample->pc = frame1;
   sample->function = frame1;
   sample->frames_count = 0;