Reviewers: yurys, loislo, Benedikt Meurer,

Message:
Folks, could you please take a look.

Description:
Add timestamps to CPU profile samples.

BUG=363976
LOG=Y

Please review this at https://codereview.chromium.org/259803002/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files (+74, -22 lines):
  M include/v8-profiler.h
  M src/api.cc
  M src/profile-generator.h
  M src/profile-generator.cc
  M src/sampler.h
  M src/sampler.cc
  M test/cctest/test-cpu-profiler.cc


Index: include/v8-profiler.h
diff --git a/include/v8-profiler.h b/include/v8-profiler.h
index 026715fda785463d8c743313576ac8bfcadce29d..483fd933f8c2150e1f6521eaca4f5b1979504001 100644
--- a/include/v8-profiler.h
+++ b/include/v8-profiler.h
@@ -106,28 +106,35 @@ class V8_EXPORT CpuProfile {
   const CpuProfileNode* GetTopDownRoot() const;

   /**
- * Returns number of samples recorded. The samples are not recorded unless
-    * |record_samples| parameter of CpuProfiler::StartCpuProfiling is true.
-    */
+ * Returns number of samples recorded. The samples are not recorded unless
+   * |record_samples| parameter of CpuProfiler::StartCpuProfiling is true.
+   */
   int GetSamplesCount() const;

   /**
-    * Returns profile node corresponding to the top frame the sample at
-    * the given index.
-    */
+   * Returns profile node corresponding to the top frame the sample at
+   * the given index.
+   */
   const CpuProfileNode* GetSample(int index) const;

   /**
-    * Returns time when the profile recording was started (in microseconds)
-    * since some unspecified starting point.
-    */
+   * Returns the timestamp of the sample. The timestamp is the number of
+   * microseconds since some unspecified starting point.
+   * The point is equal to the starting point used by GetStartTime.
+   */
+  int64_t GetSampleTimestamp(int index) const;
+
+  /**
+   * Returns time when the profile recording was started (in microseconds)
+   * since some unspecified starting point.
+   */
   int64_t GetStartTime() const;

   /**
-    * Returns time when the profile recording was stopped (in microseconds)
- * since some unspecified starting point. The point is however equal to the
-    * starting point used by GetStartTime.
-    */
+   * Returns time when the profile recording was stopped (in microseconds)
+   * since some unspecified starting point.
+   * The point is equal to the starting point used by GetStartTime.
+   */
   int64_t GetEndTime() const;

   /**
Index: src/api.cc
diff --git a/src/api.cc b/src/api.cc
index 705cae55b00b4afb3bec52ed087f8b2f493f9e32..3af59e9380dd9dbde927c9c0b5b7dd94a1598e71 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -7083,6 +7083,12 @@ const CpuProfileNode* CpuProfile::GetSample(int index) const {
 }


+int64_t CpuProfile::GetSampleTimestamp(int index) const {
+ const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this); + return (profile->sample_timestamp(index) - i::TimeTicks()).InMicroseconds();
+}
+
+
 int64_t CpuProfile::GetStartTime() const {
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
   return (profile->start_time() - i::TimeTicks()).InMicroseconds();
Index: src/profile-generator.cc
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index ae37648e5ea99cb1cf754cbafb56c5f020575ce1..2587317c8ae09639323e62995108a74e5d74875c 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -359,9 +359,12 @@ CpuProfile::CpuProfile(const char* title, bool record_samples)
 }


-void CpuProfile::AddPath(const Vector<CodeEntry*>& path) {
+void CpuProfile::AddPath(TimeTicks timestamp, const Vector<CodeEntry*>& path) {
   ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path);
-  if (record_samples_) samples_.Add(top_frame_node);
+  if (record_samples_) {
+    timestamps_.Add(timestamp);
+    samples_.Add(top_frame_node);
+  }
 }


@@ -545,13 +548,13 @@ void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {


 void CpuProfilesCollection::AddPathToCurrentProfiles(
-    const Vector<CodeEntry*>& path) {
+    TimeTicks timestamp, const Vector<CodeEntry*>& path) {
   // As starting / stopping profiles is rare relatively to this
   // method, we don't bother minimizing the duration of lock holding,
   // e.g. copying contents of the list to a local vector.
   current_profiles_semaphore_.Wait();
   for (int i = 0; i < current_profiles_.length(); ++i) {
-    current_profiles_[i]->AddPath(path);
+    current_profiles_[i]->AddPath(timestamp, path);
   }
   current_profiles_semaphore_.Signal();
 }
@@ -674,7 +677,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
     }
   }

-  profiles_->AddPathToCurrentProfiles(entries);
+  profiles_->AddPathToCurrentProfiles(sample.timestamp, entries);
 }


Index: src/profile-generator.h
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 1f23ee20ffe5bf8827bb28de6800568814a02b61..52636507038ab0a609f92d25e39a7b23fcb12f00 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -199,7 +199,7 @@ class CpuProfile {
   CpuProfile(const char* title, bool record_samples);

   // Add pc -> ... -> main() call path to the profile.
-  void AddPath(const Vector<CodeEntry*>& path);
+  void AddPath(TimeTicks timestamp, const Vector<CodeEntry*>& path);
   void CalculateTotalTicksAndSamplingRate();

   const char* title() const { return title_; }
@@ -207,6 +207,7 @@ class CpuProfile {

   int samples_count() const { return samples_.length(); }
   ProfileNode* sample(int index) const { return samples_.at(index); }
+ TimeTicks sample_timestamp(int index) const { return timestamps_.at(index); }

   TimeTicks start_time() const { return start_time_; }
   TimeTicks end_time() const { return end_time_; }
@@ -221,6 +222,7 @@ class CpuProfile {
   TimeTicks start_time_;
   TimeTicks end_time_;
   List<ProfileNode*> samples_;
+  List<TimeTicks> timestamps_;
   ProfileTree top_down_;

   DISALLOW_COPY_AND_ASSIGN(CpuProfile);
@@ -305,7 +307,8 @@ class CpuProfilesCollection {
       int column_number = v8::CpuProfileNode::kNoColumnNumberInfo);

   // Called from profile generator thread.
-  void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
+  void AddPathToCurrentProfiles(
+      TimeTicks timestamp, const Vector<CodeEntry*>& path);

   // Limits the number of profiles that can be simultaneously collected.
   static const int kMaxSimultaneousProfiles = 100;
Index: src/sampler.cc
diff --git a/src/sampler.cc b/src/sampler.cc
index c6830e69047612a5d7a3f73a255c9114cdce4df1..bb1935bddfd2436dd7e4e82965ed4d838136a05f 100644
--- a/src/sampler.cc
+++ b/src/sampler.cc
@@ -589,6 +589,7 @@ SamplerThread* SamplerThread::instance_ = NULL;
 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
                                    const RegisterState& regs) {
   ASSERT(isolate->IsInitialized());
+  timestamp = TimeTicks::HighResolutionNow();
   pc = regs.pc;
   state = isolate->current_vm_state();

Index: src/sampler.h
diff --git a/src/sampler.h b/src/sampler.h
index b17a2ed8d50e383c5a16da4c56f085464402a512..a051e257b65a432f06fdd9518c1f17bd28eb1b34 100644
--- a/src/sampler.h
+++ b/src/sampler.h
@@ -69,6 +69,7 @@ struct TickSample {
   };
   static const int kMaxFramesCount = 64;
   Address stack[kMaxFramesCount];  // Call stack.
+  TimeTicks timestamp;
   int frames_count : 8;  // Number of captured frames.
   bool has_external_callback : 1;
   StackFrame::Type top_frame_type : 4;
Index: test/cctest/test-cpu-profiler.cc
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc index d3fcf7d7edee3ea842834152a547c9618bdab92e..6cff7424b7bf7bb8fcd79e4400da66baec0861c7 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -401,12 +401,12 @@ TEST(ProfileStartEndTime) {
 static v8::CpuProfile* RunProfiler(
     v8::Handle<v8::Context> env, v8::Handle<v8::Function> function,
     v8::Handle<v8::Value> argv[], int argc,
-    unsigned min_js_samples) {
+    unsigned min_js_samples, bool collect_samples = false) {
   v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
   v8::Local<v8::String> profile_name =
       v8::String::NewFromUtf8(env->GetIsolate(), "my_profile");

-  cpu_profiler->StartProfiling(profile_name);
+  cpu_profiler->StartProfiling(profile_name, collect_samples);

   i::Sampler* sampler =
reinterpret_cast<i::Isolate*>(env->GetIsolate())->logger()->sampler();
@@ -587,6 +587,37 @@ TEST(CollectCpuProfile) {
 }


+TEST(CollectCpuProfileSamples) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
+ cpu_profiler_test_source))->Run();
+  v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "start")));
+
+  int32_t profiling_interval_ms = 200;
+  v8::Handle<v8::Value> args[] = {
+    v8::Integer::New(env->GetIsolate(), profiling_interval_ms)
+  };
+  v8::CpuProfile* profile =
+ RunProfiler(env.local(), function, args, ARRAY_SIZE(args), 200, true);
+
+  CHECK_LE(200, profile->GetSamplesCount());
+  uint64_t end_time = profile->GetEndTime();
+  uint64_t current_time = profile->GetStartTime();
+  CHECK_LE(current_time, end_time);
+  for (int i = 0; i < profile->GetSamplesCount(); i++) {
+    CHECK_NE(NULL, profile->GetSample(i));
+    uint64_t timestamp = profile->GetSampleTimestamp(i);
+    CHECK_LE(current_time, timestamp);
+    CHECK_LE(timestamp, end_time);
+    current_time = timestamp;
+  }
+
+  profile->Delete();
+}
+

 static const char* cpu_profiler_test_source2 = "function loop() {}\n"
 "function delay() { loop(); }\n"


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to