llvm-project/lldb/test/API/commands/trace/TestTraceLoad.py
Walter Erquinigo bdf3e7e5b8 [trace][intelpt] Add task timer classes
I'm adding two new classes that can be used to measure the duration of long
tasks as process and thread level, e.g. decoding, fetching data from
lldb-server, etc. In this first patch, I'm using it to measure the time it takes
to decode each thread, which is printed out with the `dump info` command. In a
later patch I'll start adding process-level tasks and I might move these
classes to the upper Trace level, instead of having them in the intel-pt
plugin. I might need to do that anyway in the future when we have to
measure HTR. For now, I want to keep the impact of this change minimal.

With it, I was able to generate the following info of a very big trace:

```
(lldb) thread trace dump info                                                                                                            Trace technology: intel-pt

thread #1: tid = 616081
  Total number of instructions: 9729366

  Memory usage:
    Raw trace size: 1024 KiB
    Total approximate memory usage (excluding raw trace): 123517.34 KiB
    Average memory usage per instruction (excluding raw trace): 13.00 bytes

  Timing:
    Decoding instructions: 1.62s

  Errors:
    Number of TSC decoding errors: 0
```

As seen above, it took 1.62 seconds to decode 9.7M instructions. This is great
news, as we don't need to do any optimization work in this area.

Differential Revision: https://reviews.llvm.org/D123357
2022-04-12 13:08:03 -07:00

111 lines
4.0 KiB
Python

import lldb
from intelpt_testcase import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test.decorators import *
class TestTraceLoad(TraceIntelPTTestCaseBase):
mydir = TestBase.compute_mydir(__file__)
NO_DEBUG_INFO_TESTCASE = True
def testLoadTrace(self):
src_dir = self.getSourceDir()
trace_definition_file = os.path.join(src_dir, "intelpt-trace", "trace.json")
self.expect("trace load -v " + trace_definition_file, substrs=["intel-pt"])
target = self.dbg.GetSelectedTarget()
process = target.GetProcess()
self.assertEqual(process.GetProcessID(), 1234)
self.assertEqual(process.GetNumThreads(), 1)
self.assertEqual(process.GetThreadAtIndex(0).GetThreadID(), 3842849)
self.assertEqual(target.GetNumModules(), 1)
module = target.GetModuleAtIndex(0)
path = module.GetFileSpec()
self.assertEqual(path.fullpath, os.path.join(src_dir, "intelpt-trace", "a.out"))
self.assertGreater(module.GetNumSections(), 0)
self.assertEqual(module.GetSectionAtIndex(0).GetFileAddress(), 0x400000)
self.assertEqual("6AA9A4E2-6F28-2F33-377D-59FECE874C71-5B41261A", module.GetUUIDString())
# check that the Process and Thread objects were created correctly
self.expect("thread info", substrs=["tid = 3842849"])
self.expect("thread list", substrs=["Process 1234 stopped", "tid = 3842849"])
self.expect("thread trace dump info", substrs=['''Trace technology: intel-pt
thread #1: tid = 3842849
Total number of instructions: 21
Memory usage:
Raw trace size: 4 KiB
Total approximate memory usage (excluding raw trace): 0.27 KiB
Average memory usage per instruction (excluding raw trace): 13.00 bytes
Timing:
Decoding instructions: ''', '''s
Errors:
Number of TSC decoding errors: 0'''])
def testLoadInvalidTraces(self):
src_dir = self.getSourceDir()
# We test first an invalid type
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad.json"), error=True,
substrs=['''error: expected object at traceSession.processes[0]
Context:
{
"processes": [
/* error: expected object */
123
],
"trace": { ... }
}
Schema:
{
"trace": {
"type": "intel-pt",
"cpuInfo": {
"vendor": "intel" | "unknown",
"family": integer,
"model": integer,
"stepping": integer
}
},'''])
# Now we test a missing field in the global session file
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad2.json"), error=True,
substrs=['error: missing value at traceSession.processes[1].triple', "Context", "Schema"])
# Now we test a missing field in the intel-pt settings
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad4.json"), error=True,
substrs=['''error: missing value at traceSession.trace.cpuInfo.family
Context:
{
"processes": [],
"trace": {
"cpuInfo": /* error: missing value */ {
"model": 79,
"stepping": 1,
"vendor": "intel"
},
"type": "intel-pt"
}
}''', "Schema"])
# Now we test an incorrect load address in the intel-pt settings
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad5.json"), error=True,
substrs=['error: expected numeric string at traceSession.processes[0].modules[0].loadAddress',
'"loadAddress": /* error: expected numeric string */ 400000,', "Schema"])
# The following wrong schema will have a valid target and an invalid one. In the case of failure,
# no targets should be created.
self.assertEqual(self.dbg.GetNumTargets(), 0)
self.expect("trace load -v " + os.path.join(src_dir, "intelpt-trace", "trace_bad3.json"), error=True,
substrs=['error: missing value at traceSession.processes[1].pid'])
self.assertEqual(self.dbg.GetNumTargets(), 0)