Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
15 changes: 14 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.
Progress::Origin origin;
};

private:
Expand All @@ -134,6 +144,9 @@ class Progress {
/// Data needed by the debugger to broadcast a progress event.
const ProgressData m_progress_data;

/// The origin of this progress event.
const Progress::Origin m_origin;

/// How much work ([0...m_total]) that has been completed.
std::atomic<uint64_t> m_completed = 0;

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,15 @@ 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_origin(origin),
m_last_report_time_ns(
std::chrono::nanoseconds(
std::chrono::steady_clock::now().time_since_epoch())
Expand Down Expand Up @@ -106,9 +109,14 @@ 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_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