Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:42:45

0001 //===-- Progress.h ----------------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLDB_CORE_PROGRESS_H
0010 #define LLDB_CORE_PROGRESS_H
0011 
0012 #include "lldb/Host/Alarm.h"
0013 #include "lldb/Utility/Timeout.h"
0014 #include "lldb/lldb-forward.h"
0015 #include "lldb/lldb-types.h"
0016 #include "llvm/ADT/StringMap.h"
0017 #include <atomic>
0018 #include <cstdint>
0019 #include <mutex>
0020 #include <optional>
0021 
0022 namespace lldb_private {
0023 
0024 /// A Progress indicator helper class.
0025 ///
0026 /// Any potentially long running sections of code in LLDB should report
0027 /// progress so that clients are aware of delays that might appear during
0028 /// debugging. Delays commonly include indexing debug information, parsing
0029 /// symbol tables for object files, downloading symbols from remote
0030 /// repositories, and many more things.
0031 ///
0032 /// The Progress class helps make sure that progress is correctly reported
0033 /// and will always send an initial progress update, updates when
0034 /// Progress::Increment() is called, and also will make sure that a progress
0035 /// completed update is reported even if the user doesn't explicitly cause one
0036 /// to be sent.
0037 ///
0038 /// The progress is reported via a callback whose type is ProgressCallback:
0039 ///
0040 ///   typedef void (*ProgressCallback)(uint64_t progress_id,
0041 ///                                    const char *message,
0042 ///                                    uint64_t completed,
0043 ///                                    uint64_t total,
0044 ///                                    void *baton);
0045 ///
0046 /// This callback will always initially be called with \a completed set to zero
0047 /// and \a total set to the total amount specified in the constructor. This is
0048 /// considered the progress start event. As Progress::Increment() is called,
0049 /// the callback will be called as long as the Progress::m_completed has not
0050 /// yet exceeded the Progress::m_total. When the callback is called with
0051 /// Progress::m_completed == Progress::m_total, that is considered a progress
0052 /// completed event. If Progress::m_completed is non-zero and less than
0053 /// Progress::m_total, then this is considered a progress update event.
0054 ///
0055 /// This callback will be called in the destructor if Progress::m_completed is
0056 /// not equal to Progress::m_total with the \a completed set to
0057 /// Progress::m_total. This ensures we always send a progress completed update
0058 /// even if the user does not.
0059 
0060 class Progress {
0061 public:
0062   /// Enum to indicate the origin of a progress event, internal or external.
0063   enum class Origin : uint8_t {
0064     eInternal = 0,
0065     eExternal = 1,
0066   };
0067 
0068   /// Construct a progress object that will report information.
0069   ///
0070   /// The constructor will create a unique progress reporting object and
0071   /// immediately send out a progress update by calling the installed callback
0072   /// with \a completed set to zero out of the specified total.
0073   ///
0074   /// @param [in] title The title of this progress activity.
0075   ///
0076   /// @param [in] details Specific information about what the progress report
0077   /// is currently working on. Although not required, if the progress report is
0078   /// updated with Progress::Increment() then this field will be overwritten
0079   /// with the new set of details passed into that function, and the details
0080   /// passed initially will act as an "item 0" for the total set of
0081   /// items being reported on.
0082   ///
0083   /// @param [in] total The total units of work to be done if specified, if
0084   /// set to std::nullopt then an indeterminate progress indicator should be
0085   /// displayed.
0086   ///
0087   /// @param [in] debugger An optional debugger pointer to specify that this
0088   /// progress is to be reported only to specific debuggers.
0089   Progress(std::string title, std::string details = {},
0090            std::optional<uint64_t> total = std::nullopt,
0091            lldb_private::Debugger *debugger = nullptr,
0092            Timeout<std::nano> minimum_report_time = std::nullopt,
0093            Origin origin = Origin::eInternal);
0094 
0095   /// Destroy the progress object.
0096   ///
0097   /// If the progress has not yet sent a completion update, the destructor
0098   /// will send out a notification where the \a completed == m_total. This
0099   /// ensures that we always send out a progress complete notification.
0100   ~Progress();
0101 
0102   /// Increment the progress and send a notification to the installed callback.
0103   ///
0104   /// If incrementing ends up exceeding m_total, m_completed will be updated
0105   /// to match m_total and no subsequent progress notifications will be sent.
0106   /// If no total was specified in the constructor, this function will not do
0107   /// anything nor send any progress updates.
0108   ///
0109   /// @param [in] amount The amount to increment m_completed by.
0110   ///
0111   /// @param [in] an optional message associated with this update.
0112   void Increment(uint64_t amount = 1,
0113                  std::optional<std::string> updated_detail = {});
0114 
0115   /// Used to indicate a non-deterministic progress report
0116   static constexpr uint64_t kNonDeterministicTotal = UINT64_MAX;
0117 
0118   /// Data belonging to this Progress event that is used for bookkeeping by
0119   /// ProgressManager.
0120   struct ProgressData {
0121     /// The title of the progress activity, also used as a category.
0122     std::string title;
0123     /// A unique integer identifier for progress reporting.
0124     uint64_t progress_id;
0125     /// The optional debugger ID to report progress to. If this has no value
0126     /// then all debuggers will receive this event.
0127     std::optional<lldb::user_id_t> debugger_id;
0128 
0129     /// The origin of the progress event, wheter it is internal or external.
0130     Origin origin;
0131   };
0132 
0133 private:
0134   void ReportProgress();
0135   static std::atomic<uint64_t> g_id;
0136 
0137   /// Total amount of work, use a std::nullopt in the constructor for non
0138   /// deterministic progress.
0139   const uint64_t m_total;
0140 
0141   // Minimum amount of time between two progress reports.
0142   const Timeout<std::nano> m_minimum_report_time;
0143 
0144   /// Data needed by the debugger to broadcast a progress event.
0145   const ProgressData m_progress_data;
0146 
0147   /// How much work ([0...m_total]) that has been completed.
0148   std::atomic<uint64_t> m_completed = 0;
0149 
0150   /// Time (in nanoseconds since epoch) of the last progress report.
0151   std::atomic<uint64_t> m_last_report_time_ns;
0152 
0153   /// Guards non-const non-atomic members of the class.
0154   std::mutex m_mutex;
0155 
0156   /// More specific information about the current file being displayed in the
0157   /// report.
0158   std::string m_details;
0159 
0160   /// The "completed" value of the last reported event.
0161   std::optional<uint64_t> m_prev_completed;
0162 };
0163 
0164 /// A class used to group progress reports by category. This is done by using a
0165 /// map that maintains a refcount of each category of progress reports that have
0166 /// come in. Keeping track of progress reports this way will be done if a
0167 /// debugger is listening to the eBroadcastBitProgressByCategory broadcast bit.
0168 class ProgressManager {
0169 public:
0170   ProgressManager();
0171   ~ProgressManager();
0172 
0173   /// Control the refcount of the progress report category as needed.
0174   void Increment(const Progress::ProgressData &);
0175   void Decrement(const Progress::ProgressData &);
0176 
0177   static void Initialize();
0178   static void Terminate();
0179   static bool Enabled();
0180   static ProgressManager &Instance();
0181 
0182 protected:
0183   enum class EventType {
0184     Begin,
0185     End,
0186   };
0187   static void ReportProgress(const Progress::ProgressData &progress_data,
0188                              EventType type);
0189 
0190   static std::optional<ProgressManager> &InstanceImpl();
0191 
0192   /// Helper function for reporting progress when the alarm in the corresponding
0193   /// entry in the map expires.
0194   void Expire(llvm::StringRef key);
0195 
0196   /// Entry used for bookkeeping.
0197   struct Entry {
0198     /// Reference count used for overlapping events.
0199     uint64_t refcount = 0;
0200 
0201     /// Data used to emit progress events.
0202     Progress::ProgressData data;
0203 
0204     /// Alarm handle used when the refcount reaches zero.
0205     Alarm::Handle handle = Alarm::INVALID_HANDLE;
0206   };
0207 
0208   /// Map used for bookkeeping.
0209   llvm::StringMap<Entry> m_entries;
0210 
0211   /// Mutex to provide the map.
0212   std::mutex m_entries_mutex;
0213 
0214   /// Alarm instance to coalesce progress events.
0215   Alarm m_alarm;
0216 };
0217 
0218 } // namespace lldb_private
0219 
0220 #endif // LLDB_CORE_PROGRESS_H