1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/logging.h" 6 #include "base/test/test_timeouts.h" 7 #include "base/win/sampling_profiler.h" 8 #include "base/win/pe_image.h" 9 #include "base/win/scoped_handle.h" 10 #include "base/win/windows_version.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 // The address of our image base. 14 extern "C" IMAGE_DOS_HEADER __ImageBase; 15 16 namespace base { 17 namespace win { 18 19 namespace { 20 21 class SamplingProfilerTest : public testing::Test { 22 public: 23 SamplingProfilerTest() : code_start(NULL), code_size(0) { 24 } 25 26 virtual void SetUp() { 27 process.Set(::OpenProcess(PROCESS_QUERY_INFORMATION, 28 FALSE, 29 ::GetCurrentProcessId())); 30 ASSERT_TRUE(process.IsValid()); 31 32 PEImage image(&__ImageBase); 33 34 // Get the address of the .text section, which is the first section output 35 // by the VS tools. 36 ASSERT_TRUE(image.GetNumSections() > 0); 37 const IMAGE_SECTION_HEADER* text_section = image.GetSectionHeader(0); 38 ASSERT_EQ(0, strncmp(".text", 39 reinterpret_cast<const char*>(text_section->Name), 40 arraysize(text_section->Name))); 41 ASSERT_NE(0U, text_section->Characteristics & IMAGE_SCN_MEM_EXECUTE); 42 43 code_start = reinterpret_cast<uint8*>(&__ImageBase) + 44 text_section->VirtualAddress; 45 code_size = text_section->Misc.VirtualSize; 46 } 47 48 protected: 49 ScopedHandle process; 50 void* code_start; 51 size_t code_size; 52 }; 53 54 } // namespace 55 56 TEST_F(SamplingProfilerTest, Initialize) { 57 SamplingProfiler profiler; 58 59 ASSERT_TRUE(profiler.Initialize(process.Get(), code_start, code_size, 8)); 60 } 61 62 TEST_F(SamplingProfilerTest, Sample) { 63 if (base::win::GetVersion() == base::win::VERSION_WIN8) { 64 LOG(INFO) << "Not running test on Windows 8"; 65 return; 66 } 67 SamplingProfiler profiler; 68 69 // Initialize with a huge bucket size, aiming for a single bucket. 70 ASSERT_TRUE( 71 profiler.Initialize(process.Get(), code_start, code_size, 31)); 72 73 ASSERT_EQ(1, profiler.buckets().size()); 74 ASSERT_EQ(0, profiler.buckets()[0]); 75 76 // We use a roomy timeout to make sure this test is not flaky. 77 // On the buildbots, there may not be a whole lot of CPU time 78 // allotted to our process in this wall-clock time duration, 79 // and samples will only accrue while this thread is busy on 80 // a CPU core. 81 base::TimeDelta spin_time = TestTimeouts::action_timeout(); 82 83 base::TimeDelta save_sampling_interval; 84 ASSERT_TRUE(SamplingProfiler::GetSamplingInterval(&save_sampling_interval)); 85 86 // Sample every 0.5 millisecs. 87 ASSERT_TRUE(SamplingProfiler::SetSamplingInterval( 88 base::TimeDelta::FromMicroseconds(500))); 89 90 ASSERT_TRUE(SamplingProfiler::SetSamplingInterval( 91 base::TimeDelta::FromMicroseconds(500))); 92 93 // Start the profiler. 94 ASSERT_TRUE(profiler.Start()); 95 96 // Get a volatile pointer to our bucket to make sure that the compiler 97 // doesn't optimize out the test in the loop that follows. 98 volatile const ULONG* bucket_ptr = &profiler.buckets()[0]; 99 100 // Spin for spin_time wall-clock seconds, or until we get some samples. 101 // Note that sleeping isn't going to do us any good, the samples only 102 // accrue while we're executing code. 103 base::Time start = base::Time::Now(); 104 base::TimeDelta elapsed; 105 do { 106 elapsed = base::Time::Now() - start; 107 } while((elapsed < spin_time) && *bucket_ptr == 0); 108 109 // Stop the profiler. 110 ASSERT_TRUE(profiler.Stop()); 111 112 // Restore the sampling interval we found. 113 ASSERT_TRUE(SamplingProfiler::SetSamplingInterval(save_sampling_interval)); 114 115 // Check that we got some samples. 116 ASSERT_NE(0U, profiler.buckets()[0]); 117 } 118 119 } // namespace win 120 } // namespace base 121