Eliminate the need for code delete events in CPU profiler.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 14 Sep 2011 11:47:03 +0000 (11:47 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 14 Sep 2011 11:47:03 +0000 (11:47 +0000)
Events are still generated for tick processor on performance testing
server to work, as soon as scripts will be updated, it will be safe
to remove code delete events emitting code.

R=erik.corry@gmail.com
BUG=v8:1466
TEST=existing tests in test-profile-generator,test-cpu-profiler and mjsunit/tools

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

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

14 files changed:
src/cpu-profiler-inl.h
src/cpu-profiler.cc
src/cpu-profiler.h
src/log.cc
src/log.h
src/profile-generator-inl.h
src/profile-generator.cc
src/profile-generator.h
src/runtime.cc
test/cctest/log-eq-of-logging-and-traversal.js
test/cctest/test-cpu-profiler.cc
test/cctest/test-log.cc
test/cctest/test-profile-generator.cc
tools/codemap.js

index 938b632214e2134f33d69f76cb5365c6c7e27927..4982197cabaf418006431f15d107fa29e6af8f2a 100644 (file)
@@ -51,11 +51,6 @@ void CodeMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
 }
 
 
-void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) {
-  code_map->DeleteCode(start);
-}
-
-
 void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
   code_map->MoveCode(from, to);
 }
index bb480fc345bb0b5191620d0753c0431a035ca8d5..65490285e75fa87f01a337d43bcd4189059e3a40 100644 (file)
@@ -137,16 +137,6 @@ void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
 }
 
 
-void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
-  CodeEventsContainer evt_rec;
-  CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
-  rec->type = CodeEventRecord::CODE_DELETE;
-  rec->order = ++enqueue_order_;
-  rec->start = from;
-  events_buffer_.Enqueue(evt_rec);
-}
-
-
 void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
                                                           Address to) {
   CodeEventsContainer evt_rec;
@@ -425,7 +415,6 @@ void CpuProfiler::CodeMoveEvent(Address from, Address to) {
 
 
 void CpuProfiler::CodeDeleteEvent(Address from) {
-  Isolate::Current()->cpu_profiler()->processor_->CodeDeleteEvent(from);
 }
 
 
index 4175e8f6805fa2fd08d4382e8fc97940b435bb13..a71c0e0ab4e9e816b3c6abee99d05e7256c248aa 100644 (file)
@@ -48,7 +48,6 @@ class TokenEnumerator;
 #define CODE_EVENTS_TYPE_LIST(V)                                   \
   V(CODE_CREATION,    CodeCreateEventRecord)                       \
   V(CODE_MOVE,        CodeMoveEventRecord)                         \
-  V(CODE_DELETE,      CodeDeleteEventRecord)                       \
   V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)
 
 
@@ -87,14 +86,6 @@ class CodeMoveEventRecord : public CodeEventRecord {
 };
 
 
-class CodeDeleteEventRecord : public CodeEventRecord {
- public:
-  Address start;
-
-  INLINE(void UpdateCodeMap(CodeMap* code_map));
-};
-
-
 class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
  public:
   Address from;
index d21bf3f5be9dd3aa565e6d7fb2552943c146ab6b..3d66b5fb1010f23e66b231bbd14d520d49a30b78 100644 (file)
@@ -1527,6 +1527,51 @@ void Logger::LogCodeObjects() {
 }
 
 
+void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
+                                 Handle<Code> code) {
+  Handle<String> func_name(shared->DebugName());
+  if (shared->script()->IsScript()) {
+    Handle<Script> script(Script::cast(shared->script()));
+    if (script->name()->IsString()) {
+      Handle<String> script_name(String::cast(script->name()));
+      int line_num = GetScriptLineNumber(script, shared->start_position());
+      if (line_num > 0) {
+        PROFILE(ISOLATE,
+                CodeCreateEvent(
+                    Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+                    *code, *shared,
+                    *script_name, line_num + 1));
+      } else {
+        // Can't distinguish eval and script here, so always use Script.
+        PROFILE(ISOLATE,
+                CodeCreateEvent(
+                    Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+                    *code, *shared, *script_name));
+      }
+    } else {
+      PROFILE(ISOLATE,
+              CodeCreateEvent(
+                  Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+                  *code, *shared, *func_name));
+    }
+  } else if (shared->IsApiFunction()) {
+    // API function.
+    FunctionTemplateInfo* fun_data = shared->get_api_func_data();
+    Object* raw_call_data = fun_data->call_code();
+    if (!raw_call_data->IsUndefined()) {
+      CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
+      Object* callback_obj = call_data->callback();
+      Address entry_point = v8::ToCData<Address>(callback_obj);
+      PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
+    }
+  } else {
+    PROFILE(ISOLATE,
+            CodeCreateEvent(
+                Logger::LAZY_COMPILE_TAG, *code, *shared, *func_name));
+  }
+}
+
+
 void Logger::LogCompiledFunctions() {
   HandleScope scope;
   const int compiled_funcs_count = EnumerateCompiledFunctions(NULL, NULL);
@@ -1540,48 +1585,7 @@ void Logger::LogCompiledFunctions() {
     if (*code_objects[i] == Isolate::Current()->builtins()->builtin(
         Builtins::kLazyCompile))
       continue;
-    Handle<SharedFunctionInfo> shared = sfis[i];
-    Handle<String> func_name(shared->DebugName());
-    if (shared->script()->IsScript()) {
-      Handle<Script> script(Script::cast(shared->script()));
-      if (script->name()->IsString()) {
-        Handle<String> script_name(String::cast(script->name()));
-        int line_num = GetScriptLineNumber(script, shared->start_position());
-        if (line_num > 0) {
-          PROFILE(ISOLATE,
-                  CodeCreateEvent(
-                    Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
-                    *code_objects[i], *shared,
-                    *script_name, line_num + 1));
-        } else {
-          // Can't distinguish eval and script here, so always use Script.
-          PROFILE(ISOLATE,
-                  CodeCreateEvent(
-                      Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
-                      *code_objects[i], *shared, *script_name));
-        }
-      } else {
-        PROFILE(ISOLATE,
-                CodeCreateEvent(
-                    Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
-                    *code_objects[i], *shared, *func_name));
-      }
-    } else if (shared->IsApiFunction()) {
-      // API function.
-      FunctionTemplateInfo* fun_data = shared->get_api_func_data();
-      Object* raw_call_data = fun_data->call_code();
-      if (!raw_call_data->IsUndefined()) {
-        CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
-        Object* callback_obj = call_data->callback();
-        Address entry_point = v8::ToCData<Address>(callback_obj);
-        PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
-      }
-    } else {
-      PROFILE(ISOLATE,
-              CodeCreateEvent(
-                  Logger::LAZY_COMPILE_TAG, *code_objects[i],
-                  *shared, *func_name));
-    }
+    LogExistingFunction(sfis[i], code_objects[i]);
   }
 }
 
