Add unix signal hit counts to the target statistics.

Android and other platforms make wide use of signals when running applications and this can slow down debug sessions. Tracking this statistic can help us to determine why a debug session is slow.

The new data appears inside each target object and reports the signal hit counts:

      "signals": [
        {
          "SIGSTOP": 1
        },
        {
          "SIGUSR1": 1
        }
      ],

Differential Revision: https://reviews.llvm.org/D112683
This commit is contained in:
Greg Clayton 2021-10-27 18:33:17 -07:00
parent eacd6e1ebe
commit 1300556479
5 changed files with 59 additions and 13 deletions

View File

@ -16,6 +16,7 @@
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/JSON.h"
namespace lldb_private {
@ -80,6 +81,18 @@ public:
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;
@ -99,6 +112,7 @@ protected:
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,

View File

@ -11,7 +11,9 @@
#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;
@ -95,6 +97,13 @@ json::Value TargetStats::ToJSON(Target &target) {
}
}
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);

View File

@ -307,7 +307,7 @@ protected:
// 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
@ -425,7 +425,7 @@ protected:
}
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 =
@ -535,7 +535,7 @@ protected:
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 &&
@ -579,7 +579,7 @@ protected:
// 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.
@ -615,7 +615,7 @@ public:
// 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;
@ -624,7 +624,7 @@ public:
process_sp->AddPreResumeAction(SentryPreResumeAction, this);
}
}
void DoReenable() {
if (process_sp && watchpoint_sp) {
bool was_disabled = watchpoint_sp->IsDisabledDuringEphemeralMode();
@ -637,13 +637,13 @@ public:
}
}
}
~WatchpointSentry() {
DoReenable();
if (process_sp)
process_sp->ClearPreResumeAction(SentryPreResumeAction, this);
}
static bool SentryPreResumeAction(void *sentry_void) {
WatchpointSentry *sentry = (WatchpointSentry *) sentry_void;
sentry->DoReenable();
@ -724,14 +724,14 @@ protected:
// 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();
@ -889,12 +889,12 @@ protected:
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())
@ -1272,6 +1272,7 @@ StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, break_id_t watch_id,
StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo,
const char *description) {
thread.GetProcess()->GetUnixSignals()->IncrementSignalHitCount(signo);
return StopInfoSP(new StopInfoUnixSignal(thread, signo, description));
}

View File

@ -15,6 +15,7 @@
#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,
@ -312,3 +313,20 @@ UnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
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);
}

View File

@ -95,6 +95,10 @@ class SendSignalTestCase(TestBase):
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()