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