• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium Authors
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 "partition_alloc/starscan/scan_loop.h"
6 
7 #include "build/build_config.h"
8 #include "partition_alloc/partition_alloc_base/cpu.h"
9 #include "partition_alloc/partition_alloc_buildflags.h"
10 #include "partition_alloc/partition_alloc_config.h"
11 
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 #if BUILDFLAG(HAS_64_BIT_POINTERS)
15 
16 namespace partition_alloc::internal {
17 
18 namespace {
19 
20 class TestScanLoop final : public ScanLoop<TestScanLoop> {
21   friend class ScanLoop<TestScanLoop>;
22 
23  public:
TestScanLoop(SimdSupport ss)24   explicit TestScanLoop(SimdSupport ss) : ScanLoop(ss) {}
25 
visited() const26   size_t visited() const { return visited_; }
27 
Reset()28   void Reset() { visited_ = 0; }
29 
30  private:
31   static constexpr uintptr_t kRegularPoolMask = 0xffffff0000000000;
32   static constexpr uintptr_t kBasePtr = 0x0000560000000000;
33 
RegularPoolBase()34   static uintptr_t RegularPoolBase() { return kBasePtr; }
RegularPoolMask()35   static uintptr_t RegularPoolMask() { return kRegularPoolMask; }
36 
CheckPointer(uintptr_t maybe_ptr)37   void CheckPointer(uintptr_t maybe_ptr) { ++visited_; }
38 
39   size_t visited_ = 0;
40 };
41 
42 static constexpr uintptr_t kValidPtr = 0x000056789abcdef0;
43 static constexpr uintptr_t kInvalidPtr = 0x0000aaaaaaaaaaaa;
44 static constexpr uintptr_t kZeroPtr = 0x0;
45 
46 // Tests all possible compbinations of incoming args.
47 template <size_t Alignment, typename... Args>
TestOnRangeWithAlignment(TestScanLoop & sl,size_t expected_visited,Args...args)48 void TestOnRangeWithAlignment(TestScanLoop& sl,
49                               size_t expected_visited,
50                               Args... args) {
51   alignas(Alignment) uintptr_t range[] = {args...};
52   std::sort(std::begin(range), std::end(range));
53   do {
54     sl.Run(reinterpret_cast<uintptr_t>(std::begin(range)),
55            reinterpret_cast<uintptr_t>(std::end(range)));
56     EXPECT_EQ(expected_visited, sl.visited());
57     sl.Reset();
58   } while (std::next_permutation(std::begin(range), std::end(range)));
59 }
60 
61 }  // namespace
62 
TEST(PartitionAllocScanLoopTest,UnvectorizedWithRegularPool)63 TEST(PartitionAllocScanLoopTest, UnvectorizedWithRegularPool) {
64   {
65     TestScanLoop sl(SimdSupport::kUnvectorized);
66     TestOnRangeWithAlignment<8>(sl, 0u, kInvalidPtr, kInvalidPtr, kInvalidPtr);
67   }
68   {
69     TestScanLoop sl(SimdSupport::kUnvectorized);
70     TestOnRangeWithAlignment<8>(sl, 1u, kValidPtr, kInvalidPtr, kInvalidPtr);
71   }
72   {
73     TestScanLoop sl(SimdSupport::kUnvectorized);
74     TestOnRangeWithAlignment<8>(sl, 2u, kValidPtr, kValidPtr, kInvalidPtr);
75   }
76   {
77     // Make sure zeros are skipped.
78     TestScanLoop sl(SimdSupport::kUnvectorized);
79     TestOnRangeWithAlignment<8>(sl, 1u, kValidPtr, kInvalidPtr, kZeroPtr);
80   }
81 }
82 
83 #if defined(ARCH_CPU_X86_64)
TEST(PartitionAllocScanLoopTest,VectorizedSSE4)84 TEST(PartitionAllocScanLoopTest, VectorizedSSE4) {
85   base::CPU cpu;
86   if (!cpu.has_sse41()) {
87     return;
88   }
89   {
90     TestScanLoop sl(SimdSupport::kSSE41);
91     TestOnRangeWithAlignment<16>(sl, 0u, kInvalidPtr, kInvalidPtr, kInvalidPtr);
92   }
93   {
94     TestScanLoop sl(SimdSupport::kSSE41);
95     TestOnRangeWithAlignment<16>(sl, 1u, kValidPtr, kInvalidPtr, kInvalidPtr);
96   }
97   {
98     TestScanLoop sl(SimdSupport::kSSE41);
99     TestOnRangeWithAlignment<16>(sl, 2u, kValidPtr, kValidPtr, kInvalidPtr);
100   }
101   {
102     TestScanLoop sl(SimdSupport::kSSE41);
103     TestOnRangeWithAlignment<16>(sl, 3u, kValidPtr, kValidPtr, kValidPtr);
104   }
105 }
106 
TEST(PartitionAllocScanLoopTest,VectorizedAVX2)107 TEST(PartitionAllocScanLoopTest, VectorizedAVX2) {
108   base::CPU cpu;
109   if (!cpu.has_avx2()) {
110     return;
111   }
112   {
113     TestScanLoop sl(SimdSupport::kAVX2);
114     TestOnRangeWithAlignment<32>(sl, 0u, kInvalidPtr, kInvalidPtr, kInvalidPtr,
115                                  kInvalidPtr, kInvalidPtr);
116   }
117   {
118     TestScanLoop sl(SimdSupport::kAVX2);
119     TestOnRangeWithAlignment<32>(sl, 1u, kValidPtr, kInvalidPtr, kInvalidPtr,
120                                  kInvalidPtr, kInvalidPtr);
121   }
122   {
123     TestScanLoop sl(SimdSupport::kAVX2);
124     TestOnRangeWithAlignment<32>(sl, 2u, kValidPtr, kValidPtr, kInvalidPtr,
125                                  kInvalidPtr, kInvalidPtr);
126   }
127   {
128     TestScanLoop sl(SimdSupport::kAVX2);
129     TestOnRangeWithAlignment<32>(sl, 3u, kValidPtr, kValidPtr, kValidPtr,
130                                  kInvalidPtr, kInvalidPtr);
131   }
132   {
133     TestScanLoop sl(SimdSupport::kAVX2);
134     TestOnRangeWithAlignment<32>(sl, 4u, kValidPtr, kValidPtr, kValidPtr,
135                                  kValidPtr, kInvalidPtr);
136   }
137   {
138     // Check that the residual pointer is also visited.
139     TestScanLoop sl(SimdSupport::kAVX2);
140     TestOnRangeWithAlignment<32>(sl, 5u, kValidPtr, kValidPtr, kValidPtr,
141                                  kValidPtr, kValidPtr);
142   }
143 }
144 #endif  // defined(ARCH_CPU_X86_64)
145 
146 #if PA_CONFIG(STARSCAN_NEON_SUPPORTED)
TEST(PartitionAllocScanLoopTest,VectorizedNEON)147 TEST(PartitionAllocScanLoopTest, VectorizedNEON) {
148   {
149     TestScanLoop sl(SimdSupport::kNEON);
150     TestOnRangeWithAlignment<16>(sl, 0u, kInvalidPtr, kInvalidPtr, kInvalidPtr);
151   }
152   {
153     TestScanLoop sl(SimdSupport::kNEON);
154     TestOnRangeWithAlignment<16>(sl, 1u, kValidPtr, kInvalidPtr, kInvalidPtr);
155   }
156   {
157     TestScanLoop sl(SimdSupport::kNEON);
158     TestOnRangeWithAlignment<16>(sl, 2u, kValidPtr, kValidPtr, kInvalidPtr);
159   }
160   {
161     TestScanLoop sl(SimdSupport::kNEON);
162     TestOnRangeWithAlignment<16>(sl, 3u, kValidPtr, kValidPtr, kValidPtr);
163   }
164   {
165     // Don't visit zeroes.
166     TestScanLoop sl(SimdSupport::kNEON);
167     TestOnRangeWithAlignment<16>(sl, 1u, kInvalidPtr, kValidPtr, kZeroPtr);
168   }
169 }
170 #endif  // PA_CONFIG(STARSCAN_NEON_SUPPORTED)
171 
172 }  // namespace partition_alloc::internal
173 
174 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
175