Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4646)

Unified Diff: test/cctest/test-sampler-api.cc

Issue 596533002: Initial implementation of GetStackSample sampling profiler API. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressing yurys@ comments. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/cctest/test-api.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/test-sampler-api.cc
diff --git a/test/cctest/test-sampler-api.cc b/test/cctest/test-sampler-api.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f18b42a83bafeda964ec373fec492dab61e98666
--- /dev/null
+++ b/test/cctest/test-sampler-api.cc
@@ -0,0 +1,206 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Tests the sampling API in include/v8.h
+
+#include <map>
+#include <string>
+#include "include/v8.h"
+#include "src/simulator.h"
yurys 2014/09/24 13:44:07 Do we still need this include?
alph 2014/09/24 14:00:51 Done.
+#include "src/utils.h"
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+namespace {
+
+class Sample {
+ public:
+ enum { kFramesLimit = 255 };
+
+ Sample() {}
+
+ typedef const void* const* const_iterator;
+ const_iterator begin() const { return data_.start(); }
+ const_iterator end() const { return &data_[data_.length()]; }
+
+ int size() const { return data_.length(); }
+ v8::internal::Vector<void*>& data() { return data_; }
+
+ private:
+ v8::internal::EmbeddedVector<void*, kFramesLimit> data_;
+};
+
+
+template <class T>
+class Singleton {
+ public:
+ static T* instance() { return instance_; }
+
+ protected:
+ Singleton() {
+ DCHECK_EQ(NULL, instance_);
yurys 2014/09/24 13:44:07 I'd rather inline this check and singlton implemen
alph 2014/09/24 14:00:51 Done.
+ instance_ = static_cast<T*>(this);
+ }
+
+ ~Singleton() { instance_ = NULL; }
+
+ private:
+ static T* instance_;
+};
+
+template <class T>
+T* Singleton<T>::instance_;
+
+
+class SamplingTestHelper : public Singleton<SamplingTestHelper> {
+ public:
+ struct CodeEventEntry {
+ std::string name;
+ const void* code_start;
+ size_t code_len;
+ };
+ typedef std::map<const void*, CodeEventEntry> CodeEntries;
+
+ explicit SamplingTestHelper(const std::string& test_function) {
+ isolate = CcTest::isolate();
+ v8::HandleScope scope(isolate);
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
+ global->Set(v8::String::NewFromUtf8(isolate, "CollectSample"),
+ v8::FunctionTemplate::New(isolate, CollectSample));
+ LocalContext env(isolate, NULL, global);
+ isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+ JitCodeEventHandler);
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate, test_function.c_str()))
+ ->Run();
+ }
+
+ ~SamplingTestHelper() { isolate = NULL; }
+
+ Sample& get_sample() { return sample_; }
yurys 2014/09/24 13:44:07 style: no get_ prefix on simple getters.
alph 2014/09/24 14:00:51 Done.
+
+ static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ instance()->DoCollectSample();
+ }
+
+ // The JavaScript calls this function when on full stack depth.
+ void DoCollectSample() {
yurys 2014/09/24 13:44:07 This should be private
alph 2014/09/24 14:00:51 Done.
+ v8::RegisterState state;
+ state.pc = NULL;
+ state.fp = &state;
+ state.sp = &state;
+ v8::SampleInfo info;
+ isolate->GetStackSample(state, sample_.data().start(),
+ static_cast<size_t>(sample_.size()), &info);
+ size_t frames_count = info.frames_count;
+ CHECK_LE(frames_count, static_cast<size_t>(sample_.size()));
+ sample_.data().Truncate(static_cast<int>(frames_count));
+ }
+
+ static void JitCodeEventHandler(const v8::JitCodeEvent* event) {
+ return instance()->DoJitCodeEventHandler(event);
+ }
+
+ void DoJitCodeEventHandler(const v8::JitCodeEvent* event) {
+ switch (event->type) {
yurys 2014/09/24 13:44:07 We should ignore code events after the sample is t
alph 2014/09/24 14:00:51 Nice catch! Done.
+ case v8::JitCodeEvent::CODE_ADDED: {
+ CodeEventEntry entry;
+ entry.name = std::string(event->name.str, event->name.len);
+ entry.code_start = event->code_start;
+ entry.code_len = event->code_len;
+ code_entries.insert(std::make_pair(entry.code_start, entry));
+ break;
+ }
+ case v8::JitCodeEvent::CODE_MOVED: {
+ CodeEntries::const_iterator it = code_entries.find(event->code_start);
+ CHECK(it != code_entries.end());
+ code_entries.erase(it);
+ CodeEventEntry entry;
+ entry.name = std::string(event->name.str, event->name.len);
+ entry.code_start = event->new_code_start;
+ entry.code_len = event->code_len;
+ code_entries.insert(std::make_pair(entry.code_start, entry));
+ break;
+ }
+ case v8::JitCodeEvent::CODE_REMOVED:
+ code_entries.erase(event->code_start);
+ break;
+ default:
+ break;
+ }
+ }
+
+ const CodeEventEntry* FindEventEntry(const void* address) {
+ CodeEntries::const_iterator it = code_entries.upper_bound(address);
+ if (it == code_entries.begin()) return NULL;
+ const CodeEventEntry& entry = (--it)->second;
+ const void* code_end =
+ static_cast<const uint8_t*>(entry.code_start) + entry.code_len;
+ return address < code_end ? &entry : NULL;
+ }
+
+ private:
+ Sample sample_;
+ v8::Isolate* isolate;
+ CodeEntries code_entries;
+};
+
+} // namespace
+
+
+// A JavaScript function which takes stack depth
+// (minimum value 2) as an argument.
+// When at the bottom of the recursion,
+// the JavaScript code calls into C++ test code,
+// waiting for the sampler to take a sample.
+static const char* test_function =
+ "function func(depth) {"
+ " if (depth == 2) CollectSample();"
+ " else return func(depth - 1);"
+ "}";
+
+
+TEST(StackDepthIsConsistent) {
+ SamplingTestHelper helper(std::string(test_function) + "func(8);");
+ CHECK_EQ(8, helper.get_sample().size());
+}
+
+
+TEST(StackDepthDoesNotExceedMaxValue) {
+ SamplingTestHelper helper(std::string(test_function) + "func(300);");
+ CHECK_EQ(Sample::kFramesLimit, helper.get_sample().size());
+}
+
+
+// The captured sample should have three pc values.
+// They should fall in the range where the compiled code resides.
+// The expected stack is:
+// bottom of stack [{anon script}, outer, inner] top of stack
+// ^ ^ ^
+// sample.stack indices 2 1 0
+TEST(StackFramesConsistent) {
+ // Note: The arguments.callee stuff is there so that the
+ // functions are not optimized away.
+ const char* test_script =
+ "function test_sampler_api_inner() {"
+ " CollectSample();"
+ " return arguments.callee.toString();"
+ "}"
+ "function test_sampler_api_outer() {"
+ " return test_sampler_api_inner() + arguments.callee.toString();"
+ "}"
+ "test_sampler_api_outer();";
+
+ SamplingTestHelper helper(test_script);
+ Sample& sample = helper.get_sample();
+ CHECK_EQ(3, sample.size());
+
+ const SamplingTestHelper::CodeEventEntry* entry;
+ entry = helper.FindEventEntry(sample.begin()[0]);
+ CHECK_NE(NULL, entry);
+ CHECK(std::string::npos != entry->name.find("test_sampler_api_inner"));
+
+ entry = helper.FindEventEntry(sample.begin()[1]);
+ CHECK_NE(NULL, entry);
+ CHECK(std::string::npos != entry->name.find("test_sampler_api_outer"));
+}
« no previous file with comments | « test/cctest/test-api.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698