1*eb293b8fSAndroid Build Coastguard Worker /*
2*eb293b8fSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*eb293b8fSAndroid Build Coastguard Worker *
4*eb293b8fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*eb293b8fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*eb293b8fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*eb293b8fSAndroid Build Coastguard Worker *
8*eb293b8fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*eb293b8fSAndroid Build Coastguard Worker *
10*eb293b8fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*eb293b8fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*eb293b8fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*eb293b8fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*eb293b8fSAndroid Build Coastguard Worker * limitations under the License.
15*eb293b8fSAndroid Build Coastguard Worker */
16*eb293b8fSAndroid Build Coastguard Worker
17*eb293b8fSAndroid Build Coastguard Worker #include <stdint.h>
18*eb293b8fSAndroid Build Coastguard Worker
19*eb293b8fSAndroid Build Coastguard Worker #include <thread>
20*eb293b8fSAndroid Build Coastguard Worker #include <vector>
21*eb293b8fSAndroid Build Coastguard Worker
22*eb293b8fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
23*eb293b8fSAndroid Build Coastguard Worker
24*eb293b8fSAndroid Build Coastguard Worker #include "MemoryCache.h"
25*eb293b8fSAndroid Build Coastguard Worker #include "utils/MemoryFake.h"
26*eb293b8fSAndroid Build Coastguard Worker
27*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
28*eb293b8fSAndroid Build Coastguard Worker
29*eb293b8fSAndroid Build Coastguard Worker class MemoryThreadCacheTest : public ::testing::Test {
30*eb293b8fSAndroid Build Coastguard Worker protected:
SetUp()31*eb293b8fSAndroid Build Coastguard Worker void SetUp() override {
32*eb293b8fSAndroid Build Coastguard Worker memory_ = new MemoryFake;
33*eb293b8fSAndroid Build Coastguard Worker memory_cache_.reset(new MemoryThreadCache(memory_));
34*eb293b8fSAndroid Build Coastguard Worker
35*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0x8000, 4096, 0xab);
36*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0x9000, 4096, 0xde);
37*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0xa000, 3000, 0x50);
38*eb293b8fSAndroid Build Coastguard Worker }
39*eb293b8fSAndroid Build Coastguard Worker
40*eb293b8fSAndroid Build Coastguard Worker MemoryFake* memory_;
41*eb293b8fSAndroid Build Coastguard Worker std::unique_ptr<MemoryThreadCache> memory_cache_;
42*eb293b8fSAndroid Build Coastguard Worker
43*eb293b8fSAndroid Build Coastguard Worker constexpr static size_t kMaxCachedSize = 64;
44*eb293b8fSAndroid Build Coastguard Worker };
45*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,cached_read)46*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, cached_read) {
47*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 1; i <= kMaxCachedSize; i++) {
48*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(i);
49*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
50*eb293b8fSAndroid Build Coastguard Worker << "Read failed at size " << i;
51*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
52*eb293b8fSAndroid Build Coastguard Worker }
53*eb293b8fSAndroid Build Coastguard Worker
54*eb293b8fSAndroid Build Coastguard Worker // Verify the cached data is used.
55*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0x8000, 4096, 0xff);
56*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 1; i <= kMaxCachedSize; i++) {
57*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(i);
58*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
59*eb293b8fSAndroid Build Coastguard Worker << "Read failed at size " << i;
60*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
61*eb293b8fSAndroid Build Coastguard Worker }
62*eb293b8fSAndroid Build Coastguard Worker }
63*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,no_cached_read_after_clear)64*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, no_cached_read_after_clear) {
65*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 1; i <= kMaxCachedSize; i++) {
66*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(i);
67*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
68*eb293b8fSAndroid Build Coastguard Worker << "Read failed at size " << i;
69*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
70*eb293b8fSAndroid Build Coastguard Worker }
71*eb293b8fSAndroid Build Coastguard Worker
72*eb293b8fSAndroid Build Coastguard Worker // Verify the cached data is not used after a reset.
73*eb293b8fSAndroid Build Coastguard Worker memory_cache_->Clear();
74*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0x8000, 4096, 0xff);
75*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 1; i <= kMaxCachedSize; i++) {
76*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(i);
77*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
78*eb293b8fSAndroid Build Coastguard Worker << "Read failed at size " << i;
79*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
80*eb293b8fSAndroid Build Coastguard Worker }
81*eb293b8fSAndroid Build Coastguard Worker }
82*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,cached_read_across_caches)83*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, cached_read_across_caches) {
84*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> expect(16, 0xab);
85*eb293b8fSAndroid Build Coastguard Worker expect.resize(32, 0xde);
86*eb293b8fSAndroid Build Coastguard Worker
87*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(32);
88*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
89*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(expect, buffer);
90*eb293b8fSAndroid Build Coastguard Worker
91*eb293b8fSAndroid Build Coastguard Worker // Verify the cached data is used.
92*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0x8000, 4096, 0xff);
93*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0x9000, 4096, 0xff);
94*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
95*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(expect, buffer);
96*eb293b8fSAndroid Build Coastguard Worker }
97*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,no_cache_read)98*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, no_cache_read) {
99*eb293b8fSAndroid Build Coastguard Worker for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
100*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(i);
101*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
102*eb293b8fSAndroid Build Coastguard Worker << "Read failed at size " << i;
103*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
104*eb293b8fSAndroid Build Coastguard Worker }
105*eb293b8fSAndroid Build Coastguard Worker
106*eb293b8fSAndroid Build Coastguard Worker // Verify the cached data is not used.
107*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0x8000, 4096, 0xff);
108*eb293b8fSAndroid Build Coastguard Worker for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
109*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(i);
110*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
111*eb293b8fSAndroid Build Coastguard Worker << "Read failed at size " << i;
112*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
113*eb293b8fSAndroid Build Coastguard Worker }
114*eb293b8fSAndroid Build Coastguard Worker }
115*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,read_for_cache_fail)116*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, read_for_cache_fail) {
117*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(kMaxCachedSize);
118*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
119*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0x50), buffer);
120*eb293b8fSAndroid Build Coastguard Worker
121*eb293b8fSAndroid Build Coastguard Worker // Verify the cached data is not used.
122*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0xa000, 3000, 0xff);
123*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
124*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0xff), buffer);
125*eb293b8fSAndroid Build Coastguard Worker }
126*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,read_for_cache_fail_cross)127*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, read_for_cache_fail_cross) {
128*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> expect(16, 0xde);
129*eb293b8fSAndroid Build Coastguard Worker expect.resize(32, 0x50);
130*eb293b8fSAndroid Build Coastguard Worker
131*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(32);
132*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
133*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(expect, buffer);
134*eb293b8fSAndroid Build Coastguard Worker
135*eb293b8fSAndroid Build Coastguard Worker // Verify the cached data is not used for the second half but for the first.
136*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0xa000, 3000, 0xff);
137*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
138*eb293b8fSAndroid Build Coastguard Worker expect.resize(16);
139*eb293b8fSAndroid Build Coastguard Worker expect.resize(32, 0xff);
140*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(expect, buffer);
141*eb293b8fSAndroid Build Coastguard Worker }
142*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,read_cached_in_thread)143*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, read_cached_in_thread) {
144*eb293b8fSAndroid Build Coastguard Worker // Read from a different thread than this one.
145*eb293b8fSAndroid Build Coastguard Worker std::thread thread([this] {
146*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 1; i <= kMaxCachedSize; i++) {
147*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(i);
148*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(this->memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
149*eb293b8fSAndroid Build Coastguard Worker << "Read failed at size " << i;
150*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
151*eb293b8fSAndroid Build Coastguard Worker }
152*eb293b8fSAndroid Build Coastguard Worker });
153*eb293b8fSAndroid Build Coastguard Worker
154*eb293b8fSAndroid Build Coastguard Worker thread.join();
155*eb293b8fSAndroid Build Coastguard Worker
156*eb293b8fSAndroid Build Coastguard Worker // Now modify the backing data, and read from the main thread verifying
157*eb293b8fSAndroid Build Coastguard Worker // it is not using cached data.
158*eb293b8fSAndroid Build Coastguard Worker memory_->SetMemoryBlock(0x8000, 4096, 0xff);
159*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 1; i <= kMaxCachedSize; i++) {
160*eb293b8fSAndroid Build Coastguard Worker std::vector<uint8_t> buffer(i);
161*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
162*eb293b8fSAndroid Build Coastguard Worker << "Read failed at size " << i;
163*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
164*eb293b8fSAndroid Build Coastguard Worker }
165*eb293b8fSAndroid Build Coastguard Worker }
166*eb293b8fSAndroid Build Coastguard Worker
ExhaustPthreadKeys(std::vector<pthread_key_t> * keys)167*eb293b8fSAndroid Build Coastguard Worker static void ExhaustPthreadKeys(std::vector<pthread_key_t>* keys) {
168*eb293b8fSAndroid Build Coastguard Worker // Use up all of the keys to force the next attempt to create one to fail.
169*eb293b8fSAndroid Build Coastguard Worker static constexpr size_t kMaxKeysToCreate = 10000;
170*eb293b8fSAndroid Build Coastguard Worker keys->resize(kMaxKeysToCreate);
171*eb293b8fSAndroid Build Coastguard Worker for (size_t i = 0; i < kMaxKeysToCreate; i++) {
172*eb293b8fSAndroid Build Coastguard Worker if (pthread_key_create(&(*keys)[i], nullptr) != 0) {
173*eb293b8fSAndroid Build Coastguard Worker keys->resize(i);
174*eb293b8fSAndroid Build Coastguard Worker break;
175*eb293b8fSAndroid Build Coastguard Worker }
176*eb293b8fSAndroid Build Coastguard Worker }
177*eb293b8fSAndroid Build Coastguard Worker ASSERT_NE(0U, keys->size()) << "No keys created.";
178*eb293b8fSAndroid Build Coastguard Worker ASSERT_LT(keys->size(), kMaxKeysToCreate) << "Cannot use up pthread keys.";
179*eb293b8fSAndroid Build Coastguard Worker }
180*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,read_uncached_due_to_error)181*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, read_uncached_due_to_error) {
182*eb293b8fSAndroid Build Coastguard Worker std::vector<pthread_key_t> keys;
183*eb293b8fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(ExhaustPthreadKeys(&keys));
184*eb293b8fSAndroid Build Coastguard Worker
185*eb293b8fSAndroid Build Coastguard Worker MemoryFake* fake = new MemoryFake;
186*eb293b8fSAndroid Build Coastguard Worker MemoryThreadCache memory(fake);
187*eb293b8fSAndroid Build Coastguard Worker fake->SetMemoryBlock(0x8000, 4096, 0xad);
188*eb293b8fSAndroid Build Coastguard Worker
189*eb293b8fSAndroid Build Coastguard Worker // Read the data, which should be uncached.
190*eb293b8fSAndroid Build Coastguard Worker uint8_t value;
191*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory.ReadFully(0x8000, &value, 1));
192*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(0xad, value);
193*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory.ReadFully(0x8001, &value, 1));
194*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(0xad, value);
195*eb293b8fSAndroid Build Coastguard Worker
196*eb293b8fSAndroid Build Coastguard Worker // Verify the previous read did not cache anything.
197*eb293b8fSAndroid Build Coastguard Worker fake->SetMemoryBlock(0x8000, 4096, 0x12);
198*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory.ReadFully(0x8000, &value, 1));
199*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(0x12, value);
200*eb293b8fSAndroid Build Coastguard Worker ASSERT_TRUE(memory.ReadFully(0x8001, &value, 1));
201*eb293b8fSAndroid Build Coastguard Worker ASSERT_EQ(0x12, value);
202*eb293b8fSAndroid Build Coastguard Worker
203*eb293b8fSAndroid Build Coastguard Worker for (pthread_key_t& key : keys) {
204*eb293b8fSAndroid Build Coastguard Worker pthread_key_delete(key);
205*eb293b8fSAndroid Build Coastguard Worker }
206*eb293b8fSAndroid Build Coastguard Worker }
207*eb293b8fSAndroid Build Coastguard Worker
TEST_F(MemoryThreadCacheTest,clear_cache_when_no_cache)208*eb293b8fSAndroid Build Coastguard Worker TEST_F(MemoryThreadCacheTest, clear_cache_when_no_cache) {
209*eb293b8fSAndroid Build Coastguard Worker std::vector<pthread_key_t> keys;
210*eb293b8fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(ExhaustPthreadKeys(&keys));
211*eb293b8fSAndroid Build Coastguard Worker
212*eb293b8fSAndroid Build Coastguard Worker MemoryFake* fake = new MemoryFake;
213*eb293b8fSAndroid Build Coastguard Worker MemoryThreadCache memory(fake);
214*eb293b8fSAndroid Build Coastguard Worker memory.Clear();
215*eb293b8fSAndroid Build Coastguard Worker
216*eb293b8fSAndroid Build Coastguard Worker for (pthread_key_t& key : keys) {
217*eb293b8fSAndroid Build Coastguard Worker pthread_key_delete(key);
218*eb293b8fSAndroid Build Coastguard Worker }
219*eb293b8fSAndroid Build Coastguard Worker }
220*eb293b8fSAndroid Build Coastguard Worker
221*eb293b8fSAndroid Build Coastguard Worker } // namespace unwindstack
222