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 // To account for a subtraction in profiler. | |
2317 intptr_t slop = i > 0 ? 1 : 0; | |
2318 sample->SetAt(i, pc_offsets[i] + slop); | |
turnidge
2016/03/11 18:31:57
So for the top frame on the stack, we put in an un
Cutch
2016/03/11 20:20:00
When querying the inline tables for a Code object,
| |
2319 i++; | |
2320 } | |
2321 sample->SetAt(i, 0); | |
turnidge
2016/03/11 18:31:57
0 is a sentinel for the SampleBuffer? Maybe a nam
Cutch
2016/03/11 20:20:00
Done.
| |
2322 } | |
2323 | |
2324 | |
2325 static uword FindPCForTokenPosition(const Code& code, | |
2326 const CodeSourceMap& code_source_map, | |
2327 TokenPosition tp) { | |
2328 CodeSourceMap::Iterator it(code_source_map); | |
2329 | |
2330 while (it.MoveNext()) { | |
2331 if (it.TokenPos() == tp) { | |
2332 return it.PcOffset() + code.EntryPoint(); | |
2333 } | |
2334 } | |
2335 | |
2336 return 0; | |
2337 } | |
2338 | |
2339 | |
2340 TEST_CASE(Profiler_GetSourceReport) { | |
2341 const char* kScript = | |
2342 "doWork(i) => i * i;\n" | |
2343 "main() {\n" | |
2344 " var sum = 0;\n" | |
2345 " for (var i = 0; i < 100; i++) {\n" | |
2346 " sum += doWork(i);\n" | |
2347 " }\n" | |
2348 " return sum;\n" | |
2349 "}\n"; | |
2350 | |
2351 // Token position of * in `i * i`. | |
2352 const TokenPosition squarePosition = TokenPosition(6); | |
2353 | |
2354 // Token position of the call to `doWork`. | |
2355 const TokenPosition callPosition = TokenPosition(39); | |
2356 | |
2357 DisableNativeProfileScope dnps; | |
2358 // Disable profiling for this thread. | |
2359 DisableThreadInterruptsScope dtis(Thread::Current()); | |
2360 | |
2361 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | |
2362 EXPECT(sample_buffer != NULL); | |
2363 | |
2364 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); | |
2365 EXPECT_VALID(lib); | |
2366 Library& root_library = Library::Handle(); | |
2367 root_library ^= Api::UnwrapHandle(lib); | |
2368 | |
2369 // Invoke main so that it gets compiled. | |
2370 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
2371 EXPECT_VALID(result); | |
2372 | |
2373 { | |
2374 // Clear the profile for this isolate. | |
2375 ClearProfileVisitor cpv(Isolate::Current()); | |
2376 sample_buffer->VisitSamples(&cpv); | |
2377 } | |
2378 | |
2379 // Query the code object for main and determine the PC some token positions. | |
turnidge
2016/03/11 18:31:57
"PC some" -> "PC at some"?
Cutch
2016/03/11 20:20:00
Done.
| |
2380 const Function& main = Function::Handle(GetFunction(root_library, "main")); | |
2381 EXPECT(!main.IsNull()); | |
2382 | |
2383 const Function& do_work = | |
2384 Function::Handle(GetFunction(root_library, "doWork")); | |
2385 EXPECT(!do_work.IsNull()); | |
2386 | |
2387 const Script& script = Script::Handle(main.script()); | |
2388 EXPECT(!script.IsNull()); | |
2389 | |
2390 const Code& main_code = Code::Handle(main.CurrentCode()); | |
2391 EXPECT(!main_code.IsNull()); | |
2392 | |
2393 const Code& do_work_code = Code::Handle(do_work.CurrentCode()); | |
2394 EXPECT(!do_work_code.IsNull()); | |
2395 | |
2396 const CodeSourceMap& main_code_source_map = | |
2397 CodeSourceMap::Handle(main_code.code_source_map()); | |
2398 EXPECT(!main_code_source_map.IsNull()); | |
2399 | |
2400 const CodeSourceMap& do_work_code_source_map = | |
2401 CodeSourceMap::Handle(do_work_code.code_source_map()); | |
2402 EXPECT(!do_work_code_source_map.IsNull()); | |
2403 | |
2404 // Dump code source map. | |
2405 CodeSourceMap::Dump(do_work_code_source_map, do_work_code, main); | |
2406 CodeSourceMap::Dump(main_code_source_map, main_code, main); | |
2407 | |
2408 // Look up some source token position's pc. | |
2409 uword squarePositionPc = | |
2410 FindPCForTokenPosition(do_work_code, | |
2411 do_work_code_source_map, | |
2412 squarePosition); | |
2413 EXPECT(squarePositionPc != 0); | |
2414 | |
2415 uword callPositionPc = | |
2416 FindPCForTokenPosition(main_code, main_code_source_map, callPosition); | |
2417 EXPECT(callPositionPc != 0); | |
2418 | |
2419 // Look up some classifying token position's pc. | |
2420 uword controlFlowPc = | |
2421 FindPCForTokenPosition(do_work_code, | |
2422 do_work_code_source_map, | |
2423 TokenPosition::kControlFlow); | |
2424 EXPECT(controlFlowPc != 0); | |
2425 | |
2426 uword tempMovePc = | |
2427 FindPCForTokenPosition(main_code, | |
2428 main_code_source_map, | |
2429 TokenPosition::kTempMove); | |
2430 EXPECT(tempMovePc != 0); | |
2431 | |
2432 // Insert fake samples. | |
2433 | |
2434 // Sample 1: | |
2435 // squarePositionPc exclusive. | |
2436 // callPositionPc inclusive. | |
2437 uword sample1[] = { | |
2438 squarePositionPc, // doWork. | |
2439 callPositionPc, // main. | |
2440 0 | |
2441 }; | |
2442 | |
2443 // Sample 2: | |
2444 // squarePositionPc exclusive. | |
2445 uword sample2[] = { | |
2446 squarePositionPc, // doWork. | |
2447 0, | |
2448 }; | |
2449 | |
2450 // Sample 3: | |
2451 // controlFlowPc exclusive. | |
2452 // callPositionPc inclusive. | |
2453 uword sample3[] = { | |
2454 controlFlowPc, // doWork. | |
2455 callPositionPc, // main. | |
2456 0 | |
2457 }; | |
2458 | |
2459 // Sample 4: | |
2460 // tempMovePc exclusive. | |
2461 uword sample4[] = { | |
2462 tempMovePc, // main. | |
2463 0 | |
2464 }; | |
2465 | |
2466 InsertFakeSample(sample_buffer, &sample1[0]); | |
2467 InsertFakeSample(sample_buffer, &sample2[0]); | |
2468 InsertFakeSample(sample_buffer, &sample3[0]); | |
2469 InsertFakeSample(sample_buffer, &sample4[0]); | |
2470 | |
2471 // Generate source report for main. | |
2472 SourceReport sourceReport(SourceReport::kProfile); | |
2473 JSONStream js; | |
2474 sourceReport.PrintJSON(&js, | |
2475 script, | |
2476 do_work.token_pos(), | |
2477 main.end_token_pos()); | |
2478 | |
2479 // Verify positions in do_work. | |
2480 EXPECT_SUBSTRING("\"positions\":[\"ControlFlow\",6]", js.ToCString()); | |
2481 // Verify exclusive ticks in do_work. | |
2482 EXPECT_SUBSTRING("\"exclusiveTicks\":[1,2]", js.ToCString()); | |
2483 // Verify inclusive ticks in do_work. | |
2484 EXPECT_SUBSTRING("\"inclusiveTicks\":[1,2]", js.ToCString()); | |
2485 | |
2486 // Verify positions in main. | |
2487 EXPECT_SUBSTRING("\"positions\":[\"TempMove\",39]", js.ToCString()); | |
2488 // Verify exclusive ticks in main. | |
2489 EXPECT_SUBSTRING("\"exclusiveTicks\":[1,0]", js.ToCString()); | |
2490 // Verify inclusive ticks in main. | |
2491 EXPECT_SUBSTRING("\"inclusiveTicks\":[1,2]", js.ToCString()); | |
turnidge
2016/03/11 18:31:57
Nice test.
Cutch
2016/03/11 20:20:00
Acknowledged.
| |
2492 } | |
2493 | |
2302 #endif // !PRODUCT | 2494 #endif // !PRODUCT |
2303 | 2495 |
2304 } // namespace dart | 2496 } // namespace dart |
OLD | NEW |