| OLD | NEW | 
|---|
| 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "platform/assert.h" | 5 #include "platform/assert.h" | 
| 6 | 6 | 
| 7 #include "vm/dart_api_impl.h" | 7 #include "vm/dart_api_impl.h" | 
| 8 #include "vm/dart_api_state.h" | 8 #include "vm/dart_api_state.h" | 
| 9 #include "vm/globals.h" | 9 #include "vm/globals.h" | 
| 10 #include "vm/profiler.h" | 10 #include "vm/profiler.h" | 
| 11 #include "vm/profiler_service.h" | 11 #include "vm/profiler_service.h" | 
|  | 12 #include "vm/source_report.h" | 
| 12 #include "vm/unit_test.h" | 13 #include "vm/unit_test.h" | 
| 13 | 14 | 
| 14 namespace dart { | 15 namespace dart { | 
| 15 | 16 | 
| 16 #ifndef PRODUCT | 17 #ifndef PRODUCT | 
| 17 | 18 | 
| 18 DECLARE_FLAG(bool, profile_vm); | 19 DECLARE_FLAG(bool, profile_vm); | 
| 19 DECLARE_FLAG(int, max_profile_depth); | 20 DECLARE_FLAG(int, max_profile_depth); | 
| 20 DECLARE_FLAG(bool, enable_inlining_annotations); | 21 DECLARE_FLAG(bool, enable_inlining_annotations); | 
| 21 DECLARE_FLAG(int, optimization_counter_threshold); | 22 DECLARE_FLAG(int, optimization_counter_threshold); | 
| (...skipping 2270 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2292     EXPECT(walker.Down()); | 2293     EXPECT(walker.Down()); | 
| 2293     EXPECT_STREQ("main", walker.CurrentName()); | 2294     EXPECT_STREQ("main", walker.CurrentName()); | 
| 2294     EXPECT_EQ(1, walker.CurrentNodeTickCount()); | 2295     EXPECT_EQ(1, walker.CurrentNodeTickCount()); | 
| 2295     EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | 2296     EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | 
| 2296     EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | 2297     EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | 
| 2297     EXPECT_STREQ("bacon", walker.CurrentToken()); | 2298     EXPECT_STREQ("bacon", walker.CurrentToken()); | 
| 2298     EXPECT(!walker.Down()); | 2299     EXPECT(!walker.Down()); | 
| 2299   } | 2300   } | 
| 2300 } | 2301 } | 
| 2301 | 2302 | 
|  | 2303 | 
|  | 2304 static void InsertFakeSample(SampleBuffer* sample_buffer, | 
|  | 2305                              uword* pc_offsets) { | 
|  | 2306   ASSERT(sample_buffer != NULL); | 
|  | 2307   Isolate* isolate = Isolate::Current(); | 
|  | 2308   Sample* sample = sample_buffer->ReserveSample(); | 
|  | 2309   ASSERT(sample != NULL); | 
|  | 2310   sample->Init(isolate, | 
|  | 2311                OS::GetCurrentMonotonicMicros(), | 
|  | 2312                OSThread::Current()->trace_id()); | 
|  | 2313 | 
|  | 2314   intptr_t i = 0; | 
|  | 2315   while (pc_offsets[i] != 0) { | 
|  | 2316     // When we collect a real stack trace, all PCs collected aside from the | 
|  | 2317     // executing one (i == 0) are actually return addresses. Return addresses | 
|  | 2318     // are one byte beyond the call instruction that is executing. The profiler | 
|  | 2319     // accounts for this and subtracts one from these addresses when querying | 
|  | 2320     // inline and token position ranges. To be consistent with real stack | 
|  | 2321     // traces, we add one byte to all PCs except the executing one. | 
|  | 2322     // See OffsetForPC in profiler_service.cc for more context. | 
|  | 2323     const intptr_t return_address_offset = i > 0 ? 1 : 0; | 
|  | 2324     sample->SetAt(i, pc_offsets[i] + return_address_offset); | 
|  | 2325     i++; | 
|  | 2326   } | 
|  | 2327   sample->SetAt(i, NULL); | 
|  | 2328 } | 
|  | 2329 | 
|  | 2330 | 
|  | 2331 static uword FindPCForTokenPosition(const Code& code, | 
|  | 2332                                     const CodeSourceMap& code_source_map, | 
|  | 2333                                     TokenPosition tp) { | 
|  | 2334   CodeSourceMap::Iterator it(code_source_map); | 
|  | 2335 | 
|  | 2336   while (it.MoveNext()) { | 
|  | 2337     if (it.TokenPos() == tp) { | 
|  | 2338       return it.PcOffset() + code.EntryPoint(); | 
|  | 2339     } | 
|  | 2340   } | 
|  | 2341 | 
|  | 2342   return 0; | 
|  | 2343 } | 
|  | 2344 | 
|  | 2345 | 
|  | 2346 TEST_CASE(Profiler_GetSourceReport) { | 
|  | 2347   const char* kScript = | 
|  | 2348       "doWork(i) => i * i;\n" | 
|  | 2349       "main() {\n" | 
|  | 2350       "  var sum = 0;\n" | 
|  | 2351       "  for (var i = 0; i < 100; i++) {\n" | 
|  | 2352       "     sum += doWork(i);\n" | 
|  | 2353       "  }\n" | 
|  | 2354       "  return sum;\n" | 
|  | 2355       "}\n"; | 
|  | 2356 | 
|  | 2357   // Token position of * in `i * i`. | 
|  | 2358   const TokenPosition squarePosition = TokenPosition(6); | 
|  | 2359 | 
|  | 2360   // Token position of the call to `doWork`. | 
|  | 2361   const TokenPosition callPosition = TokenPosition(39); | 
|  | 2362 | 
|  | 2363   DisableNativeProfileScope dnps; | 
|  | 2364   // Disable profiling for this thread. | 
|  | 2365   DisableThreadInterruptsScope dtis(Thread::Current()); | 
|  | 2366 | 
|  | 2367   SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 
|  | 2368   EXPECT(sample_buffer != NULL); | 
|  | 2369 | 
|  | 2370   Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); | 
|  | 2371   EXPECT_VALID(lib); | 
|  | 2372   Library& root_library = Library::Handle(); | 
|  | 2373   root_library ^= Api::UnwrapHandle(lib); | 
|  | 2374 | 
|  | 2375   // Invoke main so that it gets compiled. | 
|  | 2376   Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | 
|  | 2377   EXPECT_VALID(result); | 
|  | 2378 | 
|  | 2379   { | 
|  | 2380     // Clear the profile for this isolate. | 
|  | 2381     ClearProfileVisitor cpv(Isolate::Current()); | 
|  | 2382     sample_buffer->VisitSamples(&cpv); | 
|  | 2383   } | 
|  | 2384 | 
|  | 2385   // Query the code object for main and determine the PC at some token | 
|  | 2386   // positions. | 
|  | 2387   const Function& main = Function::Handle(GetFunction(root_library, "main")); | 
|  | 2388   EXPECT(!main.IsNull()); | 
|  | 2389 | 
|  | 2390   const Function& do_work = | 
|  | 2391       Function::Handle(GetFunction(root_library, "doWork")); | 
|  | 2392   EXPECT(!do_work.IsNull()); | 
|  | 2393 | 
|  | 2394   const Script& script = Script::Handle(main.script()); | 
|  | 2395   EXPECT(!script.IsNull()); | 
|  | 2396 | 
|  | 2397   const Code& main_code = Code::Handle(main.CurrentCode()); | 
|  | 2398   EXPECT(!main_code.IsNull()); | 
|  | 2399 | 
|  | 2400   const Code& do_work_code = Code::Handle(do_work.CurrentCode()); | 
|  | 2401   EXPECT(!do_work_code.IsNull()); | 
|  | 2402 | 
|  | 2403   const CodeSourceMap& main_code_source_map = | 
|  | 2404       CodeSourceMap::Handle(main_code.code_source_map()); | 
|  | 2405   EXPECT(!main_code_source_map.IsNull()); | 
|  | 2406 | 
|  | 2407   const CodeSourceMap& do_work_code_source_map = | 
|  | 2408       CodeSourceMap::Handle(do_work_code.code_source_map()); | 
|  | 2409   EXPECT(!do_work_code_source_map.IsNull()); | 
|  | 2410 | 
|  | 2411   // Dump code source map. | 
|  | 2412   CodeSourceMap::Dump(do_work_code_source_map, do_work_code, main); | 
|  | 2413   CodeSourceMap::Dump(main_code_source_map, main_code, main); | 
|  | 2414 | 
|  | 2415   // Look up some source token position's pc. | 
|  | 2416   uword squarePositionPc = | 
|  | 2417       FindPCForTokenPosition(do_work_code, | 
|  | 2418                              do_work_code_source_map, | 
|  | 2419                              squarePosition); | 
|  | 2420   EXPECT(squarePositionPc != 0); | 
|  | 2421 | 
|  | 2422   uword callPositionPc = | 
|  | 2423       FindPCForTokenPosition(main_code, main_code_source_map, callPosition); | 
|  | 2424   EXPECT(callPositionPc != 0); | 
|  | 2425 | 
|  | 2426   // Look up some classifying token position's pc. | 
|  | 2427   uword controlFlowPc = | 
|  | 2428       FindPCForTokenPosition(do_work_code, | 
|  | 2429                              do_work_code_source_map, | 
|  | 2430                              TokenPosition::kControlFlow); | 
|  | 2431   EXPECT(controlFlowPc != 0); | 
|  | 2432 | 
|  | 2433   uword tempMovePc = | 
|  | 2434       FindPCForTokenPosition(main_code, | 
|  | 2435                              main_code_source_map, | 
|  | 2436                              TokenPosition::kTempMove); | 
|  | 2437   EXPECT(tempMovePc != 0); | 
|  | 2438 | 
|  | 2439   // Insert fake samples. | 
|  | 2440 | 
|  | 2441   // Sample 1: | 
|  | 2442   // squarePositionPc exclusive. | 
|  | 2443   // callPositionPc inclusive. | 
|  | 2444   uword sample1[] = { | 
|  | 2445     squarePositionPc,  // doWork. | 
|  | 2446     callPositionPc,    // main. | 
|  | 2447     0 | 
|  | 2448   }; | 
|  | 2449 | 
|  | 2450   // Sample 2: | 
|  | 2451   // squarePositionPc exclusive. | 
|  | 2452   uword sample2[] = { | 
|  | 2453     squarePositionPc,  // doWork. | 
|  | 2454     0, | 
|  | 2455   }; | 
|  | 2456 | 
|  | 2457   // Sample 3: | 
|  | 2458   // controlFlowPc exclusive. | 
|  | 2459   // callPositionPc inclusive. | 
|  | 2460   uword sample3[] = { | 
|  | 2461     controlFlowPc,   // doWork. | 
|  | 2462     callPositionPc,  // main. | 
|  | 2463     0 | 
|  | 2464   }; | 
|  | 2465 | 
|  | 2466   // Sample 4: | 
|  | 2467   // tempMovePc exclusive. | 
|  | 2468   uword sample4[] = { | 
|  | 2469     tempMovePc,  // main. | 
|  | 2470     0 | 
|  | 2471   }; | 
|  | 2472 | 
|  | 2473   InsertFakeSample(sample_buffer, &sample1[0]); | 
|  | 2474   InsertFakeSample(sample_buffer, &sample2[0]); | 
|  | 2475   InsertFakeSample(sample_buffer, &sample3[0]); | 
|  | 2476   InsertFakeSample(sample_buffer, &sample4[0]); | 
|  | 2477 | 
|  | 2478   // Generate source report for main. | 
|  | 2479   SourceReport sourceReport(SourceReport::kProfile); | 
|  | 2480   JSONStream js; | 
|  | 2481   sourceReport.PrintJSON(&js, | 
|  | 2482                          script, | 
|  | 2483                          do_work.token_pos(), | 
|  | 2484                          main.end_token_pos()); | 
|  | 2485 | 
|  | 2486   // Verify positions in do_work. | 
|  | 2487   EXPECT_SUBSTRING("\"positions\":[\"ControlFlow\",6]", js.ToCString()); | 
|  | 2488   // Verify exclusive ticks in do_work. | 
|  | 2489   EXPECT_SUBSTRING("\"exclusiveTicks\":[1,2]", js.ToCString()); | 
|  | 2490   // Verify inclusive ticks in do_work. | 
|  | 2491   EXPECT_SUBSTRING("\"inclusiveTicks\":[1,2]", js.ToCString()); | 
|  | 2492 | 
|  | 2493   // Verify positions in main. | 
|  | 2494   EXPECT_SUBSTRING("\"positions\":[\"TempMove\",39]", js.ToCString()); | 
|  | 2495   // Verify exclusive ticks in main. | 
|  | 2496   EXPECT_SUBSTRING("\"exclusiveTicks\":[1,0]", js.ToCString()); | 
|  | 2497   // Verify inclusive ticks in main. | 
|  | 2498   EXPECT_SUBSTRING("\"inclusiveTicks\":[1,2]", js.ToCString()); | 
|  | 2499 } | 
|  | 2500 | 
| 2302 #endif  // !PRODUCT | 2501 #endif  // !PRODUCT | 
| 2303 | 2502 | 
| 2304 }  // namespace dart | 2503 }  // namespace dart | 
| OLD | NEW | 
|---|