Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb] Speed up FindInMemory tests #111951

Merged
merged 2 commits into from
Oct 18, 2024

Conversation

igorkudrin
Copy link
Collaborator

@igorkudrin igorkudrin commented Oct 11, 2024

A memory region can be relatively large. Searching for a value in the entire region is time-consuming, especially when running tests against a remote target, because the memory data is transferred in small chunks over a relatively slow GDB Remote Protocol. The patch limits the address range to be searched to 2K, which seems sufficient for these tests. In my setup, for local runs, these tests now take half the time they did before the patch. For a remote target, the improvement is even more significant.

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 11, 2024

@llvm/pr-subscribers-lldb

Author: Igor Kudrin (igorkudrin)

Changes

A memory region can be relatively large. Searching for a value in the entire region is time-consuming, especially when running tests against a remote target, because the memory data is transferred in small chunks over a relatively slow GDB remote protocol. The patch limits the address range to be searched to 2K, which seems sufficient for these tests. In my setup, for local runs, these tests now take half the time they did before the patch. For a remote target, the improvement is even more significant.


Full diff: https://github.com/llvm/llvm-project/pull/111951.diff

3 Files Affected:

  • (modified) lldb/test/API/python_api/find_in_memory/TestFindInMemory.py (+5-5)
  • (modified) lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py (+8-8)
  • (modified) lldb/test/API/python_api/find_in_memory/address_ranges_helper.py (+32-18)
diff --git a/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py b/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
index 9ab4619b1f8f4f..04e807c5c6201d 100644
--- a/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
+++ b/lldb/test/API/python_api/find_in_memory/TestFindInMemory.py
@@ -55,7 +55,7 @@ def test_find_in_memory_ok(self):
         error = lldb.SBError()
         addr = self.process.FindInMemory(
             SINGLE_INSTANCE_PATTERN_STACK,
-            GetStackRange(self),
+            GetStackRange(self, True),
             1,
             error,
         )
@@ -70,7 +70,7 @@ def test_find_in_memory_double_instance_ok(self):
         error = lldb.SBError()
         addr = self.process.FindInMemory(
             DOUBLE_INSTANCE_PATTERN_HEAP,
-            GetHeapRanges(self)[0],
+            GetHeapRanges(self, True)[0],
             1,
             error,
         )
@@ -86,7 +86,7 @@ def test_find_in_memory_invalid_alignment(self):
         error = lldb.SBError()
         addr = self.process.FindInMemory(
             SINGLE_INSTANCE_PATTERN_STACK,
-            GetStackRange(self),
+            GetStackRange(self, True),
             0,
             error,
         )
@@ -118,7 +118,7 @@ def test_find_in_memory_invalid_buffer(self):
         error = lldb.SBError()
         addr = self.process.FindInMemory(
             "",
-            GetStackRange(self),
+            GetStackRange(self, True),
             1,
             error,
         )
@@ -131,7 +131,7 @@ def test_find_in_memory_unaligned(self):
         self.assertTrue(self.process, PROCESS_IS_VALID)
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
         error = lldb.SBError()
