Revision: 5523
Author: [email protected]
Date: Fri Sep 24 04:45:12 2010
Log: Provide more functions to CPU profiler (fix issue 858).

The cause for missing functions is that some of them are created
from compiled code (see FastNewClosureStub), and thus not get
registered in profiler's code map.

My solution is to hook on GC visitor to provide JS functions
addresses to profiler, only if it is enabled.

BUG=858
TEST=

Review URL: http://codereview.chromium.org/3417019
http://code.google.com/p/v8/source/detail?r=5523

Modified:
 /branches/bleeding_edge/src/cpu-profiler.cc
 /branches/bleeding_edge/src/cpu-profiler.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/log.cc
 /branches/bleeding_edge/src/log.h
 /branches/bleeding_edge/src/mark-compact.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/profile-generator.cc
 /branches/bleeding_edge/src/profile-generator.h
 /branches/bleeding_edge/src/stub-cache.cc

=======================================
--- /branches/bleeding_edge/src/cpu-profiler.cc Wed Sep  1 06:08:39 2010
+++ /branches/bleeding_edge/src/cpu-profiler.cc Fri Sep 24 04:45:12 2010
@@ -32,6 +32,7 @@
 #ifdef ENABLE_LOGGING_AND_PROFILING

 #include "frames-inl.h"
+#include "hashmap.h"
 #include "log-inl.h"

 #include "../include/v8-profiler.h"
@@ -50,7 +51,13 @@
       ticks_buffer_(sizeof(TickSampleEventRecord),
                     kTickSamplesBufferChunkSize,
                     kTickSamplesBufferChunksCount),
-      enqueue_order_(0) {
+      enqueue_order_(0),
+      known_functions_(new HashMap(AddressesMatch)) {
+}
+
+
+ProfilerEventsProcessor::~ProfilerEventsProcessor() {
+  delete known_functions_;
 }


@@ -152,16 +159,32 @@
   rec->entry = generator_->NewCodeEntry(security_token_id);
   rec->code_start = start;
   events_buffer_.Enqueue(evt_rec);
+
+  known_functions_->Lookup(alias, AddressHash(alias), true);
 }


 void ProfilerEventsProcessor::FunctionMoveEvent(Address from, Address to) {
   CodeMoveEvent(from, to);
+
+  if (IsKnownFunction(from)) {
+    known_functions_->Remove(from, AddressHash(from));
+    known_functions_->Lookup(to, AddressHash(to), true);
+  }
 }


 void ProfilerEventsProcessor::FunctionDeleteEvent(Address from) {
   CodeDeleteEvent(from);
+
+  known_functions_->Remove(from, AddressHash(from));
+}
+
+
+bool ProfilerEventsProcessor::IsKnownFunction(Address start) {
+  HashMap::Entry* entry =
+      known_functions_->Lookup(start, AddressHash(start), false);
+  return entry != NULL;
 }


@@ -401,6 +424,40 @@
       function->code()->address(),
       security_token_id);
 }
+
+
+void CpuProfiler::FunctionCreateEventFromMove(JSFunction* function,
+                                              HeapObject* source) {
+  // This function is called from GC iterators (during Scavenge,
+  // MC, and MS), so marking bits can be set on objects. That's
+  // why unchecked accessors are used here.
+
+  // The same function can be reported several times.
+ if (function->unchecked_code() == Builtins::builtin(Builtins::LazyCompile) + || singleton_->processor_->IsKnownFunction(function->address())) return;
+
+  int security_token_id = TokenEnumerator::kNoSecurityToken;
+  // In debug mode, assertions may fail for contexts,
+  // and we can live without security tokens in debug mode.
+#ifndef DEBUG
+  if (function->unchecked_context()->IsContext()) {
+    security_token_id = singleton_->token_enumerator_->GetTokenId(
+        function->context()->global_context()->security_token());
+  }
+  // Security token may not be moved yet.
+  if (security_token_id == TokenEnumerator::kNoSecurityToken) {
+    JSFunction* old_function = reinterpret_cast<JSFunction*>(source);
+    if (old_function->unchecked_context()->IsContext()) {
+      security_token_id = singleton_->token_enumerator_->GetTokenId(
+          old_function->context()->global_context()->security_token());
+    }
+  }
+#endif
+  singleton_->processor_->FunctionCreateEvent(
+      function->address(),
+      function->unchecked_code()->address(),
+      security_token_id);
+}


 void CpuProfiler::FunctionMoveEvent(Address from, Address to) {
@@ -473,7 +530,12 @@
     processor_->Start();
     // Enumerate stuff we already have in the heap.
     if (Heap::HasBeenSetup()) {
-      Logger::LogCodeObjects();
+      if (!FLAG_prof_browser_mode) {
+        bool saved_log_code_flag = FLAG_log_code;
+        FLAG_log_code = true;
+        Logger::LogCodeObjects();
+        FLAG_log_code = saved_log_code_flag;
+      }
       Logger::LogCompiledFunctions();
       Logger::LogFunctionObjects();
       Logger::LogAccessorCallbacks();
=======================================
--- /branches/bleeding_edge/src/cpu-profiler.h  Tue Aug 10 05:06:42 2010
+++ /branches/bleeding_edge/src/cpu-profiler.h  Fri Sep 24 04:45:12 2010
@@ -41,6 +41,7 @@
 class CodeMap;
 class CpuProfile;
 class CpuProfilesCollection;
+class HashMap;
 class ProfileGenerator;
 class TokenEnumerator;

@@ -132,7 +133,7 @@
 class ProfilerEventsProcessor : public Thread {
  public:
   explicit ProfilerEventsProcessor(ProfileGenerator* generator);
-  virtual ~ProfilerEventsProcessor() { }
+  virtual ~ProfilerEventsProcessor();

   // Thread control.
   virtual void Run();
@@ -163,6 +164,7 @@
                              Address start, unsigned size);
   // Puts current stack into tick sample events buffer.
   void AddCurrentStack();
+  bool IsKnownFunction(Address start);

   // Tick sample events are filled directly in the buffer of the circular
   // queue (because the structure is of fixed width, but usually not all
@@ -183,6 +185,13 @@
   bool ProcessTicks(unsigned dequeue_order);

INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
+  INLINE(static bool AddressesMatch(void* key1, void* key2)) {
+    return key1 == key2;
+  }
+  INLINE(static uint32_t AddressHash(Address addr)) {
+    return ComputeIntegerHash(
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
+  }

   ProfileGenerator* generator_;
   bool running_;
@@ -190,6 +199,9 @@
   SamplingCircularQueue ticks_buffer_;
   UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
   unsigned enqueue_order_;
+
+  // Used from the VM thread.
+  HashMap* known_functions_;
 };

 } }  // namespace v8::internal
