This patch add the ability to cache the manual DWARF indexing results to disk for faster subsequent debug sessions. Manual DWARF indexing is time consuming and causes all DWARF to be fully parsed and indexed each time you debug a binary that doesn't have an acceptable accelerator table. Acceptable accelerator tables include .debug_names in DWARF5 or Apple accelerator tables. This patch breaks up testing by testing all of the encoding and decoding of required C++ objects in a gtest unit test, and then has a test to verify the debug info cache is generated correctly. This patch also adds the ability to track when a symbol table or DWARF index is loaded or saved to the cache in the "statistics dump" command. This is essential to know in statistics as it can help explain why a debug session was slower or faster than expected. Reviewed By: labath, wallace Differential Revision: https://reviews.llvm.org/D115951
101 lines
4.6 KiB
Python
101 lines
4.6 KiB
Python
"""Test the LLDB module cache funcionality."""
|
|
|
|
import glob
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
import os
|
|
import time
|
|
|
|
|
|
class ModuleCacheTestcaseSimple(TestBase):
|
|
|
|
mydir = TestBase.compute_mydir(__file__)
|
|
|
|
def setUp(self):
|
|
# Call super's setUp().
|
|
TestBase.setUp(self)
|
|
# Find the line number in a(int) to break at.
|
|
self.cache_dir = os.path.join(self.getBuildDir(), 'lldb-module-cache')
|
|
# Set the lldb module cache directory to a directory inside the build
|
|
# artifacts directory so no other tests are interfered with.
|
|
self.runCmd('settings set symbols.lldb-index-cache-path "%s"' % (self.cache_dir))
|
|
self.runCmd('settings set symbols.enable-lldb-index-cache true')
|
|
self.build()
|
|
|
|
|
|
def get_module_cache_files(self, basename):
|
|
module_file_glob = os.path.join(self.cache_dir, "llvmcache-*%s*" % (basename))
|
|
return glob.glob(module_file_glob)
|
|
|
|
# Doesn't depend on any specific debug information.
|
|
@no_debug_info_test
|
|
@skipIfWindows
|
|
def test(self):
|
|
"""
|
|
Test module cache functionality for a simple object file.
|
|
|
|
This will test that if we enable the module cache, we have a
|
|
corresponding index cache entry for the symbol table for the
|
|
executable. It also removes the executable, rebuilds so that the
|
|
modification time of the binary gets updated, and then creates a new
|
|
target and should cause the cache to get updated so the cache file
|
|
should get an updated modification time.
|
|
"""
|
|
exe = self.getBuildArtifact("a.out")
|
|
|
|
# Create a module with no depedencies.
|
|
target = self.createTestTarget(load_dependent_modules=False)
|
|
|
|
# Get the executable module and get the number of symbols to make
|
|
# sure the symbol table gets parsed and cached. The module cache is
|
|
# enabled in the setUp() function.
|
|
main_module = target.GetModuleAtIndex(0)
|
|
self.assertTrue(main_module.IsValid())
|
|
# Make sure the symbol table gets loaded and cached
|
|
main_module.GetNumSymbols()
|
|
cache_files = self.get_module_cache_files("a.out")
|
|
self.assertEqual(len(cache_files), 1,
|
|
"make sure there is only one cache file for 'a.out'")
|
|
symtab_cache_path = cache_files[0]
|
|
exe_mtime_1 = os.path.getmtime(exe)
|
|
symtab_mtime_1 = os.path.getmtime(symtab_cache_path)
|
|
# Now remove the executable and sleep for a few seconds to make sure we
|
|
# get a different creation and modification time for the file since some
|
|
# OSs store the modification time in seconds since Jan 1, 1970.
|
|
os.remove(exe)
|
|
self.assertEqual(os.path.exists(exe), False,
|
|
'make sure we were able to remove the executable')
|
|
time.sleep(2)
|
|
# Now rebuild the binary so it has a different content which should
|
|
# update the UUID to make the cache miss when it tries to load the
|
|
# symbol table from the binary at the same path.
|
|
self.build(dictionary={'CFLAGS_EXTRAS': '-DEXTRA_FUNCTION'})
|
|
self.assertEqual(os.path.exists(exe), True,
|
|
'make sure executable exists after rebuild')
|
|
# Make sure the modification time has changed or this test will fail.
|
|
exe_mtime_2 = os.path.getmtime(exe)
|
|
self.assertNotEqual(
|
|
exe_mtime_1,
|
|
exe_mtime_2,
|
|
"make sure the modification time of the executable has changed")
|
|
# Make sure the module cache still has an out of date cache with the
|
|
# same old modification time.
|
|
self.assertEqual(symtab_mtime_1,
|
|
os.path.getmtime(symtab_cache_path),
|
|
"check that the 'symtab' cache file modification time doesn't match the executable modification time after rebuild")
|
|
# Create a new target and get the symbols again, and make sure the cache
|
|
# gets updated for the symbol table cache
|
|
target = self.createTestTarget(load_dependent_modules=False)
|
|
main_module = target.GetModuleAtIndex(0)
|
|
self.assertTrue(main_module.IsValid())
|
|
main_module.GetNumSymbols()
|
|
self.assertEqual(os.path.exists(symtab_cache_path), True,
|
|
'make sure "symtab" cache files exists after cache is updated')
|
|
symtab_mtime_2 = os.path.getmtime(symtab_cache_path)
|
|
self.assertNotEqual(
|
|
symtab_mtime_1,
|
|
symtab_mtime_2,
|
|
'make sure modification time of "symtab-..." changed')
|