gem5  [DEVELOP-FOR-23.0]
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
proxy_ptr.test.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Google, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met: redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer;
8  * redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution;
11  * neither the name of the copyright holders nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <gtest/gtest.h>
29 
30 #include <vector>
31 
32 #include "sim/proxy_ptr.hh"
33 
34 using namespace gem5;
35 
36 struct Access
37 {
38  bool read;
41 
42  Access(bool _read, Addr _addr, Addr _size) :
43  read(_read), addr(_addr), size(_size)
44  {}
45 
46  bool
47  operator == (const Access &other) const
48  {
49  return read == other.read &&
50  addr == other.addr &&
51  size == other.size;
52  }
53 
54  bool
55  operator != (const Access &other) const
56  {
57  return !(*this == other);
58  }
59 };
60 
62 
64 {
65  public:
68 
69  BackingStore(Addr _base, size_t _size) : store(_size, 0), base(_base) {}
70 
71  void
73  {
74  panic_if(addr < base || addr + size > base + store.size(),
75  "Range [%#x,%#x) outside of [%#x,%#x).",
76  addr, addr + size, base, base + store.size());
77  }
78 
79  mutable Accesses accesses;
80 
81  ::testing::AssertionResult
82  expect_access(size_t idx, const Access &other) const
83  {
84  if (idx >= accesses.size()) {
85  return ::testing::AssertionFailure() << "index " << idx <<
86  " out of bounds";
87  }
88 
89  if (accesses[idx] != other) {
90  return ::testing::AssertionFailure() << "access[" << idx <<
91  "] was " << accesses[idx] << ", expected " << other;
92  }
93  return ::testing::AssertionSuccess();
94  }
95 
96  ::testing::AssertionResult
98  {
99  if (accesses.size() != expected.size()) {
100  return ::testing::AssertionFailure() <<
101  "Wrong number of accesses, was " << accesses.size() <<
102  " expected " << expected.size();
103  }
104 
105  auto failure = ::testing::AssertionFailure();
106  bool success = true;
107  if (accesses.size() == expected.size()) {
108  for (size_t idx = 0; idx < expected.size(); idx++) {
109  auto result = expect_access(idx, expected[idx]);
110  if (!result) {
111  failure << result.message();
112  success = false;
113  }
114  }
115  }
116 
117  if (!success)
118  return failure;
119  else
120  return ::testing::AssertionSuccess();
121  }
122 
123  void
124  writeBlob(Addr ptr, const void *data, int size)
125  {
126  rangeCheck(ptr, size);
127  accesses.emplace_back(false, ptr, size);
128  memcpy(store.data() + (ptr - base), data, size);
129  }
130 
131  void
132  readBlob(Addr ptr, void *data, int size)
133  {
134  rangeCheck(ptr, size);
135  accesses.emplace_back(true, ptr, size);
136  memcpy(data, store.data() + (ptr - base), size);
137  }
138 };
139 
140 ::testing::AssertionResult
141 accessed(const char *expr1, const char *expr2,
142  const BackingStore &store, const Accesses &expected)
143 {
144  return store.expect_accesses(expected);
145 }
146 
147 #define EXPECT_ACCESSES(store, ...) \
148  do { \
149  Accesses expected({__VA_ARGS__}); \
150  EXPECT_PRED_FORMAT2(accessed, store, expected); \
151  store.accesses.clear(); \
152  } while (false)
153 
154 std::ostream &
155 operator << (std::ostream &os, const Access &access)
156 {
157  ccprintf(os, "%s(%#x, %d)", access.read ? "read" : "write",
158  access.addr, access.size);
159  return os;
160 }
161 
163 {
164  public:
166 
167  TestProxy(BackingStore &_store) : store(_store) {}
168  // Sneaky constructor for testing guest_abi integration.
169  TestProxy(ThreadContext *tc) : store(*(BackingStore *)tc) {}
170 
171  void
172  writeBlob(Addr ptr, const void *data, int size)
173  {
174  store.writeBlob(ptr, data, size);
175  }
176 
177  void
178  readBlob(Addr ptr, void *data, int size)
179  {
180  store.readBlob(ptr, data, size);
181  }
182 };
183 
184 template <typename T>
186 
187 template <typename T>
189 
190 TEST(ProxyPtr, Clean)
191 {
192  BackingStore store(0x1000, 0x1000);
193 
194  EXPECT_ACCESSES(store);
195 
196  {
197  ConstTestPtr<uint32_t> test_ptr(0x1100, store);
198 
199  EXPECT_ACCESSES(store, { true, test_ptr.addr(), sizeof(uint32_t) });
200  }
201 
202  EXPECT_ACCESSES(store);
203 
204  {
205  TestPtr<uint32_t> test_ptr(0x1100, store);
206 
207  EXPECT_ACCESSES(store, { true, test_ptr.addr(), sizeof(uint32_t) });
208  }
209 
210  EXPECT_ACCESSES(store);
211 }
212 
213 TEST(ProxyPtr, Dirty)
214 {
215  BackingStore store(0x1000, 0x1100);
216 
217  EXPECT_ACCESSES(store);
218 
219  {
220  TestPtr<uint32_t> test_ptr(0x1100, store);
221 
222  *test_ptr = 0xa5a5a5a5;
223 
224  EXPECT_ACCESSES(store, { true, test_ptr.addr(), sizeof(uint32_t) });
225  }
226 
227  EXPECT_ACCESSES(store, { false, 0x1100, sizeof(uint32_t) });
228  EXPECT_EQ(store.store[0x100], 0xa5);
229  EXPECT_EQ(store.store[0x101], 0xa5);
230  EXPECT_EQ(store.store[0x102], 0xa5);
231  EXPECT_EQ(store.store[0x103], 0xa5);
232 }
233 
234 
235 TEST(ProxyPtr, LoadAndFlush)
236 {
237  BackingStore store(0x1000, 0x1100);
238 
239  store.store[0x100] = 0xa5;
240  store.store[0x101] = 0xa5;
241  store.store[0x102] = 0xa5;
242  store.store[0x103] = 0xa5;
243 
244  TestPtr<uint32_t> test_ptr(0x1100, store);
245 
246  // Check that the backing store is unmodified.
247  EXPECT_EQ(store.store[0x100], 0xa5);
248  EXPECT_EQ(store.store[0x101], 0xa5);
249  EXPECT_EQ(store.store[0x102], 0xa5);
250  EXPECT_EQ(store.store[0x103], 0xa5);
251 
252  // Change the value in our local buffered copy.
253  *test_ptr = 0x5a5a5a5a;
254 
255  // Verify that the backing store hasn't been changed.
256  EXPECT_EQ(store.store[0x100], 0xa5);
257  EXPECT_EQ(store.store[0x101], 0xa5);
258  EXPECT_EQ(store.store[0x102], 0xa5);
259  EXPECT_EQ(store.store[0x103], 0xa5);
260 
261  // Flush out our modifications.
262  test_ptr.flush();
263 
264  // Verify that they've been written back to the store.
265  EXPECT_EQ(store.store[0x100], 0x5a);
266  EXPECT_EQ(store.store[0x101], 0x5a);
267  EXPECT_EQ(store.store[0x102], 0x5a);
268  EXPECT_EQ(store.store[0x103], 0x5a);
269 
270  // Update the store and try to flush again.
271  store.store[0x100] = 0xaa;
272  test_ptr.flush();
273 
274  // Verify that no flush happened, since our ptr was "clean".
275  EXPECT_EQ(store.store[0x100], 0xaa);
276 
277  // Force a flush.
278  test_ptr.flush(true);
279 
280  // Verify that the flush happened even though the ptr was "clean".
281  EXPECT_EQ(store.store[0x100], 0x5a);
282 
283  // Update the store.
284  store.store[0x100] = 0xa5;
285  store.store[0x101] = 0xa5;
286  store.store[0x102] = 0xa5;
287  store.store[0x103] = 0xa5;
288 
289  // Verify that our local copy hasn't changed.
290  EXPECT_EQ(*(const uint32_t *)test_ptr, 0x5a5a5a5a);
291 
292  // Reload the pointer from the store.
293  test_ptr.load();
294  EXPECT_EQ(*(const uint32_t *)test_ptr, 0xa5a5a5a5);
295 }
296 
297 TEST(ProxyPtr, ConstOperators)
298 {
299  bool is_same;
300 
301  BackingStore store(0x1000, 0x1000);
302 
303  const Addr addr1 = 0x1100;
304  const Addr addr2 = 0x1200;
305 
306  using PtrType = uint32_t;
307 
308  ConstTestPtr<PtrType> test_ptr1(addr1, store);
309  EXPECT_EQ(test_ptr1.addr(), addr1);
310 
311  ConstTestPtr<PtrType> test_ptr2(addr2, store);
312  EXPECT_EQ(test_ptr2.addr(), addr2);
313 
314  // Pointer +/- integer.
315  auto next_ptr = test_ptr1 + 2;
316  EXPECT_EQ(next_ptr.addr(), addr1 + 2 * sizeof(PtrType));
317 
318  auto reverse_next_ptr = 2 + test_ptr1;
319  EXPECT_EQ(reverse_next_ptr.addr(), addr1 + 2 * sizeof(PtrType));
320 
321  auto prev_ptr = test_ptr1 - 2;
322  EXPECT_EQ(prev_ptr.addr(), addr1 - 2 * sizeof(PtrType));
323 
324  // Pointer-pointer subtraction.
325  auto diff = test_ptr2 - test_ptr1;
326  EXPECT_EQ(diff, (addr2 - addr1) / sizeof(PtrType));
327 
328  // Assignment.
329  ConstTestPtr<PtrType> target(addr2, store);
330  EXPECT_EQ(target.addr(), addr2);
331 
332  target = test_ptr1;
333  EXPECT_EQ(target.addr(), addr1);
334 
335  // Conversions.
336  EXPECT_TRUE(test_ptr1);
337  ConstTestPtr<PtrType> null(0, store);
338  EXPECT_FALSE(null);
339 
340  EXPECT_NE((const PtrType *)test_ptr1, nullptr);
341  EXPECT_EQ((const PtrType *)null, nullptr);
342 
343  // Dereferences.
344  is_same = std::is_same_v<decltype(*test_ptr1), const PtrType &>;
345  EXPECT_TRUE(is_same);
346 
347  store.store[0x100] = 0x55;
348  store.store[0x101] = 0x55;
349  store.store[0x102] = 0x55;
350  store.store[0x103] = 0x55;
351 
352  // Force an update since we changed the backing store behind our ptrs back.
353  test_ptr1.load();
354 
355  EXPECT_EQ(*test_ptr1, 0x55555555);
356 
357  store.store[0x100] = 0x11;
358  store.store[0x101] = 0x22;
359  store.store[0x102] = 0x33;
360  store.store[0x103] = 0x44;
361 
362  struct TestStruct
363  {
364  uint8_t a;
365  uint8_t b;
366  uint8_t c;
367  uint8_t d;
368  };
369 
370  ConstTestPtr<TestStruct> struct_ptr(addr1, store);
371  EXPECT_EQ(struct_ptr->a, 0x11);
372  EXPECT_EQ(struct_ptr->b, 0x22);
373  EXPECT_EQ(struct_ptr->c, 0x33);
374  EXPECT_EQ(struct_ptr->d, 0x44);
375 
376  is_same = std::is_same_v<decltype((struct_ptr->a)), const uint8_t &>;
377  EXPECT_TRUE(is_same);
378 }
379 
380 TEST(ProxyPtr, NonConstOperators)
381 {
382  bool is_same;
383 
384  BackingStore store(0x1000, 0x1000);
385 
386  const Addr addr1 = 0x1100;
387  const Addr addr2 = 0x1200;
388 
389  using PtrType = uint32_t;
390 
391  TestPtr<PtrType> test_ptr1(addr1, store);
392  EXPECT_EQ(test_ptr1.addr(), addr1);
393 
394  TestPtr<PtrType> test_ptr2(addr2, store);
395  EXPECT_EQ(test_ptr2.addr(), addr2);
396 
397  // Pointer +/- integer.
398  auto next_ptr = test_ptr1 + 2;
399  EXPECT_EQ(next_ptr.addr(), addr1 + 2 * sizeof(PtrType));
400 
401  auto reverse_next_ptr = 2 + test_ptr1;
402  EXPECT_EQ(reverse_next_ptr.addr(), addr1 + 2 * sizeof(PtrType));
403 
404  auto prev_ptr = test_ptr1 - 2;
405  EXPECT_EQ(prev_ptr.addr(), addr1 - 2 * sizeof(PtrType));
406 
407  // Pointer-pointer subtraction.
408  auto diff = test_ptr2 - test_ptr1;
409  EXPECT_EQ(diff, (addr2 - addr1) / sizeof(PtrType));
410 
411  // Assignment.
412  TestPtr<PtrType> target(addr2, store);
413  EXPECT_EQ(target.addr(), addr2);
414 
415  target = test_ptr1;
416  EXPECT_EQ(target.addr(), addr1);
417 
418  // Conversions.
419  EXPECT_TRUE(test_ptr1);
420  TestPtr<PtrType> null(0, store);
421  EXPECT_FALSE(null);
422 
423  EXPECT_NE((PtrType *)test_ptr1, nullptr);
424  EXPECT_EQ((PtrType *)null, nullptr);
425  EXPECT_NE((const PtrType *)test_ptr1, nullptr);
426  EXPECT_EQ((const PtrType *)null, nullptr);
427 
428  // Dereferences.
429  is_same = std::is_same_v<decltype(*test_ptr1), PtrType &>;
430  EXPECT_TRUE(is_same);
431 
432  // Flush test_ptr1, which has been conservatively marked as dirty.
433  test_ptr1.flush();
434 
435  store.store[0x100] = 0x55;
436  store.store[0x101] = 0x55;
437  store.store[0x102] = 0x55;
438  store.store[0x103] = 0x55;
439 
440  // Force an update since we changed the backing store behind our ptrs back.
441  test_ptr1.load();
442 
443  EXPECT_EQ(*test_ptr1, 0x55555555);
444 
445  store.store[0x100] = 0x11;
446  store.store[0x101] = 0x22;
447  store.store[0x102] = 0x33;
448  store.store[0x103] = 0x44;
449 
450  struct TestStruct
451  {
452  uint8_t a;
453  uint8_t b;
454  uint8_t c;
455  uint8_t d;
456  };
457 
458  TestPtr<TestStruct> struct_ptr(addr1, store);
459  EXPECT_EQ(struct_ptr->a, 0x11);
460  EXPECT_EQ(struct_ptr->b, 0x22);
461  EXPECT_EQ(struct_ptr->c, 0x33);
462  EXPECT_EQ(struct_ptr->d, 0x44);
463 
464  is_same = std::is_same_v<decltype((struct_ptr->a)), uint8_t &>;
465  EXPECT_TRUE(is_same);
466 }
467 
468 struct TestABI
469 {
470  using UintPtr = uint64_t;
471  using State = int;
472 };
473 
474 namespace gem5
475 {
476 
477 namespace guest_abi
478 {
479 
480 template <>
482 {
483  static Addr
485  {
486  return 0x1000;
487  }
488 };
489 
490 } // namespace guest_abi
491 } // namespace gem5
492 
493 bool abiCalled = false;
494 bool abiCalledConst = false;
495 
496 void
498 {
499  abiCalled = true;
500  EXPECT_EQ(ptr.addr(), 0x1000);
501 }
502 
503 void
505 {
506  abiCalledConst = true;
507  EXPECT_EQ(ptr.addr(), 0x1000);
508 }
509 
510 TEST(ProxyPtrTest, GuestABI)
511 {
512  BackingStore store(0x1000, 0x1000);
513 
514  EXPECT_FALSE(abiCalled);
515  EXPECT_FALSE(abiCalledConst);
516 
517  invokeSimcall<TestABI>((ThreadContext *)&store, abiTestFunc);
518 
519  EXPECT_TRUE(abiCalled);
520  EXPECT_FALSE(abiCalledConst);
521 
522  invokeSimcall<TestABI>((ThreadContext *)&store, abiTestFuncConst);
523 
524  EXPECT_TRUE(abiCalled);
525  EXPECT_TRUE(abiCalledConst);
526 }
gem5::ConstProxyPtr::addr
Addr addr() const
Definition: proxy_ptr.hh:173
TEST
TEST(ProxyPtr, Clean)
Definition: proxy_ptr.test.cc:190
gem5::ConstProxyPtr
Definition: proxy_ptr.hh:109
TestProxy::readBlob
void readBlob(Addr ptr, void *data, int size)
Definition: proxy_ptr.test.cc:178
TestABI::UintPtr
uint64_t UintPtr
Definition: proxy_ptr.test.cc:470
data
const char data[]
Definition: circlebuf.test.cc:48
BackingStore::expect_access
::testing::AssertionResult expect_access(size_t idx, const Access &other) const
Definition: proxy_ptr.test.cc:82
BackingStore
Definition: proxy_ptr.test.cc:63
Access::Access
Access(bool _read, Addr _addr, Addr _size)
Definition: proxy_ptr.test.cc:42
gem5::operator<<
static std::ostream & operator<<(std::ostream &os, const DummyMatRegContainer &d)
Definition: matrix.hh:564
gem5::ArmISA::a
Bitfield< 8 > a
Definition: misc_types.hh:66
BackingStore::expect_accesses
::testing::AssertionResult expect_accesses(Accesses expected) const
Definition: proxy_ptr.test.cc:97
BackingStore::BackingStore
BackingStore(Addr _base, size_t _size)
Definition: proxy_ptr.test.cc:69
std::vector< Access >
proxy_ptr.hh
gem5::X86ISA::base
Bitfield< 51, 12 > base
Definition: pagetable.hh:141
TestProxy::TestProxy
TestProxy(BackingStore &_store)
Definition: proxy_ptr.test.cc:167
TestProxy::store
BackingStore & store
Definition: proxy_ptr.test.cc:165
gem5::ccprintf
void ccprintf(cp::Print &print)
Definition: cprintf.hh:130
Access
Definition: proxy_ptr.test.cc:36
gem5::VegaISA::c
Bitfield< 2 > c
Definition: pagetable.hh:63
BackingStore::writeBlob
void writeBlob(Addr ptr, const void *data, int size)
Definition: proxy_ptr.test.cc:124
gem5::ArmISA::b
Bitfield< 7 > b
Definition: misc_types.hh:438
gem5::ThreadContext
ThreadContext is the external interface to all thread state for anything outside of the CPU.
Definition: thread_context.hh:88
gem5::ArmISA::d
Bitfield< 9 > d
Definition: misc_types.hh:64
TestProxy::TestProxy
TestProxy(ThreadContext *tc)
Definition: proxy_ptr.test.cc:169
BackingStore::accesses
Accesses accesses
Definition: proxy_ptr.test.cc:79
gem5::ProxyPtr
Definition: proxy_ptr.hh:238
gem5::guest_abi::Argument< TestABI, Addr >::get
static Addr get(ThreadContext *tc, typename TestABI::State &state)
Definition: proxy_ptr.test.cc:484
EXPECT_ACCESSES
#define EXPECT_ACCESSES(store,...)
Definition: proxy_ptr.test.cc:147
gem5::Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
gem5::ProxyPtr::flush
void flush(bool force=false)
Definition: proxy_ptr.hh:265
abiTestFuncConst
void abiTestFuncConst(ThreadContext *tc, ConstTestPtr< uint8_t > ptr)
Definition: proxy_ptr.test.cc:504
Access::addr
Addr addr
Definition: proxy_ptr.test.cc:39
TestProxy::writeBlob
void writeBlob(Addr ptr, const void *data, int size)
Definition: proxy_ptr.test.cc:172
abiTestFunc
void abiTestFunc(ThreadContext *tc, TestPtr< uint8_t > ptr)
Definition: proxy_ptr.test.cc:497
state
atomic_var_t state
Definition: helpers.cc:188
panic_if
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:214
TestABI::State
int State
Definition: proxy_ptr.test.cc:471
abiCalled
bool abiCalled
Definition: proxy_ptr.test.cc:493
gem5::X86ISA::os
Bitfield< 17 > os
Definition: misc.hh:810
Access::size
Addr size
Definition: proxy_ptr.test.cc:40
gem5::operator==
static bool operator==(const PCStateBase &a, const PCStateBase &b)
Definition: pcstate.hh:155
TestProxy
Definition: proxy_ptr.test.cc:162
accessed
::testing::AssertionResult accessed(const char *expr1, const char *expr2, const BackingStore &store, const Accesses &expected)
Definition: proxy_ptr.test.cc:141
gem5::guest_abi::Argument
Definition: definition.hh:98
BackingStore::store
std::vector< uint8_t > store
Definition: proxy_ptr.test.cc:66
Access::read
bool read
Definition: proxy_ptr.test.cc:38
BackingStore::readBlob
void readBlob(Addr ptr, void *data, int size)
Definition: proxy_ptr.test.cc:132
TestABI
Definition: proxy_ptr.test.cc:468
abiCalledConst
bool abiCalledConst
Definition: proxy_ptr.test.cc:494
BackingStore::base
Addr base
Definition: proxy_ptr.test.cc:67
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: gpu_translation_state.hh:37
gem5::operator!=
static bool operator!=(const PCStateBase &a, const PCStateBase &b)
Definition: pcstate.hh:161
BackingStore::rangeCheck
void rangeCheck(Addr addr, Addr size)
Definition: proxy_ptr.test.cc:72
expected
std::vector< SwitchingFiber * > expected({ &a, &b, &a, &a, &a, &b, &c, &a, &c, &c, &c })
gem5::X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:84

Generated on Sun Jul 30 2023 01:56:59 for gem5 by doxygen 1.8.17