Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/v8.h" | |
| 10 #include "test/cctest/cctest.h" | |
| 11 | |
| 12 #if V8_OS_POSIX && !V8_OS_CYGWIN | |
| 13 #include <ucontext.h> | |
| 14 #elif V8_OS_WIN || V8_OS_CYGWIN | |
| 15 #include "src/base/win32-headers.h" | |
| 16 #endif | |
| 17 | |
| 18 using v8::Local; | |
| 19 | |
| 20 namespace { | |
| 21 // The Sample which CollectSample fills up | |
| 22 v8::Sample* sample; | |
| 23 | |
| 24 // The isolate used in the test | |
| 25 v8::Isolate* isolate; | |
| 26 | |
| 27 // Forward declaration | |
| 28 // (platform specific implementation at the bottom of this file) | |
| 29 v8::RegisterState GetRegisterState(); | |
| 30 | |
| 31 // The JavaScript calls this function when on full stack depth. | |
| 32 void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 33 isolate->GetSample(GetRegisterState(), sample); | |
| 34 } | |
| 35 | |
| 36 | |
| 37 // A JavaScript function which takes stack depth | |
| 38 // (minimum value 2) as an argument. | |
| 39 // When at the bottom of the recursion, | |
| 40 // the JavaScript code calls into C++ test code, | |
| 41 // waiting for the sampler to take a sample. | |
| 42 static const char* test_function = | |
| 43 "function func(depth) {" | |
| 44 " if (depth == 2) CollectSample();" | |
| 45 " else return func(depth - 1);" | |
| 46 "}"; | |
| 47 } | |
|
alph
2014/09/19 11:43:05
nit:
} // namespace
| |
| 48 | |
| 49 | |
| 50 #define SAMPLER_API_TESTS_BOOTSTRAP() \ | |
| 51 v8::Sample sample_; \ | |
| 52 sample = &sample_; \ | |
| 53 isolate = CcTest::isolate(); \ | |
| 54 v8::HandleScope scope(isolate); \ | |
| 55 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); \ | |
| 56 global->Set(v8::String::NewFromUtf8(isolate, "CollectSample"), \ | |
| 57 v8::FunctionTemplate::New(isolate, CollectSample)); \ | |
| 58 LocalContext env(isolate, NULL, global) | |
| 59 | |
| 60 | |
| 61 TEST(StackDepthIsConsistent) { | |
| 62 SAMPLER_API_TESTS_BOOTSTRAP(); | |
| 63 | |
| 64 std::string source(test_function); | |
| 65 source.append("func(8);"); | |
| 66 v8::Script::Compile(v8::String::NewFromUtf8(isolate, source.c_str()))->Run(); | |
| 67 | |
| 68 CHECK_EQ(8, sample->size()); | |
| 69 } | |
| 70 | |
| 71 | |
| 72 TEST(StackDepthDoesNotExceedMaxValue) { | |
| 73 SAMPLER_API_TESTS_BOOTSTRAP(); | |
| 74 | |
| 75 std::string source(test_function); | |
| 76 source.append("func(300);"); | |
| 77 v8::Script::Compile(v8::String::NewFromUtf8(isolate, source.c_str()))->Run(); | |
| 78 | |
| 79 int MAX_SIZE = v8::Sample::kMaxSize; | |
| 80 CHECK_EQ(MAX_SIZE, sample->size()); | |
| 81 } | |
| 82 | |
| 83 | |
| 84 namespace { | |
| 85 std::vector<v8::JitCodeEvent> inner_funcs; | |
| 86 std::vector<v8::JitCodeEvent> outer_funcs; | |
| 87 | |
| 88 void TestJitCodeEventHandler(const v8::JitCodeEvent* event) { | |
| 89 if (event->type != v8::JitCodeEvent::CODE_ADDED) return; | |
| 90 std::string name(event->name.str, event->name.len); | |
| 91 if (name.find("test_sampler_api_inner") != std::string::npos) | |
| 92 inner_funcs.push_back(*event); | |
| 93 if (name.find("test_sampler_api_outer") != std::string::npos) | |
| 94 outer_funcs.push_back(*event); | |
| 95 } | |
| 96 | |
| 97 | |
| 98 // Note: The arguments.callee stuff is there so that the | |
| 99 // functions are not optimized away. | |
| 100 static const char* test_script = | |
| 101 "function test_sampler_api_inner() {" | |
| 102 " CollectSample();" | |
| 103 " return arguments.callee.toString();" | |
| 104 "}" | |
| 105 "function test_sampler_api_outer() {" | |
| 106 " return test_sampler_api_inner() + arguments.callee.toString();" | |
| 107 "}" | |
| 108 "test_sampler_api_outer();"; | |
| 109 } | |
|
alph
2014/09/19 11:43:05
ditto
| |
| 110 | |
| 111 | |
| 112 // The captured sample should have three pc values. | |
| 113 // They should fall in the range where the compiled code | |
| 114 // The expected stack is: | |
| 115 // bottom of stack [{anon script}, outer, inner] top of stack | |
| 116 // ^ ^ ^ | |
| 117 // sample.stack indices 2 1 0 | |
| 118 TEST(StackFramesConsistent) { | |
| 119 SAMPLER_API_TESTS_BOOTSTRAP(); | |
| 120 | |
| 121 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, | |
| 122 TestJitCodeEventHandler); | |
| 123 v8::Script::Compile(v8::String::NewFromUtf8(isolate, test_script))->Run(); | |
| 124 | |
| 125 CHECK_EQ(3, sample->size()); | |
| 126 | |
| 127 bool stack_top_is_inner = false; | |
| 128 bool below_inner_is_outer = false; | |
| 129 | |
| 130 for (unsigned i = 0; i < inner_funcs.size(); i++) { | |
| 131 void* start_addr = inner_funcs[i].code_start; | |
| 132 void* end_addr = reinterpret_cast<void*>( | |
| 133 (int64_t)inner_funcs[i].code_start + inner_funcs[i].code_len); | |
| 134 if ((*sample->begin() >= start_addr) && (*sample->begin() < end_addr)) | |
| 135 stack_top_is_inner = true; | |
| 136 } | |
| 137 | |
| 138 for (unsigned i = 0; i < outer_funcs.size(); i++) { | |
| 139 void* start_addr = outer_funcs[i].code_start; | |
| 140 void* end_addr = reinterpret_cast<void*>( | |
| 141 (int64_t)outer_funcs[i].code_start + outer_funcs[i].code_len); | |
| 142 if ((*(sample->begin() + 1) >= start_addr) && | |
| 143 (*(sample->begin() + 1) < end_addr)) | |
| 144 below_inner_is_outer = true; | |
| 145 } | |
| 146 | |
| 147 CHECK(stack_top_is_inner); | |
| 148 CHECK(below_inner_is_outer); | |
| 149 } | |
| 150 | |
| 151 | |
| 152 // Platform specific implementation of GetStackAndFramePointers | |
| 153 namespace { | |
| 154 v8::RegisterState GetRegisterState() { | |
| 155 #if V8_OS_POSIX && !V8_OS_CYGWIN | |
| 156 ucontext_t context; | |
| 157 getcontext(&context); | |
| 158 #elif V8_OS_WIN || V8_OS_CYGWIN | |
| 159 CONTEXT context; | |
| 160 memset(&context, 0, sizeof(context)); | |
| 161 context.ContextFlags = CONTEXT_FULL; | |
| 162 GetThreadContext(OpenThread(THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | | |
| 163 THREAD_QUERY_INFORMATION, | |
| 164 false, GetCurrentThreadId()), | |
| 165 &context); | |
| 166 #endif // V8_OS_POSIX && !V8_OS_CYGWIN / V8_OS_WIN || V8_OS_CYGWIN | |
| 167 return v8::RegisterState(context); | |
| 168 } | |
| 169 } | |
|
alph
2014/09/19 11:43:05
ditto
| |
| OLD | NEW |