================
@@ -489,6 +497,168 @@ TEST_F(MemoryTest, TestReadStopsAtAnInvalidRange) {
EXPECT_TRUE(process->m_reads.empty());
}
+TEST_F(MemoryTest, TestReadRangesFromCaches) {
+ CacheTestProcess proc;
+ ASSERT_TRUE(proc.process());
+ DummyProcess *process = proc.process();
+ const lldb::addr_t line = proc.line();
+
+ { // A short fetch must expose only the bytes it read, and must not disturb a
+ // range the caches already served.
+ TestMemoryCache cache(*process);
+ AddCacheChunk(cache, 0xB000, 40, 0xAA);
+ AddCacheChunk(cache, 0xC000, 8, 0xCC);
+ process->SetMaxReadSize(20);
+ process->SetFiller(0xBB);
+ process->m_reads.clear();
+ llvm::SmallVector<uint8_t, 0> buffer(72, 0);
+ llvm::SmallVector<Range<addr_t, size_t>> ranges = {{0xB000, 64},
+ {0xC000, 8}};
+ llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> results =
+ cache.ReadRanges(ranges, buffer);
+ ASSERT_EQ(results.size(), 2u);
+ ASSERT_EQ(results[0].size(), 20u);
+ EXPECT_TRUE(AllBytesAre(results[0], 0xBB));
+ ASSERT_EQ(results[1].size(), 8u);
+ EXPECT_TRUE(AllBytesAre(results[1], 0xCC));
+ }
+
+ { // A range ReadRanges fetched is cached, so asking for it again serves it
+ // without going to the inferior.
+ TestMemoryCache cache(*process);
+ process->SetMaxReadSize(4 * line);
+ process->SetFiller(0xBB);
+ process->m_reads.clear();
+ llvm::SmallVector<uint8_t, 0> buffer(24, 0);
+ llvm::SmallVector<Range<addr_t, size_t>> ranges = {{0x16000, 24}};
+ llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> results =
+ cache.ReadRanges(ranges, buffer);
+ ASSERT_EQ(results.size(), 1u);
+ ASSERT_EQ(results[0].size(), 24u);
+ EXPECT_TRUE(AllBytesAre(results[0], 0xBB));
+ ASSERT_FALSE(process->m_reads.empty());
+
+ process->SetMaxReadSize(0);
+ process->m_reads.clear();
+ llvm::SmallVector<uint8_t, 0> again(24, 0);
+ llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> second =
+ cache.ReadRanges(ranges, again);
+ ASSERT_EQ(second.size(), 1u);
+ ASSERT_EQ(second[0].size(), 24u);
+ EXPECT_TRUE(AllBytesAre(second[0], 0xBB));
+ EXPECT_TRUE(process->m_reads.empty());
+ }
+
+ { // A range inside an invalid range gets an empty result without reaching
the
+ // inferior, and leaves the ranges on either side of it alone.
+ TestMemoryCache cache(*process);
+ AddCacheChunk(cache, 0x17000, 8, 0xAA);
+ cache.AddInvalidRange(0x17100, 8);
+ process->SetMaxReadSize(4 * line);
+ process->SetFiller(0xBB);
+ process->m_reads.clear();
+ llvm::SmallVector<uint8_t, 0> buffer(24, 0);
+ llvm::SmallVector<Range<addr_t, size_t>> ranges = {
+ {0x17000, 8}, {0x17100, 8}, {0x17200, 8}};
+ llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> results =
+ cache.ReadRanges(ranges, buffer);
+ ASSERT_EQ(results.size(), 3u);
+ ASSERT_EQ(results[0].size(), 8u); // a cache hit
+ EXPECT_TRUE(AllBytesAre(results[0], 0xAA));
+ EXPECT_TRUE(results[1].empty()); // the invalid range
+ ASSERT_EQ(results[2].size(), 8u); // a miss, fetched
+ EXPECT_TRUE(AllBytesAre(results[2], 0xBB));
+ // Only the miss reached the inferior.
+ ASSERT_EQ(process->m_reads.size(), 1u);
+ EXPECT_EQ(process->m_reads[0].first, 0x17200u);
+ EXPECT_EQ(process->m_reads[0].second, 8u);
+ }
+}
+
+TEST_F(MemoryTest, TestReadRequestShape) {
+ CacheTestProcess proc;
+ ASSERT_TRUE(proc.process());
+ DummyProcess *process = proc.process();
+ const lldb::addr_t line = proc.line();
+
+ { // A read longer than a line that L1 cannot serve whole goes to the
inferior
+ // as one request for the whole range.
+ // v base v base + line
+ // cache: |AAAAAAAAAAAAAA|AA|
+ // process:|BBBBBBBBBBBBBB|BBBBBBBBBBBB|BBBBBBBBBBBB|
+ // buf: |BBBBBBBBBBBBBB|BBBBBBBBBBBB|BBBBBBBBBBBB|
+ TestMemoryCache cache(*process);
+ Status error;
+ const lldb::addr_t base = 0x15000;
+ AddCacheChunk(cache, base, line + 8, 0xAA); // a whole line plus a
remainder
+ process->SetMaxReadSize(4 * line);
+ process->SetFiller(0xBB);
+ process->m_reads.clear();
+ std::vector<uint8_t> buf(3 * line, 0);
+ ASSERT_EQ(cache.Read(base, buf.data(), buf.size(), error), buf.size());
+ EXPECT_TRUE(AllBytesAre(buf, 0xBB));
+ // One request, for exactly what the caller asked.
+ ASSERT_EQ(process->m_reads.size(), 1u);
+ EXPECT_EQ(process->m_reads[0].first, base);
+ EXPECT_EQ(process->m_reads[0].second, buf.size());
+
+ // Cached where it was read from, so the same read now sends nothing and
+ // returns the same bytes.
+ process->SetMaxReadSize(0);
+ process->m_reads.clear();
+ std::vector<uint8_t> again(3 * line, 0);
+ EXPECT_EQ(cache.Read(base, again.data(), again.size(), error),
+ again.size());
+ EXPECT_EQ(again, buf);
+ EXPECT_TRUE(process->m_reads.empty());
+ }
+}
+
+// A flushed range whose end wraps past UINT64_MAX must stop at the top line.
----------------
qiyao wrote:
Yes, add `FIXME` in the followup commit.
https://github.com/llvm/llvm-project/pull/221015
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits