Skip to content

[LLDB] Add external progress bit category #120171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion lldb/include/lldb/Core/Progress.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ namespace lldb_private {

class Progress {
public:
/// Enum to indicate the origin of a progress event, internal or external.
enum class Origin : uint8_t {
eInternal = 0,
eExternal = 1,
};

/// Construct a progress object that will report information.
///
/// The constructor will create a unique progress reporting object and
Expand All @@ -83,7 +89,8 @@ class Progress {
Progress(std::string title, std::string details = {},
std::optional<uint64_t> total = std::nullopt,
lldb_private::Debugger *debugger = nullptr,
Timeout<std::nano> minimum_report_time = std::nullopt);
Timeout<std::nano> minimum_report_time = std::nullopt,
Origin origin = Origin::eInternal);

/// Destroy the progress object.
///
Expand Down Expand Up @@ -118,6 +125,9 @@ class Progress {
/// The optional debugger ID to report progress to. If this has no value
/// then all debuggers will receive this event.
std::optional<lldb::user_id_t> debugger_id;

/// The origin of the progress event, wheter it is internal or external.
Origin origin;
};

private:
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,8 @@ enum DebuggerBroadcastBit {
eBroadcastBitError = (1 << 2),
eBroadcastSymbolChange = (1 << 3),
eBroadcastBitProgressCategory = (1 << 4),
eBroadcastBitExternalProgress = (1 << 5),
eBroadcastBitExternalProgressCategory = (1 << 6),
};

/// Used for expressing severity in logs and diagnostics.
Expand Down
21 changes: 16 additions & 5 deletions lldb/source/Core/Progress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ static llvm::ManagedStatic<llvm::SignpostEmitter> g_progress_signposts;
Progress::Progress(std::string title, std::string details,
std::optional<uint64_t> total,
lldb_private::Debugger *debugger,
Timeout<std::nano> minimum_report_time)
Timeout<std::nano> minimum_report_time,
Progress::Origin origin)
: m_total(total.value_or(Progress::kNonDeterministicTotal)),
m_minimum_report_time(minimum_report_time),
m_progress_data{title, ++g_id,
debugger ? std::optional<user_id_t>(debugger->GetID())
: std::nullopt},
: std::nullopt,
origin},
m_last_report_time_ns(
std::chrono::nanoseconds(
std::chrono::steady_clock::now().time_since_epoch())
Expand Down Expand Up @@ -106,9 +108,15 @@ void Progress::ReportProgress() {
if (completed < m_prev_completed)
return; // An overflow in the m_completed counter. Just ignore these events.

// Change the category bit if we're an internal or external progress.
uint32_t progress_category_bit =
m_progress_data.origin == Progress::Origin::eExternal
? lldb::eBroadcastBitExternalProgress
: lldb::eBroadcastBitProgress;

Debugger::ReportProgress(m_progress_data.progress_id, m_progress_data.title,
m_details, completed, m_total,
m_progress_data.debugger_id);
m_progress_data.debugger_id, progress_category_bit);
m_prev_completed = completed;
}

Expand Down Expand Up @@ -201,10 +209,13 @@ void ProgressManager::ReportProgress(
// broadcasting to it since that bit doesn't need that information.
const uint64_t completed =
(type == EventType::Begin) ? 0 : Progress::kNonDeterministicTotal;
const uint32_t progress_category_bit =
progress_data.origin == Progress::Origin::eExternal
? lldb::eBroadcastBitExternalProgressCategory
: lldb::eBroadcastBitProgressCategory;
Debugger::ReportProgress(progress_data.progress_id, progress_data.title, "",
completed, Progress::kNonDeterministicTotal,
progress_data.debugger_id,
lldb::eBroadcastBitProgressCategory);
progress_data.debugger_id, progress_category_bit);
}

void ProgressManager::Expire(llvm::StringRef key) {
Expand Down
101 changes: 101 additions & 0 deletions lldb/unittests/Core/ProgressReportTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,104 @@ TEST_F(ProgressReportTest, TestProgressManagerDisjointReports) {

ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT));
}

