LLDB mainline
Progress.h
Go to the documentation of this file.
1//===-- Progress.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_CORE_PROGRESS_H
10#define LLDB_CORE_PROGRESS_H
11
12#include "lldb/Host/Alarm.h"
14#include "lldb/lldb-forward.h"
15#include "lldb/lldb-types.h"
16#include "llvm/ADT/StringMap.h"
17#include <atomic>
18#include <cstdint>
19#include <mutex>
20#include <optional>
21
22namespace lldb_private {
23
24/// A Progress indicator helper class.
25///
26/// Any potentially long running sections of code in LLDB should report
27/// progress so that clients are aware of delays that might appear during
28/// debugging. Delays commonly include indexing debug information, parsing
29/// symbol tables for object files, downloading symbols from remote
30/// repositories, and many more things.
31///
32/// The Progress class helps make sure that progress is correctly reported
33/// and will always send an initial progress update, updates when
34/// Progress::Increment() is called, and also will make sure that a progress
35/// completed update is reported even if the user doesn't explicitly cause one
36/// to be sent.
37///
38/// The progress is reported via a callback whose type is ProgressCallback:
39///
40/// typedef void (*ProgressCallback)(uint64_t progress_id,
41/// const char *message,
42/// uint64_t completed,
43/// uint64_t total,
44/// void *baton);
45///
46/// This callback will always initially be called with \a completed set to zero
47/// and \a total set to the total amount specified in the constructor. This is
48/// considered the progress start event. As Progress::Increment() is called,
49/// the callback will be called as long as the Progress::m_completed has not
50/// yet exceeded the Progress::m_total. When the callback is called with
51/// Progress::m_completed == Progress::m_total, that is considered a progress
52/// completed event. If Progress::m_completed is non-zero and less than
53/// Progress::m_total, then this is considered a progress update event.
54///
55/// This callback will be called in the destructor if Progress::m_completed is
56/// not equal to Progress::m_total with the \a completed set to
57/// Progress::m_total. This ensures we always send a progress completed update
58/// even if the user does not.
59
60class Progress {
61public:
62 /// Construct a progress object that will report information.
63 ///
64 /// The constructor will create a unique progress reporting object and
65 /// immediately send out a progress update by calling the installed callback
66 /// with \a completed set to zero out of the specified total.
67 ///
68 /// @param [in] title The title of this progress activity.
69 ///
70 /// @param [in] details Specific information about what the progress report
71 /// is currently working on. Although not required, if the progress report is
72 /// updated with Progress::Increment() then this field will be overwritten
73 /// with the new set of details passed into that function, and the details
74 /// passed initially will act as an "item 0" for the total set of
75 /// items being reported on.
76 ///
77 /// @param [in] total The total units of work to be done if specified, if
78 /// set to std::nullopt then an indeterminate progress indicator should be
79 /// displayed.
80 ///
81 /// @param [in] debugger An optional debugger pointer to specify that this
82 /// progress is to be reported only to specific debuggers.
83 Progress(std::string title, std::string details = {},
84 std::optional<uint64_t> total = std::nullopt,
85 lldb_private::Debugger *debugger = nullptr,
86 Timeout<std::nano> minimum_report_time = std::nullopt);
87
88 /// Destroy the progress object.
89 ///
90 /// If the progress has not yet sent a completion update, the destructor
91 /// will send out a notification where the \a completed == m_total. This
92 /// ensures that we always send out a progress complete notification.
93 ~Progress();
94
95 /// Increment the progress and send a notification to the installed callback.
96 ///
97 /// If incrementing ends up exceeding m_total, m_completed will be updated
98 /// to match m_total and no subsequent progress notifications will be sent.
99 /// If no total was specified in the constructor, this function will not do
100 /// anything nor send any progress updates.
101 ///
102 /// @param [in] amount The amount to increment m_completed by.
103 ///
104 /// @param [in] an optional message associated with this update.
105 void Increment(uint64_t amount = 1,
106 std::optional<std::string> updated_detail = {});
107
108 /// Used to indicate a non-deterministic progress report
109 static constexpr uint64_t kNonDeterministicTotal = UINT64_MAX;
110
111 /// Data belonging to this Progress event that is used for bookkeeping by
112 /// ProgressManager.
114 /// The title of the progress activity, also used as a category.
115 std::string title;
116 /// A unique integer identifier for progress reporting.
117 uint64_t progress_id;
118 /// The optional debugger ID to report progress to. If this has no value
119 /// then all debuggers will receive this event.
120 std::optional<lldb::user_id_t> debugger_id;
121 };
122
123private:
124 void ReportProgress();
125 static std::atomic<uint64_t> g_id;
126
127 /// Total amount of work, use a std::nullopt in the constructor for non
128 /// deterministic progress.
129 const uint64_t m_total;
130
131 // Minimum amount of time between two progress reports.
133
134 /// Data needed by the debugger to broadcast a progress event.
136
137 /// How much work ([0...m_total]) that has been completed.
138 std::atomic<uint64_t> m_completed = 0;
139
140 /// Time (in nanoseconds since epoch) of the last progress report.
141 std::atomic<uint64_t> m_last_report_time_ns;
142
143 /// Guards non-const non-atomic members of the class.
144 std::mutex m_mutex;
145
146 /// More specific information about the current file being displayed in the
147 /// report.
148 std::string m_details;
149
150 /// The "completed" value of the last reported event.
151 std::optional<uint64_t> m_prev_completed;
152};
153
154/// A class used to group progress reports by category. This is done by using a
155/// map that maintains a refcount of each category of progress reports that have
156/// come in. Keeping track of progress reports this way will be done if a
157/// debugger is listening to the eBroadcastBitProgressByCategory broadcast bit.
159public:
162
163 /// Control the refcount of the progress report category as needed.
164 void Increment(const Progress::ProgressData &);
165 void Decrement(const Progress::ProgressData &);
166
167 static void Initialize();
168 static void Terminate();
169 static bool Enabled();
170 static ProgressManager &Instance();
171
172protected:
173 enum class EventType {
174 Begin,
175 End,
176 };
177 static void ReportProgress(const Progress::ProgressData &progress_data,
178 EventType type);
179
180 static std::optional<ProgressManager> &InstanceImpl();
181
182 /// Helper function for reporting progress when the alarm in the corresponding
183 /// entry in the map expires.
184 void Expire(llvm::StringRef key);
185
186 /// Entry used for bookkeeping.
187 struct Entry {
188 /// Reference count used for overlapping events.
189 uint64_t refcount = 0;
190
191 /// Data used to emit progress events.
193
194 /// Alarm handle used when the refcount reaches zero.
196 };
197
198 /// Map used for bookkeeping.
199 llvm::StringMap<Entry> m_entries;
200
201 /// Mutex to provide the map.
202 std::mutex m_entries_mutex;
203
204 /// Alarm instance to coalesce progress events.
206};
207
208} // namespace lldb_private
209
210#endif // LLDB_CORE_PROGRESS_H
enables scheduling a callback function after a specified timeout.
Definition: Alarm.h:24
static constexpr Handle INVALID_HANDLE
Definition: Alarm.h:58
uint64_t Handle
Definition: Alarm.h:26
A class to manage flag bits.
Definition: Debugger.h:80
A class used to group progress reports by category.
Definition: Progress.h:158
void Decrement(const Progress::ProgressData &)
Definition: Progress.cpp:172
static void ReportProgress(const Progress::ProgressData &progress_data, EventType type)
Definition: Progress.cpp:197
Alarm m_alarm
Alarm instance to coalesce progress events.
Definition: Progress.h:205
static ProgressManager & Instance()
Definition: Progress.cpp:132
void Expire(llvm::StringRef key)
Helper function for reporting progress when the alarm in the corresponding entry in the map expires.
Definition: Progress.cpp:210
static std::optional< ProgressManager > & InstanceImpl()
Definition: Progress.cpp:137
llvm::StringMap< Entry > m_entries
Map used for bookkeeping.
Definition: Progress.h:199
void Increment(const Progress::ProgressData &)
Control the refcount of the progress report category as needed.
Definition: Progress.cpp:142
std::mutex m_entries_mutex
Mutex to provide the map.
Definition: Progress.h:202
A Progress indicator helper class.
Definition: Progress.h:60
const Timeout< std::nano > m_minimum_report_time
Definition: Progress.h:132
void Increment(uint64_t amount=1, std::optional< std::string > updated_detail={})
Increment the progress and send a notification to the installed callback.
Definition: Progress.cpp:68
static std::atomic< uint64_t > g_id
Definition: Progress.h:125
std::atomic< uint64_t > m_last_report_time_ns
Time (in nanoseconds since epoch) of the last progress report.
Definition: Progress.h:141
std::string m_details
More specific information about the current file being displayed in the report.
Definition: Progress.h:148
static constexpr uint64_t kNonDeterministicTotal
Used to indicate a non-deterministic progress report.
Definition: Progress.h:109
std::mutex m_mutex
Guards non-const non-atomic members of the class.
Definition: Progress.h:144
std::atomic< uint64_t > m_completed
How much work ([0...m_total]) that has been completed.
Definition: Progress.h:138
std::optional< uint64_t > m_prev_completed
The "completed" value of the last reported event.
Definition: Progress.h:151
~Progress()
Destroy the progress object.
Definition: Progress.cpp:53
const ProgressData m_progress_data
Data needed by the debugger to broadcast a progress event.
Definition: Progress.h:135
const uint64_t m_total
Total amount of work, use a std::nullopt in the constructor for non deterministic progress.
Definition: Progress.h:129
#define UINT64_MAX
Definition: lldb-defines.h:23
A class that represents a running process on the host machine.
Entry used for bookkeeping.
Definition: Progress.h:187
Progress::ProgressData data
Data used to emit progress events.
Definition: Progress.h:192
Alarm::Handle handle
Alarm handle used when the refcount reaches zero.
Definition: Progress.h:195
uint64_t refcount
Reference count used for overlapping events.
Definition: Progress.h:189
Data belonging to this Progress event that is used for bookkeeping by ProgressManager.
Definition: Progress.h:113
std::optional< lldb::user_id_t > debugger_id
The optional debugger ID to report progress to.
Definition: Progress.h:120
std::string title
The title of the progress activity, also used as a category.
Definition: Progress.h:115
uint64_t progress_id
A unique integer identifier for progress reporting.
Definition: Progress.h:117