| 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 public sampling API in include/v8.h |
| 6 |
| 7 #include <string> |
| 8 |
| 9 #include "include/v8.h" |
| 10 #include "include/v8stdint.h" |
| 11 |
| 12 #include "src/v8.h" |
| 13 |
| 14 #include "src/base/platform/platform.h" |
| 15 |
| 16 #include "test/cctest/cctest.h" |
| 17 |
| 18 using v8::Local; |
| 19 |
| 20 namespace { |
| 21 // Sampler thread waits on this semaphore. |
| 22 v8::base::Semaphore* SamplerSemaphore = new v8::base::Semaphore(0); |
| 23 |
| 24 // V8 thread (the JavaScript code) waits on this semaphore. |
| 25 v8::base::Semaphore* V8Semaphore = new v8::base::Semaphore(0); |
| 26 |
| 27 // The JavaScript calls this function when on full stack depth. |
| 28 void SignalAndWaitForSampler( |
| 29 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 30 // Tell the sampler that it can take a sample now. |
| 31 SamplerSemaphore->Signal(); |
| 32 |
| 33 // Wait for the sampler to finish collecting a sample. |
| 34 V8Semaphore->Wait(); |
| 35 } |
| 36 } |
| 37 |
| 38 |
| 39 // A thread which collects samples from v8. |
| 40 class V8_FINAL SamplerThread : public v8::base::Thread { |
| 41 public: |
| 42 explicit SamplerThread(v8::Isolate* isolate) |
| 43 : Thread(v8::base::Thread::Options("sampler-api-tester")), |
| 44 isolate_(isolate) { |
| 45 } |
| 46 |
| 47 virtual ~SamplerThread() {} |
| 48 |
| 49 virtual void Run() { |
| 50 SamplerSemaphore->Wait(); // Wait for JS to reach full stack depth. |
| 51 isolate_->GetSample(&sample); |
| 52 V8Semaphore->Signal(); // Tell JS that sample collection is done. |
| 53 } |
| 54 |
| 55 v8::Sample sample; |
| 56 |
| 57 private: |
| 58 v8::Isolate* isolate_; |
| 59 }; |
| 60 |
| 61 |
| 62 // A JavaScript function which takes stack depth |
| 63 // (minimum value 2) as an argument. |
| 64 // When at the bottom of the recursion, |
| 65 // the JavaScript code calls into C++ test code, |
| 66 // waiting for the sampler to take a sample. |
| 67 static const char* sampler_api_test_function = "function func(depth) {" |
| 68 " if (depth == 2) SignalAndWaitForSampler();" |
| 69 " else return func(depth - 1);" |
| 70 "}"; |
| 71 |
| 72 |
| 73 // TODO(gholap): Right now, we are just checking whether GetSample |
| 74 // gets samples and whether the stack depth is reasonable. |
| 75 // After implementing code event listener API, add tests |
| 76 // to further verify the correctness of collected samples. |
| 77 TEST(StackDepthIsConsistent) { |
| 78 v8::Isolate* isolate = CcTest::isolate(); |
| 79 v8::HandleScope scope(isolate); |
| 80 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); |
| 81 global->Set( |
| 82 v8::String::NewFromUtf8(isolate, "SignalAndWaitForSampler"), |
| 83 v8::FunctionTemplate::New(isolate, SignalAndWaitForSampler)); |
| 84 |
| 85 LocalContext env(isolate, NULL, global); |
| 86 std::string source(sampler_api_test_function); |
| 87 source.append("func(8);"); |
| 88 Local<v8::Script> script = v8::Script::Compile( |
| 89 v8::String::NewFromUtf8(isolate, source.c_str())); |
| 90 SamplerThread sampler(isolate); |
| 91 |
| 92 sampler.Start(); |
| 93 script->Run(); |
| 94 sampler.Join(); |
| 95 |
| 96 CHECK_EQ(8, sampler.sample.frames_count); |
| 97 } |
| 98 |
| 99 |
| 100 TEST(StackDepthDoesNotExceedMaxValue) { |
| 101 v8::Isolate* isolate = CcTest::isolate(); |
| 102 v8::HandleScope scope(isolate); |
| 103 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); |
| 104 global->Set( |
| 105 v8::String::NewFromUtf8(isolate, "SignalAndWaitForSampler"), |
| 106 v8::FunctionTemplate::New(isolate, SignalAndWaitForSampler)); |
| 107 |
| 108 LocalContext env(isolate, NULL, global); |
| 109 std::string source(sampler_api_test_function); |
| 110 source.append("func(300);"); |
| 111 Local<v8::Script> script = v8::Script::Compile( |
| 112 v8::String::NewFromUtf8(isolate, source.c_str())); |
| 113 SamplerThread sampler(isolate); |
| 114 |
| 115 sampler.Start(); |
| 116 script->Run(); |
| 117 sampler.Join(); |
| 118 |
| 119 int MAX_FRAMES_COUNT = v8::Sample::kMaxFramesCount; |
| 120 CHECK_EQ(MAX_FRAMES_COUNT, sampler.sample.frames_count); |
| 121 } |
| 122 |
| 123 |
| 124 namespace { |
| 125 class TestCodeEventHandler : public v8::CodeEventHandler { |
| 126 public: |
| 127 virtual void Create(const void* from, |
| 128 const int size, |
| 129 const std::string& name) { |
| 130 if (name.find("outer") == 0) { |
| 131 outer_starts.push_back(from); |
| 132 outer_ends.push_back((const void*)((int64_t)from + size)); |
| 133 } else if (name.find("inner") == 0) { |
| 134 inner_starts.push_back(from); |
| 135 inner_ends.push_back((const void*)((int64_t)from + size)); |
| 136 } |
| 137 } |
| 138 |
| 139 virtual void Delete(const void* from) {} |
| 140 virtual void Move(const void* from, const void* to) {} |
| 141 virtual void SharedLibrary(const std::string& library_path, |
| 142 const void* start, |
| 143 const void* end) {} |
| 144 |
| 145 std::vector<const void*> outer_starts; |
| 146 std::vector<const void*> outer_ends; |
| 147 std::vector<const void*> inner_starts; |
| 148 std::vector<const void*> inner_ends; |
| 149 }; |
| 150 } |
| 151 |
| 152 |
| 153 // Note: The argumnets.callee stuff is there so that the |
| 154 // functions are not optimized away. |
| 155 static const char* sampler_api_test_script = |
| 156 "function inner() {" |
| 157 " SignalAndWaitForSampler();" |
| 158 " return arguments.callee.toString();" |
| 159 "}" |
| 160 "function outer() {return inner() + arguments.callee.toString()}" |
| 161 "outer();"; |
| 162 |
| 163 |
| 164 // The captured sample should have three pc values. |
| 165 // They should fall in the range where the compiled code |
| 166 // The expected stack is: |
| 167 // bottom of stack [{anon script}, outer, inner] top of stack |
| 168 // ^ ^ ^ |
| 169 // sample.stack indices 2 1 0 |
| 170 TEST(StackFramesConsistent) { |
| 171 v8::Isolate* isolate = CcTest::isolate(); |
| 172 TestCodeEventHandler code_event_handler; |
| 173 isolate->InstallCodeEventHandler(&code_event_handler); |
| 174 v8::HandleScope scope(isolate); |
| 175 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); |
| 176 global->Set( |
| 177 v8::String::NewFromUtf8(isolate, "SignalAndWaitForSampler"), |
| 178 v8::FunctionTemplate::New(isolate, SignalAndWaitForSampler)); |
| 179 |
| 180 LocalContext env(isolate, NULL, global); |
| 181 Local<v8::Script> script = v8::Script::Compile( |
| 182 v8::String::NewFromUtf8(isolate, sampler_api_test_script)); |
| 183 SamplerThread sampler(isolate); |
| 184 |
| 185 sampler.Start(); |
| 186 script->Run(); |
| 187 sampler.Join(); |
| 188 |
| 189 CHECK_EQ(3, sampler.sample.frames_count); |
| 190 |
| 191 bool stack_top_is_inner = false; |
| 192 bool below_inner_is_outer = false; |
| 193 |
| 194 for (unsigned i = 0; i < code_event_handler.inner_starts.size(); i++) { |
| 195 if ((sampler.sample.stack[0] >= code_event_handler.inner_starts[i]) && |
| 196 (sampler.sample.stack[0] < code_event_handler.inner_ends[i])) |
| 197 stack_top_is_inner = true; |
| 198 } |
| 199 |
| 200 for (unsigned i = 0; i < code_event_handler.outer_starts.size(); i++) { |
| 201 if ((sampler.sample.stack[1] >= code_event_handler.outer_starts[i]) && |
| 202 (sampler.sample.stack[1] < code_event_handler.outer_ends[i])) |
| 203 below_inner_is_outer = true; |
| 204 } |
| 205 |
| 206 CHECK_EQ(true, stack_top_is_inner); |
| 207 CHECK_EQ(true, below_inner_is_outer); |
| 208 } |
| OLD | NEW |