1 : // Copyright 2013 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/trace/service/mapped_buffer.h"
16 :
17 : #include "gtest/gtest.h"
18 : #include "syzygy/trace/service/buffer_consumer.h"
19 : #include "syzygy/trace/service/buffer_pool.h"
20 : #include "syzygy/trace/service/service.h"
21 : #include "syzygy/trace/service/session.h"
22 :
23 : namespace trace {
24 : namespace service {
25 :
26 : namespace {
27 :
28 : // A dummy buffer consumer for use with our dummy session.
29 : class DummyBufferConsumer : public BufferConsumer {
30 : public:
31 i : virtual ~DummyBufferConsumer() { }
32 i : virtual bool Open(Session* session) OVERRIDE { return true; }
33 i : virtual bool Close(Session* session) OVERRIDE { return true; }
34 i : virtual bool ConsumeBuffer(Buffer* buffer) OVERRIDE { return true; }
35 i : virtual size_t block_size() const OVERRIDE { return 1024; }
36 : };
37 :
38 : // A factory for producing DummyBufferConsumer instances.
39 : class DummyBufferConsumerFactory : public BufferConsumerFactory {
40 : public:
41 : virtual bool CreateConsumer(
42 i : scoped_refptr<BufferConsumer>* consumer) OVERRIDE {
43 i : *consumer = new DummyBufferConsumer();
44 i : return true;
45 i : }
46 : };
47 :
48 : class MappedBufferTest : public testing::Test {
49 : public:
50 : // This needs to be <= the system allocation granularity (which is 64kb).
51 : static const size_t kBufferSize = 4096;
52 :
53 E : MappedBufferTest() : b1(NULL), b2(NULL) {
54 E : SYSTEM_INFO sys_info = {};
55 E : ::GetSystemInfo(&sys_info);
56 E : DCHECK_LT(kBufferSize, sys_info.dwAllocationGranularity);
57 E : }
58 :
59 E : virtual void SetUp() OVERRIDE {
60 E : service.reset(new Service(&dummy_buffer_consumer_factory));
61 E : session = new Session(service.get());
62 :
63 E : pool.reset(new BufferPool());
64 E : ASSERT_TRUE(pool->Init(session.get(), 2, kBufferSize));
65 :
66 E : b1 = pool->begin();
67 E : b2 = b1 + 1;
68 E : ASSERT_EQ(2, pool->end() - pool->begin());
69 E : }
70 :
71 E : virtual void TearDown() OVERRIDE {
72 E : b1 = NULL;
73 E : b2 = NULL;
74 :
75 E : pool.reset();
76 E : session = NULL;
77 E : service.reset();
78 E : }
79 :
80 : // These are needed because they are all injected dependencies of each other,
81 : // and ultimately a session is an injected dependency of a BufferPool.
82 : // However, I don't need them to be actually running as MappedBuffer
83 : // interaction with BufferPool is limited to the memory mapped file handle.
84 : DummyBufferConsumerFactory dummy_buffer_consumer_factory;
85 : scoped_ptr<Service> service;
86 : scoped_refptr<Session> session;
87 : scoped_ptr<BufferPool> pool;
88 : Buffer* b1;
89 : Buffer* b2;
90 : };
91 :
92 : // A simple wrapper that exposes the innards of a mapped buffer.
93 : class TestMappedBuffer : public MappedBuffer {
94 : public:
95 E : explicit TestMappedBuffer(Buffer* buffer) : MappedBuffer(buffer) { }
96 E : Buffer* buffer() const { return buffer_; }
97 E : uint8* base() const { return base_; }
98 : };
99 :
100 : } // namespace
101 :
102 E : TEST_F(MappedBufferTest, MapAndUnmap) {
103 E : TestMappedBuffer mb(b1);
104 E : EXPECT_EQ(b1, mb.buffer());
105 E : EXPECT_TRUE(mb.base() == NULL);
106 E : EXPECT_TRUE(mb.data() == NULL);
107 E : EXPECT_FALSE(mb.IsMapped());
108 :
109 : // Do a no-op unmap.
110 E : EXPECT_TRUE(mb.Unmap());
111 E : EXPECT_EQ(b1, mb.buffer());
112 E : EXPECT_TRUE(mb.base() == NULL);
113 E : EXPECT_TRUE(mb.data() == NULL);
114 E : EXPECT_FALSE(mb.IsMapped());
115 :
116 : // Map the buffer.
117 E : EXPECT_TRUE(mb.Map());
118 E : EXPECT_EQ(b1, mb.buffer());
119 E : EXPECT_TRUE(mb.base() != NULL);
120 E : EXPECT_TRUE(mb.data() != NULL);
121 E : EXPECT_EQ(mb.base(), mb.data());
122 E : EXPECT_TRUE(mb.IsMapped());
123 E : uint8* base = mb.base();
124 E : uint8* data = mb.data();
125 :
126 : // Do a no-op map.
127 E : EXPECT_TRUE(mb.Map());
128 E : EXPECT_EQ(b1, mb.buffer());
129 E : EXPECT_TRUE(mb.base() != NULL);
130 E : EXPECT_TRUE(mb.data() != NULL);
131 E : EXPECT_EQ(mb.base(), mb.data());
132 E : EXPECT_EQ(base, mb.base());
133 E : EXPECT_EQ(data, mb.data());
134 E : EXPECT_TRUE(mb.IsMapped());
135 :
136 : // Unmap the buffer.
137 E : EXPECT_TRUE(mb.Unmap());
138 E : EXPECT_EQ(b1, mb.buffer());
139 E : EXPECT_TRUE(mb.base() == NULL);
140 E : EXPECT_TRUE(mb.data() == NULL);
141 E : EXPECT_FALSE(mb.IsMapped());
142 E : }
143 :
144 E : TEST_F(MappedBufferTest, AlignmentCalculationIsCorrect) {
145 E : TestMappedBuffer mb(b2);
146 :
147 : // Map the buffer.
148 E : EXPECT_TRUE(mb.Map());
149 E : EXPECT_TRUE(mb.base() != NULL);
150 E : EXPECT_TRUE(mb.data() != NULL);
151 E : EXPECT_EQ(mb.data(), mb.base() + kBufferSize);
152 E : }
153 :
154 E : TEST_F(MappedBufferTest, MappedViewIsReaped) {
155 E : MEMORY_BASIC_INFORMATION info = {};
156 E : SIZE_T ret = 0;
157 E : uint8* base = NULL;
158 :
159 : {
160 E : TestMappedBuffer mb(b1);
161 E : mb.Map();
162 E : base = mb.base();
163 E : EXPECT_TRUE(base != NULL);
164 E : ret = ::VirtualQuery(base, &info, sizeof(info));
165 E : EXPECT_EQ(sizeof(info), ret);
166 E : EXPECT_EQ(base, info.BaseAddress);
167 E : EXPECT_LE(kBufferSize, info.RegionSize);
168 E : EXPECT_EQ(MEM_MAPPED, info.Type);
169 :
170 : // Test that the mapping is reaped when unmap is explicitly called.
171 E : mb.Unmap();
172 E : ret = ::VirtualQuery(base, &info, sizeof(info));
173 E : EXPECT_EQ(sizeof(info), ret);
174 E : EXPECT_EQ(MEM_FREE, info.State);
175 :
176 E : mb.Map();
177 E : base = mb.base();
178 E : EXPECT_TRUE(base != NULL);
179 E : ret = ::VirtualQuery(base, &info, sizeof(info));
180 E : EXPECT_EQ(sizeof(info), ret);
181 E : EXPECT_EQ(base, info.BaseAddress);
182 E : EXPECT_LE(kBufferSize, info.RegionSize);
183 E : EXPECT_EQ(MEM_MAPPED, info.Type);
184 E : }
185 :
186 : // And also make sure it is reaped when the object goes out of scope.
187 E : ret = ::VirtualQuery(base, &info, sizeof(info));
188 E : EXPECT_EQ(sizeof(info), ret);
189 E : EXPECT_EQ(MEM_FREE, info.State);
190 E : }
191 :
192 : } // namespace service
193 : } // namespace trace
|