This changes Python API tests to use a single build shared across all test functions, instead of the previous default behavior of a separate build dir for each test function. This build behavior opt-out, tests can use the previous behavior of one individual (unshared) build directory per test function, by setting `SHARED_BUILD_TESTCASE` to False (in the test class). The motivation is to make the test suite more efficient, by not repeatedly building the same test source. When running tests on my macOS machine, this reduces the time of `ninja check-lldb-api` by almost 60% (sample numbers: from ~492s down to ~207s = 58%). Almost 5min time saved. Each test function still calls `self.build()`, but only the first call will do a build, in the subsequent tests `make` will be a no-op because the sources won't have changed.
152 lines
6.2 KiB
Python
152 lines
6.2 KiB
Python
import glob
|
|
import json
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
import os
|
|
import time
|
|
|
|
|
|
class DebugIndexCacheTestcase(TestBase):
|
|
SHARED_BUILD_TESTCASE = False
|
|
|
|
def setUp(self):
|
|
# Call super's setUp().
|
|
TestBase.setUp(self)
|
|
# Set the lldb module cache directory to a directory inside the build
|
|
# artifacts directory so no other tests are interfered with.
|
|
self.cache_dir = os.path.join(self.getBuildDir(), "lldb-module-cache")
|
|
|
|
def get_module_cache_files(self, basename):
|
|
module_cache_glob = os.path.join(
|
|
self.cache_dir, "llvmcache-*%s*dwarf-index*" % (basename)
|
|
)
|
|
return glob.glob(module_cache_glob)
|
|
|
|
def get_stats(self, log_path=None):
|
|
"""
|
|
Get the output of the "statistics dump" and return the JSON as a
|
|
python dictionary.
|
|
"""
|
|
# If log_path is set, open the path and emit the output of the command
|
|
# for debugging purposes.
|
|
if log_path is not None:
|
|
f = open(log_path, "w")
|
|
else:
|
|
f = None
|
|
return_obj = lldb.SBCommandReturnObject()
|
|
command = "statistics dump "
|
|
if f:
|
|
f.write("(lldb) %s\n" % (command))
|
|
self.ci.HandleCommand(command, return_obj, False)
|
|
metrics_json = return_obj.GetOutput()
|
|
if f:
|
|
f.write(metrics_json)
|
|
return json.loads(metrics_json)
|
|
|
|
def enable_lldb_index_cache(self):
|
|
self.runCmd(
|
|
'settings set symbols.lldb-index-cache-path "%s"' % (self.cache_dir)
|
|
)
|
|
self.runCmd("settings set symbols.enable-lldb-index-cache true")
|
|
|
|
@no_debug_info_test
|
|
def test_with_caching_enabled(self):
|
|
"""
|
|
Test module cache functionality for debug info index caching.
|
|
|
|
We test that a debug info index file is created for the debug
|
|
information when caching is enabled with a file that contains
|
|
at least one of each kind of DIE in ManualDWARFIndex::IndexSet.
|
|
|
|
The input file has DWARF that will fill in every member of the
|
|
ManualDWARFIndex::IndexSet class to ensure we can encode all of the
|
|
required information.
|
|
|
|
With caching enabled, we also verify that the appropriate statistics
|
|
specify that the cache file was saved to the cache.
|
|
"""
|
|
self.enable_lldb_index_cache()
|
|
src_dir = self.getSourceDir()
|
|
yaml_path = os.path.join(src_dir, "exe.yaml")
|
|
yaml_base, ext = os.path.splitext(yaml_path)
|
|
obj_path = self.getBuildArtifact("main.o")
|
|
self.yaml2obj(yaml_path, obj_path)
|
|
|
|
# Create a target with the object file we just created from YAML
|
|
target = self.dbg.CreateTarget(obj_path)
|
|
self.assertTrue(target, VALID_TARGET)
|
|
|
|
debug_index_cache_files = self.get_module_cache_files("main.o")
|
|
self.assertEqual(
|
|
len(debug_index_cache_files),
|
|
1,
|
|
"make sure there is one file in the module cache directory (%s) for main.o that is a debug info cache"
|
|
% (self.cache_dir),
|
|
)
|
|
|
|
# Verify that the module statistics have the information that specifies
|
|
# if we loaded or saved the debug index and symtab to the cache
|
|
stats = self.get_stats()
|
|
module_stats = stats["modules"][0]
|
|
self.assertFalse(module_stats["debugInfoIndexLoadedFromCache"])
|
|
self.assertTrue(module_stats["debugInfoIndexSavedToCache"])
|
|
self.assertFalse(module_stats["symbolTableLoadedFromCache"])
|
|
self.assertTrue(module_stats["symbolTableSavedToCache"])
|
|
# Verify the top level stats track how many things were loaded or saved
|
|
# to the cache.
|
|
self.assertEqual(stats["totalDebugInfoIndexLoadedFromCache"], 0)
|
|
self.assertEqual(stats["totalDebugInfoIndexSavedToCache"], 1)
|
|
self.assertEqual(stats["totalSymbolTablesLoadedFromCache"], 0)
|
|
self.assertEqual(stats["totalSymbolTablesSavedToCache"], 1)
|
|
|
|
@no_debug_info_test
|
|
def test_with_caching_disabled(self):
|
|
"""
|
|
Test module cache functionality for debug info index caching.
|
|
|
|
We test that a debug info index file is not created for the debug
|
|
information when caching is disabled with a file that contains
|
|
at least one of each kind of DIE in ManualDWARFIndex::IndexSet.
|
|
|
|
The input file has DWARF that will fill in every member of the
|
|
ManualDWARFIndex::IndexSet class to ensure we can encode all of the
|
|
required information.
|
|
|
|
With caching disabled, we also verify that the appropriate
|
|
statistics specify that the cache file was not saved to the cache.
|
|
"""
|
|
src_dir = self.getSourceDir()
|
|
yaml_path = os.path.join(src_dir, "exe.yaml")
|
|
yaml_base, ext = os.path.splitext(yaml_path)
|
|
obj_path = self.getBuildArtifact("main.o")
|
|
self.yaml2obj(yaml_path, obj_path)
|
|
|
|
# Create a target with the object file we just created from YAML
|
|
target = self.dbg.CreateTarget(obj_path)
|
|
self.assertTrue(target, VALID_TARGET)
|
|
|
|
debug_index_cache_files = self.get_module_cache_files("main.o")
|
|
self.assertEqual(
|
|
len(debug_index_cache_files),
|
|
0,
|
|
"make sure there is no file in the module cache directory (%s) for main.o that is a debug info cache"
|
|
% (self.cache_dir),
|
|
)
|
|
|
|
# Verify that the module statistics have the information that specifies
|
|
# if we loaded or saved the debug index and symtab to the cache
|
|
stats = self.get_stats()
|
|
module_stats = stats["modules"][0]
|
|
self.assertFalse(module_stats["debugInfoIndexLoadedFromCache"])
|
|
self.assertFalse(module_stats["debugInfoIndexSavedToCache"])
|
|
self.assertFalse(module_stats["symbolTableLoadedFromCache"])
|
|
self.assertFalse(module_stats["symbolTableSavedToCache"])
|
|
# Verify the top level stats track how many things were loaded or saved
|
|
# to the cache.
|
|
self.assertEqual(stats["totalDebugInfoIndexLoadedFromCache"], 0)
|
|
self.assertEqual(stats["totalDebugInfoIndexSavedToCache"], 0)
|
|
self.assertEqual(stats["totalSymbolTablesLoadedFromCache"], 0)
|
|
self.assertEqual(stats["totalSymbolTablesSavedToCache"], 0)
|