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

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

Issue 422593003: Initial GetSample implementation. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Moved thread logic out of GetSample 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
« src/sampler.cc ('K') | « test/cctest/test-log-stack-tracer.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 public 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/v8.h"
11 #include "test/cctest/cctest.h"
12
13 #if V8_OS_POSIX && !V8_OS_CYGWIN
14 #include <pthread.h>
15 #include <signal.h>
16 #elif V8_OS_WIN || V8_OS_CYGWIN
17 #include "src/base/win32-headers.h"
18 #endif
19
20 using v8::Local;
21
22 namespace {
23 // Sampler thread waits on this semaphore.
24 v8::base::Semaphore* sampler_semaphore = new v8::base::Semaphore(0);
25
26 // V8 thread (the JavaScript code) waits on this semaphore.
27 v8::base::Semaphore* v8_semaphore = new v8::base::Semaphore(0);
28
29 // The JavaScript calls this function when on full stack depth.
30 void SignalAndWaitForSampler(
31 const v8::FunctionCallbackInfo<v8::Value>& args) {
32 // Tell the sampler that it can take a sample now.
33 sampler_semaphore->Signal();
34
35 // Wait for the sampler to finish collecting a sample.
36 v8_semaphore->Wait();
37 }
38
39 // A thread which collects samples from v8.
40 class 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 #if V8_OS_POSIX && !V8_OS_CYGWIN
46 sampled_thread_id_ = pthread_self();
47 #elif V8_OS_WIN || V8_OS_CYGWIN
48 HANDLE sampled_thread_ = OpenThread(THREAD_GET_CONTEXT |
49 THREAD_SUSPEND_RESUME |
50 THREAD_QUERY_INFORMATION,
51 false,
52 GetCurrentThreadId());
53 #endif
54 }
55
56 virtual ~SamplerThread() {}
57
58 virtual void Run() {
59 sampler_semaphore->Wait(); // Wait for JS to reach full stack depth.
60
61 #if V8_OS_POSIX && !V8_OS_CYGWIN
62
63 pthread_kill(sampled_thread_id_, SIGPROF);
64 isolate_->GetSample(&sample);
65
66 #elif V8_OS_WIN || V8_OS_CYGWIN
67
68 SuspendThread(sampled_thread_);
69 CONTEXT context;
70 memset(&context, 0, sizeof(context));
71 context.ContextFlags = CONTEXT_FULL;
72 GetThreadContext(sampled_thread_, &context);
73 isolate_->GetSample(context, &sample);
74 ResumeThread(sampled_thread_);
75
76 #endif
77
78 v8_semaphore->Signal(); // Tell JS that sample collection is done.
79 }
80
81 v8::Sample sample;
82
83 private:
84 v8::Isolate* isolate_;
85 #if V8_OS_POSIX && !V8_OS_CYGWIN
86 pthread_t sampled_thread_id_;
87 #elif V8_OS_WIN || V8_OS_CYGWIN
88 HANDLE sampled_thread_;
89 #endif
90 };
91 }
92
93
94 #define SAMPLER_API_TESTS_BOOTSTRAP() \
95 v8::internal::FLAG_new_sampler_api = true; \
96 v8::Isolate* isolate = CcTest::isolate(); \
97 v8::HandleScope scope(isolate); \
98 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate); \
99 global->Set(v8::String::NewFromUtf8(isolate, "SignalAndWaitForSampler"), \
100 v8::FunctionTemplate::New(isolate, SignalAndWaitForSampler)); \
101 LocalContext env(isolate, NULL, global); \
102 SamplerThread sampler(isolate)
103
104 #define SAMPLER_API_TESTS_COLLECT_SAMPLE() \
105 sampler.Start(); \
106 script->Run(); \
107 sampler.Join()
108
109 // A JavaScript function which takes stack depth
110 // (minimum value 2) as an argument.
111 // When at the bottom of the recursion,
112 // the JavaScript code calls into C++ test code,
113 // waiting for the sampler to take a sample.
114 static const char* sampler_api_test_function = "function func(depth) {"
115 " if (depth == 2) SignalAndWaitForSampler();"
116 " else return func(depth - 1);"
117 "}";
118
119
120 TEST(StackDepthIsConsistent) {
121 SAMPLER_API_TESTS_BOOTSTRAP();
122
123 std::string source(sampler_api_test_function);
124 source.append("func(8);");
125 Local<v8::Script> script = v8::Script::Compile(
126 v8::String::NewFromUtf8(isolate, source.c_str()));
127
128 SAMPLER_API_TESTS_COLLECT_SAMPLE();
129
130 CHECK_EQ(8, sampler.sample.size());
131 }
132
133
134 TEST(StackDepthDoesNotExceedMaxValue) {
135 SAMPLER_API_TESTS_BOOTSTRAP();
136
137 std::string source(sampler_api_test_function);
138 source.append("func(300);");
139 Local<v8::Script> script = v8::Script::Compile(
140 v8::String::NewFromUtf8(isolate, source.c_str()));
141
142 SAMPLER_API_TESTS_COLLECT_SAMPLE();
143
144 int MAX_SIZE = v8::Sample::kMaxSize;
145 CHECK_EQ(MAX_SIZE, sampler.sample.size());
146 }
147
148
149 namespace {
150 std::vector<v8::JitCodeEvent> inner_funcs;
151 std::vector<v8::JitCodeEvent> outer_funcs;
152
153 void TestJitCodeEventHandler(const v8::JitCodeEvent* event) {
154 if (event->type != v8::JitCodeEvent::CODE_ADDED) return;
155 std::string name(event->name.str, event->name.len);
156 if (name.find("test_sampler_api_inner") != std::string::npos)
157 inner_funcs.push_back(*event);
158 if (name.find("test_sampler_api_outer") != std::string::npos)
159 outer_funcs.push_back(*event);
160 }
161 }
162
163
164 // Note: The argumnets.callee stuff is there so that the
165 // functions are not optimized away.
166 static const char* sampler_api_test_script =
167 "function test_sampler_api_inner() {"
168 " SignalAndWaitForSampler();"
169 " return arguments.callee.toString();"
170 "}"
171 "function test_sampler_api_outer() {"
172 " return test_sampler_api_inner() + arguments.callee.toString();"
173 "}"
174 "test_sampler_api_outer();";
175
176
177 // The captured sample should have three pc values.
178 // They should fall in the range where the compiled code
179 // The expected stack is:
180 // bottom of stack [{anon script}, outer, inner] top of stack
181 // ^ ^ ^
182 // sample.stack indices 2 1 0
183 TEST(StackFramesConsistent) {
184 SAMPLER_API_TESTS_BOOTSTRAP();
185
186 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault,
187 TestJitCodeEventHandler);
188 Local<v8::Script> script = v8::Script::Compile(
189 v8::String::NewFromUtf8(isolate, sampler_api_test_script));
190
191 SAMPLER_API_TESTS_COLLECT_SAMPLE();
192
193 CHECK_EQ(3, sampler.sample.size());
194
195 bool stack_top_is_inner = false;
196 bool below_inner_is_outer = false;
197
198 for (unsigned i = 0; i < inner_funcs.size(); i++) {
199 void* start_addr = inner_funcs[i].code_start;
200 void* end_addr = reinterpret_cast<void*>((int64_t)inner_funcs[i].code_start
201 + inner_funcs[i].code_len);
202 if ((*sampler.sample.begin() >= start_addr) &&
203 (*sampler.sample.begin() < end_addr))
204 stack_top_is_inner = true;
205 }
206
207 for (unsigned i = 0; i < outer_funcs.size(); i++) {
208 void* start_addr = outer_funcs[i].code_start;
209 void* end_addr = reinterpret_cast<void*>((int64_t)outer_funcs[i].code_start
210 + outer_funcs[i].code_len);
211 if ((*(sampler.sample.begin() + 1) >= start_addr) &&
212 (*(sampler.sample.begin() + 1) < end_addr))
213 below_inner_is_outer = true;
214 }
215
216 CHECK_EQ(true, stack_top_is_inner);
217 CHECK_EQ(true, below_inner_is_outer);
218 }
OLDNEW
« src/sampler.cc ('K') | « test/cctest/test-log-stack-tracer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698