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