@@ -242,6 +254,10 @@
   static void CodeMoveEvent(Address from, Address to);
   static void CodeDeleteEvent(Address from);
   static void FunctionCreateEvent(JSFunction* function);
+  // Reports function creation in case we had missed it (e.g.
+  // if it was created from compiled code).
+  static void FunctionCreateEventFromMove(JSFunction* function,
+                                          HeapObject* source);
   static void FunctionMoveEvent(Address from, Address to);
   static void FunctionDeleteEvent(Address from);
   static void GetterCallbackEvent(String* name, Address entry_point);
=======================================
--- /branches/bleeding_edge/src/heap.cc Thu Sep 23 05:49:59 2010
+++ /branches/bleeding_edge/src/heap.cc Fri Sep 24 04:45:12 2010
@@ -1218,7 +1218,14 @@
     RecordCopiedObject(target);
 #endif
     HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address()));
-
+#if defined(ENABLE_LOGGING_AND_PROFILING)
+    if (Logger::is_logging() || CpuProfiler::is_profiling()) {
+      if (target->IsJSFunction()) {
+        PROFILE(FunctionMoveEvent(source->address(), target->address()));
+ PROFILE(FunctionCreateEventFromMove(JSFunction::cast(target), source));
+      }
+    }
+#endif
     return target;
   }

=======================================
--- /branches/bleeding_edge/src/log.cc  Thu Sep 16 01:23:34 2010
+++ /branches/bleeding_edge/src/log.cc  Fri Sep 24 04:45:12 2010
@@ -871,14 +871,17 @@

 void Logger::FunctionCreateEvent(JSFunction* function) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
+  // This function can be called from GC iterators (during Scavenge,
+  // MC, and MS), so marking bits can be set on objects. That's
+  // why unchecked accessors are used here.
   static Address prev_code = NULL;
   if (!Log::IsEnabled() || !FLAG_log_code) return;
   LogMessageBuilder msg;
   msg.Append("%s,", log_events_[FUNCTION_CREATION_EVENT]);
   msg.AppendAddress(function->address());
   msg.Append(',');
-  msg.AppendAddress(function->code()->address(), prev_code);
-  prev_code = function->code()->address();
+  msg.AppendAddress(function->unchecked_code()->address(), prev_code);
+  prev_code = function->unchecked_code()->address();
   if (FLAG_compress_log) {
     ASSERT(compression_helper_ != NULL);
     if (!compression_helper_->HandleMessage(&msg)) return;
@@ -887,6 +890,16 @@
   msg.WriteToLogFile();
 #endif
 }
+
+
+void Logger::FunctionCreateEventFromMove(JSFunction* function,
+                                         HeapObject*) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ if (function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile)) {
+    FunctionCreateEvent(function);
+  }
+#endif
+}


 void Logger::FunctionMoveEvent(Address from, Address to) {
=======================================
--- /branches/bleeding_edge/src/log.h   Mon Jun  7 01:27:32 2010
+++ /branches/bleeding_edge/src/log.h   Fri Sep 24 04:45:12 2010
@@ -216,6 +216,8 @@
   static void CodeDeleteEvent(Address from);
   // Emits a function object create event.
   static void FunctionCreateEvent(JSFunction* function);
+  static void FunctionCreateEventFromMove(JSFunction* function,
+                                          HeapObject*);
   // Emits a function move event.
   static void FunctionMoveEvent(Address from, Address to);
   // Emits a function delete event.
=======================================
--- /branches/bleeding_edge/src/mark-compact.cc Thu Sep 23 02:15:26 2010
+++ /branches/bleeding_edge/src/mark-compact.cc Fri Sep 24 04:45:12 2010
@@ -2520,6 +2520,7 @@
   HeapObject* copied_to = HeapObject::FromAddress(new_addr);
   if (copied_to->IsJSFunction()) {
     PROFILE(FunctionMoveEvent(old_addr, new_addr));
+    PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to), obj));
   }
   HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));

