| 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 |