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

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: Fix ARM32 build. 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
« no previous file with comments | « 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 "src/simulator.h"
11 #include "test/cctest/cctest.h"
12
13 namespace {
14
15 class Sample {
16 public:
17 enum { kFramesLimit = 255 };
18
19 Sample() {}
20
21 typedef const void* const* const_iterator;
22 const_iterator begin() const { return data_.start(); }
23 const_iterator end() const { return &data_[data_.length()]; }
24
25 int size() const { return data_.length(); }
26 v8::internal::Vector<void*>& data() { return data_; }
27
28 private:
29 v8::internal::EmbeddedVector<void*, kFramesLimit> data_;
30 };
31
32
33 #if defined(USE_SIMULATOR)
34 class SimulatorHelper {
35 public:
36 inline bool Init(v8::Isolate* isolate) {
37 simulator_ = reinterpret_cast<v8::internal::Isolate*>(isolate)
38 ->thread_local_top()
39 ->simulator_;
40 // Check if there is active simulator.
41 return simulator_ != NULL;
42 }
43
44 inline void FillRegisters(v8::RegisterState* state) {
45 #if V8_TARGET_ARCH_ARM
46 state->pc = reinterpret_cast<void*>(simulator_->get_pc());
47 state->sp = reinterpret_cast<void*>(
48 simulator_->get_register(v8::internal::Simulator::sp));
49 state->fp = reinterpret_cast<void*>(
50 simulator_->get_register(v8::internal::Simulator::r11));
51 #elif V8_TARGET_ARCH_ARM64
52 if (simulator_->sp() == 0 || simulator_->fp() == 0) {
53 // It's possible that the simulator is interrupted while it is updating
54 // the sp or fp register. ARM64 simulator does this in two steps:
55 // first setting it to zero and then setting it to a new value.
56 // Bailout if sp/fp doesn't contain the new value.
57 return;
58 }
59 state->pc = reinterpret_cast<void*>(simulator_->pc());
60 state->sp = reinterpret_cast<void*>(simulator_->sp());
61 state->fp = reinterpret_cast<void*>(simulator_->fp());
62 #elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
63 state->pc = reinterpret_cast<void*>(simulator_->get_pc());
64 state->sp = reinterpret_cast<void*>(
65 simulator_->get_register(v8::internal::Simulator::sp));
66 state->fp = reinterpret_cast<void*>(
67 simulator_->get_register(v8::internal::Simulator::fp));
68 #endif
69 }
70
71 private:
72 v8::internal::Simulator* simulator_;
73 };
74 #endif // USE_SIMULATOR
75
76
77 class SamplingTestHelper {
78 public:
79 struct CodeEventEntry {
80 std::string name;
81 const void* code_start;
82 size_t code_len;
83 };
84 typedef std::map<const void*, CodeEventEntry> CodeEntries;
85
86 explicit SamplingTestHelper(const std::string& test_function)
87 : sample_is_taken_(false), isolate_(CcTest::isolate()) {
88 DCHECK_EQ(NULL, instance_);
89 instance_ = this;
90 v8::HandleScope scope(isolate_);
91 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
92 global->Set(v8::String::NewFromUtf8(isolate_, "CollectSample"),
93 v8::FunctionTemplate::New(isolate_, CollectSample));
94 LocalContext env(isolate_, NULL, global);
95 isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
96 JitCodeEventHandler);
97 v8::Script::Compile(
98 v8::String::NewFromUtf8(isolate_, test_function.c_str()))->Run();
99 }
100
101 ~SamplingTestHelper() {
102 isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
103 instance_ = NULL;
104 }
105
106 Sample& sample() { return sample_; }
107
108 const CodeEventEntry* FindEventEntry(const void* address) {
109 CodeEntries::const_iterator it = code_entries_.upper_bound(address);
110 if (it == code_entries_.begin()) return NULL;
111 const CodeEventEntry& entry = (--it)->second;
112 const void* code_end =
113 static_cast<const uint8_t*>(entry.code_start) + entry.code_len;
114 return address < code_end ? &entry : NULL;
115 }
116
117 private:
118 static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
119 instance_->DoCollectSample();
120 }
121
122 static void JitCodeEventHandler(const v8::JitCodeEvent* event) {
123 instance_->DoJitCodeEventHandler(event);
124 }
125
126 // The JavaScript calls this function when on full stack depth.
127 void DoCollectSample() {
128 v8::RegisterState state;
129 #if defined(USE_SIMULATOR)
130 SimulatorHelper simulator_helper;
131 if (!simulator_helper.Init(isolate_)) return;
132 simulator_helper.FillRegisters(&state);
133 #else
134 state.pc = NULL;
135 state.fp = &state;
136 state.sp = &state;
137 #endif
138 v8::SampleInfo info;
139 isolate_->GetStackSample(state, sample_.data().start(),
140 static_cast<size_t>(sample_.size()), &info);
141 size_t frames_count = info.frames_count;
142 CHECK_LE(frames_count, static_cast<size_t>(sample_.size()));
143 sample_.data().Truncate(static_cast<int>(frames_count));
144 sample_is_taken_ = true;
145 }
146
147 void DoJitCodeEventHandler(const v8::JitCodeEvent* event) {
148 if (sample_is_taken_) return;
149 switch (event->type) {
150 case v8::JitCodeEvent::CODE_ADDED: {
151 CodeEventEntry entry;
152 entry.name = std::string(event->name.str, event->name.len);
153 entry.code_start = event->code_start;
154 entry.code_len = event->code_len;
155 code_entries_.insert(std::make_pair(entry.code_start, entry));
156 break;
157 }
158 case v8::JitCodeEvent::CODE_MOVED: {
159 CodeEntries::iterator it = code_entries_.find(event->code_start);
160 CHECK(it != code_entries_.end());
161 code_entries_.erase(it);
162 CodeEventEntry entry;
163 entry.name = std::string(event->name.str, event->name.len);
164 entry.code_start = event->new_code_start;
165 entry.code_len = event->code_len;
166 code_entries_.insert(std::make_pair(entry.code_start, entry));
167 break;
168 }
169 case v8::JitCodeEvent::CODE_REMOVED:
170 code_entries_.erase(event->code_start);
171 break;
172 default:
173 break;
174 }
175 }
176
177 Sample sample_;
178 bool sample_is_taken_;
179 v8::Isolate* isolate_;
180 CodeEntries code_entries_;
181
182 static SamplingTestHelper* instance_;
183 };
184
185 SamplingTestHelper* SamplingTestHelper::instance_;
186
187 } // namespace
188
189
190 // A JavaScript function which takes stack depth
191 // (minimum value 2) as an argument.
192 // When at the bottom of the recursion,
193 // the JavaScript code calls into C++ test code,
194 // waiting for the sampler to take a sample.
195 static const char* test_function =
196 "function func(depth) {"
197 " if (depth == 2) CollectSample();"
198 " else return func(depth - 1);"
199 "}";
200
201
202 TEST(StackDepthIsConsistent) {
203 SamplingTestHelper helper(std::string(test_function) + "func(8);");
204 CHECK_EQ(8, helper.sample().size());
205 }
206
207
208 TEST(StackDepthDoesNotExceedMaxValue) {
209 SamplingTestHelper helper(std::string(test_function) + "func(300);");
210 CHECK_EQ(Sample::kFramesLimit, helper.sample().size());
211 }
212
213
214 // The captured sample should have three pc values.
215 // They should fall in the range where the compiled code resides.
216 // The expected stack is:
217 // bottom of stack [{anon script}, outer, inner] top of stack
218 // ^ ^ ^
219 // sample.stack indices 2 1 0
220 TEST(StackFramesConsistent) {
221 // Note: The arguments.callee stuff is there so that the
222 // functions are not optimized away.
223 const char* test_script =
224 "function test_sampler_api_inner() {"
225 " CollectSample();"
226 " return arguments.callee.toString();"
227 "}"
228 "function test_sampler_api_outer() {"
229 " return test_sampler_api_inner() + arguments.callee.toString();"
230 "}"
231 "test_sampler_api_outer();";
232
233 SamplingTestHelper helper(test_script);
234 Sample& sample = helper.sample();
235 CHECK_EQ(3, sample.size());
236
237 const SamplingTestHelper::CodeEventEntry* entry;
238 entry = helper.FindEventEntry(sample.begin()[0]);
239 CHECK_NE(NULL, entry);
240 CHECK(std::string::npos != entry->name.find("test_sampler_api_inner"));
241
242 entry = helper.FindEventEntry(sample.begin()[1]);
243 CHECK_NE(NULL, entry);
244 CHECK(std::string::npos != entry->name.find("test_sampler_api_outer"));
245 }
OLDNEW
« 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