index 02250595f840015ef47afe5ae490d97a63730f85..fe19810a2cc550eee2dc4c7703c4e06391948725 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -281,6 +281,8 @@ class Logger {
   void ResumeProfiler();
   bool IsProfilerPaused();
 
+  void LogExistingFunction(Handle<SharedFunctionInfo> shared,
+                           Handle<Code> code);
   // Logs all compiled functions found in the heap.
   void LogCompiledFunctions();
   // Logs all accessor callbacks found in the heap.
index 8f4bc6c1f23f2c87255ed65eed5166326dec4b55..88d6e879410911c83f795e5c062a9c9f1c48a117 100644 (file)
@@ -78,22 +78,6 @@ ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry)
 }
 
 
-void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
-  CodeTree::Locator locator;
-  tree_.Insert(addr, &locator);
-  locator.set_value(CodeEntryInfo(entry, size));
-}
-
-
-void CodeMap::MoveCode(Address from, Address to) {
-  tree_.Move(from, to);
-}
-
-void CodeMap::DeleteCode(Address addr) {
-  tree_.Remove(addr);
-}
-
-
 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
   switch (tag) {
     case GC:
index 74dfbf445c219d9cc947aac77140b31cc49cc0c0..a7384a62aa5afa124df4c334ac0f6c1a581680a8 100644 (file)
@@ -492,6 +492,28 @@ const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue =
     CodeMap::CodeEntryInfo(NULL, 0);
 
 
+void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
+  DeleteAllCoveredCode(addr, addr + size);
+  CodeTree::Locator locator;
+  tree_.Insert(addr, &locator);
+  locator.set_value(CodeEntryInfo(entry, size));
+}
+
+
+void CodeMap::DeleteAllCoveredCode(Address start, Address end) {
+  List<Address> to_delete;
+  Address addr = end - 1;
+  while (addr >= start) {
+    CodeTree::Locator locator;
+    if (!tree_.FindGreatestLessThan(addr, &locator)) break;
+    Address start2 = locator.key(), end2 = start2 + locator.value().size;
+    if (start2 < end && start < end2) to_delete.Add(start2);
+    addr = start2 - 1;
+  }
+  for (int i = 0; i < to_delete.length(); ++i) tree_.Remove(to_delete[i]);
+}
+
+
 CodeEntry* CodeMap::FindEntry(Address addr) {
   CodeTree::Locator locator;
   if (tree_.FindGreatestLessThan(addr, &locator)) {
@@ -520,6 +542,16 @@ int CodeMap::GetSharedId(Address addr) {
 }
 
 
+void CodeMap::MoveCode(Address from, Address to) {
+  if (from == to) return;
+  CodeTree::Locator locator;
+  if (!tree_.Find(from, &locator)) return;
+  CodeEntryInfo entry = locator.value();
+  tree_.Remove(from);
+  AddCode(to, entry.entry, entry.size);
+}
+
+
 void CodeMap::CodeTreePrinter::Call(
     const Address& key, const CodeMap::CodeEntryInfo& value) {
   OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
index 6bada36d577f96ad9a1a261f245a5f642d57f7b7..f3737eafb9b09b558145009ee3e5e2bd6fd4bb37 100644 (file)
@@ -238,9 +238,8 @@ class CpuProfile {
 class CodeMap {
  public:
   CodeMap() : next_shared_id_(1) { }
-  INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
-  INLINE(void MoveCode(Address from, Address to));
-  INLINE(void DeleteCode(Address addr));
+  void AddCode(Address addr, CodeEntry* entry, unsigned size);
+  void MoveCode(Address from, Address to);
   CodeEntry* FindEntry(Address addr);
   int GetSharedId(Address addr);
 
@@ -270,6 +269,8 @@ class CodeMap {
     void Call(const Address& key, const CodeEntryInfo& value);
   };
 
+  void DeleteAllCoveredCode(Address start, Address end);
+
   // Fake CodeEntry pointer to distinguish shared function entries.
   static CodeEntry* const kSharedFunctionCodeEntry;
 
index b7db295c2e667756dfeaca9a1616992c321dd31e..b1010d3a6ae15b33d9ead4289220f4b17ca6a5e8 100644 (file)
@@ -2243,6 +2243,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
     // are guaranteed to be in old space.
     target->set_literals(*literals, SKIP_WRITE_BARRIER);
     target->set_next_function_link(isolate->heap()->undefined_value());
+
+    if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
+      isolate->logger()->LogExistingFunction(
+          shared, Handle<Code>(shared->code()));
+    }
   }
 
   target->set_context(*context);
index cd52da545a6d9ae24d69c61b52aa28349769cfbd..05643bfb8abb9afaf11be41ad0b2fd779e1f6012 100644 (file)
@@ -43,8 +43,7 @@ function LogProcessor() {
           processor: this.processCodeCreation },
       'code-move': { parsers: [parseInt, parseInt],
           processor: this.processCodeMove },
-      'code-delete': { parsers: [parseInt],
-          processor: this.processCodeDelete },
+      'code-delete': null,
       'sfi-move': { parsers: [parseInt, parseInt],
           processor: this.processFunctionMove },
       'shared-library': null,
@@ -73,10 +72,6 @@ LogProcessor.prototype.processCodeMove = function(from, to) {
   this.profile.moveCode(from, to);
 };
 
-LogProcessor.prototype.processCodeDelete = function(start) {
-  this.profile.deleteCode(start);
-};
-
 LogProcessor.prototype.processFunctionMove = function(from, to) {
   this.profile.moveFunc(from, to);
 };
@@ -132,8 +127,8 @@ function RunTest() {
      "Script", "String", "RegExp", "Date", "Error"];
 
   function entitiesEqual(entityA, entityB) {
-    if (entityA === null && entityB !== null) return true;
-    if (entityA !== null && entityB === null) return false;
+    if ((entityA === null && entityB !== null) ||
+      (entityA !== null && entityB === null)) return true;
     return entityA.size === entityB.size && entityNamesEqual(entityA, entityB);
   }
 
@@ -145,6 +140,8 @@ function RunTest() {
   // find the same entries. We skip builtins during log parsing, but compiled
   // functions traversal may erroneously recognize them as functions, so we are
   // expecting more functions in traversal vs. logging.
+  // Since we don't track code deletions, logging can also report more entries
+  // than traversal.
   while (l_pos < l_len && t_pos < t_len) {
     var entryA = logging_entries[l_pos];
     var entryB = traversal_entries[t_pos];
@@ -166,11 +163,6 @@ function RunTest() {
     if (!entities_equal) equal = false;
     comparison.push([entities_equal, address, entityA, entityB]);
   }
-  if (l_pos < l_len) equal = false;
-  while (l_pos < l_len) {
-    var entryA = logging_entries[l_pos++];
-    comparison.push([false, entryA[0], entryA[1], null]);
-  }
   return [equal, comparison];
 }
 
index 81c487da8a3db1feedafd0aa7da0a3debdbd95fc..f567a0f77097606e6057c0050ba362cae91146cf 100644 (file)
@@ -107,7 +107,7 @@ TEST(CodeEvents) {
                             0x80);
   processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
   processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
-  processor.CodeDeleteEvent(ToAddress(0x1600));
+  processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
   // Enqueue a tick event to enable code events processing.
   EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
 
index dfbc733e0df0623c40f3904fc04c50e596e7fe2d..72e663c4623012c21c1807369412eedf32c9c7a8 100644 (file)
@@ -25,6 +25,7 @@ using v8::internal::StrLength;
 
 namespace {
 
+
 class ScopedLoggerInitializer {
  public:
   explicit ScopedLoggerInitializer(bool prof_lazy)
@@ -470,8 +471,9 @@ TEST(IsLoggingPreserved) {
 
 typedef i::NativesCollection<i::TEST> TestSources;
 
-// Test that logging of code create / move / delete events
-// is equivalent to traversal of a resulting heap.
+
+// Test that logging of code create / move events is equivalent to traversal of
+// a resulting heap.
 TEST(EquivalenceOfLoggingAndTraversal) {
   // This test needs to be run on a "clean" V8 to ensure that snapshot log
   // is loaded. This is always true when running using tools/test.py because
index 4a29e59c56feba23c977e24f93167f919b10e045..76fd244e9716e40a69068a30abfbaa258cfc55d3 100644 (file)
@@ -549,13 +549,14 @@ TEST(CodeMapMoveAndDeleteCode) {
   code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
   CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
   CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
-  code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1800));
+  code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700));  // Deprecate bbb.
   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
-  CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
-  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
-  code_map.DeleteCode(ToAddress(0x1700));
+  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700)));
+  CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
+                   TokenEnumerator::kNoSecurityToken);
+  code_map.AddCode(ToAddress(0x1750), &entry3, 0x100);
   CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
-  CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
+  CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750)));
 }
 
 
