1import glob
2import json
3import lldb
4from lldbsuite.test.decorators import *
5from lldbsuite.test.lldbtest import *
6from lldbsuite.test import lldbutil
7import os
8import time
9
10
11class DebugIndexCacheTestcase(TestBase):
12
13    mydir = TestBase.compute_mydir(__file__)
14
15    def setUp(self):
16        # Call super's setUp().
17        TestBase.setUp(self)
18        # Set the lldb module cache directory to a directory inside the build
19        # artifacts directory so no other tests are interfered with.
20        self.cache_dir = os.path.join(self.getBuildDir(), 'lldb-module-cache')
21
22    def get_module_cache_files(self, basename):
23        module_cache_glob = os.path.join(self.cache_dir,
24                                         "llvmcache-*%s*dwarf-index*" % (basename))
25        return glob.glob(module_cache_glob)
26
27    def get_stats(self, log_path=None):
28        """
29            Get the output of the "statistics dump" and return the JSON as a
30            python dictionary.
31        """
32        # If log_path is set, open the path and emit the output of the command
33        # for debugging purposes.
34        if log_path is not None:
35            f = open(log_path, 'w')
36        else:
37            f = None
38        return_obj = lldb.SBCommandReturnObject()
39        command = "statistics dump "
40        if f:
41            f.write('(lldb) %s\n' % (command))
42        self.ci.HandleCommand(command, return_obj, False)
43        metrics_json = return_obj.GetOutput()
44        if f:
45            f.write(metrics_json)
46        return json.loads(metrics_json)
47
48    def enable_lldb_index_cache(self):
49        self.runCmd('settings set symbols.lldb-index-cache-path "%s"' % (self.cache_dir))
50        self.runCmd('settings set symbols.enable-lldb-index-cache true')
51
52    @no_debug_info_test
53    def test_with_caching_enabled(self):
54        """
55            Test module cache functionality for debug info index caching.
56
57            We test that a debug info index file is created for the debug
58            information when caching is enabled with a file that contains
59            at least one of each kind of DIE in ManualDWARFIndex::IndexSet.
60
61            The input file has DWARF that will fill in every member of the
62            ManualDWARFIndex::IndexSet class to ensure we can encode all of the
63            required information.
64
65            With caching enabled, we also verify that the appropriate statistics
66            specify that the cache file was saved to the cache.
67        """
68        self.enable_lldb_index_cache()
69        src_dir = self.getSourceDir()
70        yaml_path = os.path.join(src_dir, "exe.yaml")
71        yaml_base, ext = os.path.splitext(yaml_path)
72        obj_path = self.getBuildArtifact("main.o")
73        self.yaml2obj(yaml_path, obj_path)
74
75        # Create a target with the object file we just created from YAML
76        target = self.dbg.CreateTarget(obj_path)
77        self.assertTrue(target, VALID_TARGET)
78
79        debug_index_cache_files = self.get_module_cache_files('main.o')
80        self.assertEqual(len(debug_index_cache_files), 1,
81                "make sure there is one file in the module cache directory (%s) for main.o that is a debug info cache" % (self.cache_dir))
82
83        # Verify that the module statistics have the information that specifies
84        # if we loaded or saved the debug index and symtab to the cache
85        stats = self.get_stats()
86        module_stats = stats['modules'][0]
87        self.assertFalse(module_stats['debugInfoIndexLoadedFromCache'])
88        self.assertTrue(module_stats['debugInfoIndexSavedToCache'])
89        self.assertFalse(module_stats['symbolTableLoadedFromCache'])
90        self.assertTrue(module_stats['symbolTableSavedToCache'])
91        # Verify the top level stats track how many things were loaded or saved
92        # to the cache.
93        self.assertEqual(stats["totalDebugInfoIndexLoadedFromCache"], 0)
94        self.assertEqual(stats["totalDebugInfoIndexSavedToCache"], 1)
95        self.assertEqual(stats["totalSymbolTablesLoadedFromCache"], 0)
96        self.assertEqual(stats["totalSymbolTablesSavedToCache"], 1)
97
98    @no_debug_info_test
99    def test_with_caching_disabled(self):
100        """
101            Test module cache functionality for debug info index caching.
102
103            We test that a debug info index file is not created for the debug
104            information when caching is disabled with a file that contains
105            at least one of each kind of DIE in ManualDWARFIndex::IndexSet.
106
107            The input file has DWARF that will fill in every member of the
108            ManualDWARFIndex::IndexSet class to ensure we can encode all of the
109            required information.
110
111            With caching disabled, we also verify that the appropriate
112            statistics specify that the cache file was not saved to the cache.
113        """
114        src_dir = self.getSourceDir()
115        yaml_path = os.path.join(src_dir, "exe.yaml")
116        yaml_base, ext = os.path.splitext(yaml_path)
117        obj_path = self.getBuildArtifact("main.o")
118        self.yaml2obj(yaml_path, obj_path)
119
120        # Create a target with the object file we just created from YAML
121        target = self.dbg.CreateTarget(obj_path)
122        self.assertTrue(target, VALID_TARGET)
123
124        debug_index_cache_files = self.get_module_cache_files('main.o')
125        self.assertEqual(len(debug_index_cache_files), 0,
126                "make sure there is no file in the module cache directory (%s) for main.o that is a debug info cache" % (self.cache_dir))
127
128        # Verify that the module statistics have the information that specifies
129        # if we loaded or saved the debug index and symtab to the cache
130        stats = self.get_stats()
131        module_stats = stats['modules'][0]
132        self.assertFalse(module_stats['debugInfoIndexLoadedFromCache'])
133        self.assertFalse(module_stats['debugInfoIndexSavedToCache'])
134        self.assertFalse(module_stats['symbolTableLoadedFromCache'])
135        self.assertFalse(module_stats['symbolTableSavedToCache'])
136        # Verify the top level stats track how many things were loaded or saved
137        # to the cache.
138        self.assertEqual(stats["totalDebugInfoIndexLoadedFromCache"], 0)
139        self.assertEqual(stats["totalDebugInfoIndexSavedToCache"], 0)
140        self.assertEqual(stats["totalSymbolTablesLoadedFromCache"], 0)
141        self.assertEqual(stats["totalSymbolTablesSavedToCache"], 0)
142