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

Side by Side Diff: base/profiler/stack_sampling_profiler_unittest.cc

Issue 2444143002: Add process lifetime annotations to stack samples. (Closed)
Patch Set: addressed review comments by wittman Created 4 years, 1 month 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 #include <stdint.h> 6 #include <stdint.h>
7 7
8 #include <cstdlib> 8 #include <cstdlib>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 30 matching lines...) Expand all
41 #endif 41 #endif
42 42
43 #if defined(OS_WIN) 43 #if defined(OS_WIN)
44 #pragma intrinsic(_ReturnAddress) 44 #pragma intrinsic(_ReturnAddress)
45 #endif 45 #endif
46 46
47 namespace base { 47 namespace base {
48 48
49 using SamplingParams = StackSamplingProfiler::SamplingParams; 49 using SamplingParams = StackSamplingProfiler::SamplingParams;
50 using Frame = StackSamplingProfiler::Frame; 50 using Frame = StackSamplingProfiler::Frame;
51 using Frames = std::vector<StackSamplingProfiler::Frame>;
51 using Module = StackSamplingProfiler::Module; 52 using Module = StackSamplingProfiler::Module;
52 using Sample = StackSamplingProfiler::Sample; 53 using Sample = StackSamplingProfiler::Sample;
53 using CallStackProfile = StackSamplingProfiler::CallStackProfile; 54 using CallStackProfile = StackSamplingProfiler::CallStackProfile;
54 using CallStackProfiles = StackSamplingProfiler::CallStackProfiles; 55 using CallStackProfiles = StackSamplingProfiler::CallStackProfiles;
55 56
56 namespace { 57 namespace {
57 58
58 // Configuration for the frames that appear on the stack. 59 // Configuration for the frames that appear on the stack.
59 struct StackConfiguration { 60 struct StackConfiguration {
60 enum Config { NORMAL, WITH_ALLOCA, WITH_OTHER_LIBRARY }; 61 enum Config { NORMAL, WITH_ALLOCA, WITH_OTHER_LIBRARY };
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 reinterpret_cast<const unsigned char*>(offset + 1); 389 reinterpret_cast<const unsigned char*>(offset + 1);
389 return next_instruction + *offset; 390 return next_instruction + *offset;
390 } 391 }
391 #endif 392 #endif
392 return function_address; 393 return function_address;
393 } 394 }
394 395
395 // Searches through the frames in |sample|, returning an iterator to the first 396 // Searches through the frames in |sample|, returning an iterator to the first
396 // frame that has an instruction pointer within |target_function|. Returns 397 // frame that has an instruction pointer within |target_function|. Returns
397 // sample.end() if no such frames are found. 398 // sample.end() if no such frames are found.
398 Sample::const_iterator FindFirstFrameWithinFunction( 399 Frames::const_iterator FindFirstFrameWithinFunction(
399 const Sample& sample, 400 const Sample& sample,
400 TargetFunction target_function) { 401 TargetFunction target_function) {
401 uintptr_t function_start = reinterpret_cast<uintptr_t>( 402 uintptr_t function_start = reinterpret_cast<uintptr_t>(
402 MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( 403 MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
403 target_function))); 404 target_function)));
404 uintptr_t function_end = 405 uintptr_t function_end =
405 reinterpret_cast<uintptr_t>(target_function(nullptr, nullptr, nullptr)); 406 reinterpret_cast<uintptr_t>(target_function(nullptr, nullptr, nullptr));
406 for (auto it = sample.begin(); it != sample.end(); ++it) { 407 for (auto it = sample.frames.begin(); it != sample.frames.end(); ++it) {
407 if ((it->instruction_pointer >= function_start) && 408 if ((it->instruction_pointer >= function_start) &&
408 (it->instruction_pointer <= function_end)) 409 (it->instruction_pointer <= function_end))
409 return it; 410 return it;
410 } 411 }
411 return sample.end(); 412 return sample.frames.end();
412 } 413 }
413 414
414 // Formats a sample into a string that can be output for test diagnostics. 415 // Formats a sample into a string that can be output for test diagnostics.
415 std::string FormatSampleForDiagnosticOutput( 416 std::string FormatSampleForDiagnosticOutput(
416 const Sample& sample, 417 const Sample& sample,
417 const std::vector<Module>& modules) { 418 const std::vector<Module>& modules) {
418 std::string output; 419 std::string output;
419 for (const Frame& frame : sample) { 420 for (const Frame& frame : sample.frames) {
420 output += StringPrintf( 421 output += StringPrintf(
421 "0x%p %s\n", reinterpret_cast<const void*>(frame.instruction_pointer), 422 "0x%p %s\n", reinterpret_cast<const void*>(frame.instruction_pointer),
422 modules[frame.module_index].filename.AsUTF8Unsafe().c_str()); 423 modules[frame.module_index].filename.AsUTF8Unsafe().c_str());
423 } 424 }
424 return output; 425 return output;
425 } 426 }
426 427
427 // Returns a duration that is longer than the test timeout. We would use 428 // Returns a duration that is longer than the test timeout. We would use
428 // TimeDelta::Max() but https://crbug.com/465948. 429 // TimeDelta::Max() but https://crbug.com/465948.
429 TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); } 430 TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 sampling_thread_completed.Wait(); 511 sampling_thread_completed.Wait();
511 512
512 // Look up the sample. 513 // Look up the sample.
513 ASSERT_EQ(1u, profiles.size()); 514 ASSERT_EQ(1u, profiles.size());
514 const CallStackProfile& profile = profiles[0]; 515 const CallStackProfile& profile = profiles[0];
515 ASSERT_EQ(1u, profile.samples.size()); 516 ASSERT_EQ(1u, profile.samples.size());
516 const Sample& sample = profile.samples[0]; 517 const Sample& sample = profile.samples[0];
517 518
518 // Check that the stack contains a frame for 519 // Check that the stack contains a frame for
519 // TargetThread::SignalAndWaitUntilSignaled(). 520 // TargetThread::SignalAndWaitUntilSignaled().
520 Sample::const_iterator end_frame = FindFirstFrameWithinFunction( 521 Frames::const_iterator end_frame = FindFirstFrameWithinFunction(
521 sample, 522 sample,
522 &TargetThread::SignalAndWaitUntilSignaled); 523 &TargetThread::SignalAndWaitUntilSignaled);
523 ASSERT_TRUE(end_frame != sample.end()) 524 ASSERT_TRUE(end_frame != sample.frames.end())
524 << "Function at " 525 << "Function at "
525 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( 526 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
526 &TargetThread::SignalAndWaitUntilSignaled)) 527 &TargetThread::SignalAndWaitUntilSignaled))
527 << " was not found in stack:\n" 528 << " was not found in stack:\n"
528 << FormatSampleForDiagnosticOutput(sample, profile.modules); 529 << FormatSampleForDiagnosticOutput(sample, profile.modules);
529 530
530 if (wait_until_unloaded) { 531 if (wait_until_unloaded) {
531 // The stack should look like this, resulting one frame after 532 // The stack should look like this, resulting one frame after
532 // SignalAndWaitUntilSignaled. The frame in the now-unloaded library is not 533 // SignalAndWaitUntilSignaled. The frame in the now-unloaded library is not
533 // recorded since we can't get module information. 534 // recorded since we can't get module information.
534 // 535 //
535 // ... WaitableEvent and system frames ... 536 // ... WaitableEvent and system frames ...
536 // TargetThread::SignalAndWaitUntilSignaled 537 // TargetThread::SignalAndWaitUntilSignaled
537 // TargetThread::OtherLibraryCallback 538 // TargetThread::OtherLibraryCallback
538 EXPECT_EQ(2, sample.end() - end_frame) 539 EXPECT_EQ(2, sample.frames.end() - end_frame)
539 << "Stack:\n" 540 << "Stack:\n"
540 << FormatSampleForDiagnosticOutput(sample, profile.modules); 541 << FormatSampleForDiagnosticOutput(sample, profile.modules);
541 } else { 542 } else {
542 // We didn't wait for the asynchonous unloading to complete, so the results 543 // We didn't wait for the asynchonous unloading to complete, so the results
543 // are non-deterministic: if the library finished unloading we should have 544 // are non-deterministic: if the library finished unloading we should have
544 // the same stack as |wait_until_unloaded|, if not we should have the full 545 // the same stack as |wait_until_unloaded|, if not we should have the full
545 // stack. The important thing is that we should not crash. 546 // stack. The important thing is that we should not crash.
546 547
547 if ((sample.end() - 1) - end_frame == 2) { 548 if ((sample.frames.end() - 1) - end_frame == 2) {
548 // This is the same case as |wait_until_unloaded|. 549 // This is the same case as |wait_until_unloaded|.
549 return; 550 return;
550 } 551 }
551 552
552 // Check that the stack contains a frame for 553 // Check that the stack contains a frame for
553 // TargetThread::CallThroughOtherLibrary(). 554 // TargetThread::CallThroughOtherLibrary().
554 Sample::const_iterator other_library_frame = FindFirstFrameWithinFunction( 555 Frames::const_iterator other_library_frame = FindFirstFrameWithinFunction(
555 sample, 556 sample,
556 &TargetThread::CallThroughOtherLibrary); 557 &TargetThread::CallThroughOtherLibrary);
557 ASSERT_TRUE(other_library_frame != sample.end()) 558 ASSERT_TRUE(other_library_frame != sample.frames.end())
558 << "Function at " 559 << "Function at "
559 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( 560 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
560 &TargetThread::CallThroughOtherLibrary)) 561 &TargetThread::CallThroughOtherLibrary))
561 << " was not found in stack:\n" 562 << " was not found in stack:\n"
562 << FormatSampleForDiagnosticOutput(sample, profile.modules); 563 << FormatSampleForDiagnosticOutput(sample, profile.modules);
563 564
564 // The stack should look like this, resulting in three frames between 565 // The stack should look like this, resulting in three frames between
565 // SignalAndWaitUntilSignaled and CallThroughOtherLibrary: 566 // SignalAndWaitUntilSignaled and CallThroughOtherLibrary:
566 // 567 //
567 // ... WaitableEvent and system frames ... 568 // ... WaitableEvent and system frames ...
(...skipping 24 matching lines...) Expand all
592 std::vector<CallStackProfile> profiles; 593 std::vector<CallStackProfile> profiles;
593 CaptureProfiles(params, AVeryLongTimeDelta(), &profiles); 594 CaptureProfiles(params, AVeryLongTimeDelta(), &profiles);
594 595
595 // Check that the profile and samples sizes are correct, and the module 596 // Check that the profile and samples sizes are correct, and the module
596 // indices are in range. 597 // indices are in range.
597 ASSERT_EQ(1u, profiles.size()); 598 ASSERT_EQ(1u, profiles.size());
598 const CallStackProfile& profile = profiles[0]; 599 const CallStackProfile& profile = profiles[0];
599 ASSERT_EQ(1u, profile.samples.size()); 600 ASSERT_EQ(1u, profile.samples.size());
600 EXPECT_EQ(params.sampling_interval, profile.sampling_period); 601 EXPECT_EQ(params.sampling_interval, profile.sampling_period);
601 const Sample& sample = profile.samples[0]; 602 const Sample& sample = profile.samples[0];
602 for (const auto& frame : sample) { 603 for (const auto& frame : sample.frames) {
603 ASSERT_GE(frame.module_index, 0u); 604 ASSERT_GE(frame.module_index, 0u);
604 ASSERT_LT(frame.module_index, profile.modules.size()); 605 ASSERT_LT(frame.module_index, profile.modules.size());
605 } 606 }
606 607
607 // Check that the stack contains a frame for 608 // Check that the stack contains a frame for
608 // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this 609 // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this
609 // executable's module. 610 // executable's module.
610 Sample::const_iterator loc = FindFirstFrameWithinFunction( 611 Frames::const_iterator loc = FindFirstFrameWithinFunction(
611 sample, 612 sample,
612 &TargetThread::SignalAndWaitUntilSignaled); 613 &TargetThread::SignalAndWaitUntilSignaled);
613 ASSERT_TRUE(loc != sample.end()) 614 ASSERT_TRUE(loc != sample.frames.end())
614 << "Function at " 615 << "Function at "
615 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( 616 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
616 &TargetThread::SignalAndWaitUntilSignaled)) 617 &TargetThread::SignalAndWaitUntilSignaled))
617 << " was not found in stack:\n" 618 << " was not found in stack:\n"
618 << FormatSampleForDiagnosticOutput(sample, profile.modules); 619 << FormatSampleForDiagnosticOutput(sample, profile.modules);
619 FilePath executable_path; 620 FilePath executable_path;
620 EXPECT_TRUE(PathService::Get(FILE_EXE, &executable_path)); 621 EXPECT_TRUE(PathService::Get(FILE_EXE, &executable_path));
621 EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename); 622 EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename);
622 } 623 }
623 624
(...skipping 25 matching lines...) Expand all
649 StackConfiguration(StackConfiguration::WITH_ALLOCA)); 650 StackConfiguration(StackConfiguration::WITH_ALLOCA));
650 651
651 // Look up the sample. 652 // Look up the sample.
652 ASSERT_EQ(1u, profiles.size()); 653 ASSERT_EQ(1u, profiles.size());
653 const CallStackProfile& profile = profiles[0]; 654 const CallStackProfile& profile = profiles[0];
654 ASSERT_EQ(1u, profile.samples.size()); 655 ASSERT_EQ(1u, profile.samples.size());
655 const Sample& sample = profile.samples[0]; 656 const Sample& sample = profile.samples[0];
656 657
657 // Check that the stack contains a frame for 658 // Check that the stack contains a frame for
658 // TargetThread::SignalAndWaitUntilSignaled(). 659 // TargetThread::SignalAndWaitUntilSignaled().
659 Sample::const_iterator end_frame = FindFirstFrameWithinFunction( 660 Frames::const_iterator end_frame = FindFirstFrameWithinFunction(
660 sample, 661 sample,
661 &TargetThread::SignalAndWaitUntilSignaled); 662 &TargetThread::SignalAndWaitUntilSignaled);
662 ASSERT_TRUE(end_frame != sample.end()) 663 ASSERT_TRUE(end_frame != sample.frames.end())
663 << "Function at " 664 << "Function at "
664 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( 665 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
665 &TargetThread::SignalAndWaitUntilSignaled)) 666 &TargetThread::SignalAndWaitUntilSignaled))
666 << " was not found in stack:\n" 667 << " was not found in stack:\n"
667 << FormatSampleForDiagnosticOutput(sample, profile.modules); 668 << FormatSampleForDiagnosticOutput(sample, profile.modules);
668 669
669 // Check that the stack contains a frame for TargetThread::CallWithAlloca(). 670 // Check that the stack contains a frame for TargetThread::CallWithAlloca().
670 Sample::const_iterator alloca_frame = FindFirstFrameWithinFunction( 671 Frames::const_iterator alloca_frame = FindFirstFrameWithinFunction(
671 sample, 672 sample,
672 &TargetThread::CallWithAlloca); 673 &TargetThread::CallWithAlloca);
673 ASSERT_TRUE(alloca_frame != sample.end()) 674 ASSERT_TRUE(alloca_frame != sample.frames.end())
674 << "Function at " 675 << "Function at "
675 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( 676 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
676 &TargetThread::CallWithAlloca)) 677 &TargetThread::CallWithAlloca))
677 << " was not found in stack:\n" 678 << " was not found in stack:\n"
678 << FormatSampleForDiagnosticOutput(sample, profile.modules); 679 << FormatSampleForDiagnosticOutput(sample, profile.modules);
679 680
680 // These frames should be adjacent on the stack. 681 // These frames should be adjacent on the stack.
681 EXPECT_EQ(1, alloca_frame - end_frame) 682 EXPECT_EQ(1, alloca_frame - end_frame)
682 << "Stack:\n" 683 << "Stack:\n"
683 << FormatSampleForDiagnosticOutput(sample, profile.modules); 684 << FormatSampleForDiagnosticOutput(sample, profile.modules);
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
919 } 920 }
920 921
921 // Look up the sample. 922 // Look up the sample.
922 ASSERT_EQ(1u, profiles.size()); 923 ASSERT_EQ(1u, profiles.size());
923 const CallStackProfile& profile = profiles[0]; 924 const CallStackProfile& profile = profiles[0];
924 ASSERT_EQ(1u, profile.samples.size()); 925 ASSERT_EQ(1u, profile.samples.size());
925 const Sample& sample = profile.samples[0]; 926 const Sample& sample = profile.samples[0];
926 927
927 // Check that the stack contains a frame for 928 // Check that the stack contains a frame for
928 // TargetThread::CallThroughOtherLibrary(). 929 // TargetThread::CallThroughOtherLibrary().
929 Sample::const_iterator other_library_frame = FindFirstFrameWithinFunction( 930 Frames::const_iterator other_library_frame = FindFirstFrameWithinFunction(
930 sample, 931 sample,
931 &TargetThread::CallThroughOtherLibrary); 932 &TargetThread::CallThroughOtherLibrary);
932 ASSERT_TRUE(other_library_frame != sample.end()) 933 ASSERT_TRUE(other_library_frame != sample.frames.end())
933 << "Function at " 934 << "Function at "
934 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( 935 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
935 &TargetThread::CallThroughOtherLibrary)) 936 &TargetThread::CallThroughOtherLibrary))
936 << " was not found in stack:\n" 937 << " was not found in stack:\n"
937 << FormatSampleForDiagnosticOutput(sample, profile.modules); 938 << FormatSampleForDiagnosticOutput(sample, profile.modules);
938 939
939 // Check that the stack contains a frame for 940 // Check that the stack contains a frame for
940 // TargetThread::SignalAndWaitUntilSignaled(). 941 // TargetThread::SignalAndWaitUntilSignaled().
941 Sample::const_iterator end_frame = FindFirstFrameWithinFunction( 942 Frames::const_iterator end_frame = FindFirstFrameWithinFunction(
942 sample, 943 sample,
943 &TargetThread::SignalAndWaitUntilSignaled); 944 &TargetThread::SignalAndWaitUntilSignaled);
944 ASSERT_TRUE(end_frame != sample.end()) 945 ASSERT_TRUE(end_frame != sample.frames.end())
945 << "Function at " 946 << "Function at "
946 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>( 947 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
947 &TargetThread::SignalAndWaitUntilSignaled)) 948 &TargetThread::SignalAndWaitUntilSignaled))
948 << " was not found in stack:\n" 949 << " was not found in stack:\n"
949 << FormatSampleForDiagnosticOutput(sample, profile.modules); 950 << FormatSampleForDiagnosticOutput(sample, profile.modules);
950 951
951 // The stack should look like this, resulting in three frames between 952 // The stack should look like this, resulting in three frames between
952 // SignalAndWaitUntilSignaled and CallThroughOtherLibrary: 953 // SignalAndWaitUntilSignaled and CallThroughOtherLibrary:
953 // 954 //
954 // ... WaitableEvent and system frames ... 955 // ... WaitableEvent and system frames ...
(...skipping 21 matching lines...) Expand all
976 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED) 977 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
977 #define MAYBE_UnloadedLibrary UnloadedLibrary 978 #define MAYBE_UnloadedLibrary UnloadedLibrary
978 #else 979 #else
979 #define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary 980 #define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
980 #endif 981 #endif
981 TEST(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) { 982 TEST(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) {
982 TestLibraryUnload(true); 983 TestLibraryUnload(true);
983 } 984 }
984 985
985 } // namespace base 986 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698