index dec494a3b3526258c0ebe8231a91e321adbe3961..129179e84564b22d634ebb7dfebc947665dc1d8a 100644 (file)
@@ -79,6 +79,7 @@ CodeMap.PAGE_SIZE =
  * @param {CodeMap.CodeEntry} codeEntry Code entry object.
  */
 CodeMap.prototype.addCode = function(start, codeEntry) {
+  this.deleteAllCoveredNodes_(this.dynamics_, start, start + codeEntry.size);
   this.dynamics_.insert(start, codeEntry);
 };
 
@@ -92,6 +93,7 @@ CodeMap.prototype.addCode = function(start, codeEntry) {
  */
 CodeMap.prototype.moveCode = function(from, to) {
   var removedNode = this.dynamics_.remove(from);
+  this.deleteAllCoveredNodes_(this.dynamics_, to, to + removedNode.value.size);
   this.dynamics_.insert(to, removedNode.value);
 };
 
@@ -143,6 +145,23 @@ CodeMap.prototype.markPages_ = function(start, end) {
 };
 
 
+/**
+ * @private
+ */
+CodeMap.prototype.deleteAllCoveredNodes_ = function(tree, start, end) {
+  var to_delete = [];
+  var addr = end - 1;
+  while (addr >= start) {
+    var node = tree.findGreatestLessThan(addr);
+    if (!node) break;
+    var start2 = node.key, end2 = start2 + node.value.size;
+    if (start2 < end && start < end2) to_delete.push(start2);
+    addr = start2 - 1;
+  }
+  for (var i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
+};
+
+
 /**
  * @private
  */