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

Side by Side 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, 2 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 unified diff | Download patch | Annotate | Revision Log
« include/v8.h ('K') | « test/cctest/test-api.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Tests the sampling API in include/v8.h
6
7 #include <map>
8 #include <string>
9 #include "include/v8.h"
10 #include "test/cctest/cctest.h"
11
12 namespace {
13
14 class Sample {
15 public:
16 enum { kFramesLimit = 255 };
17
18 Sample() {}
19
20 typedef const void* const* const_iterator;
21 const_iterator begin() const { return data_.start(); }
22 const_iterator end() const { return &data_[data_.length()]; }
23
24 int size() const { return data_.length(); }
25 v8::internal::Vector<void*>& data() { return data_; }
26
27 private:
28 v8::internal::EmbeddedVector<void*, kFramesLimit> data_;
29 };
30
31
32 class SamplingTestHelper {
33 public:
34 struct CodeEventEntry {
35 std::string name;
36 const void* code_start;
37 size_t code_len;
38 };
39 typedef std::map<const void*, CodeEventEntry> CodeEntries;
40
41 explicit SamplingTestHelper(const std::string& test_function)
42 : sample_is_taken_(false), isolate_(CcTest::isolate()) {
43 DCHECK_EQ(NULL, instance_);
44 instance_ = this;
45 v8::HandleScope scope(isolate_);
46 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
47 global->Set(v8::String::NewFromUtf8(isolate_, "CollectSample"),
48 v8::FunctionTemplate::New(isolate_, CollectSample));
49 LocalContext env(isolate_, NULL, global);
50 isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
51 JitCodeEventHandler);
52 v8::Script::Compile(
53 v8::String::NewFromUtf8(isolate_, test_function.c_str()))->Run();
54 }
55
56 ~SamplingTestHelper() {
57 isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
58 instance_ = NULL;
59 }
60
61 Sample& sample() { return sample_; }
62
63 const CodeEventEntry* FindEventEntry(const void* address) {
64 CodeEntries::const_iterator it = code_entries_.upper_bound(address);
65 if (it == code_entries_.begin()) return NULL;
66 const CodeEventEntry& entry = (--it)->second;
67 const void* code_end =
68 static_cast<const uint8_t*>(entry.code_start) + entry.code_len;
69 return address < code_end ? &entry : NULL;
70 }
71
72 private:
73 static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
74 instance_->DoCollectSample();
75 }
76
77 static void JitCodeEventHandler(const v8::JitCodeEvent* event) {
78 instance_->DoJitCodeEventHandler(event);
79 }
80
81 // The JavaScript calls this function when on full stack depth.
82 void DoCollectSample() {
83 v8::RegisterState state;
84 state.pc = NULL;
85 state.fp = &state;
86 state.sp = &state;
87 v8::SampleInfo info;
88 isolate_->GetStackSample(state, sample_.data().start(),
89 static_cast<size_t>(sample_.size()), &info);
90 size_t frames_count = info.frames_count;
91 CHECK_LE(frames_count, static_cast<size_t>(sample_.size()));
92 sample_.data().Truncate(static_cast<int>(frames_count));
93 sample_is_taken_ = true;
94 }
95
96 void DoJitCodeEventHandler(const v8::JitCodeEvent* event) {
97 if (sample_is_taken_) return;
98 switch (event->type) {
99 case v8::JitCodeEvent::CODE_ADDED: {
100 CodeEventEntry entry;
101 entry.name = std::string(event->name.str, event->name.len);
102 entry.code_start = event->code_start;
103 entry.code_len = event->code_len;
104 code_entries_.insert(std::make_pair(entry.code_start, entry));
105 break;
106 }
107 case v8::JitCodeEvent::CODE_MOVED: {
108 CodeEntries::const_iterator it = code_entries_.find(event->code_start);
109 CHECK(it != code_entries_.end());
110 code_entries_.erase(it);
111 CodeEventEntry entry;
112 entry.name = std::string(event->name.str, event->name.len);
113 entry.code_start = event->new_code_start;
114 entry.code_len = event->code_len;
115 code_entries_.insert(std::make_pair(entry.code_start, entry));
116 break;
117 }
118 case v8::JitCodeEvent::CODE_REMOVED:
119 code_entries_.erase(event->code_start);
120 break;
121 default:
122 break;
123 }
124 }
125
126 Sample sample_;
127 bool sample_is_taken_;
128 v8::Isolate* isolate_;
129 CodeEntries code_entries_;
130
131 static SamplingTestHelper* instance_;
132 };
133
134 SamplingTestHelper* SamplingTestHelper::instance_;
135
136 } // namespace
137
138
139 // A JavaScript function which takes stack depth
140 // (minimum value 2) as an argument.
141 // When at the bottom of the recursion,
142 // the JavaScript code calls into C++ test code,
143 // waiting for the sampler to take a sample.
144 static const char* test_function =
145 "function func(depth) {"
146 " if (depth == 2) CollectSample();"
147 " else return func(depth - 1);"
148 "}";
149
150
151 TEST(StackDepthIsConsistent) {
152 SamplingTestHelper helper(std::string(test_function) + "func(8);");
153 CHECK_EQ(8, helper.sample().size());
154 }
155
156
157 TEST(StackDepthDoesNotExceedMaxValue) {
158 SamplingTestHelper helper(std::string(test_function) + "func(300);");
159 CHECK_EQ(Sample::kFramesLimit, helper.sample().size());
160 }
161
162
163 // The captured sample should have three pc values.
164 // They should fall in the range where the compiled code resides.
165 // The expected stack is:
166 // bottom of stack [{anon script}, outer, inner] top of stack
167 // ^ ^ ^
168 // sample.stack indices 2 1 0
169 TEST(StackFramesConsistent) {
170 // Note: The arguments.callee stuff is there so that the
171 // functions are not optimized away.
172 const char* test_script =
173 "function test_sampler_api_inner() {"
174 " CollectSample();"
175 " return arguments.callee.toString();"
176 "}"
177 "function test_sampler_api_outer() {"
178 " return test_sampler_api_inner() + arguments.callee.toString();"
179 "}"
180 "test_sampler_api_outer();";
181
182 SamplingTestHelper helper(test_script);
183 Sample& sample = helper.sample();
184 CHECK_EQ(3, sample.size());
185
186 const SamplingTestHelper::CodeEventEntry* entry;
187 entry = helper.FindEventEntry(sample.begin()[0]);
188 CHECK_NE(NULL, entry);
189 CHECK(std::string::npos != entry->name.find("test_sampler_api_inner"));
190
191 entry = helper.FindEventEntry(sample.begin()[1]);
192 CHECK_NE(NULL, entry);
193 CHECK(std::string::npos != entry->name.find("test_sampler_api_outer"));
194 }
OLDNEW
« 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