wallace updated this revision to Diff 442765.
wallace added a comment.
make relative all paths being returned in the description file
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D129239/new/
https://reviews.llvm.org/D129239
Files:
lldb/bindings/interface/SBTrace.i
lldb/include/lldb/API/SBTrace.h
lldb/include/lldb/Target/Trace.h
lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
lldb/source/API/SBTrace.cpp
lldb/source/Commands/CommandObjectProcess.cpp
lldb/source/Commands/CommandObjectTrace.cpp
lldb/source/Commands/Options.td
lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h
lldb/test/API/commands/trace/TestTraceLoad.py
Index: lldb/test/API/commands/trace/TestTraceLoad.py
===================================================================
--- lldb/test/API/commands/trace/TestTraceLoad.py
+++ lldb/test/API/commands/trace/TestTraceLoad.py
@@ -20,6 +20,39 @@
substrs=["67911: [tsc=40450075477799536] 0x0000000000400bd7 addl $0x1, -0x4(%rbp)",
"m.out`bar() + 26 at multi_thread.cpp:20:6"])
+ @testSBAPIAndCommands
+ def testLoadCompactMultiCoreTrace(self):
+ src_dir = self.getSourceDir()
+ trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace.json")
+ self.traceLoad(traceDescriptionFilePath=trace_description_file_path, substrs=["intel-pt"])
+
+ self.expect("thread trace dump info 2", substrs=["Total number of continuous executions found: 153"])
+
+ # we'll save the trace in compact format
+ compact_trace_bundle_dir = os.path.join(self.getBuildDir(), "intelpt-multi-core-trace-compact")
+ self.traceSave(compact_trace_bundle_dir, compact=True)
+
+ # we'll delete the previous target and make sure it's trace object is deleted
+ self.dbg.DeleteTarget(self.dbg.GetTargetAtIndex(0))
+ self.expect("thread trace dump instructions 2 -t", substrs=["error: invalid target"], error=True)
+
+ # we'll load the compact trace and make sure it works
+ self.traceLoad(os.path.join(compact_trace_bundle_dir, "trace.json"), substrs=["intel-pt"])
+ self.expect("thread trace dump instructions 2 -t",
+ substrs=["19522: [tsc=40450075478109270] (error) expected tracing enabled event",
+ "m.out`foo() + 65 at multi_thread.cpp:12:21",
+ "19520: [tsc=40450075477657246] 0x0000000000400ba7 jg 0x400bb3"])
+ self.expect("thread trace dump instructions 3 -t",
+ substrs=["67911: [tsc=40450075477799536] 0x0000000000400bd7 addl $0x1, -0x4(%rbp)",
+ "m.out`bar() + 26 at multi_thread.cpp:20:6"])
+
+ # This reduced the number of continuous executions to look at
+ self.expect("thread trace dump info 2", substrs=["Total number of continuous executions found: 3"])
+
+ # We clean up for the next run of this test
+ self.dbg.DeleteTarget(self.dbg.GetTargetAtIndex(0))
+
+
@testSBAPIAndCommands
def testLoadMultiCoreTraceWithStringNumbers(self):
src_dir = self.getSourceDir()
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h
@@ -31,10 +31,16 @@
/// \param[in] directory
/// The directory where the trace bundle will be created.
///
+ /// \param[in] compact
+ /// Filter out information irrelevant to the traced processes in the
+ /// context switch and intel pt traces when using per-cpu mode. This
+ /// effectively reduces the size of those traces.
+ ///
/// \return
- /// \a llvm::success if the operation was successful, or an \a llvm::Error
- /// otherwise.
- llvm::Error SaveToDisk(TraceIntelPT &trace_ipt, FileSpec directory);
+ /// A \a FileSpec pointing to the bundle description file, or an \a
+ /// llvm::Error otherwise.
+ llvm::Expected<FileSpec> SaveToDisk(TraceIntelPT &trace_ipt,
+ FileSpec directory, bool compact);
};
} // namespace trace_intel_pt
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
@@ -7,8 +7,11 @@
//===----------------------------------------------------------------------===//
#include "TraceIntelPTBundleSaver.h"
+
+#include "PerfContextSwitchDecoder.h"
#include "TraceIntelPT.h"
#include "TraceIntelPTJSONStructs.h"
+
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Target/Process.h"
@@ -30,6 +33,13 @@
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
+/// Strip the \p directory component from the given \p path. It assumes that \p
+/// directory is a prefix of \p path.
+static std::string GetRelativePath(const FileSpec &directory,
+ const FileSpec &path) {
+ return path.GetPath().substr(directory.GetPath().size() + 1);
+}
+
/// Write a stream of bytes from \p data to the given output file.
/// It creates or overwrites the output file, but not append.
static llvm::Error WriteBytesToDisk(FileSpec &output_file,
@@ -57,11 +67,11 @@
/// The directory where the JSON file will be saved.
///
/// \return
-/// \a llvm::Success if the operation was successful, or an \a llvm::Error
-/// otherwise.
-static llvm::Error
+/// A \a FileSpec pointing to the bundle description file, or an \a
+/// llvm::Error otherwise.
+static Expected<FileSpec>
SaveTraceBundleDescription(const llvm::json::Value &trace_bundle_description,
- const FileSpec &directory) {
+ const FileSpec &directory) {
FileSpec trace_path = directory;
trace_path.AppendPathComponent("trace.json");
std::ofstream os(trace_path.GetPath());
@@ -71,7 +81,7 @@
return createStringError(inconvertibleErrorCode(),
formatv("couldn't write to the file {0}",
trace_path.GetPath().c_str()));
- return Error::success();
+ return trace_path;
}
/// Build the threads sub-section of the trace bundle description file.
@@ -106,7 +116,7 @@
if (trace_sp->GetTracedCpus().empty()) {
FileSpec output_file = threads_dir;
output_file.AppendPathComponent(std::to_string(tid) + ".intelpt_trace");
- json_thread.ipt_trace = output_file.GetPath();
+ json_thread.ipt_trace = GetRelativePath(directory, output_file);
llvm::Error err = process.GetTarget().GetTrace()->OnThreadBinaryDataRead(
tid, IntelPTDataKinds::kIptTrace,
@@ -122,8 +132,68 @@
return json_threads;
}
+/// \return
+/// an \a llvm::Error in case of failures, \a None if the trace is not written
+/// to disk because the trace is empty and the \p compact flag is present, or
+/// the FileSpec of the trace file on disk.
+static Expected<Optional<FileSpec>>
+WriteContextSwitchTrace(TraceIntelPT &trace_ipt, lldb::cpu_id_t cpu_id,
+ const FileSpec &cpus_dir, bool compact) {
+ FileSpec output_context_switch_trace = cpus_dir;
+ output_context_switch_trace.AppendPathComponent(std::to_string(cpu_id) +
+ ".perf_context_switch_trace");
+
+ bool should_skip = false;
+
+ Error err = trace_ipt.OnCpuBinaryDataRead(
+ cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
+ [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
+ if (!compact)
+ return WriteBytesToDisk(output_context_switch_trace, data);
+
+ std::set<lldb::pid_t> pids;
+ for (Process *process : trace_ipt.GetAllProcesses())
+ pids.insert(process->GetID());
+
+ Expected<std::vector<uint8_t>> compact_context_switch_trace =
+ FilterProcessesFromContextSwitchTrace(data, pids);
+ if (!compact_context_switch_trace)
+ return compact_context_switch_trace.takeError();
+
+ if (compact_context_switch_trace->empty()) {
+ should_skip = true;
+ return Error::success();
+ }
+
+ return WriteBytesToDisk(output_context_switch_trace,
+ *compact_context_switch_trace);
+ });
+ if (err)
+ return std::move(err);
+
+ if (should_skip)
+ return None;
+ return output_context_switch_trace;
+}
+
+static Expected<FileSpec> WriteIntelPTTrace(TraceIntelPT &trace_ipt,
+ lldb::cpu_id_t cpu_id,
+ const FileSpec &cpus_dir) {
+ FileSpec output_trace = cpus_dir;
+ output_trace.AppendPathComponent(std::to_string(cpu_id) + ".intelpt_trace");
+
+ Error err = trace_ipt.OnCpuBinaryDataRead(
+ cpu_id, IntelPTDataKinds::kIptTrace,
+ [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
+ return WriteBytesToDisk(output_trace, data);
+ });
+ if (err)
+ return std::move(err);
+ return output_trace;
+}
+
static llvm::Expected<llvm::Optional<std::vector<JSONCpu>>>
-BuildCpusSection(TraceIntelPT &trace_ipt, FileSpec directory) {
+BuildCpusSection(TraceIntelPT &trace_ipt, FileSpec directory, bool compact) {
if (trace_ipt.GetTracedCpus().empty())
return None;
@@ -135,36 +205,21 @@
for (lldb::cpu_id_t cpu_id : trace_ipt.GetTracedCpus()) {
JSONCpu json_cpu;
json_cpu.id = cpu_id;
+ Expected<Optional<FileSpec>> context_switch_trace_path =
+ WriteContextSwitchTrace(trace_ipt, cpu_id, cpus_dir, compact);
+ if (!context_switch_trace_path)
+ return context_switch_trace_path.takeError();
+ if (!*context_switch_trace_path)
+ continue;
+ json_cpu.context_switch_trace =
+ GetRelativePath(directory, **context_switch_trace_path);
- {
- FileSpec output_trace = cpus_dir;
- output_trace.AppendPathComponent(std::to_string(cpu_id) +
- ".intelpt_trace");
- json_cpu.ipt_trace = output_trace.GetPath();
-
- llvm::Error err = trace_ipt.OnCpuBinaryDataRead(
- cpu_id, IntelPTDataKinds::kIptTrace,
- [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
- return WriteBytesToDisk(output_trace, data);
- });
- if (err)
- return std::move(err);
- }
-
- {
- FileSpec output_context_switch_trace = cpus_dir;
- output_context_switch_trace.AppendPathComponent(
- std::to_string(cpu_id) + ".perf_context_switch_trace");
- json_cpu.context_switch_trace = output_context_switch_trace.GetPath();
+ if (Expected<FileSpec> ipt_trace_path =
+ WriteIntelPTTrace(trace_ipt, cpu_id, cpus_dir))
+ json_cpu.ipt_trace = GetRelativePath(directory, *ipt_trace_path);
+ else
+ return ipt_trace_path.takeError();
- llvm::Error err = trace_ipt.OnCpuBinaryDataRead(
- cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
- [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
- return WriteBytesToDisk(output_context_switch_trace, data);
- });
- if (err)
- return std::move(err);
- }
json_cpus.push_back(std::move(json_cpu));
}
return json_cpus;
@@ -222,14 +277,14 @@
path_to_copy_module.AppendPathComponent(system_path);
sys::fs::create_directories(path_to_copy_module.GetDirectory().AsCString());
- if (std::error_code ec = llvm::sys::fs::copy_file(
- system_path, path_to_copy_module.GetPath()))
+ if (std::error_code ec =
+ llvm::sys::fs::copy_file(file, path_to_copy_module.GetPath()))
return createStringError(
inconvertibleErrorCode(),
formatv("couldn't write to the file. {0}", ec.message()));
json_modules.push_back(
- JSONModule{system_path, path_to_copy_module.GetPath(),
+ JSONModule{system_path, GetRelativePath(directory, path_to_copy_module),
JSONUINT64{load_addr}, module_sp->GetUUID().GetAsString()});
}
return json_modules;
@@ -280,8 +335,9 @@
return processes;
}
-Error TraceIntelPTBundleSaver::SaveToDisk(TraceIntelPT &trace_ipt,
- FileSpec directory) {
+Expected<FileSpec> TraceIntelPTBundleSaver::SaveToDisk(TraceIntelPT &trace_ipt,
+ FileSpec directory,
+ bool compact) {
if (std::error_code ec =
sys::fs::create_directories(directory.GetPath().c_str()))
return llvm::errorCodeToError(ec);
@@ -299,7 +355,7 @@
return json_processes.takeError();
Expected<Optional<std::vector<JSONCpu>>> json_cpus =
- BuildCpusSection(trace_ipt, directory);
+ BuildCpusSection(trace_ipt, directory, compact);
if (!json_cpus)
return json_cpus.takeError();
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -25,7 +25,8 @@
public:
void Dump(Stream *s) const override;
- llvm::Error SaveLiveTraceToDisk(FileSpec directory) override;
+ llvm::Expected<FileSpec> SaveToDisk(FileSpec directory,
+ bool compact) override;
~TraceIntelPT() override = default;
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -55,9 +55,9 @@
void TraceIntelPT::Dump(Stream *s) const {}
-llvm::Error TraceIntelPT::SaveLiveTraceToDisk(FileSpec directory) {
+Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) {
RefreshLiveProcessState();
- return TraceIntelPTBundleSaver().SaveToDisk(*this, directory);
+ return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact);
}
Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(
Index: lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
+++ lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
@@ -14,6 +14,7 @@
#include "llvm/Support/Error.h"
+#include <set>
#include <vector>
namespace lldb_private {
@@ -139,6 +140,10 @@
lldb::cpu_id_t cpu_id,
const LinuxPerfZeroTscConversion &tsc_conversion);
+llvm::Expected<std::vector<uint8_t>>
+FilterProcessesFromContextSwitchTrace(llvm::ArrayRef<uint8_t> data,
+ const std::set<lldb::pid_t> &pids);
+
} // namespace trace_intel_pt
} // namespace lldb_private
Index: lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
+++ lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
@@ -16,8 +16,13 @@
/// non-linux platforms.
/// \{
#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13)
-#define PERF_RECORD_MAX 19
+
+#define PERF_RECORD_LOST 2
+#define PERF_RECORD_THROTTLE 5
+#define PERF_RECORD_UNTHROTTLE 6
+#define PERF_RECORD_LOST_SAMPLES 13
#define PERF_RECORD_SWITCH_CPU_WIDE 15
+#define PERF_RECORD_MAX 19
struct perf_event_header {
uint32_t type;
@@ -54,6 +59,11 @@
bool IsContextSwitchRecord() const {
return type == PERF_RECORD_SWITCH_CPU_WIDE;
}
+
+ bool IsErrorRecord() const {
+ return type == PERF_RECORD_LOST || type == PERF_RECORD_THROTTLE ||
+ type == PERF_RECORD_UNTHROTTLE || type == PERF_RECORD_LOST_SAMPLES;
+ }
};
/// \}
@@ -286,3 +296,36 @@
return executions;
}
+
+Expected<std::vector<uint8_t>>
+lldb_private::trace_intel_pt::FilterProcessesFromContextSwitchTrace(
+ llvm::ArrayRef<uint8_t> data, const std::set<lldb::pid_t> &pids) {
+ size_t offset = 0;
+ std::vector<uint8_t> out_data;
+
+ while (offset < data.size()) {
+ const perf_event_header &perf_record =
+ *reinterpret_cast<const perf_event_header *>(data.data() + offset);
+ if (Error err = perf_record.SanityCheck())
+ return std::move(err);
+ bool should_copy = false;
+ if (perf_record.IsContextSwitchRecord()) {
+ const PerfContextSwitchRecord &context_switch_record =
+ *reinterpret_cast<const PerfContextSwitchRecord *>(data.data() +
+ offset);
+ if (pids.count(context_switch_record.pid))
+ should_copy = true;
+ } else if (perf_record.IsErrorRecord()) {
+ should_copy = true;
+ }
+
+ if (should_copy) {
+ for (size_t i = 0; i < perf_record.size; i++) {
+ out_data.push_back(data[offset + i]);
+ }
+ }
+
+ offset += perf_record.size;
+ }
+ return out_data;
+}
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -786,9 +786,14 @@
let Command = "process trace save" in {
def process_trace_save_directory: Option<"directory", "d">,
Group<1>,
- Arg<"Value">, Required,
+ Arg<"Filename">, Required,
Desc<"The directory where the trace will be saved."
"It will be created if it does not exist.">;
+ def process_trace_save_compact: Option<"compact", "c">,
+ Group<1>,
+ Desc<"Try not to save to disk information irrelevant to the traced "
+ "processes. Each trace plug-in implements this in a different "
+ "fashion.">;
}
let Command = "script import" in {
Index: lldb/source/Commands/CommandObjectTrace.cpp
===================================================================
--- lldb/source/Commands/CommandObjectTrace.cpp
+++ lldb/source/Commands/CommandObjectTrace.cpp
@@ -76,10 +76,18 @@
interpreter, "trace load",
"Load a post-mortem processor trace session from a trace bundle.",
"trace load") {
- CommandArgumentData session_file_arg{eArgTypePath, eArgRepeatPlain};
+ CommandArgumentData session_file_arg{eArgTypeFilename, eArgRepeatPlain};
m_arguments.push_back({session_file_arg});
}
+ void
+ HandleArgumentCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector) override {
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
+ request, nullptr);
+ }
+
~CommandObjectTraceLoad() override = default;
Options *GetOptions() override { return &m_options; }
Index: lldb/source/Commands/CommandObjectProcess.cpp
===================================================================
--- lldb/source/Commands/CommandObjectProcess.cpp
+++ lldb/source/Commands/CommandObjectProcess.cpp
@@ -579,14 +579,14 @@
}
}
}
-
+
Target *target = m_exe_ctx.GetTargetPtr();
BreakpointIDList run_to_bkpt_ids;
// Don't pass an empty run_to_breakpoint list, as Verify will look for the
// default breakpoint.
if (m_options.m_run_to_bkpt_args.GetArgumentCount() > 0)
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
- m_options.m_run_to_bkpt_args, target, result, &run_to_bkpt_ids,
+ m_options.m_run_to_bkpt_args, target, result, &run_to_bkpt_ids,
BreakpointName::Permissions::disablePerm);
if (!result.Succeeded()) {
return false;
@@ -604,7 +604,7 @@
std::vector<break_id_t> bkpts_disabled;
std::vector<BreakpointID> locs_disabled;
if (num_run_to_bkpt_ids != 0) {
- // Go through the ID's specified, and separate the breakpoints from are
+ // Go through the ID's specified, and separate the breakpoints from are
// the breakpoint.location specifications since the latter require
// special handling. We also figure out whether there's at least one
// specifier in the set that is enabled.
@@ -613,23 +613,22 @@
std::unordered_set<break_id_t> bkpts_with_locs_seen;
BreakpointIDList with_locs;
bool any_enabled = false;
-
+
for (size_t idx = 0; idx < num_run_to_bkpt_ids; idx++) {
BreakpointID bkpt_id = run_to_bkpt_ids.GetBreakpointIDAtIndex(idx);
break_id_t bp_id = bkpt_id.GetBreakpointID();
break_id_t loc_id = bkpt_id.GetLocationID();
- BreakpointSP bp_sp
- = bkpt_list.FindBreakpointByID(bp_id);
- // Note, VerifyBreakpointOrLocationIDs checks for existence, so we
+ BreakpointSP bp_sp = bkpt_list.FindBreakpointByID(bp_id);
+ // Note, VerifyBreakpointOrLocationIDs checks for existence, so we
// don't need to do it again here.
if (bp_sp->IsEnabled()) {
if (loc_id == LLDB_INVALID_BREAK_ID) {
- // A breakpoint (without location) was specified. Make sure that
+ // A breakpoint (without location) was specified. Make sure that
// at least one of the locations is enabled.
size_t num_locations = bp_sp->GetNumLocations();
for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) {
- BreakpointLocationSP loc_sp
- = bp_sp->GetLocationAtIndex(loc_idx);
+ BreakpointLocationSP loc_sp =
+ bp_sp->GetLocationAtIndex(loc_idx);
if (loc_sp->IsEnabled()) {
any_enabled = true;
break;
@@ -641,7 +640,7 @@
if (loc_sp->IsEnabled())
any_enabled = true;
}
-
+
// Then sort the bp & bp.loc entries for later use:
if (bkpt_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
bkpts_seen.insert(bkpt_id.GetBreakpointID());
@@ -653,14 +652,14 @@
}
// Do all the error checking here so once we start disabling we don't
// have to back out half-way through.
-
+
// Make sure at least one of the specified breakpoints is enabled.
if (!any_enabled) {
result.AppendError("at least one of the continue-to breakpoints must "
"be enabled.");
return false;
}
-
+
// Also, if you specify BOTH a breakpoint and one of it's locations,
// we flag that as an error, since it won't do what you expect, the
// breakpoint directive will mean "run to all locations", which is not
@@ -671,7 +670,7 @@
"one of its locations: {0}", bp_id);
}
}
-
+
// Now go through the breakpoints in the target, disabling all the ones
// that the user didn't mention:
for (BreakpointSP bp_sp : bkpt_list.Breakpoints()) {
@@ -695,8 +694,8 @@
BreakpointLocationSP loc_sp = bp_sp->GetLocationAtIndex(loc_idx);
tmp_id.SetBreakpointLocationID(loc_idx);
size_t position = 0;
- if (!with_locs.FindBreakpointID(tmp_id, &position)
- && loc_sp->IsEnabled()) {
+ if (!with_locs.FindBreakpointID(tmp_id, &position) &&
+ loc_sp->IsEnabled()) {
locs_disabled.push_back(tmp_id);
loc_sp->SetEnabled(false);
}
@@ -723,20 +722,20 @@
Status error;
// For now we can only do -b with synchronous:
bool old_sync = GetDebugger().GetAsyncExecution();
-
+
if (run_to_bkpt_ids.GetSize() != 0) {
GetDebugger().SetAsyncExecution(false);
synchronous_execution = true;
- }
+ }
if (synchronous_execution)
error = process->ResumeSynchronous(&stream);
else
error = process->Resume();
-
+
if (run_to_bkpt_ids.GetSize() != 0) {
GetDebugger().SetAsyncExecution(old_sync);
- }
-
+ }
+
// Now re-enable the breakpoints we disabled:
BreakpointList &bkpt_list = target->GetBreakpointList();
for (break_id_t bp_id : bkpts_disabled) {
@@ -745,11 +744,11 @@
bp_sp->SetEnabled(true);
}
for (const BreakpointID &bkpt_id : locs_disabled) {
- BreakpointSP bp_sp
- = bkpt_list.FindBreakpointByID(bkpt_id.GetBreakpointID());
+ BreakpointSP bp_sp =
+ bkpt_list.FindBreakpointByID(bkpt_id.GetBreakpointID());
if (bp_sp) {
- BreakpointLocationSP loc_sp
- = bp_sp->FindLocationByID(bkpt_id.GetLocationID());
+ BreakpointLocationSP loc_sp =
+ bp_sp->FindLocationByID(bkpt_id.GetLocationID());
if (loc_sp)
loc_sp->SetEnabled(true);
}
@@ -1731,7 +1730,7 @@
bool DoExecute(Args &signal_args, CommandReturnObject &result) override {
Target &target = GetSelectedOrDummyTarget();
- // Any signals that are being set should be added to the Target's
+ // Any signals that are being set should be added to the Target's
// DummySignals so they will get applied on rerun, etc.
// If we have a process, however, we can do a more accurate job of vetting
// the user's options.
@@ -1761,9 +1760,9 @@
"true or false.\n");
return false;
}
-
- bool no_actions = (stop_action == -1 && pass_action == -1
- && notify_action == -1);
+
+ bool no_actions =
+ (stop_action == -1 && pass_action == -1 && notify_action == -1);
if (m_options.only_target_values && !no_actions) {
result.AppendError("-t is for reporting, not setting, target values.");
return false;
@@ -1832,9 +1831,9 @@
}
auto set_lazy_bool = [] (int action) -> LazyBool {
LazyBool lazy;
- if (action == -1)
+ if (action == -1)
lazy = eLazyBoolCalculate;
- else if (action)
+ else if (action)
lazy = eLazyBoolYes;
else
lazy = eLazyBoolNo;
@@ -1876,8 +1875,7 @@
PrintSignalInformation(result.GetOutputStream(), signal_args,
num_signals_set, signals_sp);
else
- target.PrintDummySignals(result.GetOutputStream(),
- signal_args);
+ target.PrintDummySignals(result.GetOutputStream(), signal_args);
if (num_signals_set > 0)
result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -1933,19 +1931,26 @@
FileSystem::Instance().Resolve(m_directory);
break;
}
+ case 'c': {
+ m_compact = true;
+ break;
+ }
default:
llvm_unreachable("Unimplemented option");
}
return error;
}
- void OptionParsingStarting(ExecutionContext *execution_context) override{};
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_compact = false;
+ };
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
return llvm::makeArrayRef(g_process_trace_save_options);
};
FileSpec m_directory;
+ bool m_compact;
};
Options *GetOptions() override { return &m_options; }
@@ -1972,10 +1977,14 @@
TraceSP trace_sp = process_sp->GetTarget().GetTrace();
- if (llvm::Error err = trace_sp->SaveLiveTraceToDisk(m_options.m_directory))
- result.AppendError(toString(std::move(err)));
- else
+ if (llvm::Expected<FileSpec> desc_file =
+ trace_sp->SaveToDisk(m_options.m_directory, m_options.m_compact)) {
+ result.AppendMessageWithFormatv(
+ "Trace bundle description file written to: {0}", *desc_file);
result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError(toString(desc_file.takeError()));
+ }
return result.Succeeded();
}
Index: lldb/source/API/SBTrace.cpp
===================================================================
--- lldb/source/API/SBTrace.cpp
+++ lldb/source/API/SBTrace.cpp
@@ -43,6 +43,24 @@
return SBTrace(trace_or_err.get());
}
+SBFileSpec SBTrace::SaveToDisk(SBError &error, const SBFileSpec &bundle_dir,
+ bool compact) {
+ LLDB_INSTRUMENT_VA(this, error, bundle_dir, compact);
+
+ error.Clear();
+ SBFileSpec file_spec;
+
+ if (!m_opaque_sp)
+ error.SetErrorString("error: invalid trace");
+ else if (Expected<FileSpec> desc_file =
+ m_opaque_sp->SaveToDisk(bundle_dir.ref(), compact))
+ file_spec.SetFileSpec(*desc_file);
+ else
+ error.SetErrorString(llvm::toString(desc_file.takeError()).c_str());
+
+ return file_spec;
+}
+
const char *SBTrace::GetStartConfigurationHelp() {
LLDB_INSTRUMENT_VA(this);
return m_opaque_sp ? m_opaque_sp->GetStartConfigurationHelp() : nullptr;
Index: lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
+++ lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
@@ -138,8 +138,20 @@
if self.USE_SB_API:
traceDescriptionFile = lldb.SBFileSpec(traceDescriptionFilePath, True)
loadTraceError = lldb.SBError()
- _trace = self.dbg.LoadTraceFromFile(loadTraceError, traceDescriptionFile)
+ self.dbg.LoadTraceFromFile(loadTraceError, traceDescriptionFile)
self.assertSBError(loadTraceError, error)
else:
command = f"trace load -v {traceDescriptionFilePath}"
self.expect(command, error=error, substrs=substrs)
+
+ def traceSave(self, traceBundleDir, compact=False, error=False, substrs=None):
+ if self.USE_SB_API:
+ save_error = lldb.SBError()
+ self.target().GetTrace().SaveToDisk(
+ save_error, lldb.SBFileSpec(traceBundleDir), compact)
+ self.assertSBError(save_error, error)
+ else:
+ command = f"process trace save -d {traceBundleDir}"
+ if compact:
+ command += " -c"
+ self.expect(command, error=error, substrs=substrs)
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -56,21 +56,24 @@
/// A stream object to dump the information to.
virtual void Dump(Stream *s) const = 0;
- /// Save the trace of a live process to the specified directory, which
- /// will be created if needed.
- /// This will also create a a file \a <directory>/trace.json with the main
- /// properties of the trace session, along with others files which contain
- /// the actual trace data. The trace.json file can be used later as input
- /// for the "trace load" command to load the trace in LLDB.
- /// The process being trace is not a live process, return an error.
+ /// Save the trace to the specified directory, which will be created if
+ /// needed. This will also create a a file \a <directory>/trace.json with the
+ /// main properties of the trace session, along with others files which
+ /// contain the actual trace data. The trace.json file can be used later as
+ /// input for the "trace load" command to load the trace in LLDB.
///
/// \param[in] directory
/// The directory where the trace files will be saved.
///
+ /// \param[in] compact
+ /// Try not to save to disk information irrelevant to the traced processes.
+ /// Each trace plug-in implements this in a different fashion.
+ ///
/// \return
- /// \a llvm::success if the operation was successful, or an \a llvm::Error
- /// otherwise.
- virtual llvm::Error SaveLiveTraceToDisk(FileSpec directory) = 0;
+ /// A \a FileSpec pointing to the bundle description file, or an \a
+ /// llvm::Error otherwise.
+ virtual llvm::Expected<FileSpec> SaveToDisk(FileSpec directory,
+ bool compact) = 0;
/// Find a trace plug-in using JSON data.
///
Index: lldb/include/lldb/API/SBTrace.h
===================================================================
--- lldb/include/lldb/API/SBTrace.h
+++ lldb/include/lldb/API/SBTrace.h
@@ -25,6 +25,28 @@
static SBTrace LoadTraceFromFile(SBError &error, SBDebugger &debugger,
const SBFileSpec &trace_description_file);
+ /// Save the trace to the specified directory, which will be created if
+ /// needed. This will also create a a file \a <directory>/trace.json with the
+ /// main properties of the trace session, along with others files which
+ /// contain the actual trace data. The trace.json file can be used later as
+ /// input for the "trace load" command to load the trace in LLDB, or for the
+ /// method \a SBDebugger.LoadTraceFromFile().
+ ///
+ /// \param[out] error
+ /// This will be set with an error in case of failures.
+ ///
+ /// \param[in] directory
+ /// The directory where the trace files will be saved.
+ ///
+ /// \param[in] compact
+ /// Try not to save to disk information irrelevant to the traced processes.
+ /// Each trace plug-in implements this in a different fashion.
+ ///
+ /// \return
+ /// A \a SBFileSpec pointing to the bundle description file.
+ SBFileSpec SaveToDisk(SBError &error, const SBFileSpec &bundle_dir,
+ bool compact = false);
+
/// \return
/// A description of the parameters to use for the \a SBTrace::Start
/// method, or \b null if the object is invalid.
Index: lldb/bindings/interface/SBTrace.i
===================================================================
--- lldb/bindings/interface/SBTrace.i
+++ lldb/bindings/interface/SBTrace.i
@@ -17,6 +17,8 @@
const char *GetStartConfigurationHelp();
+ SBFileSpec SaveToDisk(SBError &error, const SBFileSpec &bundle_dir, bool compact = false);
+
SBError Start(const SBStructuredData &configuration);
SBError Start(const SBThread &thread, const SBStructuredData &configuration);
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits