#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/Support/JSON.h"
namespace lldb_private {
void RemoveSignal(int signo);
+ /// Track how many times signals are hit as stop reasons.
+ void IncrementSignalHitCount(int signo);
+
+ /// Get the hit count statistics for signals.
+ ///
+ /// Gettings statistics on the hit counts of signals can help explain why some
+ /// debug sessions are slow since each stop takes a few hundred ms and some
+ /// software use signals a lot and can cause slow debugging performance if
+ /// they are used too often. Even if a signal is not stopped at, it will auto
+ /// continue the process and a delay will happen.
+ llvm::json::Value GetHitCountStatistics() const;
+
// Returns a current version of the data stored in this class. Version gets
// incremented each time Set... method is called.
uint64_t GetVersion() const;
ConstString m_name;
ConstString m_alias;
std::string m_description;
+ uint32_t m_hit_count = 0;
bool m_suppress : 1, m_stop : 1, m_notify : 1;
Signal(const char *name, bool default_suppress, bool default_stop,
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
using namespace lldb;
using namespace lldb_private;
}
}
+ ProcessSP process_sp = target.GetProcessSP();
+ if (process_sp) {
+ UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals();
+ if (unix_signals_sp)
+ target_metrics_json.try_emplace("signals",
+ unix_signals_sp->GetHitCountStatistics());
+ }
target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array));
target_metrics_json.try_emplace("totalBreakpointResolveTime",
totalBreakpointResolveTime);
// There's one other complication here. We may have run an async
// breakpoint callback that said we should stop. We only want to
- // override that if another breakpoint action says we shouldn't
+ // override that if another breakpoint action says we shouldn't
// stop. If nobody else has an opinion, then we should stop if the
// async callback says we should. An example of this is the async
// shared library load notification breakpoint and the setting
}
internal_breakpoint = bp_loc_sp->GetBreakpoint().IsInternal();
-
+
// First run the precondition, but since the precondition is per
// breakpoint, only run it once per breakpoint.
std::pair<std::unordered_set<break_id_t>::iterator, bool> result =
else
actually_said_continue = true;
}
-
+
// If we are going to stop for this breakpoint, then remove the
// breakpoint.
if (callback_says_stop && bp_loc_sp &&
// Override should_stop decision when we have completed step plan
// additionally to the breakpoint
m_should_stop = true;
-
+
// We know we're stopping for a completed plan and we don't want to
// show the breakpoint stop, so compute the public stop info immediately
// here.
// performing watchpoint actions.
class WatchpointSentry {
public:
- WatchpointSentry(ProcessSP p_sp, WatchpointSP w_sp) : process_sp(p_sp),
+ WatchpointSentry(ProcessSP p_sp, WatchpointSP w_sp) : process_sp(p_sp),
watchpoint_sp(w_sp) {
if (process_sp && watchpoint_sp) {
const bool notify = false;
process_sp->AddPreResumeAction(SentryPreResumeAction, this);
}
}
-
+
void DoReenable() {
if (process_sp && watchpoint_sp) {
bool was_disabled = watchpoint_sp->IsDisabledDuringEphemeralMode();
}
}
}
-
+
~WatchpointSentry() {
DoReenable();
if (process_sp)
process_sp->ClearPreResumeAction(SentryPreResumeAction, this);
}
-
+
static bool SentryPreResumeAction(void *sentry_void) {
WatchpointSentry *sentry = (WatchpointSentry *) sentry_void;
sentry->DoReenable();
// course of this code. Also by default we're going to stop, so set that
// here.
m_should_stop = true;
-
+
ThreadSP thread_sp(m_thread_wp.lock());
if (thread_sp) {
WatchpointSP wp_sp(
thread_sp->CalculateTarget()->GetWatchpointList().FindByID(
- GetValue()));
+ GetValue()));
if (wp_sp) {
ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
ProcessSP process_sp = exe_ctx.GetProcessSP();
bool old_async = debugger.GetAsyncExecution();
debugger.SetAsyncExecution(true);
-
+
StoppointCallbackContext context(event_ptr, exe_ctx, false);
bool stop_requested = wp_sp->InvokeCallback(&context);
-
+
debugger.SetAsyncExecution(old_async);
-
+
// Also make sure that the callback hasn't continued the target. If
// it did, when we'll set m_should_stop to false and get out of here.
if (HasTargetRunSinceMe())
StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo,
const char *description) {
+ thread.GetProcess()->GetUnixSignals()->IncrementSignalHitCount(signo);
return StopInfoSP(new StopInfoUnixSignal(thread, signo, description));
}
#include "lldb/Utility/ArchSpec.h"
using namespace lldb_private;
+using namespace llvm;
UnixSignals::Signal::Signal(const char *name, bool default_suppress,
bool default_stop, bool default_notify,
return result;
}
+
+void UnixSignals::IncrementSignalHitCount(int signo) {
+ collection::iterator pos = m_signals.find(signo);
+ if (pos != m_signals.end())
+ pos->second.m_hit_count += 1;
+}
+
+json::Value UnixSignals::GetHitCountStatistics() const {
+ json::Array json_signals;
+ for (const auto &pair: m_signals) {
+ if (pair.second.m_hit_count > 0)
+ json_signals.emplace_back(json::Object{
+ { pair.second.m_name.GetCString(), pair.second.m_hit_count }
+ });
+ }
+ return std::move(json_signals);
+}
thread.GetStopReasonDataAtIndex(0), lldbutil.get_signal_number('SIGUSR1'),
"The stop signal was SIGUSR1")
+ self.match("statistics dump",
+ [r'"signals": \[', r'"SIGUSR1": 1'])
+
+
def match_state(self, process_listener, expected_state):
num_seconds = 5
broadcaster = self.process().GetBroadcaster()