Adding support for reporting addresses of JIT compiled code to OProfile.
authormikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 5 Mar 2009 10:53:08 +0000 (10:53 +0000)
committermikhail.naganov@gmail.com <mikhail.naganov@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 5 Mar 2009 10:53:08 +0000 (10:53 +0000)
Please be warned that current gHardy versions have OProfile 0.9.3
which doesn't have JIT API. You need to install OProfile 0.9.4
with a 32-bit version of opagent library. Instructions are on the
internal Wiki page: http://wiki/Main/V8UsingOProfile

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

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

SConstruct
src/SConscript
src/compiler.cc
src/flag-definitions.h
src/log.cc
src/log.h
src/objects.h
src/oprofile-agent.cc [new file with mode: 0644]
src/oprofile-agent.h [new file with mode: 0644]
src/v8.cc

index 43293e6..d9dbda0 100644 (file)
@@ -68,6 +68,9 @@ LIBRARY_FLAGS = {
     'wordsize:64': {
       'CCFLAGS':      ['-m32'],
       'LINKFLAGS':    ['-m32']
+    },
+    'prof:oprofile': {
+      'CPPDEFINES':   ['ENABLE_OPROFILE_AGENT']
     }
   },
   'msvc': {
@@ -249,6 +252,10 @@ SAMPLE_FLAGS = {
     },
     'mode:debug': {
       'CCFLAGS':      ['-g', '-O0']
+    },
+    'prof:oprofile': {
+      'LIBPATH': ['/usr/lib32', '/usr/lib32/oprofile'],
+      'LIBS': ['opagent']
     }
   },
   'msvc': {
@@ -362,7 +369,7 @@ SIMPLE_OPTIONS = {
     'help': 'build using snapshots for faster start-up'
   },
   'prof': {
-    'values': ['on', 'off'],
+    'values': ['on', 'off', 'oprofile'],
     'default': 'off',
     'help': 'enable profiling of build target'
   },
@@ -435,6 +442,8 @@ def VerifyOptions(env):
     return False
   if env['os'] == 'win32' and env['library'] == 'shared' and env['prof'] == 'on':
     Abort("Profiling on windows only supported for static library.")
+  if env['prof'] == 'oprofile' and env['os'] != 'linux':
+    Abort("OProfile is only supported on Linux.")
   for (name, option) in SIMPLE_OPTIONS.iteritems():
     if (not option.get('default')) and (name not in ARGUMENTS):
       message = ("A value for option %s must be specified (%s)." %
index ef4d651..4a16b4b 100644 (file)
@@ -67,7 +67,7 @@ SOURCES = {
   ],
   'simulator:arm': ['simulator-arm.cc'],
   'os:freebsd': ['platform-freebsd.cc'],
-  'os:linux':   ['platform-linux.cc'],
+  'os:linux':   ['platform-linux.cc', 'oprofile-agent.cc'],
   'os:macos':   ['platform-macos.cc'],
   'os:nullos':  ['platform-nullos.cc'],
   'os:win32':   ['platform-win32.cc'],
index 89917d8..c82fa09 100644 (file)
@@ -35,6 +35,7 @@
 #include "scopes.h"
 #include "rewriter.h"
 #include "usage-analyzer.h"
+#include "oprofile-agent.h"
 
 namespace v8 { namespace internal {
 
@@ -123,16 +124,20 @@ static Handle<JSFunction> MakeFunction(bool is_global,
     return Handle<JSFunction>::null();
   }
 
-#ifdef ENABLE_LOGGING_AND_PROFILING
+#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
   // Log the code generation for the script. Check explicit whether logging is
   // to avoid allocating when not required.
-  if (Logger::is_enabled()) {
+  if (Logger::is_enabled() || OProfileAgent::is_enabled()) {
     if (script->name()->IsString()) {
       SmartPointer<char> data =
           String::cast(script->name())->ToCString(DISALLOW_NULLS);
       LOG(CodeCreateEvent(is_eval ? "Eval" : "Script", *code, *data));
+      OProfileAgent::CreateNativeCodeRegion(*data, code->address(),
+                                            code->ExecutableSize());
     } else {
       LOG(CodeCreateEvent(is_eval ? "Eval" : "Script", *code, ""));
+      OProfileAgent::CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
+          code->address(), code->ExecutableSize());
     }
   }
 #endif
@@ -306,11 +311,11 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
     return false;
   }
 
-#ifdef ENABLE_LOGGING_AND_PROFILING
+#if defined ENABLE_LOGGING_AND_PROFILING || defined ENABLE_OPROFILE_AGENT
   // Log the code generation. If source information is available include script
   // name and line number. Check explicit whether logging is enabled as finding
   // the line number is not for free.
-  if (Logger::is_enabled()) {
+  if (Logger::is_enabled() || OProfileAgent::is_enabled()) {
     if (script->name()->IsString()) {
       int line_num = script->GetLineNumber(start_position);
       if (line_num > 0) {
@@ -318,8 +323,14 @@ bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared,
       }
       LOG(CodeCreateEvent("LazyCompile", *code, *lit->name(),
                           String::cast(script->name()), line_num));
+      OProfileAgent::CreateNativeCodeRegion(*lit->name(),
+                                            String::cast(script->name()),
+                                            line_num, code->address(),
+                                            code->ExecutableSize());
     } else {
       LOG(CodeCreateEvent("LazyCompile", *code, *lit->name()));
+      OProfileAgent::CreateNativeCodeRegion(*lit->name(), code->address(),
+                                            code->ExecutableSize());
     }
   }
 #endif
index cc94afe..73593d8 100644 (file)
@@ -334,6 +334,8 @@ DEFINE_bool(log_regexp, false, "Log regular expression execution.")
 DEFINE_bool(sliding_state_window, false,
             "Update sliding state window counters.")
 DEFINE_string(logfile, "v8.log", "Specify the name of the log file.")
+DEFINE_bool(oprofile, false,
+            "Enable JIT agent for OProfile.")
 
 //
 // Disassembler only flags
index 21167dd..34631cd 100644 (file)
@@ -711,24 +711,13 @@ void Logger::DeleteEvent(const char* name, void* object) {
 }
 
 
-#ifdef ENABLE_LOGGING_AND_PROFILING
-int Logger::CodeObjectSize(Code* code) {
-  // Check that the assumptions about the layout of the code object holds.
-  ASSERT_EQ(reinterpret_cast<unsigned int>(code->instruction_start()) -
-            reinterpret_cast<unsigned int>(code->address()),
-            Code::kHeaderSize);
-  return code->instruction_size() + Code::kHeaderSize;
-}
-#endif
-
-
 void Logger::CodeCreateEvent(const char* tag, Code* code, const char* comment) {
 #ifdef ENABLE_LOGGING_AND_PROFILING
   if (logfile_ == NULL || !FLAG_log_code) return;
   LogMessageBuilder msg;
   msg.Append("code-creation,%s,0x%x,%d,\"", tag,
              reinterpret_cast<unsigned int>(code->address()),
-             CodeObjectSize(code));
+             code->ExecutableSize());
   for (const char* p = comment; *p != '\0'; p++) {
     if (*p == '"') {
       msg.Append('\\');
@@ -750,7 +739,7 @@ void Logger::CodeCreateEvent(const char* tag, Code* code, String* name) {
       name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
   msg.Append("code-creation,%s,0x%x,%d,\"%s\"\n", tag,
              reinterpret_cast<unsigned int>(code->address()),
-             CodeObjectSize(code), *str);
+             code->ExecutableSize(), *str);
   msg.WriteToLogFile();
 #endif
 }
@@ -767,7 +756,7 @@ void Logger::CodeCreateEvent(const char* tag, Code* code, String* name,
       source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
   msg.Append("code-creation,%s,0x%x,%d,\"%s %s:%d\"\n", tag,
              reinterpret_cast<unsigned int>(code->address()),
-             CodeObjectSize(code),
+             code->ExecutableSize(),
              *str, *sourcestr, line);
   msg.WriteToLogFile();
 #endif
@@ -780,7 +769,7 @@ void Logger::CodeCreateEvent(const char* tag, Code* code, int args_count) {
   LogMessageBuilder msg;
   msg.Append("code-creation,%s,0x%x,%d,\"args_count: %d\"\n", tag,
              reinterpret_cast<unsigned int>(code->address()),
-             CodeObjectSize(code),
+             code->ExecutableSize(),
              args_count);
   msg.WriteToLogFile();
 #endif
index 03009b4..4adec19 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -215,10 +215,6 @@ class Logger {
 
  private:
 
-  // Calculate the size of the code object to report for log events. This takes
-  // the layout of the code object into account.
-  static int CodeObjectSize(Code* code);
-
   // Emits the source code of a regexp. Used by regexp events.
   static void LogRegExpSource(Handle<JSRegExp> regexp);
 
@@ -268,6 +264,8 @@ class Logger {
   friend class Profiler;
   friend class SlidingStateWindow;
   friend class VMState;
+#else
+  static bool is_enabled() { return false; }
 #endif
 };
 
index b01f330..c7d4808 100644 (file)
@@ -2258,6 +2258,16 @@ class Code: public HeapObject {
     return RoundUp(kHeaderSize + body_size + sinfo_size, kCodeAlignment);
   }
 
+  // Calculate the size of the code object to report for log events. This takes
+  // the layout of the code object into account.
+  int ExecutableSize() {
+    // Check that the assumptions about the layout of the code object holds.
+    ASSERT_EQ(reinterpret_cast<unsigned int>(instruction_start()) -
+              reinterpret_cast<unsigned int>(address()),
+              Code::kHeaderSize);
+    return instruction_size() + Code::kHeaderSize;
+  }
+
   // Locating source position.
   int SourcePosition(Address pc);
   int SourceStatementPosition(Address pc);
diff --git a/src/oprofile-agent.cc b/src/oprofile-agent.cc
new file mode 100644 (file)
index 0000000..e9f7d3e
--- /dev/null
@@ -0,0 +1,111 @@
+// Copyright 2006-2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "oprofile-agent.h"
+
+namespace v8 { namespace internal {
+
+#ifdef ENABLE_OPROFILE_AGENT
+op_agent_t OProfileAgent::handle_ = NULL;
+#endif
+
+
+bool OProfileAgent::Initialize() {
+#ifdef ENABLE_OPROFILE_AGENT
+  if (FLAG_oprofile) {
+    if (handle_ != NULL) return false;
+
+    // Disable code moving by GC.
+    FLAG_always_compact = false;
+    FLAG_never_compact = true;
+
+    handle_ = op_open_agent();
+    return (handle_ != NULL);
+  } else {
+    return true;
+  }
+#else
+  return true;
+#endif
+}
+
+
+void OProfileAgent::TearDown() {
+#ifdef ENABLE_OPROFILE_AGENT
+  if (handle_ != NULL) {
+    op_close_agent(handle_);
+  }
+#endif
+}
+
+
+void OProfileAgent::CreateNativeCodeRegion(const char* name,
+    const void* ptr, unsigned int size) {
+#ifdef ENABLE_OPROFILE_AGENT
+  if (handle_ == NULL) return;
+  op_write_native_code(handle_, name, (uint64_t)ptr, ptr, size);
+#endif
+}
+
+
+void OProfileAgent::CreateNativeCodeRegion(String* name,
+    const void* ptr, unsigned int size) {
+#ifdef ENABLE_OPROFILE_AGENT
+  if (handle_ != NULL) {
+    const char* func_name;
+    SmartPointer<char> str =
+        name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+    func_name = name->length() > 0 ? *str : "<anonymous>";
+    CreateNativeCodeRegion(func_name, ptr, size);
+  }
+#endif
+}
+
+
+void OProfileAgent::CreateNativeCodeRegion(String* name, String* source,
+    int line_num, const void* ptr, unsigned int size) {
+#ifdef ENABLE_OPROFILE_AGENT
+  if (handle_ != NULL) {
+    Vector<char> buf = Vector<char>::New(OProfileAgent::kFormattingBufSize);
+    const char* func_name;
+    SmartPointer<char> str =
+        name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+    func_name = name->length() > 0 ? *str : "<anonymous>";
+    SmartPointer<char> source_str =
+        source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
+    if (v8::internal::OS::SNPrintF(buf, "%s %s:%d",
+                                   func_name, *source_str, line_num) != -1) {
+      CreateNativeCodeRegion(buf.start(), ptr, size);
+    } else {
+      CreateNativeCodeRegion("<script/func name too long>", ptr, size);
+    }
+  }
+#endif
+}
+} }
diff --git a/src/oprofile-agent.h b/src/oprofile-agent.h
new file mode 100644 (file)
index 0000000..75cfe18
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2006-2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_OPROFILE_AGENT_H_
+#define V8_OPROFILE_AGENT_H_
+
+#include <stdlib.h>
+
+#include "globals.h"
+
+#ifdef ENABLE_OPROFILE_AGENT
+// opagent.h uses uint64_t type, which can be missing in
+// system headers (they have __uint64_t), but is defined
+// in V8's headers.
+#include <opagent.h>  // NOLINT
+#endif
+
+namespace v8 { namespace internal {
+
+class OProfileAgent {
+ public:
+  static bool Initialize();
+  static void TearDown();
+  static void CreateNativeCodeRegion(const char* name,
+                                     const void* ptr, unsigned int size);
+  static void CreateNativeCodeRegion(String* name,
+                                     const void* ptr, unsigned int size);
+  static void CreateNativeCodeRegion(String* name, String* source, int line_num,
+                                     const void* ptr, unsigned int size);
+#ifdef ENABLE_OPROFILE_AGENT
+  static bool is_enabled() { return handle_ != NULL; }
+
+ private:
+  static op_agent_t handle_;
+
+  // Size of the buffer that is used for composing code areas names.
+  static const int kFormattingBufSize = 256;
+#else
+  static bool is_enabled() { return false; }
+#endif
+};
+} }
+
+#endif  // V8_OPROFILE_AGENT_H_
index cf78c0d..7eb39bc 100644 (file)
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -31,6 +31,7 @@
 #include "debug.h"
 #include "serialize.h"
 #include "stub-cache.h"
+#include "oprofile-agent.h"
 
 namespace v8 { namespace internal {
 
@@ -85,6 +86,8 @@ bool V8::Initialize(Deserializer *des) {
   // objects in place for creating the code object used for probing.
   CPU::Setup();
 
+  OProfileAgent::Initialize();
+
   return true;
 }
 
@@ -93,6 +96,8 @@ void V8::TearDown() {
   if (HasBeenDisposed()) return;
   if (!HasBeenSetup()) return;
 
+  OProfileAgent::TearDown();
+
   if (FLAG_preemption) {
     v8::Locker locker;
     v8::Locker::StopPreemption();