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

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: Enabled tests on MacOS and ARM 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
« include/v8.h ('K') | « 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..da601431f9a2418f70f2bbf2e57dd34f704b3e22
--- /dev/null
+++ b/test/cctest/test-sampler-api.cc
@@ -0,0 +1,194 @@
+// 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 "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_;
+};
+
+
+class 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)
+ : sample_is_taken_(false), isolate_(CcTest::isolate()) {
+ DCHECK_EQ(NULL, instance_);
+ instance_ = this;
+ 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_->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
+ instance_ = NULL;
+ }
+
+ Sample& sample() { return sample_; }
+
+ 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:
+ static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ instance_->DoCollectSample();
+ }
+
+ static void JitCodeEventHandler(const v8::JitCodeEvent* event) {
+ instance_->DoJitCodeEventHandler(event);
+ }
+
+ // The JavaScript calls this function when on full stack depth.
+ void DoCollectSample() {
+ 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));
+ sample_is_taken_ = true;
+ }
+
+ void DoJitCodeEventHandler(const v8::JitCodeEvent* event) {
+ if (sample_is_taken_) return;
+ switch (event->type) {
+ 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;
+ }
+ }
+
+ Sample sample_;
+ bool sample_is_taken_;
+ v8::Isolate* isolate_;
+ CodeEntries code_entries_;
+
+ static SamplingTestHelper* instance_;
+};
+
+SamplingTestHelper* SamplingTestHelper::instance_;
+
+} // 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.sample().size());
+}
+
+
+TEST(StackDepthDoesNotExceedMaxValue) {
+ SamplingTestHelper helper(std::string(test_function) + "func(300);");
+ CHECK_EQ(Sample::kFramesLimit, helper.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.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"));
+}
« include/v8.h ('K') | « test/cctest/test-api.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698