TEST_F(ProgressReportTest, TestExternalReportCreation) {
ListenerSP listener_sp =
CreateListenerFor(lldb::eBroadcastBitExternalProgress);
EventSP event_sp;
const ProgressEventData *data;

// Scope this for RAII on the progress objects.
// Create progress reports and check that their respective events for having
// started and ended are broadcasted.
{
Progress progress1("Progress report 1", "Starting report 1",
/*total=*/std::nullopt, /*debugger=*/nullptr,
/*minimum_report_time=*/std::chrono::seconds(0),
Progress::Origin::eExternal);
Progress progress2("Progress report 2", "Starting report 2",
/*total=*/std::nullopt, /*debugger=*/nullptr,
/*minimum_report_time=*/std::chrono::seconds(0),
Progress::Origin::eExternal);
Progress progress3("Progress report 3", "Starting report 3",
/*total=*/std::nullopt, /*debugger=*/nullptr,
/*minimum_report_time=*/std::chrono::seconds(0),
Progress::Origin::eExternal);
}

// Start popping events from the queue, they should have been recevied
// in this order:
// Starting progress: 1, 2, 3
// Ending progress: 3, 2, 1
ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
data = ProgressEventData::GetEventDataFromEvent(event_sp.get());

EXPECT_EQ(data->GetDetails(), "Starting report 1");
EXPECT_FALSE(data->IsFinite());
EXPECT_FALSE(data->GetCompleted());
EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);
EXPECT_EQ(data->GetMessage(), "Progress report 1: Starting report 1");

ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
data = ProgressEventData::GetEventDataFromEvent(event_sp.get());

EXPECT_EQ(data->GetDetails(), "Starting report 2");
EXPECT_FALSE(data->IsFinite());
EXPECT_FALSE(data->GetCompleted());
EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);
EXPECT_EQ(data->GetMessage(), "Progress report 2: Starting report 2");

ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
data = ProgressEventData::GetEventDataFromEvent(event_sp.get());

EXPECT_EQ(data->GetDetails(), "Starting report 3");
EXPECT_FALSE(data->IsFinite());
EXPECT_FALSE(data->GetCompleted());
EXPECT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);
EXPECT_EQ(data->GetMessage(), "Progress report 3: Starting report 3");

// Progress report objects should be destroyed at this point so
// get each report from the queue and check that they've been
// destroyed in reverse order.
ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
data = ProgressEventData::GetEventDataFromEvent(event_sp.get());

EXPECT_EQ(data->GetTitle(), "Progress report 3");
EXPECT_TRUE(data->GetCompleted());
EXPECT_FALSE(data->IsFinite());
EXPECT_EQ(data->GetMessage(), "Progress report 3: Starting report 3");

ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
data = ProgressEventData::GetEventDataFromEvent(event_sp.get());

EXPECT_EQ(data->GetTitle(), "Progress report 2");
EXPECT_TRUE(data->GetCompleted());
EXPECT_FALSE(data->IsFinite());
EXPECT_EQ(data->GetMessage(), "Progress report 2: Starting report 2");

ASSERT_TRUE(listener_sp->GetEvent(event_sp, TIMEOUT));
data = ProgressEventData::GetEventDataFromEvent(event_sp.get());

EXPECT_EQ(data->GetTitle(), "Progress report 1");
EXPECT_TRUE(data->GetCompleted());
EXPECT_FALSE(data->IsFinite());
EXPECT_EQ(data->GetMessage(), "Progress report 1: Starting report 1");
}

TEST_F(ProgressReportTest, TestExternalReportNotReceived) {
ListenerSP listener_sp = CreateListenerFor(lldb::eBroadcastBitProgress);
EventSP event_sp;

// Scope this for RAII on the progress objects.
// Create progress reports and check that their respective events for having
// started and ended are broadcasted.
{
Progress progress1("External Progress report 1",
"Starting external report 1",
/*total=*/std::nullopt, /*debugger=*/nullptr,
/*minimum_report_time=*/std::chrono::seconds(0),
Progress::Origin::eExternal);
}

ASSERT_FALSE(listener_sp->GetEvent(event_sp, TIMEOUT));
}
Loading