1 //===-- ProgressEvent.cpp ---------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
13 #include "VSCodeForward.h"
15 #include "llvm/Support/JSON.h"
17 namespace lldb_vscode
{
19 enum ProgressEventType
{
26 using ProgressEventReportCallback
= std::function
<void(ProgressEvent
&)>;
30 /// Actual constructor to use that returns an optional, as the event might be
31 /// not apt for the IDE, e.g. an unnamed start event, or a redundant one.
33 /// \param[in] progress_id
34 /// ID for this event.
36 /// \param[in] message
37 /// Message to display in the UI. Required for start events.
39 /// \param[in] completed
40 /// Number of jobs completed.
43 /// Total number of jobs, or \b UINT64_MAX if not determined.
45 /// \param[in] prev_event
46 /// Previous event if this one is an update. If \b nullptr, then a start
47 /// event will be created.
48 static llvm::Optional
<ProgressEvent
>
49 Create(uint64_t progress_id
, llvm::Optional
<llvm::StringRef
> message
,
50 uint64_t completed
, uint64_t total
,
51 const ProgressEvent
*prev_event
= nullptr);
53 llvm::json::Value
ToJSON() const;
56 /// \b true if two event messages would result in the same event for the
57 /// IDE, e.g. same rounded percentage.
58 bool EqualsForIDE(const ProgressEvent
&other
) const;
60 llvm::StringRef
GetEventName() const;
62 ProgressEventType
GetEventType() const;
64 /// Report this progress event to the provided callback only if enough time
65 /// has passed since the creation of the event and since the previous reported
67 bool Report(ProgressEventReportCallback callback
);
69 bool Reported() const;
72 ProgressEvent(uint64_t progress_id
, llvm::Optional
<llvm::StringRef
> message
,
73 uint64_t completed
, uint64_t total
,
74 const ProgressEvent
*prev_event
);
76 uint64_t m_progress_id
;
77 std::string m_message
;
78 ProgressEventType m_event_type
;
79 llvm::Optional
<uint32_t> m_percentage
;
80 std::chrono::duration
<double> m_creation_time
=
81 std::chrono::system_clock::now().time_since_epoch();
82 std::chrono::duration
<double> m_minimum_allowed_report_time
;
83 bool m_reported
= false;
86 /// Class that keeps the start event and its most recent update.
87 /// It controls when the event should start being reported to the IDE.
88 class ProgressEventManager
{
90 ProgressEventManager(const ProgressEvent
&start_event
,
91 ProgressEventReportCallback report_callback
);
93 /// Report the start event and the most recent update if the event has lasted
97 /// \b false if the event hasn't finished and hasn't reported anything
99 bool ReportIfNeeded();
101 /// Receive a new progress event for the start event and try to report it if
103 void Update(uint64_t progress_id
, uint64_t completed
, uint64_t total
);
106 /// \b true if a \a progressEnd event has been notified. There's no
107 /// need to try to report manually an event that has finished.
108 bool Finished() const;
110 const ProgressEvent
&GetMostRecentEvent() const;
113 ProgressEvent m_start_event
;
114 llvm::Optional
<ProgressEvent
> m_last_update_event
;
116 ProgressEventReportCallback m_report_callback
;
119 using ProgressEventManagerSP
= std::shared_ptr
<ProgressEventManager
>;
121 /// Class that filters out progress event messages that shouldn't be reported
122 /// to the IDE, because they are invalid, they carry no new information, or they
123 /// don't last long enough.
125 /// We need to limit the amount of events that are sent to the IDE, as they slow
126 /// the render thread of the UI user, and they end up spamming the DAP
127 /// connection, which also takes some processing time out of the IDE.
128 class ProgressEventReporter
{
130 /// \param[in] report_callback
131 /// Function to invoke to report the event to the IDE.
132 ProgressEventReporter(ProgressEventReportCallback report_callback
);
134 ~ProgressEventReporter();
136 /// Add a new event to the internal queue and report the event if
138 void Push(uint64_t progress_id
, const char *message
, uint64_t completed
,
142 /// Report to the IDE events that haven't been reported to the IDE and have
143 /// lasted long enough.
144 void ReportStartEvents();
146 ProgressEventReportCallback m_report_callback
;
147 std::map
<uint64_t, ProgressEventManagerSP
> m_event_managers
;
148 /// Queue of start events in chronological order
149 std::queue
<ProgressEventManagerSP
> m_unreported_start_events
;
150 /// Thread used to invoke \a ReportStartEvents periodically.
151 std::thread m_thread
;
152 bool m_thread_should_exit
;
153 /// Mutex that prevents running \a Push and \a ReportStartEvents
154 /// simultaneously, as both read and modify the same underlying objects.
158 } // namespace lldb_vscode