-        range = GetAlignedRange(self)
+        range = GetAlignedRange(self, True)
 
         # First we make sure the pattern is found with alignment 1
         addr = self.process.FindInMemory(
diff --git a/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py b/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py
index 31bc0e99f4914f..895c527430f218 100644
--- a/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py
+++ b/lldb/test/API/python_api/find_in_memory/TestFindRangesInMemory.py
@@ -30,7 +30,7 @@ def test_find_ranges_in_memory_two_matches(self):
         self.assertTrue(self.process, PROCESS_IS_VALID)
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
 
-        addr_ranges = GetHeapRanges(self)
+        addr_ranges = GetHeapRanges(self, True)
         error = lldb.SBError()
         matches = self.process.FindRangesInMemory(
             DOUBLE_INSTANCE_PATTERN_HEAP,
@@ -48,7 +48,7 @@ def test_find_ranges_in_memory_one_match(self):
         self.assertTrue(self.process, PROCESS_IS_VALID)
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
 
-        addr_ranges = GetStackRanges(self)
+        addr_ranges = GetStackRanges(self, True)
         error = lldb.SBError()
         matches = self.process.FindRangesInMemory(
             SINGLE_INSTANCE_PATTERN_STACK,
@@ -66,7 +66,7 @@ def test_find_ranges_in_memory_one_match_multiple_ranges(self):
         self.assertTrue(self.process, PROCESS_IS_VALID)
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
 
-        addr_ranges = GetRanges(self)
+        addr_ranges = GetRanges(self, True)
         addr_ranges.Append(lldb.SBAddressRange())
         self.assertGreater(addr_ranges.GetSize(), 2)
         error = lldb.SBError()
@@ -86,7 +86,7 @@ def test_find_ranges_in_memory_one_match_max(self):
         self.assertTrue(self.process, PROCESS_IS_VALID)
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
 
-        addr_ranges = GetHeapRanges(self)
+        addr_ranges = GetHeapRanges(self, True)
         error = lldb.SBError()
         matches = self.process.FindRangesInMemory(
             DOUBLE_INSTANCE_PATTERN_HEAP,
@@ -104,7 +104,7 @@ def test_find_ranges_in_memory_invalid_alignment(self):
         self.assertTrue(self.process, PROCESS_IS_VALID)
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
 
-        addr_ranges = GetHeapRanges(self)
+        addr_ranges = GetHeapRanges(self, True)
         error = lldb.SBError()
         matches = self.process.FindRangesInMemory(
             DOUBLE_INSTANCE_PATTERN_HEAP,
@@ -160,7 +160,7 @@ def test_find_ranges_in_memory_invalid_buffer(self):
         self.assertTrue(self.process, PROCESS_IS_VALID)
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
 
-        addr_ranges = GetHeapRanges(self)
+        addr_ranges = GetHeapRanges(self, True)
         error = lldb.SBError()
         matches = self.process.FindRangesInMemory(
             "",
@@ -178,7 +178,7 @@ def test_find_ranges_in_memory_invalid_max_matches(self):
         self.assertTrue(self.process, PROCESS_IS_VALID)
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
 
-        addr_ranges = GetHeapRanges(self)
+        addr_ranges = GetHeapRanges(self, True)
         error = lldb.SBError()
         matches = self.process.FindRangesInMemory(
             DOUBLE_INSTANCE_PATTERN_HEAP,
@@ -197,7 +197,7 @@ def test_find_in_memory_unaligned(self):
         self.assertState(self.process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
 
         addr_ranges = lldb.SBAddressRangeList()
-        addr_ranges.Append(GetAlignedRange(self))
+        addr_ranges.Append(GetAlignedRange(self, True))
         error = lldb.SBError()
 
         matches = self.process.FindRangesInMemory(
diff --git a/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py b/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py
index 810fb9fee38615..6c77b3e911c5d5 100644
--- a/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py
+++ b/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py
@@ -6,27 +6,30 @@
 UNALIGNED_INSTANCE_PATTERN_HEAP = ALIGNED_INSTANCE_PATTERN_HEAP[1:]
 
 
-def GetAlignedRange(test_base):
+def GetAlignedRange(test_base, shrink=False):
     frame = test_base.thread.GetSelectedFrame()
     ex = frame.EvaluateExpression("aligned_string_ptr")
     test_base.assertTrue(ex.IsValid())
-    return GetRangeFromAddrValue(test_base, ex)
+    return GetRangeFromAddrValue(test_base, ex, shrink)
 
 
-def GetStackRange(test_base):
+def GetStackRange(test_base, shrink=False):
     frame = test_base.thread.GetSelectedFrame()
     ex = frame.EvaluateExpression("&stack_pointer")
     test_base.assertTrue(ex.IsValid())
-    return GetRangeFromAddrValue(test_base, ex)
+    return GetRangeFromAddrValue(test_base, ex, shrink)
 
 
-def GetStackRanges(test_base):
+def GetStackRanges(test_base, shrink=False):
     addr_ranges = lldb.SBAddressRangeList()
     addr_ranges.Append(GetStackRange(test_base))
     return addr_ranges
 
 
-def GetRangeFromAddrValue(test_base, addr):
+def GetRangeFromAddrValue(test_base, addr, shrink=False):
+    """ Return the address range containing 'addr'.
+        If 'shrink' is True, the size of the region will not exceed 2K.
+    """
     region = lldb.SBMemoryRegionInfo()
     test_base.assertTrue(
         test_base.process.GetMemoryRegionInfo(
@@ -36,38 +39,49 @@ def GetRangeFromAddrValue(test_base, addr):
 
     test_base.assertTrue(region.IsReadable())
     test_base.assertFalse(region.IsExecutable())
+    
+    base = region.GetRegionBase()
+    end = region.GetRegionEnd()
 
-    address_start = lldb.SBAddress(region.GetRegionBase(), test_base.target)
-    stack_size = region.GetRegionEnd() - region.GetRegionBase()
-    return lldb.SBAddressRange(address_start, stack_size)
+    if shrink:
+        addr2 = addr.GetValueAsUnsigned()
+        addr2 -= addr2 % 512
+        base = max(base, addr2 - 1024)
+        end = min(end, addr2 + 1024)
 
+    start = lldb.SBAddress(base, test_base.target)
+    size = end - base
 
-def IsWithinRange(addr, range, target):
+    return lldb.SBAddressRange(start, size)
+
+
+def IsWithinRange(addr, size, range, target):
     start_addr = range.GetBaseAddress().GetLoadAddress(target)
     end_addr = start_addr + range.GetByteSize()
     addr = addr.GetValueAsUnsigned()
-    return addr >= start_addr and addr < end_addr
+    return addr >= start_addr and addr + size <= end_addr
 
 
-def GetHeapRanges(test_base):
+def GetHeapRanges(test_base, shrink=False):
     frame = test_base.thread.GetSelectedFrame()
 
     ex = frame.EvaluateExpression("heap_pointer1")
     test_base.assertTrue(ex.IsValid())
-    range = GetRangeFromAddrValue(test_base, ex)
+    range = GetRangeFromAddrValue(test_base, ex, shrink)
     addr_ranges = lldb.SBAddressRangeList()
     addr_ranges.Append(range)
 
     ex = frame.EvaluateExpression("heap_pointer2")
     test_base.assertTrue(ex.IsValid())
-    if not IsWithinRange(ex, addr_ranges[0], test_base.target):
-        addr_ranges.Append(GetRangeFromAddrValue(test_base, ex))
+    size = len(DOUBLE_INSTANCE_PATTERN_HEAP)
+    if not IsWithinRange(ex, size, addr_ranges[0], test_base.target):
+        addr_ranges.Append(GetRangeFromAddrValue(test_base, ex, shrink))
 
     return addr_ranges
 
 
-def GetRanges(test_base):
-    ranges = GetHeapRanges(test_base)
-    ranges.Append(GetStackRanges(test_base))
+def GetRanges(test_base, shrink=False):
+    ranges = GetHeapRanges(test_base, shrink)
+    ranges.Append(GetStackRanges(test_base, shrink))
 
     return ranges

Copy link

github-actions bot commented Oct 11, 2024

✅ With the latest revision this PR passed the Python code formatter.

A memory region can be relatively large. Searching for a value in the
entire region is time-consuming, especially when running tests against
a remote target, because the memory data is transferred in small chunks
over a relatively slow GDB Remote Protocol. The patch limits the address
range to be searched to 2K, which seems sufficient for these tests. In
my setup, for local runs, these tests now take half the time they did
before the patch. For a remote target, the improvement is even more
significant.
@igorkudrin igorkudrin force-pushed the lldb-speed-up-find-in-memory-tests branch from 6ea1173 to e027444 Compare October 11, 2024 05:50
addr_ranges = lldb.SBAddressRangeList()
addr_ranges.Append(GetStackRange(test_base))
return addr_ranges


def GetRangeFromAddrValue(test_base, addr):
def GetRangeFromAddrValue(test_base, addr, shrink=False):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are only used for testing, why not remove the shrink parameter and always keep the memory region below 2K?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all tests do actual searches. For example, test_check_stack_pointer() in TestFindInMemory.py checks that ranges for two different stack pointers are the same.

@igorkudrin igorkudrin merged commit b88d94c into llvm:main Oct 18, 2024
7 checks passed
@igorkudrin igorkudrin deleted the lldb-speed-up-find-in-memory-tests branch October 18, 2024 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants