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

Side by Side Diff: test/cctest/test-sampler-api.cc

Issue 588623002: Implemented GetSample like POSIX backtrace() Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Printing return value of GetSample (for ARM try server) 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « test/cctest/cctest.gyp ('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 <string>
8 #include "include/v8.h"
9 #include "src/base/platform/platform.h"
10 #include "src/sampler.h"
11 #include "src/v8.h"
12 #include "test/cctest/cctest.h"
13
14 using v8::Local;
15
16 namespace {
17 static const int kMaxSampleDepth = 10;
18
19 // The Sample which CollectSample fills up
20 void* sample[kMaxSampleDepth];
21 int sample_depth;
22
23 // The isolate used in the test
24 v8::Isolate* isolate;
25
26 #if V8_OS_POSIX && !V8_OS_CYGWIN
27 v8::RegisterState GetRegisterState(void* context);
28
29 // Signaal handler signals on this semaphore once it finishes.
30 v8::base::Semaphore* semaphore;
31
32 static void HandleSigprof(int signal, siginfo_t* info, void* context) {
33 USE(info);
34 if (signal != SIGPROF) return;
35 fprintf(stderr, "inside the handler\n");
36 sample_depth = isolate->GetSample(GetRegisterState(context),
37 sample,
38 kMaxSampleDepth);
39 semaphore->Signal();
40 }
41
42
43 void InstallSignalHandler() {
44 struct sigaction sa;
45 sa.sa_sigaction = &HandleSigprof;
46 sigemptyset(&sa.sa_mask);
47 #if V8_OS_QNX
48 sa.sa_flags = SA_SIGINFO;
49 #else
50 sa.sa_flags = SA_RESTART | SA_SIGINFO;
51 #endif
52 sigaction(SIGPROF, &sa, 0);
53 }
54
55
56 // The JavaScript calls this function when on full stack depth.
57 void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
58 semaphore = new v8::base::Semaphore(0);
59 InstallSignalHandler();
60 pthread_kill(pthread_self(), SIGPROF);
61 fprintf(stderr, "Sent the signal\n");
62 semaphore->Wait();
63 delete semaphore;
64 semaphore = NULL;
65 }
66
67 #elif V8_OS_WIN || V8_OS_CYGWIN
68 v8::RegisterState GetRegisterState();
69
70 // The JavaScript calls this function when on full stack depth.
71 void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
72 sample_depth = isolate->GetSample(GetRegisterState(),
73 sample,
74 kMaxSampleDepth);
75 }
76 #endif // V8_OS_POSIX && !V8_OS_CYGWIN / V8_OS_WIN || V8_OS_CYGWIN
77
78 // A JavaScript function which takes stack depth
79 // (minimum value 2) as an argument.
80 // When at the bottom of the recursion,
81 // the JavaScript code calls into C++ test code,
82 // waiting for the sampler to take a sample.
83 static const char* test_function =
84 "function func(depth) {"
85 " if (depth == 2) CollectSample();"
86 " else return func(depth - 1);"
87 "}";
88 } // namespace
89
90
91 #define SAMPLER_API_TESTS_BOOTSTRAP() \
92 isolate = CcTest::isolate(); \
93 sample_depth = 0; \
94 v8::HandleScope scope(isolate); \
95 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); \
96 global->Set(v8::String::NewFromUtf8(isolate, "CollectSample"), \
97 v8::FunctionTemplate::New(isolate, CollectSample)); \
98 LocalContext env(isolate, NULL, global)
99
100
101 TEST(StackDepthIsConsistent) {
102 SAMPLER_API_TESTS_BOOTSTRAP();
103
104 std::string source(test_function);
105 source.append("func(8);");
106 v8::Script::Compile(v8::String::NewFromUtf8(isolate, source.c_str()))->Run();
107
108 CHECK_EQ(8, sample_depth);
109 }
110
111
112 // TEST(StackDepthDoesNotExceedMaxValue) {
113 // SAMPLER_API_TESTS_BOOTSTRAP();
114
115 // std::string source(test_function);
116 // source.append("func(300);");
117 // v8::Script::Compile(v8::String::NewFromUtf8(isolate, source.c_str()))->Run( );
118
119 // CHECK_EQ(kMaxSampleDepth, sample_depth);
120 // }
121
122
123 // namespace {
124 // std::vector<v8::JitCodeEvent> inner_funcs;
125 // std::vector<v8::JitCodeEvent> outer_funcs;
126
127 // void TestJitCodeEventHandler(const v8::JitCodeEvent* event) {
128 // if (event->type != v8::JitCodeEvent::CODE_ADDED) return;
129 // std::string name(event->name.str, event->name.len);
130 // if (name.find("test_sampler_api_inner") != std::string::npos)
131 // inner_funcs.push_back(*event);
132 // if (name.find("test_sampler_api_outer") != std::string::npos)
133 // outer_funcs.push_back(*event);
134 // }
135
136
137 // // Note: The arguments.callee stuff is there so that the
138 // // functions are not optimized away.
139 // static const char* test_script =
140 // "function test_sampler_api_inner() {"
141 // " CollectSample();"
142 // " return arguments.callee.toString();"
143 // "}"
144 // "function test_sampler_api_outer() {"
145 // " return test_sampler_api_inner() + arguments.callee.toString();"
146 // "}"
147 // "test_sampler_api_outer();";
148 // } // namespace
149
150
151 // // The captured sample should have three pc values.
152 // // They should fall in the range where the compiled code
153 // // The expected stack is:
154 // // bottom of stack [{anon script}, outer, inner] top of stack
155 // // ^ ^ ^
156 // // sample.stack indices 2 1 0
157 // TEST(StackFramesConsistent) {
158 // SAMPLER_API_TESTS_BOOTSTRAP();
159
160 // isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
161 // TestJitCodeEventHandler);
162 // v8::Script::Compile(v8::String::NewFromUtf8(isolate, test_script))->Run();
163
164 // CHECK_EQ(3, sample_depth);
165
166 // bool stack_top_is_inner = false;
167 // bool below_inner_is_outer = false;
168
169 // for (unsigned i = 0; i < inner_funcs.size(); i++) {
170 // void* start_addr = inner_funcs[i].code_start;
171 // void* end_addr = reinterpret_cast<void*>(
172 // (int64_t)inner_funcs[i].code_start + inner_funcs[i].code_len);
173 // if ((sample[0] >= start_addr) && (sample[0] < end_addr))
174 // stack_top_is_inner = true;
175 // }
176
177 // for (unsigned i = 0; i < outer_funcs.size(); i++) {
178 // void* start_addr = outer_funcs[i].code_start;
179 // void* end_addr = reinterpret_cast<void*>(
180 // (int64_t)outer_funcs[i].code_start + outer_funcs[i].code_len);
181 // if ((sample[1] >= start_addr) &&
182 // (sample[1] < end_addr))
183 // below_inner_is_outer = true;
184 // }
185
186 // CHECK(stack_top_is_inner);
187 // CHECK(below_inner_is_outer);
188 // }
189
190
191 // Platform specific implementation of GetRegisterState
192 namespace {
193 #if V8_OS_POSIX && !V8_OS_CYGWIN
194 v8::RegisterState GetRegisterState(void* context) {
195 v8::RegisterState state;
196 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
197 #if !V8_OS_OPENBSD
198 mcontext_t& mcontext = ucontext->uc_mcontext;
199 #endif
200 #if V8_OS_LINUX
201 #if V8_HOST_ARCH_IA32
202 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]);
203 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]);
204 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]);
205 #elif V8_HOST_ARCH_X64
206 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
207 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
208 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
209 #elif V8_HOST_ARCH_ARM
210 #if defined(__GLIBC__) && !defined(__UCLIBC__) && \
211 (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
212 // Old GLibc ARM versions used a gregs[] array to access the register
213 // values from mcontext_t.
214 state.pc = reinterpret_cast<void*>(mcontext.gregs[R15]);
215 state.sp = reinterpret_cast<void*>(mcontext.gregs[R13]);
216 state.fp = reinterpret_cast<void*>(mcontext.gregs[R11]);
217 #else
218 state.pc = reinterpret_cast<void*>(mcontext.arm_pc);
219 state.sp = reinterpret_cast<void*>(mcontext.arm_sp);
220 state.fp = reinterpret_cast<void*>(mcontext.arm_fp);
221 #endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
222 // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
223 #elif V8_HOST_ARCH_ARM64
224 state.pc = reinterpret_cast<void*>(mcontext.pc);
225 state.sp = reinterpret_cast<void*>(mcontext.sp);
226 // FP is an alias for x29.
227 state.fp = reinterpret_cast<void*>(mcontext.regs[29]);
228 #elif V8_HOST_ARCH_MIPS
229 state.pc = reinterpret_cast<void*>(mcontext.pc);
230 state.sp = reinterpret_cast<void*>(mcontext.gregs[29]);
231 state.fp = reinterpret_cast<void*>(mcontext.gregs[30]);
232 #elif V8_HOST_ARCH_MIPS64
233 state.pc = reinterpret_cast<void*>(mcontext.pc);
234 state.sp = reinterpret_cast<void*>(mcontext.gregs[29]);
235 state.fp = reinterpret_cast<void*>(mcontext.gregs[30]);
236 #endif // V8_HOST_ARCH_*
237 #elif V8_OS_MACOSX
238 #if V8_HOST_ARCH_X64
239 #if __DARWIN_UNIX03
240 state.pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
241 state.sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
242 state.fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
243 #else // !__DARWIN_UNIX03
244 state.pc = reinterpret_cast<void*>(mcontext->ss.rip);
245 state.sp = reinterpret_cast<void*>(mcontext->ss.rsp);
246 state.fp = reinterpret_cast<void*>(mcontext->ss.rbp);
247 #endif // __DARWIN_UNIX03
248 #elif V8_HOST_ARCH_IA32
249 #if __DARWIN_UNIX03
250 state.pc = reinterpret_cast<void*>(mcontext->__ss.__eip);
251 state.sp = reinterpret_cast<void*>(mcontext->__ss.__esp);
252 state.fp = reinterpret_cast<void*>(mcontext->__ss.__ebp);
253 #else // !__DARWIN_UNIX03
254 state.pc = reinterpret_cast<void*>(mcontext->ss.eip);
255 state.sp = reinterpret_cast<void*>(mcontext->ss.esp);
256 state.fp = reinterpret_cast<void*>(mcontext->ss.ebp);
257 #endif // __DARWIN_UNIX03
258 #endif // V8_HOST_ARCH_IA32
259 #elif V8_OS_FREEBSD
260 #if V8_HOST_ARCH_IA32
261 state.pc = reinterpret_cast<void*>(mcontext.mc_eip);
262 state.sp = reinterpret_cast<void*>(mcontext.mc_esp);
263 state.fp = reinterpret_cast<void*>(mcontext.mc_ebp);
264 #elif V8_HOST_ARCH_X64
265 state.pc = reinterpret_cast<void*>(mcontext.mc_rip);
266 state.sp = reinterpret_cast<void*>(mcontext.mc_rsp);
267 state.fp = reinterpret_cast<void*>(mcontext.mc_rbp);
268 #elif V8_HOST_ARCH_ARM
269 state.pc = reinterpret_cast<void*>(mcontext.mc_r15);
270 state.sp = reinterpret_cast<void*>(mcontext.mc_r13);
271 state.fp = reinterpret_cast<void*>(mcontext.mc_r11);
272 #endif // V8_HOST_ARCH_*
273 #elif V8_OS_NETBSD
274 #if V8_HOST_ARCH_IA32
275 state.pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]);
276 state.sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]);
277 state.fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]);
278 #elif V8_HOST_ARCH_X64
279 state.pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]);
280 state.sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]);
281 state.fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]);
282 #endif // V8_HOST_ARCH_*
283 #elif V8_OS_OPENBSD
284 #if V8_HOST_ARCH_IA32
285 state.pc = reinterpret_cast<void*>(ucontext->sc_eip);
286 state.sp = reinterpret_cast<void*>(ucontext->sc_esp);
287 state.fp = reinterpret_cast<void*>(ucontext->sc_ebp);
288 #elif V8_HOST_ARCH_X64
289 state.pc = reinterpret_cast<void*>(ucontext->sc_rip);
290 state.sp = reinterpret_cast<void*>(ucontext->sc_rsp);
291 state.fp = reinterpret_cast<void*>(ucontext->sc_rbp);
292 #endif // V8_HOST_ARCH_*
293 #elif V8_OS_SOLARIS
294 state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]);
295 state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]);
296 state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]);
297 #elif V8_OS_QNX
298 #if V8_HOST_ARCH_IA32
299 state.pc = reinterpret_cast<void*>(mcontext.cpu.eip);
300 state.sp = reinterpret_cast<void*>(mcontext.cpu.esp);
301 state.fp = reinterpret_cast<void*>(mcontext.cpu.ebp);
302 #elif V8_HOST_ARCH_ARM
303 state.pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]);
304 state.sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]);
305 state.fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]);
306 #endif // V8_HOST_ARCH_*
307 #endif // V8_OS_QNX
308 return state;
309 }
310
311 #elif V8_OS_WIN || V8_OS_CYGWIN
312 v8::RegisterState GetRegisterState() {
313 CONTEXT context;
314 v8::RegisterState state;
315 memset(&context, 0, sizeof(context));
316 context.ContextFlags = CONTEXT_FULL;
317 GetThreadContext(OpenThread(THREAD_GET_CONTEXT |
318 THREAD_SUSPEND_RESUME |
319 THREAD_QUERY_INFORMATION,
320 false,
321 GetCurrentThreadId()),
322 &context);
323 #if V8_HOST_ARCH_X64
324 state.pc = reinterpret_cast<void*>(context.Rip);
325 state.sp = reinterpret_cast<void*>(context.Rsp);
326 state.fp = reinterpret_cast<void*>(context.Rbp);
327 #else
328 state.pc = reinterpret_cast<void*>(context.Eip);
329 state.sp = reinterpret_cast<void*>(context.Esp);
330 state.fp = reinterpret_cast<void*>(context.Ebp);
331 #endif
332 return state;
333 }
334 #endif // V8_OS_POSIX && !V8_OS_CYGWIN / V8_OS_WIN || V8_OS_CYGWIN
335 } // namespace
OLDNEW
« no previous file with comments | « test/cctest/cctest.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698