Skip to content

Commit 6b048ae

Browse files
authored
[LLDB] Add SBProgress so Python scripts can also report progress (llvm#119052)
Recently I've been working on a lot of internal Python tooling, and in certain cases I want to report async to the script over DAP. Progress.h already handles this, so I've exposed Progress via the SB API so Python scripts can also update progress objects. I actually have no idea how to test this, so I just wrote a [toy command to test it](https://gist.github.com/Jlalond/48d85e75a91f7a137e3142e6a13d0947) ![image](https://github.com/user-attachments/assets/7317cbb8-9145-4fdb-bacf-9864bf50c467) I also copied the first section of the extensive Progress.h class documentation to the docstrings.
1 parent 128e2e4 commit 6b048ae

File tree

10 files changed

+167
-2
lines changed

10 files changed

+167
-2
lines changed

lldb/bindings/headers.swig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "lldb/API/SBProcess.h"
5353
#include "lldb/API/SBProcessInfo.h"
5454
#include "lldb/API/SBProcessInfoList.h"
55+
#include "lldb/API/SBProgress.h"
5556
#include "lldb/API/SBQueue.h"
5657
#include "lldb/API/SBQueueItem.h"
5758
#include "lldb/API/SBReproducer.h"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
%feature("docstring",
2+
"A Progress indicator helper class.
3+
4+
Any potentially long running sections of code in LLDB should report
5+
progress so that clients are aware of delays that might appear during
6+
debugging. Delays commonly include indexing debug information, parsing
7+
symbol tables for object files, downloading symbols from remote
8+
repositories, and many more things.
9+
10+
The Progress class helps make sure that progress is correctly reported
11+
and will always send an initial progress update, updates when
12+
Progress::Increment() is called, and also will make sure that a progress
13+
completed update is reported even if the user doesn't explicitly cause one
14+
to be sent.") lldb::SBProgress;

lldb/bindings/interfaces.swig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
%include "./interface/SBPlatformDocstrings.i"
5555
%include "./interface/SBProcessDocstrings.i"
5656
%include "./interface/SBProcessInfoDocstrings.i"
57+
%include "./interface/SBProgressDocstrings.i"
5758
%include "./interface/SBQueueDocstrings.i"
5859
%include "./interface/SBQueueItemDocstrings.i"
5960
%include "./interface/SBReproducerDocstrings.i"
@@ -133,6 +134,7 @@
133134
%include "lldb/API/SBProcess.h"
134135
%include "lldb/API/SBProcessInfo.h"
135136
%include "lldb/API/SBProcessInfoList.h"
137+
%include "lldb/API/SBProgress.h"
136138
%include "lldb/API/SBQueue.h"
137139
%include "lldb/API/SBQueueItem.h"
138140
%include "lldb/API/SBReproducer.h"

lldb/include/lldb/API/SBDebugger.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ class LLDB_API SBDebugger {
203203
lldb::SBCommandInterpreter GetCommandInterpreter();
204204

205205
void HandleCommand(const char *command);
206-
206+
207207
void RequestInterrupt();
208208
void CancelInterruptRequest();
209209
bool InterruptRequested();
@@ -517,6 +517,7 @@ class LLDB_API SBDebugger {
517517
friend class SBPlatform;
518518
friend class SBTarget;
519519
friend class SBTrace;
520+
friend class SBProgress;
520521

521522
lldb::SBTarget FindTargetWithLLDBProcess(const lldb::ProcessSP &processSP);
522523

lldb/include/lldb/API/SBProgress.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//===-- SBProgress.h --------------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_API_SBPROGRESS_H
10+
#define LLDB_API_SBPROGRESS_H
11+
12+
#include "lldb/API/SBDebugger.h"
13+
#include "lldb/API/SBDefines.h"
14+
15+
namespace lldb {
16+
17+
/// A Progress indicator helper class.
18+
///
19+
/// Any potentially long running sections of code in LLDB should report
20+
/// progress so that clients are aware of delays that might appear during
21+
/// debugging. Delays commonly include indexing debug information, parsing
22+
/// symbol tables for object files, downloading symbols from remote
23+
/// repositories, and many more things.
24+
///
25+
/// The Progress class helps make sure that progress is correctly reported
26+
/// and will always send an initial progress update, updates when
27+
/// Progress::Increment() is called, and also will make sure that a progress
28+
/// completed update is reported even if the user doesn't explicitly cause one
29+
/// to be sent.
30+
class LLDB_API SBProgress {
31+
public:
32+
/// Construct a progress object with a title, details and a given debugger.
33+
/// \param title
34+
/// The title of the progress object.
35+
/// \param details
36+
/// The details of the progress object.
37+
/// \param debugger
38+
/// The debugger for this progress object to report to.
39+
SBProgress(const char *title, const char *details, SBDebugger &debugger);
40+
41+
/// Construct a progress object with a title, details, the total units of work
42+
/// to be done, and a given debugger.
43+
/// \param title
44+
/// The title of the progress object.
45+
/// \param details
46+
/// The details of the progress object.
47+
/// \param total_units
48+
/// The total number of units of work to be done.
49+
/// \param debugger
50+
/// The debugger for this progress object to report to.
51+
SBProgress(const char *title, const char *details, uint64_t total_units,
52+
SBDebugger &debugger);
53+
54+
~SBProgress();
55+
56+
void Increment(uint64_t amount, const char *description = nullptr);
57+
58+
protected:
59+
lldb_private::Progress &ref() const;
60+
61+
private:
62+
std::unique_ptr<lldb_private::Progress> m_opaque_up;
63+
}; // SBProgress
64+
} // namespace lldb
65+
66+
#endif // LLDB_API_SBPROGRESS_H

lldb/include/lldb/lldb-forward.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ class Symtab;
233233
class SyntheticChildren;
234234
class SyntheticChildrenFrontEnd;
235235
class SystemRuntime;
236+
class Progress;
236237
class Target;
237238
class TargetList;
238239
class TargetProperties;

lldb/source/API/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
8383
SBModule.cpp
8484
SBModuleSpec.cpp
8585
SBPlatform.cpp
86+
SBProgress.cpp
8687
SBProcess.cpp
8788
SBProcessInfo.cpp
8889
SBProcessInfoList.cpp

lldb/source/API/SBProgress.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===-- SBProgress.cpp --------------------------------------------------*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "lldb/API/SBProgress.h"
10+
#include "lldb/Core/Progress.h"
11+
#include "lldb/Utility/Instrumentation.h"
12+
13+
using namespace lldb;
14+
15+
SBProgress::SBProgress(const char *title, const char *details,
16+
SBDebugger &debugger) {
17+
LLDB_INSTRUMENT_VA(this, title, details, debugger);
18+
19+
m_opaque_up = std::make_unique<lldb_private::Progress>(
20+
title, details, /*total=*/std::nullopt, debugger.get(),
21+
/*minimum_report_time=*/std::nullopt,
22+
lldb_private::Progress::Origin::eExternal);
23+
}
24+
25+
SBProgress::SBProgress(const char *title, const char *details,
26+
uint64_t total_units, SBDebugger &debugger) {
27+
LLDB_INSTRUMENT_VA(this, title, details, total_units, debugger);
28+
29+
m_opaque_up = std::make_unique<lldb_private::Progress>(
30+
title, details, total_units, debugger.get(),
31+
/*minimum_report_time=*/std::nullopt,
32+
lldb_private::Progress::Origin::eExternal);
33+
}
34+
35+
SBProgress::~SBProgress() = default;
36+
37+
void SBProgress::Increment(uint64_t amount, const char *description) {
38+
LLDB_INSTRUMENT_VA(amount, description);
39+
40+
m_opaque_up->Increment(amount, description);
41+
}
42+
43+
lldb_private::Progress &SBProgress::ref() const { return *m_opaque_up; }

lldb/source/Core/Debugger.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1952,7 +1952,8 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
19521952
listener_sp->StartListeningForEvents(
19531953
&m_broadcaster, lldb::eBroadcastBitProgress | lldb::eBroadcastBitWarning |
19541954
lldb::eBroadcastBitError |
1955-
lldb::eBroadcastSymbolChange);
1955+
lldb::eBroadcastSymbolChange |
1956+
lldb::eBroadcastBitExternalProgress);
19561957

19571958
// Let the thread that spawned us know that we have started up and that we
19581959
// are now listening to all required events so no events get missed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Test the SBProgress API."""
2+
3+
import lldb
4+
from lldbsuite.test.lldbtest import *
5+
6+
7+
class SBProgressTestCase(TestBase):
8+
def test_with_external_bit_set(self):
9+
"""Test SBProgress events are listened to when the external bit is set."""
10+
11+
progress = lldb.SBProgress("Test SBProgress", "Test progress", self.dbg)
12+
listener = lldb.SBListener("Test listener")
13+
broadcaster = self.dbg.GetBroadcaster()
14+
broadcaster.AddListener(listener, lldb.eBroadcastBitExternalProgress)
15+
event = lldb.SBEvent()
16+
17+
expected_string = "Test progress first increment"
18+
progress.Increment(1, expected_string)
19+
self.assertTrue(listener.PeekAtNextEvent(event))
20+
stream = lldb.SBStream()
21+
event.GetDescription(stream)
22+
self.assertIn(expected_string, stream.GetData())
23+
24+
def test_without_external_bit_set(self):
25+
"""Test SBProgress events are not listened to on the internal progress bit."""
26+
27+
progress = lldb.SBProgress("Test SBProgress", "Test progress", self.dbg)
28+
listener = lldb.SBListener("Test listener")
29+
broadcaster = self.dbg.GetBroadcaster()
30+
broadcaster.AddListener(listener, lldb.eBroadcastBitProgress)
31+
event = lldb.SBEvent()
32+
33+
expected_string = "Test progress first increment"
34+
progress.Increment(1, expected_string)
35+
self.assertFalse(listener.PeekAtNextEvent(event))

0 commit comments

Comments
 (0)