xref: /freebsd/contrib/llvm-project/lldb/include/lldb/Core/Progress.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/Utility/Timeout.h"
13 #include "lldb/lldb-forward.h"
14 #include "lldb/lldb-types.h"
15 #include "llvm/ADT/StringMap.h"
16 #include <atomic>
17 #include <cstdint>
18 #include <mutex>
19 #include <optional>
20 #include <string>
21 
22 namespace 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 
60 class Progress {
61 public:
62   /// Enum to indicate the origin of a progress event, internal or external.
63   enum class Origin : uint8_t {
64     eInternal = 0,
65     eExternal = 1,
66   };
67 
68   /// Construct a progress object that will report information.
69   ///
70   /// The constructor will create a unique progress reporting object and
71   /// immediately send out a progress update by calling the installed callback
72   /// with \a completed set to zero out of the specified total.
73   ///
74   /// @param [in] title The title of this progress activity.
75   ///
76   /// @param [in] details Specific information about what the progress report
77   /// is currently working on. Although not required, if the progress report is
78   /// updated with Progress::Increment() then this field will be overwritten
79   /// with the new set of details passed into that function, and the details
80   /// passed initially will act as an "item 0" for the total set of
81   /// items being reported on.
82   ///
83   /// @param [in] total The total units of work to be done if specified, if
84   /// set to std::nullopt then an indeterminate progress indicator should be
85   /// displayed.
86   ///
87   /// @param [in] debugger An optional debugger pointer to specify that this
88   /// progress is to be reported only to specific debuggers.
89   Progress(std::string title, std::string details = {},
90            std::optional<uint64_t> total = std::nullopt,
91            lldb_private::Debugger *debugger = nullptr,
92            Timeout<std::nano> minimum_report_time = std::nullopt,
93            Origin origin = Origin::eInternal);
94 
95   /// Destroy the progress object.
96   ///
97   /// If the progress has not yet sent a completion update, the destructor
98   /// will send out a notification where the \a completed == m_total. This
99   /// ensures that we always send out a progress complete notification.
100   ~Progress();
101 
102   /// Increment the progress and send a notification to the installed callback.
103   ///
104   /// If incrementing ends up exceeding m_total, m_completed will be updated
105   /// to match m_total and no subsequent progress notifications will be sent.
106   /// If no total was specified in the constructor, this function will not do
107   /// anything nor send any progress updates.
108   ///
109   /// @param [in] amount The amount to increment m_completed by.
110   ///
111   /// @param [in] an optional message associated with this update.
112   void Increment(uint64_t amount = 1,
113                  std::optional<std::string> updated_detail = {});
114 
115   /// Used to indicate a non-deterministic progress report
116   static constexpr uint64_t kNonDeterministicTotal = UINT64_MAX;
117 
118   /// The default report time for high frequency progress reports.
119   static constexpr std::chrono::milliseconds kDefaultHighFrequencyReportTime =
120       std::chrono::milliseconds(20);
121 
122 private:
123   void ReportProgress();
124   static std::atomic<uint64_t> g_id;
125 
126   /// Total amount of work, use a std::nullopt in the constructor for non
127   /// deterministic progress.
128   const uint64_t m_total;
129 
130   // Minimum amount of time between two progress reports.
131   const Timeout<std::nano> m_minimum_report_time;
132 
133   /// The title of the progress activity, also used as a category.
134   const std::string m_title;
135 
136   /// A unique integer identifier for progress reporting.
137   const uint64_t m_progress_id;
138 
139   /// The optional debugger ID to report progress to. If this has no value
140   /// then all debuggers will receive this event.
141   const std::optional<lldb::user_id_t> m_debugger_id;
142 
143   /// The origin of the progress event, whether it is internal or external.
144   const Origin m_origin;
145 
146   /// How much work ([0...m_total]) that has been completed.
147   std::atomic<uint64_t> m_completed = 0;
148 
149   /// Time (in nanoseconds since epoch) of the last progress report.
150   std::atomic<uint64_t> m_last_report_time_ns;
151 
152   /// Guards non-const non-atomic members of the class.
153   std::mutex m_mutex;
154 
155   /// More specific information about the current file being displayed in the
156   /// report.
157   std::string m_details;
158 
159   /// The "completed" value of the last reported event.
160   std::optional<uint64_t> m_prev_completed;
161 };
162 
163 } // namespace lldb_private
164 
165 #endif // LLDB_CORE_PROGRESS_H
166