This patch adds a load core time, right now we don't have much insight into the performance of load core, especially for large coredumps. To start collecting information on this I've added some minor instrumentation code to measure the two call sites of `LoadCore`. I've also added a test to validate the new metric is output in statistics dump
188 lines
7.1 KiB
Python
188 lines
7.1 KiB
Python
# Test the SBAPI for GetStatistics()
|
|
|
|
import json
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
|
|
class TestStatsAPI(TestBase):
|
|
NO_DEBUG_INFO_TESTCASE = True
|
|
|
|
def test_stats_api(self):
|
|
"""
|
|
Test SBTarget::GetStatistics() API.
|
|
"""
|
|
self.build()
|
|
exe = self.getBuildArtifact("a.out")
|
|
# Launch a process and break
|
|
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
|
|
self, "break here", lldb.SBFileSpec("main.c")
|
|
)
|
|
|
|
# Test enabling/disabling stats
|
|
self.assertFalse(target.GetCollectingStats())
|
|
target.SetCollectingStats(True)
|
|
self.assertTrue(target.GetCollectingStats())
|
|
target.SetCollectingStats(False)
|
|
self.assertFalse(target.GetCollectingStats())
|
|
|
|
# Test the function to get the statistics in JSON'ish.
|
|
stats = target.GetStatistics()
|
|
stream = lldb.SBStream()
|
|
res = stats.GetAsJSON(stream)
|
|
debug_stats = json.loads(stream.GetData())
|
|
self.assertIn(
|
|
"targets",
|
|
debug_stats,
|
|
'Make sure the "targets" key in in target.GetStatistics()',
|
|
)
|
|
self.assertIn(
|
|
"modules",
|
|
debug_stats,
|
|
'Make sure the "modules" key in in target.GetStatistics()',
|
|
)
|
|
stats_json = debug_stats["targets"][0]
|
|
self.assertIn(
|
|
"expressionEvaluation",
|
|
stats_json,
|
|
'Make sure the "expressionEvaluation" key in in target.GetStatistics()["targets"][0]',
|
|
)
|
|
self.assertIn(
|
|
"frameVariable",
|
|
stats_json,
|
|
'Make sure the "frameVariable" key in in target.GetStatistics()["targets"][0]',
|
|
)
|
|
self.assertNotIn(
|
|
"loadCoreTime",
|
|
stats_json,
|
|
"LoadCoreTime should not be present in a live, non-coredump target",
|
|
)
|
|
expressionEvaluation = stats_json["expressionEvaluation"]
|
|
self.assertIn(
|
|
"successes",
|
|
expressionEvaluation,
|
|
'Make sure the "successes" key in in "expressionEvaluation" dictionary"',
|
|
)
|
|
self.assertIn(
|
|
"failures",
|
|
expressionEvaluation,
|
|
'Make sure the "failures" key in in "expressionEvaluation" dictionary"',
|
|
)
|
|
frameVariable = stats_json["frameVariable"]
|
|
self.assertIn(
|
|
"successes",
|
|
frameVariable,
|
|
'Make sure the "successes" key in in "frameVariable" dictionary"',
|
|
)
|
|
self.assertIn(
|
|
"failures",
|
|
frameVariable,
|
|
'Make sure the "failures" key in in "frameVariable" dictionary"',
|
|
)
|
|
|
|
# Test statistics summary.
|
|
stats_options = lldb.SBStatisticsOptions()
|
|
stats_options.SetSummaryOnly(True)
|
|
stats_summary = target.GetStatistics(stats_options)
|
|
stream_summary = lldb.SBStream()
|
|
stats_summary.GetAsJSON(stream_summary)
|
|
debug_stats_summary = json.loads(stream_summary.GetData())
|
|
self.assertNotIn("modules", debug_stats_summary)
|
|
self.assertNotIn("commands", debug_stats_summary)
|
|
|
|
# Summary values should be the same as in full statistics.
|
|
# The exceptions to this are:
|
|
# - The parse time on Mac OS X is not deterministic.
|
|
# - Memory usage may grow over time due to the use of ConstString.
|
|
for key, value in debug_stats_summary.items():
|
|
self.assertIn(key, debug_stats)
|
|
if key != "memory" and key != "targets" and not key.endswith("Time"):
|
|
self.assertEqual(debug_stats[key], value)
|
|
|
|
def test_command_stats_api(self):
|
|
"""
|
|
Test GetCommandInterpreter::GetStatistics() API.
|
|
"""
|
|
self.build()
|
|
exe = self.getBuildArtifact("a.out")
|
|
lldbutil.run_to_name_breakpoint(self, "main")
|
|
|
|
interp = self.dbg.GetCommandInterpreter()
|
|
result = lldb.SBCommandReturnObject()
|
|
interp.HandleCommand("bt", result)
|
|
|
|
stream = lldb.SBStream()
|
|
res = interp.GetStatistics().GetAsJSON(stream)
|
|
command_stats = json.loads(stream.GetData())
|
|
|
|
# Verify bt command is correctly parsed into final form.
|
|
self.assertEqual(command_stats["thread backtrace"], 1)
|
|
# Verify original raw command is not duplicatedly captured.
|
|
self.assertNotIn("bt", command_stats)
|
|
# Verify bt's regex command is not duplicatedly captured.
|
|
self.assertNotIn("_regexp-bt", command_stats)
|
|
|
|
@add_test_categories(["dwo"])
|
|
def test_command_stats_force(self):
|
|
"""
|
|
Test reporting all pssible debug info stats by force loading all debug
|
|
info. For example, dwo files
|
|
"""
|
|
src_dir = self.getSourceDir()
|
|
dwo_yaml_path = os.path.join(src_dir, "main-main.dwo.yaml")
|
|
exe_yaml_path = os.path.join(src_dir, "main.yaml")
|
|
dwo_path = self.getBuildArtifact("main-main.dwo")
|
|
exe_path = self.getBuildArtifact("main")
|
|
self.yaml2obj(dwo_yaml_path, dwo_path)
|
|
self.yaml2obj(exe_yaml_path, exe_path)
|
|
|
|
# Turn on symbols on-demand loading
|
|
self.runCmd("settings set symbols.load-on-demand true")
|
|
|
|
# We need the current working directory to be set to the build directory
|
|
os.chdir(self.getBuildDir())
|
|
# Create a target with the object file we just created from YAML
|
|
target = self.dbg.CreateTarget(exe_path)
|
|
self.assertTrue(target, VALID_TARGET)
|
|
|
|
# Get statistics
|
|
stats_options = lldb.SBStatisticsOptions()
|
|
stats = target.GetStatistics(stats_options)
|
|
stream = lldb.SBStream()
|
|
stats.GetAsJSON(stream)
|
|
debug_stats = json.loads(stream.GetData())
|
|
self.assertEqual(debug_stats["totalDebugInfoByteSize"], 193)
|
|
|
|
# Get statistics with force loading
|
|
stats_options.SetReportAllAvailableDebugInfo(True)
|
|
stats_force = target.GetStatistics(stats_options)
|
|
stream_force = lldb.SBStream()
|
|
stats_force.GetAsJSON(stream_force)
|
|
debug_stats_force = json.loads(stream_force.GetData())
|
|
self.assertEqual(debug_stats_force["totalDebugInfoByteSize"], 445)
|
|
|
|
def test_core_load_time(self):
|
|
"""
|
|
Test to see if the coredump path is included in statistics dump.
|
|
"""
|
|
yaml_file = "arm64-minidump-build-ids.yaml"
|
|
src_dir = self.getSourceDir()
|
|
minidump_path = self.getBuildArtifact(os.path.basename(yaml_file) + ".dmp")
|
|
self.yaml2obj(os.path.join(src_dir, yaml_file), minidump_path)
|
|
target = self.dbg.CreateTarget(None)
|
|
process = target.LoadCore(minidump_path)
|
|
self.assertTrue(process.IsValid())
|
|
|
|
stats_options = lldb.SBStatisticsOptions()
|
|
stats = target.GetStatistics(stats_options)
|
|
stream = lldb.SBStream()
|
|
stats.GetAsJSON(stream)
|
|
debug_stats = json.loads(stream.GetData())
|
|
self.assertTrue("targets" in debug_stats)
|
|
target_info = debug_stats["targets"][0]
|
|
self.assertTrue("loadCoreTime" in target_info)
|
|
self.assertTrue(float(target_info["loadCoreTime"]) > 0.0)
|