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