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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/cctest/cctest.gyp ('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..070315578c716ca86cdae29051c4bc2504d036f5
--- /dev/null
+++ b/test/cctest/test-sampler-api.cc
@@ -0,0 +1,335 @@
+// 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 <string>
+#include "include/v8.h"
+#include "src/base/platform/platform.h"
+#include "src/sampler.h"
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+using v8::Local;
+
+namespace {
+static const int kMaxSampleDepth = 10;
+
+// The Sample which CollectSample fills up
+void* sample[kMaxSampleDepth];
+int sample_depth;
+
+// The isolate used in the test
+v8::Isolate* isolate;
+
+#if V8_OS_POSIX && !V8_OS_CYGWIN
+v8::RegisterState GetRegisterState(void* context);
+
+// Signaal handler signals on this semaphore once it finishes.
+v8::base::Semaphore* semaphore;
+
+static void HandleSigprof(int signal, siginfo_t* info, void* context) {
+ USE(info);
+ if (signal != SIGPROF) return;
+ fprintf(stderr, "inside the handler\n");
+ sample_depth = isolate->GetSample(GetRegisterState(context),
+ sample,
+ kMaxSampleDepth);
+ semaphore->Signal();
+}
+
+
+void InstallSignalHandler() {
+ struct sigaction sa;
+ sa.sa_sigaction = &HandleSigprof;
+ sigemptyset(&sa.sa_mask);
+#if V8_OS_QNX
+ sa.sa_flags = SA_SIGINFO;
+#else
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+#endif
+ sigaction(SIGPROF, &sa, 0);
+}
+
+
+// The JavaScript calls this function when on full stack depth.
+void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ semaphore = new v8::base::Semaphore(0);
+ InstallSignalHandler();
+ pthread_kill(pthread_self(), SIGPROF);
+ fprintf(stderr, "Sent the signal\n");
+ semaphore->Wait();
+ delete semaphore;
+ semaphore = NULL;
+}
+
+#elif V8_OS_WIN || V8_OS_CYGWIN
+v8::RegisterState GetRegisterState();
+
+// The JavaScript calls this function when on full stack depth.
+void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ sample_depth = isolate->GetSample(GetRegisterState(),
+ sample,
+ kMaxSampleDepth);
+}
+#endif // V8_OS_POSIX && !V8_OS_CYGWIN / V8_OS_WIN || V8_OS_CYGWIN
+
+// 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);"
+ "}";
+} // namespace
+
+
+#define SAMPLER_API_TESTS_BOOTSTRAP() \
+ isolate = CcTest::isolate(); \
+ sample_depth = 0; \
+ 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)
+
+
+TEST(StackDepthIsConsistent) {
+ SAMPLER_API_TESTS_BOOTSTRAP();
+
+ std::string source(test_function);
+ source.append("func(8);");
+ v8::Script::Compile(v8::String::NewFromUtf8(isolate, source.c_str()))->Run();
+
+ CHECK_EQ(8, sample_depth);
+}
+
+
+// TEST(StackDepthDoesNotExceedMaxValue) {
+// SAMPLER_API_TESTS_BOOTSTRAP();
+
+// std::string source(test_function);
+// source.append("func(300);");
+// v8::Script::Compile(v8::String::NewFromUtf8(isolate, source.c_str()))->Run();
+
+// CHECK_EQ(kMaxSampleDepth, sample_depth);
+// }
+
+
+// namespace {
+// std::vector<v8::JitCodeEvent> inner_funcs;
+// std::vector<v8::JitCodeEvent> outer_funcs;
+
+// void TestJitCodeEventHandler(const v8::JitCodeEvent* event) {
+// if (event->type != v8::JitCodeEvent::CODE_ADDED) return;
+// std::string name(event->name.str, event->name.len);
+// if (name.find("test_sampler_api_inner") != std::string::npos)
+// inner_funcs.push_back(*event);
+// if (name.find("test_sampler_api_outer") != std::string::npos)
+// outer_funcs.push_back(*event);
+// }
+
+
+// // Note: The arguments.callee stuff is there so that the
+// // functions are not optimized away.
+// static 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();";
+// } // namespace
+
+
+// // The captured sample should have three pc values.
+// // They should fall in the range where the compiled code
+// // The expected stack is:
+// // bottom of stack [{anon script}, outer, inner] top of stack
+// // ^ ^ ^
+// // sample.stack indices 2 1 0
+// TEST(StackFramesConsistent) {
+// SAMPLER_API_TESTS_BOOTSTRAP();
+
+// isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+// TestJitCodeEventHandler);
+// v8::Script::Compile(v8::String::NewFromUtf8(isolate, test_script))->Run();
+
+// CHECK_EQ(3, sample_depth);
+
+// bool stack_top_is_inner = false;
+// bool below_inner_is_outer = false;
+
+// for (unsigned i = 0; i < inner_funcs.size(); i++) {
+// void* start_addr = inner_funcs[i].code_start;
+// void* end_addr = reinterpret_cast<void*>(
+// (int64_t)inner_funcs[i].code_start + inner_funcs[i].code_len);
+// if ((sample[0] >= start_addr) && (sample[0] < end_addr))
+// stack_top_is_inner = true;
+// }
+
+// for (unsigned i = 0; i < outer_funcs.size(); i++) {
+// void* start_addr = outer_funcs[i].code_start;
+// void* end_addr = reinterpret_cast<void*>(
+// (int64_t)outer_funcs[i].code_start + outer_funcs[i].code_len);
+// if ((sample[1] >= start_addr) &&
+// (sample[1] < end_addr))
+// below_inner_is_outer = true;
+// }
+
+// CHECK(stack_top_is_inner);
+// CHECK(below_inner_is_outer);
+// }
+
+
+// Platform specific implementation of GetRegisterState
+namespace {
+#if V8_OS_POSIX && !V8_OS_CYGWIN
+v8::RegisterState GetRegisterState(void* context) {
+ v8::RegisterState state;
+ ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+#if !V8_OS_OPENBSD
+ mcontext_t& mcontext = ucontext->uc_mcontext;
+#endif
+#if V8_OS_LINUX
+#if V8_HOST_ARCH_IA32
+ state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]);
+ state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]);
+ state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]);
+#elif V8_HOST_ARCH_X64
+ state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
+ state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
+ state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
+#elif V8_HOST_ARCH_ARM
+#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
+ (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+ // Old GLibc ARM versions used a gregs[] array to access the register
+ // values from mcontext_t.
+ state.pc = reinterpret_cast<void*>(mcontext.gregs[R15]);
+ state.sp = reinterpret_cast<void*>(mcontext.gregs[R13]);
+ state.fp = reinterpret_cast<void*>(mcontext.gregs[R11]);
+#else
+ state.pc = reinterpret_cast<void*>(mcontext.arm_pc);
+ state.sp = reinterpret_cast<void*>(mcontext.arm_sp);
+ state.fp = reinterpret_cast<void*>(mcontext.arm_fp);
+#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
+ // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#elif V8_HOST_ARCH_ARM64
+ state.pc = reinterpret_cast<void*>(mcontext.pc);
+ state.sp = reinterpret_cast<void*>(mcontext.sp);
+ // FP is an alias for x29.
+ state.fp = reinterpret_cast<void*>(mcontext.regs[29]);
+#elif V8_HOST_ARCH_MIPS
+ state.pc = reinterpret_cast<void*>(mcontext.pc);
+ state.sp = reinterpret_cast<void*>(mcontext.gregs[29]);
+ state.fp = reinterpret_cast<void*>(mcontext.gregs[30]);
+#elif V8_HOST_ARCH_MIPS64
+ state.pc = reinterpret_cast<void*>(mcontext.pc);
+ state.sp = reinterpret_cast<void*>(mcontext.gregs[29]);
+ state.fp = reinterpret_cast<void*>(mcontext.gregs[30]);
+#endif // V8_HOST_ARCH_*
+#elif V8_OS_MACOSX
+#if V8_HOST_ARCH_X64
+#if __DARWIN_UNIX03
+ state.pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
+ state.sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
+ state.fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
+#else // !__DARWIN_UNIX03
+ state.pc = reinterpret_cast<void*>(mcontext->ss.rip);
+ state.sp = reinterpret_cast<void*>(mcontext->ss.rsp);
+ state.fp = reinterpret_cast<void*>(mcontext->ss.rbp);
+#endif // __DARWIN_UNIX03
+#elif V8_HOST_ARCH_IA32
+#if __DARWIN_UNIX03
+ state.pc = reinterpret_cast<void*>(mcontext->__ss.__eip);
+ state.sp = reinterpret_cast<void*>(mcontext->__ss.__esp);
+ state.fp = reinterpret_cast<void*>(mcontext->__ss.__ebp);
+#else // !__DARWIN_UNIX03
+ state.pc = reinterpret_cast<void*>(mcontext->ss.eip);
+ state.sp = reinterpret_cast<void*>(mcontext->ss.esp);
+ state.fp = reinterpret_cast<void*>(mcontext->ss.ebp);
+#endif // __DARWIN_UNIX03
+#endif // V8_HOST_ARCH_IA32
+#elif V8_OS_FREEBSD
+#if V8_HOST_ARCH_IA32
+ state.pc = reinterpret_cast<void*>(mcontext.mc_eip);
+ state.sp = reinterpret_cast<void*>(mcontext.mc_esp);
+ state.fp = reinterpret_cast<void*>(mcontext.mc_ebp);
+#elif V8_HOST_ARCH_X64
+ state.pc = reinterpret_cast<void*>(mcontext.mc_rip);
+ state.sp = reinterpret_cast<void*>(mcontext.mc_rsp);
+ state.fp = reinterpret_cast<void*>(mcontext.mc_rbp);
+#elif V8_HOST_ARCH_ARM
+ state.pc = reinterpret_cast<void*>(mcontext.mc_r15);
+ state.sp = reinterpret_cast<void*>(mcontext.mc_r13);
+ state.fp = reinterpret_cast<void*>(mcontext.mc_r11);
+#endif // V8_HOST_ARCH_*
+#elif V8_OS_NETBSD
+#if V8_HOST_ARCH_IA32
+ state.pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]);
+ state.sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]);
+ state.fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]);
+#elif V8_HOST_ARCH_X64
+ state.pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]);
+ state.sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]);
+ state.fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]);
+#endif // V8_HOST_ARCH_*
+#elif V8_OS_OPENBSD
+#if V8_HOST_ARCH_IA32
+ state.pc = reinterpret_cast<void*>(ucontext->sc_eip);
+ state.sp = reinterpret_cast<void*>(ucontext->sc_esp);
+ state.fp = reinterpret_cast<void*>(ucontext->sc_ebp);
+#elif V8_HOST_ARCH_X64
+ state.pc = reinterpret_cast<void*>(ucontext->sc_rip);
+ state.sp = reinterpret_cast<void*>(ucontext->sc_rsp);
+ state.fp = reinterpret_cast<void*>(ucontext->sc_rbp);
+#endif // V8_HOST_ARCH_*
+#elif V8_OS_SOLARIS
+ state.pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]);
+ state.sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]);
+ state.fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]);
+#elif V8_OS_QNX
+#if V8_HOST_ARCH_IA32
+ state.pc = reinterpret_cast<void*>(mcontext.cpu.eip);
+ state.sp = reinterpret_cast<void*>(mcontext.cpu.esp);
+ state.fp = reinterpret_cast<void*>(mcontext.cpu.ebp);
+#elif V8_HOST_ARCH_ARM
+ state.pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]);
+ state.sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]);
+ state.fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]);
+#endif // V8_HOST_ARCH_*
+#endif // V8_OS_QNX
+ return state;
+}
+
+#elif V8_OS_WIN || V8_OS_CYGWIN
+v8::RegisterState GetRegisterState() {
+ CONTEXT context;
+ v8::RegisterState state;
+ memset(&context, 0, sizeof(context));
+ context.ContextFlags = CONTEXT_FULL;
+ GetThreadContext(OpenThread(THREAD_GET_CONTEXT |
+ THREAD_SUSPEND_RESUME |
+ THREAD_QUERY_INFORMATION,
+ false,
+ GetCurrentThreadId()),
+ &context);
+#if V8_HOST_ARCH_X64
+ state.pc = reinterpret_cast<void*>(context.Rip);
+ state.sp = reinterpret_cast<void*>(context.Rsp);
+ state.fp = reinterpret_cast<void*>(context.Rbp);
+#else
+ state.pc = reinterpret_cast<void*>(context.Eip);
+ state.sp = reinterpret_cast<void*>(context.Esp);
+ state.fp = reinterpret_cast<void*>(context.Ebp);
+#endif
+ return state;
+}
+#endif // V8_OS_POSIX && !V8_OS_CYGWIN / V8_OS_WIN || V8_OS_CYGWIN
+} // namespace
« 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