OLD | NEW |
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
2 // | 2 // |
3 // Tests of profiler-related functions from log.h | 3 // Tests of profiler-related functions from log.h |
4 | 4 |
5 #ifdef ENABLE_LOGGING_AND_PROFILING | 5 #ifdef ENABLE_LOGGING_AND_PROFILING |
6 | 6 |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 | 8 |
9 #include "v8.h" | 9 #include "v8.h" |
10 | 10 |
(...skipping 19 matching lines...) Expand all Loading... |
30 using v8::internal::TickSample; | 30 using v8::internal::TickSample; |
31 using v8::internal::Top; | 31 using v8::internal::Top; |
32 | 32 |
33 namespace i = v8::internal; | 33 namespace i = v8::internal; |
34 | 34 |
35 | 35 |
36 static v8::Persistent<v8::Context> env; | 36 static v8::Persistent<v8::Context> env; |
37 | 37 |
38 | 38 |
39 static struct { | 39 static struct { |
40 StackTracer* tracer; | |
41 TickSample* sample; | 40 TickSample* sample; |
42 } trace_env = { NULL, NULL }; | 41 } trace_env = { NULL }; |
43 | 42 |
44 | 43 |
45 static void InitTraceEnv(StackTracer* tracer, TickSample* sample) { | 44 static void InitTraceEnv(TickSample* sample) { |
46 trace_env.tracer = tracer; | |
47 trace_env.sample = sample; | 45 trace_env.sample = sample; |
48 } | 46 } |
49 | 47 |
50 | 48 |
51 static void DoTrace(Address fp) { | 49 static void DoTrace(Address fp) { |
52 trace_env.sample->fp = reinterpret_cast<uintptr_t>(fp); | 50 trace_env.sample->fp = reinterpret_cast<uintptr_t>(fp); |
53 // sp is only used to define stack high bound | 51 // sp is only used to define stack high bound |
54 trace_env.sample->sp = | 52 trace_env.sample->sp = |
55 reinterpret_cast<unsigned int>(trace_env.sample) - 10240; | 53 reinterpret_cast<unsigned int>(trace_env.sample) - 10240; |
56 trace_env.tracer->Trace(trace_env.sample); | 54 StackTracer::Trace(trace_env.sample); |
57 } | 55 } |
58 | 56 |
59 | 57 |
60 // Hide c_entry_fp to emulate situation when sampling is done while | 58 // Hide c_entry_fp to emulate situation when sampling is done while |
61 // pure JS code is being executed | 59 // pure JS code is being executed |
62 static void DoTraceHideCEntryFPAddress(Address fp) { | 60 static void DoTraceHideCEntryFPAddress(Address fp) { |
63 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); | 61 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); |
64 CHECK(saved_c_frame_fp); | 62 CHECK(saved_c_frame_fp); |
65 *(Top::c_entry_fp_address()) = 0; | 63 *(Top::c_entry_fp_address()) = 0; |
66 DoTrace(fp); | 64 DoTrace(fp); |
(...skipping 25 matching lines...) Expand all Loading... |
92 | 90 |
93 // --- T r a c e E x t e n s i o n --- | 91 // --- T r a c e E x t e n s i o n --- |
94 | 92 |
95 class TraceExtension : public v8::Extension { | 93 class TraceExtension : public v8::Extension { |
96 public: | 94 public: |
97 TraceExtension() : v8::Extension("v8/trace", kSource) { } | 95 TraceExtension() : v8::Extension("v8/trace", kSource) { } |
98 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 96 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
99 v8::Handle<String> name); | 97 v8::Handle<String> name); |
100 static v8::Handle<v8::Value> Trace(const v8::Arguments& args); | 98 static v8::Handle<v8::Value> Trace(const v8::Arguments& args); |
101 static v8::Handle<v8::Value> JSTrace(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: | 102 private: |
103 static Address GetFP(const v8::Arguments& args); | 103 static Address GetFP(const v8::Arguments& args); |
104 static const char* kSource; | 104 static const char* kSource; |
105 }; | 105 }; |
106 | 106 |
107 | 107 |
108 const char* TraceExtension::kSource = | 108 const char* TraceExtension::kSource = |
109 "native function trace();" | 109 "native function trace();" |
110 "native function js_trace();"; | 110 "native function js_trace();" |
111 | 111 "native function js_entry_sp();" |
| 112 "native function js_entry_sp_level2();"; |
112 | 113 |
113 v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction( | 114 v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction( |
114 v8::Handle<String> name) { | 115 v8::Handle<String> name) { |
115 if (name->Equals(String::New("trace"))) { | 116 if (name->Equals(String::New("trace"))) { |
116 return v8::FunctionTemplate::New(TraceExtension::Trace); | 117 return v8::FunctionTemplate::New(TraceExtension::Trace); |
117 } else if (name->Equals(String::New("js_trace"))) { | 118 } else if (name->Equals(String::New("js_trace"))) { |
118 return v8::FunctionTemplate::New(TraceExtension::JSTrace); | 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); |
119 } else { | 124 } else { |
120 CHECK(false); | 125 CHECK(false); |
121 return v8::Handle<v8::FunctionTemplate>(); | 126 return v8::Handle<v8::FunctionTemplate>(); |
122 } | 127 } |
123 } | 128 } |
124 | 129 |
125 | 130 |
126 Address TraceExtension::GetFP(const v8::Arguments& args) { | 131 Address TraceExtension::GetFP(const v8::Arguments& args) { |
127 CHECK_EQ(1, args.Length()); | 132 CHECK_EQ(1, args.Length()); |
128 Address fp = reinterpret_cast<Address>(args[0]->Int32Value() << 2); | 133 Address fp = reinterpret_cast<Address>(args[0]->Int32Value() << 2); |
129 printf("Trace: %p\n", fp); | 134 printf("Trace: %p\n", fp); |
130 return fp; | 135 return fp; |
131 } | 136 } |
132 | 137 |
133 | 138 |
134 v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) { | 139 v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) { |
135 DoTrace(GetFP(args)); | 140 DoTrace(GetFP(args)); |
136 return v8::Undefined(); | 141 return v8::Undefined(); |
137 } | 142 } |
138 | 143 |
139 | 144 |
140 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { | 145 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { |
141 DoTraceHideCEntryFPAddress(GetFP(args)); | 146 DoTraceHideCEntryFPAddress(GetFP(args)); |
142 return v8::Undefined(); | 147 return v8::Undefined(); |
143 } | 148 } |
144 | 149 |
145 | 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 |
146 static TraceExtension kTraceExtension; | 179 static TraceExtension kTraceExtension; |
147 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension); | 180 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension); |
148 | 181 |
149 | 182 |
150 static void InitializeVM() { | 183 static void InitializeVM() { |
151 if (env.IsEmpty()) { | 184 if (env.IsEmpty()) { |
152 v8::HandleScope scope; | 185 v8::HandleScope scope; |
153 const char* extensions[] = { "v8/trace" }; | 186 const char* extensions[] = { "v8/trace" }; |
154 v8::ExtensionConfiguration config(1, extensions); | 187 v8::ExtensionConfiguration config(1, extensions); |
155 env = v8::Context::New(&config); | 188 env = v8::Context::New(&config); |
156 } | 189 } |
157 v8::HandleScope scope; | 190 v8::HandleScope scope; |
158 env->Enter(); | 191 env->Enter(); |
159 } | 192 } |
160 | 193 |
161 | 194 |
162 static Handle<JSFunction> CompileFunction(const char* source) { | 195 static Handle<JSFunction> CompileFunction(const char* source) { |
163 return v8::Utils::OpenHandle(*Script::Compile(String::New(source))); | 196 return v8::Utils::OpenHandle(*Script::Compile(String::New(source))); |
164 } | 197 } |
165 | 198 |
166 | 199 |
167 static void CompileRun(const char* source) { | |
168 Script::Compile(String::New(source))->Run(); | |
169 } | |
170 | |
171 | |
172 static Local<Value> GetGlobalProperty(const char* name) { | 200 static Local<Value> GetGlobalProperty(const char* name) { |
173 return env->Global()->Get(String::New(name)); | 201 return env->Global()->Get(String::New(name)); |
174 } | 202 } |
175 | 203 |
176 | 204 |
177 static Handle<JSFunction> GetGlobalJSFunction(const char* name) { | 205 static Handle<JSFunction> GetGlobalJSFunction(const char* name) { |
178 Handle<JSFunction> js_func(JSFunction::cast( | 206 Handle<JSFunction> js_func(JSFunction::cast( |
179 *(v8::Utils::OpenHandle( | 207 *(v8::Utils::OpenHandle( |
180 *GetGlobalProperty(name))))); | 208 *GetGlobalProperty(name))))); |
181 return js_func; | 209 return js_func; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 CHECK(func_code->IsCode()); | 276 CHECK(func_code->IsCode()); |
249 func_code->Print(); | 277 func_code->Print(); |
250 #endif | 278 #endif |
251 | 279 |
252 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); | 280 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); |
253 } | 281 } |
254 | 282 |
255 | 283 |
256 TEST(CFromJSStackTrace) { | 284 TEST(CFromJSStackTrace) { |
257 TickSample sample; | 285 TickSample sample; |
258 StackTracer tracer(reinterpret_cast<uintptr_t>(&sample)); | 286 InitTraceEnv(&sample); |
259 InitTraceEnv(&tracer, &sample); | |
260 | 287 |
261 InitializeVM(); | 288 InitializeVM(); |
262 v8::HandleScope scope; | 289 v8::HandleScope scope; |
263 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); | 290 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); |
264 CompileRun( | 291 CompileRun( |
265 "function JSTrace() {" | 292 "function JSTrace() {" |
266 " JSFuncDoTrace();" | 293 " JSFuncDoTrace();" |
267 "};\n" | 294 "};\n" |
268 "JSTrace();"); | 295 "JSTrace();"); |
269 CHECK_GT(sample.frames_count, 1); | 296 CHECK_GT(sample.frames_count, 1); |
270 // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace" | 297 // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace" |
271 CheckRetAddrIsInJSFunction("JSFuncDoTrace", | 298 CheckRetAddrIsInJSFunction("JSFuncDoTrace", |
272 sample.stack[0]); | 299 sample.stack[0]); |
273 CheckRetAddrIsInJSFunction("JSTrace", | 300 CheckRetAddrIsInJSFunction("JSTrace", |
274 sample.stack[1]); | 301 sample.stack[1]); |
275 } | 302 } |
276 | 303 |
277 | 304 |
278 TEST(PureJSStackTrace) { | 305 TEST(PureJSStackTrace) { |
279 TickSample sample; | 306 TickSample sample; |
280 StackTracer tracer(reinterpret_cast<uintptr_t>(&sample)); | 307 InitTraceEnv(&sample); |
281 InitTraceEnv(&tracer, &sample); | |
282 | 308 |
283 InitializeVM(); | 309 InitializeVM(); |
284 v8::HandleScope scope; | 310 v8::HandleScope scope; |
285 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); | 311 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); |
286 CompileRun( | 312 CompileRun( |
287 "function JSTrace() {" | 313 "function JSTrace() {" |
288 " JSFuncDoTrace();" | 314 " JSFuncDoTrace();" |
289 "};\n" | 315 "};\n" |
290 "function OuterJSTrace() {" | 316 "function OuterJSTrace() {" |
291 " JSTrace();" | 317 " JSTrace();" |
(...skipping 24 matching lines...) Expand all Loading... |
316 CFuncDoTrace(); | 342 CFuncDoTrace(); |
317 return 0; | 343 return 0; |
318 } else { | 344 } else { |
319 return CFunc(depth - 1) + 1; | 345 return CFunc(depth - 1) + 1; |
320 } | 346 } |
321 } | 347 } |
322 | 348 |
323 | 349 |
324 TEST(PureCStackTrace) { | 350 TEST(PureCStackTrace) { |
325 TickSample sample; | 351 TickSample sample; |
326 StackTracer tracer(reinterpret_cast<uintptr_t>(&sample)); | 352 InitTraceEnv(&sample); |
327 InitTraceEnv(&tracer, &sample); | |
328 // Check that sampler doesn't crash | 353 // Check that sampler doesn't crash |
329 CHECK_EQ(10, CFunc(10)); | 354 CHECK_EQ(10, CFunc(10)); |
330 } | 355 } |
331 | 356 |
332 | 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 |
333 #endif // ENABLE_LOGGING_AND_PROFILING | 370 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |