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

Side by Side Diff: test/cctest/test-log-ia32.cc

Issue 160446: X64: enable stack sampling in profiler. (Closed)
Patch Set: Created 11 years, 4 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
OLDNEW
(Empty)
1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 //
3 // Tests of profiler-related functions from log.h
4
5 #ifdef ENABLE_LOGGING_AND_PROFILING
6
7 #include <stdlib.h>
8
9 #include "v8.h"
10
11 #include "codegen.h"
12 #include "log.h"
13 #include "top.h"
14 #include "cctest.h"
15 #include "disassembler.h"
16 #include "register-allocator-inl.h"
17
18 using v8::Function;
19 using v8::Local;
20 using v8::Object;
21 using v8::Script;
22 using v8::String;
23 using v8::Value;
24
25 using v8::internal::byte;
26 using v8::internal::Address;
27 using v8::internal::Handle;
28 using v8::internal::JSFunction;
29 using v8::internal::StackTracer;
30 using v8::internal::TickSample;
31 using v8::internal::Top;
32
33 namespace i = v8::internal;
34
35
36 static v8::Persistent<v8::Context> env;
37
38
39 static struct {
40 TickSample* sample;
41 } trace_env = { NULL };
42
43
44 static void InitTraceEnv(TickSample* sample) {
45 trace_env.sample = sample;
46 }
47
48
49 static void DoTrace(Address fp) {
50 trace_env.sample->fp = reinterpret_cast<uintptr_t>(fp);
51 // sp is only used to define stack high bound
52 trace_env.sample->sp =
53 reinterpret_cast<unsigned int>(trace_env.sample) - 10240;
54 StackTracer::Trace(trace_env.sample);
55 }
56
57
58 // Hide c_entry_fp to emulate situation when sampling is done while
59 // pure JS code is being executed
60 static void DoTraceHideCEntryFPAddress(Address fp) {
61 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address());
62 CHECK(saved_c_frame_fp);
63 *(Top::c_entry_fp_address()) = 0;
64 DoTrace(fp);
65 *(Top::c_entry_fp_address()) = saved_c_frame_fp;
66 }
67
68
69 static void CheckRetAddrIsInFunction(const char* func_name,
70 Address ret_addr,
71 Address func_start_addr,
72 unsigned int func_len) {
73 printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n",
74 func_name, func_start_addr, ret_addr, func_start_addr + func_len);
75 CHECK_GE(ret_addr, func_start_addr);
76 CHECK_GE(func_start_addr + func_len, ret_addr);
77 }
78
79
80 static void CheckRetAddrIsInJSFunction(const char* func_name,
81 Address ret_addr,
82 Handle<JSFunction> func) {
83 v8::internal::Code* func_code = func->code();
84 CheckRetAddrIsInFunction(
85 func_name, ret_addr,
86 func_code->instruction_start(),
87 func_code->ExecutableSize());
88 }
89
90
91 // --- T r a c e E x t e n s i o n ---
92
93 class TraceExtension : public v8::Extension {
94 public:
95 TraceExtension() : v8::Extension("v8/trace", kSource) { }
96 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
97 v8::Handle<String> name);
98 static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
99 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
100 static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args);
101 static v8::Handle<v8::Value> JSEntrySPLevel2(const v8::Arguments& args);
102 private:
103 static Address GetFP(const v8::Arguments& args);
104 static const char* kSource;
105 };
106
107
108 const char* TraceExtension::kSource =
109 "native function trace();"
110 "native function js_trace();"
111 "native function js_entry_sp();"
112 "native function js_entry_sp_level2();";
113
114 v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
115 v8::Handle<String> name) {
116 if (name->Equals(String::New("trace"))) {
117 return v8::FunctionTemplate::New(TraceExtension::Trace);
118 } else if (name->Equals(String::New("js_trace"))) {
119 return v8::FunctionTemplate::New(TraceExtension::JSTrace);
120 } else if (name->Equals(String::New("js_entry_sp"))) {
121 return v8::FunctionTemplate::New(TraceExtension::JSEntrySP);
122 } else if (name->Equals(String::New("js_entry_sp_level2"))) {
123 return v8::FunctionTemplate::New(TraceExtension::JSEntrySPLevel2);
124 } else {
125 CHECK(false);
126 return v8::Handle<v8::FunctionTemplate>();
127 }
128 }
129
130
131 Address TraceExtension::GetFP(const v8::Arguments& args) {
132 CHECK_EQ(1, args.Length());
133 Address fp = reinterpret_cast<Address>(args[0]->Int32Value() << 2);
134 printf("Trace: %p\n", fp);
135 return fp;
136 }
137
138
139 v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
140 DoTrace(GetFP(args));
141 return v8::Undefined();
142 }
143
144
145 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
146 DoTraceHideCEntryFPAddress(GetFP(args));
147 return v8::Undefined();
148 }
149
150
151 static Address GetJsEntrySp() {
152 CHECK_NE(NULL, Top::GetCurrentThread());
153 return Top::js_entry_sp(Top::GetCurrentThread());
154 }
155
156
157 v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) {
158 CHECK_NE(0, GetJsEntrySp());
159 return v8::Undefined();
160 }
161
162
163 static void CompileRun(const char* source) {
164 Script::Compile(String::New(source))->Run();
165 }
166
167
168 v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2(
169 const v8::Arguments& args) {
170 v8::HandleScope scope;
171 const Address js_entry_sp = GetJsEntrySp();
172 CHECK_NE(0, js_entry_sp);
173 CompileRun("js_entry_sp();");
174 CHECK_EQ(js_entry_sp, GetJsEntrySp());
175 return v8::Undefined();
176 }
177
178
179 static TraceExtension kTraceExtension;
180 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
181
182
183 static void InitializeVM() {
184 if (env.IsEmpty()) {
185 v8::HandleScope scope;
186 const char* extensions[] = { "v8/trace" };
187 v8::ExtensionConfiguration config(1, extensions);
188 env = v8::Context::New(&config);
189 }
190 v8::HandleScope scope;
191 env->Enter();
192 }
193
194
195 static Handle<JSFunction> CompileFunction(const char* source) {
196 return v8::Utils::OpenHandle(*Script::Compile(String::New(source)));
197 }
198
199
200 static Local<Value> GetGlobalProperty(const char* name) {
201 return env->Global()->Get(String::New(name));
202 }
203
204
205 static Handle<JSFunction> GetGlobalJSFunction(const char* name) {
206 Handle<JSFunction> js_func(JSFunction::cast(
207 *(v8::Utils::OpenHandle(
208 *GetGlobalProperty(name)))));
209 return js_func;
210 }
211
212
213 static void CheckRetAddrIsInJSFunction(const char* func_name,
214 Address ret_addr) {
215 CheckRetAddrIsInJSFunction(func_name, ret_addr,
216 GetGlobalJSFunction(func_name));
217 }
218
219
220 static void SetGlobalProperty(const char* name, Local<Value> value) {
221 env->Global()->Set(String::New(name), value);
222 }
223
224
225 static Handle<v8::internal::String> NewString(const char* s) {
226 return i::Factory::NewStringFromAscii(i::CStrVector(s));
227 }
228
229
230 namespace v8 {
231 namespace internal {
232
233 class CodeGeneratorPatcher {
234 public:
235 CodeGeneratorPatcher() {
236 CodeGenerator::InlineRuntimeLUT genGetFramePointer =
237 {&CodeGenerator::GenerateGetFramePointer, "_GetFramePointer"};
238 // _FastCharCodeAt is not used in our tests.
239 bool result = CodeGenerator::PatchInlineRuntimeEntry(
240 NewString("_FastCharCodeAt"),
241 genGetFramePointer, &oldInlineEntry);
242 CHECK(result);
243 }
244
245 ~CodeGeneratorPatcher() {
246 CHECK(CodeGenerator::PatchInlineRuntimeEntry(
247 NewString("_GetFramePointer"),
248 oldInlineEntry, NULL));
249 }
250
251 private:
252 CodeGenerator::InlineRuntimeLUT oldInlineEntry;
253 };
254
255 } } // namespace v8::internal
256
257
258 // Creates a global function named 'func_name' that calls the tracing
259 // function 'trace_func_name' with an actual EBP register value,
260 // shifted right to be presented as Smi.
261 static void CreateTraceCallerFunction(const char* func_name,
262 const char* trace_func_name) {
263 i::EmbeddedVector<char, 256> trace_call_buf;
264 i::OS::SNPrintF(trace_call_buf, "%s(%%_GetFramePointer());", trace_func_name);
265
266 // Compile the script.
267 i::CodeGeneratorPatcher patcher;
268 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
269 i::FLAG_allow_natives_syntax = true;
270 Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
271 CHECK(!func.is_null());
272 i::FLAG_allow_natives_syntax = allow_natives_syntax;
273
274 #ifdef DEBUG
275 v8::internal::Code* func_code = func->code();
276 CHECK(func_code->IsCode());
277 func_code->Print();
278 #endif
279
280 SetGlobalProperty(func_name, v8::ToApi<Value>(func));
281 }
282
283
284 TEST(CFromJSStackTrace) {
285 TickSample sample;
286 InitTraceEnv(&sample);
287
288 InitializeVM();
289 v8::HandleScope scope;
290 CreateTraceCallerFunction("JSFuncDoTrace", "trace");
291 CompileRun(
292 "function JSTrace() {"
293 " JSFuncDoTrace();"
294 "};\n"
295 "JSTrace();");
296 CHECK_GT(sample.frames_count, 1);
297 // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace"
298 CheckRetAddrIsInJSFunction("JSFuncDoTrace",
299 sample.stack[0]);
300 CheckRetAddrIsInJSFunction("JSTrace",
301 sample.stack[1]);
302 }
303
304
305 TEST(PureJSStackTrace) {
306 TickSample sample;
307 InitTraceEnv(&sample);
308
309 InitializeVM();
310 v8::HandleScope scope;
311 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
312 CompileRun(
313 "function JSTrace() {"
314 " JSFuncDoTrace();"
315 "};\n"
316 "function OuterJSTrace() {"
317 " JSTrace();"
318 "};\n"
319 "OuterJSTrace();");
320 CHECK_GT(sample.frames_count, 1);
321 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
322 CheckRetAddrIsInJSFunction("JSTrace",
323 sample.stack[0]);
324 CheckRetAddrIsInJSFunction("OuterJSTrace",
325 sample.stack[1]);
326 }
327
328
329 static void CFuncDoTrace() {
330 Address fp;
331 #ifdef __GNUC__
332 fp = reinterpret_cast<Address>(__builtin_frame_address(0));
333 #elif defined _MSC_VER
334 __asm mov [fp], ebp // NOLINT
335 #endif
336 DoTrace(fp);
337 }
338
339
340 static int CFunc(int depth) {
341 if (depth <= 0) {
342 CFuncDoTrace();
343 return 0;
344 } else {
345 return CFunc(depth - 1) + 1;
346 }
347 }
348
349
350 TEST(PureCStackTrace) {
351 TickSample sample;
352 InitTraceEnv(&sample);
353 // Check that sampler doesn't crash
354 CHECK_EQ(10, CFunc(10));
355 }
356
357
358 TEST(JsEntrySp) {
359 InitializeVM();
360 v8::HandleScope scope;
361 CHECK_EQ(0, GetJsEntrySp());
362 CompileRun("a = 1; b = a + 1;");
363 CHECK_EQ(0, GetJsEntrySp());
364 CompileRun("js_entry_sp();");
365 CHECK_EQ(0, GetJsEntrySp());
366 CompileRun("js_entry_sp_level2();");
367 CHECK_EQ(0, GetJsEntrySp());
368 }
369
370 #endif // ENABLE_LOGGING_AND_PROFILING
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698