@@ -2612,6 +2613,7 @@
   HeapObject* copied_to = HeapObject::FromAddress(new_addr);
   if (copied_to->IsJSFunction()) {
     PROFILE(FunctionMoveEvent(old_addr, new_addr));
+    PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to), obj));
   }
   HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr));

=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Fri Sep 24 01:18:33 2010
+++ /branches/bleeding_edge/src/objects-inl.h   Fri Sep 24 04:45:12 2010
@@ -81,7 +81,6 @@
     WRITE_FIELD(this, offset, value);                                   \
     CONDITIONAL_WRITE_BARRIER(this, offset, mode);                      \
   }
-


 #define SMI_ACCESSORS(holder, name, offset)             \
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Mon Sep 20 02:29:12 2010 +++ /branches/bleeding_edge/src/profile-generator.cc Fri Sep 24 04:45:12 2010
@@ -134,10 +134,13 @@

 uint32_t CodeEntry::GetCallUid() const {
   uint32_t hash = ComputeIntegerHash(tag_);
-  hash ^= static_cast<int32_t>(reinterpret_cast<intptr_t>(name_prefix_));
-  hash ^= static_cast<int32_t>(reinterpret_cast<intptr_t>(name_));
-  hash ^= static_cast<int32_t>(reinterpret_cast<intptr_t>(resource_name_));
-  hash ^= static_cast<int32_t>(line_number_);
+  hash ^= ComputeIntegerHash(
+      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)));
+  hash ^= ComputeIntegerHash(
+      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)));
+  hash ^= ComputeIntegerHash(
+      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)));
+  hash ^= ComputeIntegerHash(line_number_);
   return hash;
 }

@@ -442,9 +445,10 @@
   CodeTree::Locator locator;
   if (tree_.Find(code_start, &locator)) {
     const CodeEntryInfo& code_info = locator.value();
-    entry->CopyData(*code_info.entry);
-    tree_.Insert(start, &locator);
-    locator.set_value(CodeEntryInfo(entry, code_info.size));
+    if (tree_.Insert(start, &locator)) {
+      entry->CopyData(*code_info.entry);
+      locator.set_value(CodeEntryInfo(entry, code_info.size));
+    }
   }
 }

=======================================
--- /branches/bleeding_edge/src/profile-generator.h     Mon Sep 20 02:29:12 2010
+++ /branches/bleeding_edge/src/profile-generator.h     Fri Sep 24 04:45:12 2010
@@ -745,7 +745,8 @@
   }

   static uint32_t AddressHash(Address addr) {
-    return static_cast<int32_t>(reinterpret_cast<intptr_t>(addr));
+    return ComputeIntegerHash(
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
   }

   bool initial_fill_mode_;
@@ -888,7 +889,8 @@
   };

   uint32_t Hash(HeapObject* object) {
-    return static_cast<uint32_t>(reinterpret_cast<intptr_t>(object));
+    return ComputeIntegerHash(
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object)));
   }
static bool HeapObjectsMatch(void* key1, void* key2) { return key1 == key2; }

@@ -995,7 +997,8 @@
   }

   INLINE(static uint32_t ObjectHash(const void* key)) {
-    return static_cast<int32_t>(reinterpret_cast<intptr_t>(key));
+    return ComputeIntegerHash(
+        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)));
   }

   void EnumerateNodes();
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc   Tue Sep 21 05:54:12 2010
+++ /branches/bleeding_edge/src/stub-cache.cc   Fri Sep 24 04:45:12 2010
@@ -1186,25 +1186,43 @@

 Object* LoadStubCompiler::GetCode(PropertyType type, String* name) {
   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
-  return GetCodeWithFlags(flags, name);
+  Object* result = GetCodeWithFlags(flags, name);
+  if (!result->IsFailure()) {
+ PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(result), name));
+  }
+  return result;
 }


 Object* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
-  return GetCodeWithFlags(flags, name);
+  Object* result = GetCodeWithFlags(flags, name);
+  if (!result->IsFailure()) {
+    PROFILE(
+ CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(result), name));
+  }
+  return result;
 }


 Object* StoreStubCompiler::GetCode(PropertyType type, String* name) {
   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
-  return GetCodeWithFlags(flags, name);
+  Object* result = GetCodeWithFlags(flags, name);
+  if (!result->IsFailure()) {
+ PROFILE(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(result), name));
+  }
+  return result;
 }


 Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
-  return GetCodeWithFlags(flags, name);
+  Object* result = GetCodeWithFlags(flags, name);
+  if (!result->IsFailure()) {
+    PROFILE(
+ CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(result), name));
+  }
+  return result;
 }


--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to