Skip to content

Commit 32c1ad2

Browse files
committed
Move stats gathering off the UI thread. Throttle it 10/second.
1 parent e774811 commit 32c1ad2

File tree

8 files changed

+91
-68
lines changed

8 files changed

+91
-68
lines changed

Common/Cpp/Stopwatch.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
*
55
*/
66

7-
#ifndef PokemonAutomation_VideoPipeline_SnapshotManager_H
8-
#define PokemonAutomation_VideoPipeline_SnapshotManager_H
7+
#ifndef PokemonAutomation_VideoPipeline_Stopwatch_H
8+
#define PokemonAutomation_VideoPipeline_Stopwatch_H
99

1010
#include "Time.h"
1111

SerialPrograms/Source/CommonFramework/VideoPipeline/UI/VideoOverlayWidget.cpp

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ VideoOverlayWidget::VideoOverlayWidget(QWidget& parent, VideoOverlaySession& ses
3535
, m_texts(std::make_shared<std::vector<OverlayText>>(session.texts()))
3636
, m_images(std::make_shared<std::vector<OverlayImage>>(session.images()))
3737
, m_log(std::make_shared<std::vector<OverlayLogLine>>(session.log_texts()))
38-
, m_stats(nullptr)
38+
// , m_stats(nullptr)
39+
, m_stats_paint("VideoOverlayWidget::paintEvent", "ms", 1000, std::chrono::seconds(10))
3940
{
4041
setAttribute(Qt::WA_NoSystemBackground);
4142
setAttribute(Qt::WA_TranslucentBackground);
@@ -81,10 +82,6 @@ void VideoOverlayWidget::update_log_background(const std::shared_ptr<const std::
8182
m_log_text_bg_boxes = bg_boxes;
8283
}
8384
#endif
84-
void VideoOverlayWidget::on_overlay_update_stats(const std::list<OverlayStat*>* stats){
85-
WriteSpinLock lg(m_lock, "VideoOverlay::update_stats()");
86-
m_stats = stats;
87-
}
8885

8986
void VideoOverlayWidget::on_watchdog_timeout(){
9087
QMetaObject::invokeMethod(this, [this]{ this->update(); });
@@ -96,6 +93,8 @@ void VideoOverlayWidget::on_watchdog_timeout(){
9693
void VideoOverlayWidget::resizeEvent(QResizeEvent* event){}
9794

9895
void VideoOverlayWidget::paintEvent(QPaintEvent*){
96+
WallClock time0 = current_time();
97+
9998
QPainter painter(this);
10099
{
101100
WriteSpinLock lg(m_lock, "VideoOverlay::paintEvent()");
@@ -112,12 +111,16 @@ void VideoOverlayWidget::paintEvent(QPaintEvent*){
112111
if (m_session.enabled_log()){
113112
render_log(painter);
114113
}
115-
if (m_session.enabled_stats() && m_stats){
114+
if (m_session.enabled_stats()){
116115
render_stats(painter);
117116
}
118117
}
119118

120119
global_watchdog().delay(*this);
120+
121+
WallClock time1 = current_time();
122+
uint32_t microseconds = (uint32_t)std::chrono::duration_cast<std::chrono::microseconds>(time1 - time0).count();
123+
m_stats_paint.report_data(m_session.logger(), microseconds);
121124
}
122125

123126

@@ -291,14 +294,7 @@ void VideoOverlayWidget::render_stats(QPainter& painter){
291294
int height = this->height();
292295
int start_x = (int)(width * 0.78);
293296

294-
std::vector<OverlayStatSnapshot> lines;
295-
for (const auto& stat : *m_stats){
296-
OverlayStatSnapshot snapshot = stat->get_current();
297-
if (!snapshot.text.empty()){
298-
lines.emplace_back(std::move(snapshot));
299-
}
300-
}
301-
297+
std::vector<OverlayStatSnapshot> lines = m_session.stats();
302298

303299
painter.fillRect(
304300
start_x,

SerialPrograms/Source/CommonFramework/VideoPipeline/UI/VideoOverlayWidget.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <QWidget>
1111
#include "Common/Cpp/Concurrency/SpinLock.h"
1212
#include "Common/Cpp/Concurrency/Watchdog.h"
13+
#include "CommonFramework/Tools/StatAccumulator.h"
1314
#include "CommonFramework/VideoPipeline/VideoOverlaySession.h"
1415

1516
namespace PokemonAutomation{
@@ -52,8 +53,6 @@ class VideoOverlayWidget : public QWidget, private VideoOverlaySession::ContentL
5253
virtual void on_overlay_update_images(const std::shared_ptr<const std::vector<OverlayImage>>& images) override;
5354
// callback function from VideoOverlaySession on overlay images updated
5455
virtual void on_overlay_update_log (const std::shared_ptr<const std::vector<OverlayLogLine>>& logs) override;
55-
// callback function from VideoOverlaySession on overlay stats updated
56-
virtual void on_overlay_update_stats (const std::list<OverlayStat*>* stats) override;
5756

5857
virtual void on_watchdog_timeout() override;
5958

@@ -89,7 +88,8 @@ class VideoOverlayWidget : public QWidget, private VideoOverlaySession::ContentL
8988
std::shared_ptr<const std::vector<OverlayText>> m_texts;
9089
std::shared_ptr<const std::vector<OverlayImage>> m_images;
9190
std::shared_ptr<const std::vector<OverlayLogLine>> m_log;
92-
const std::list<OverlayStat*>* m_stats;
91+
92+
PeriodicStatsReporterI32 m_stats_paint;
9393
};
9494

9595

SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.cpp

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ namespace PokemonAutomation{
1717
void VideoOverlaySession::add_listener(ContentListener& listener){
1818
WriteSpinLock lg(m_lock);
1919
m_content_listeners.insert(&listener);
20-
listener.on_overlay_update_stats(&m_stats_order);
2120
}
2221
void VideoOverlaySession::remove_listener(ContentListener& listener){
2322
WriteSpinLock lg(m_lock);
@@ -27,13 +26,17 @@ void VideoOverlaySession::remove_listener(ContentListener& listener){
2726

2827

2928
VideoOverlaySession::~VideoOverlaySession(){
30-
ReadSpinLock lg(m_lock);
31-
for (ContentListener* listener : m_content_listeners){
32-
listener->on_overlay_update_stats(nullptr);
29+
{
30+
std::lock_guard<std::mutex> lg(m_stats_lock);
31+
m_stopping = true;
3332
}
33+
m_stats_cv.notify_all();
34+
m_stats_updater.join();
3435
}
35-
VideoOverlaySession::VideoOverlaySession(VideoOverlayOption& option)
36-
: m_option(option)
36+
VideoOverlaySession::VideoOverlaySession(Logger& logger, VideoOverlayOption& option)
37+
: m_logger(logger)
38+
, m_option(option)
39+
, m_stats_updater(&VideoOverlaySession::stats_thread, this)
3740
{}
3841

3942

@@ -71,6 +74,25 @@ void VideoOverlaySession::set(const VideoOverlayOption& option){
7174
}
7275

7376

77+
void VideoOverlaySession::stats_thread(){
78+
std::unique_lock<std::mutex> lg(m_stats_lock);
79+
while (!m_stopping){
80+
{
81+
std::vector<OverlayStatSnapshot> lines;
82+
ReadSpinLock lg0(m_lock);
83+
for (const auto& stat : m_stats){
84+
OverlayStatSnapshot snapshot = stat.first->get_current();
85+
if (!snapshot.text.empty()){
86+
lines.emplace_back(std::move(snapshot));
87+
}
88+
}
89+
m_stat_lines = std::move(lines);
90+
}
91+
m_stats_cv.wait_for(lg, std::chrono::milliseconds(100));
92+
}
93+
}
94+
95+
7496
void VideoOverlaySession::set_enabled_boxes(bool enabled){
7597
m_option.boxes.store(enabled, std::memory_order_relaxed);
7698
ReadSpinLock lg(m_lock, "VideoOverlaySession::set_enabled_boxes()");
@@ -108,6 +130,9 @@ void VideoOverlaySession::set_enabled_stats(bool enabled){
108130
}
109131

110132

133+
//
134+
// Boxes
135+
//
111136

112137
void VideoOverlaySession::add_box(const OverlayBox& box){
113138
WriteSpinLock lg(m_lock, "VideoOverlaySession::add_box()");
@@ -135,7 +160,6 @@ void VideoOverlaySession::push_box_update(){
135160
listener->on_overlay_update_boxes(ptr);
136161
}
137162
}
138-
139163
std::vector<OverlayBox> VideoOverlaySession::boxes() const{
140164
ReadSpinLock lg(m_lock);
141165
std::vector<OverlayBox> ret;
@@ -145,6 +169,11 @@ std::vector<OverlayBox> VideoOverlaySession::boxes() const{
145169
return ret;
146170
}
147171

172+
173+
//
174+
// Texts
175+
//
176+
148177
void VideoOverlaySession::add_text(const OverlayText& text){
149178
WriteSpinLock lg(m_lock, "VideoOverlaySession::add_text()");
150179
m_texts.insert(&text);
@@ -171,7 +200,6 @@ void VideoOverlaySession::push_text_update(){
171200
listener->on_overlay_update_text(ptr);
172201
}
173202
}
174-
175203
std::vector<OverlayText> VideoOverlaySession::texts() const{
176204
ReadSpinLock lg(m_lock);
177205
std::vector<OverlayText> ret;
@@ -182,6 +210,10 @@ std::vector<OverlayText> VideoOverlaySession::texts() const{
182210
}
183211

184212

213+
//
214+
// Images
215+
//
216+
185217
void VideoOverlaySession::add_image(const OverlayImage& image){
186218
WriteSpinLock lg(m_lock, "VideoOverlaySession::add_image()");
187219
m_images.insert(&image);
@@ -208,7 +240,6 @@ void VideoOverlaySession::push_image_update(){
208240
listener->on_overlay_update_images(ptr);
209241
}
210242
}
211-
212243
std::vector<OverlayImage> VideoOverlaySession::images() const{
213244
ReadSpinLock lg(m_lock);
214245
std::vector<OverlayImage> ret;
@@ -219,6 +250,10 @@ std::vector<OverlayImage> VideoOverlaySession::images() const{
219250
}
220251

221252

253+
//
254+
// Log
255+
//
256+
222257
void VideoOverlaySession::add_log(std::string message, Color color){
223258
WriteSpinLock lg(m_lock, "VideoOverlaySession::add_log_text()");
224259
m_log_texts.emplace_front(color, std::move(message));
@@ -229,7 +264,6 @@ void VideoOverlaySession::add_log(std::string message, Color color){
229264

230265
push_log_text_update();
231266
}
232-
233267
void VideoOverlaySession::clear_log(){
234268
WriteSpinLock lg(m_lock, "VideoOverlaySession::clear_log_texts()");
235269
m_log_texts.clear();
@@ -251,7 +285,6 @@ void VideoOverlaySession::push_log_text_update(){
251285
listener->on_overlay_update_log(ptr);
252286
}
253287
}
254-
255288
std::vector<OverlayLogLine> VideoOverlaySession::log_texts() const{
256289
ReadSpinLock lg(m_lock);
257290
std::vector<OverlayLogLine> ret;
@@ -262,7 +295,9 @@ std::vector<OverlayLogLine> VideoOverlaySession::log_texts() const{
262295
}
263296

264297

265-
298+
//
299+
// Stats
300+
//
266301

267302
void VideoOverlaySession::add_stat(OverlayStat& stat){
268303
WriteSpinLock lg(m_lock);
@@ -271,11 +306,6 @@ void VideoOverlaySession::add_stat(OverlayStat& stat){
271306
return;
272307
}
273308

274-
// Remove all stats so they aren't being referenced.
275-
for (ContentListener* listener : m_content_listeners){
276-
listener->on_overlay_update_stats(nullptr);
277-
}
278-
279309
m_stats_order.emplace_back(&stat);
280310
auto list_iter = m_stats_order.end();
281311
--list_iter;
@@ -285,11 +315,6 @@ void VideoOverlaySession::add_stat(OverlayStat& stat){
285315
m_stats_order.pop_back();
286316
throw;
287317
}
288-
289-
// Add all the stats back.
290-
for (ContentListener* listener : m_content_listeners){
291-
listener->on_overlay_update_stats(&m_stats_order);
292-
}
293318
}
294319
void VideoOverlaySession::remove_stat(OverlayStat& stat){
295320
WriteSpinLock lg(m_lock);
@@ -298,20 +323,14 @@ void VideoOverlaySession::remove_stat(OverlayStat& stat){
298323
return;
299324
}
300325

301-
// Remove all stats so they aren't being referenced.
302-
for (ContentListener* listener : m_content_listeners){
303-
listener->on_overlay_update_stats(nullptr);
304-
}
305-
306326
m_stats_order.erase(iter->second);
307327
m_stats.erase(iter);
308-
309-
// Add all the stats back.
310-
for (ContentListener* listener : m_content_listeners){
311-
listener->on_overlay_update_stats(&m_stats_order);
312-
}
313328
}
314329

330+
std::vector<OverlayStatSnapshot> VideoOverlaySession::stats() const{
331+
ReadSpinLock lg(m_lock);
332+
return m_stat_lines;
333+
}
315334

316335

317336

SerialPrograms/Source/CommonFramework/VideoPipeline/VideoOverlaySession.h

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#include <set>
2020
#include <map>
2121
#include <deque>
22+
#include <mutex>
23+
#include <condition_variable>
24+
#include <thread>
25+
#include "Common/Cpp/AbstractLogger.h"
2226
#include "Common/Cpp/Color.h"
2327
#include "Common/Cpp/Concurrency/SpinLock.h"
2428
#include "VideoOverlay.h"
@@ -59,16 +63,6 @@ class VideoOverlaySession : public VideoOverlay{
5963
// is modified by VideoOverlaySession::add/remove_log().
6064
virtual void on_overlay_update_log (const std::shared_ptr<const std::vector<OverlayLogLine>>& boxes){}
6165

62-
// This one is different from the others. The listeners will store this
63-
// pointer and access it directly and asynchronously. If you need to
64-
// change the structure of the list itself, you must first call this
65-
// with null to remove it from all the listeners. Then add the updated
66-
// one back when you're done.
67-
// This is called immediately when attaching a listener to give the
68-
// current stats. The listener must drop all references to the stats
69-
// before detaching.
70-
virtual void on_overlay_update_stats(const std::list<OverlayStat*>* stats){}
71-
7266
};
7367

7468
// Add a UI class to listen to any overlay change. The UI class needs to inherit Listener.
@@ -80,7 +74,9 @@ class VideoOverlaySession : public VideoOverlay{
8074

8175
public:
8276
~VideoOverlaySession();
83-
VideoOverlaySession(VideoOverlayOption& option);
77+
VideoOverlaySession(Logger& logger, VideoOverlayOption& option);
78+
79+
Logger& logger() const{ return m_logger; }
8480

8581
void get(VideoOverlayOption& option);
8682
void set(const VideoOverlayOption& option);
@@ -114,6 +110,9 @@ class VideoOverlaySession : public VideoOverlay{
114110
// is modified by VideoOverlaySession::add/remove_log().
115111
std::vector<OverlayLogLine> log_texts() const;
116112

113+
std::vector<OverlayStatSnapshot> stats() const;
114+
115+
117116
virtual void add_box(const OverlayBox& box) override;
118117
virtual void remove_box(const OverlayBox& box) override;
119118

@@ -131,18 +130,20 @@ class VideoOverlaySession : public VideoOverlay{
131130

132131

133132
private:
133+
void stats_thread();
134+
134135
// Push updates to the various listeners.
135136
void push_box_update();
136137
void push_text_update();
137138
void push_image_update();
138139
void push_log_text_update();
139140

140-
141141
private:
142-
mutable SpinLock m_lock;
143-
142+
Logger& m_logger;
144143
VideoOverlayOption& m_option;
145144

145+
mutable SpinLock m_lock;
146+
146147
std::set<const OverlayBox*> m_boxes;
147148
std::set<const OverlayText*> m_texts;
148149
std::set<const OverlayImage*> m_images;
@@ -152,6 +153,12 @@ class VideoOverlaySession : public VideoOverlay{
152153
std::map<OverlayStat*, std::list<OverlayStat*>::iterator> m_stats;
153154

154155
std::set<ContentListener*> m_content_listeners;
156+
157+
bool m_stopping = false;
158+
std::vector<OverlayStatSnapshot> m_stat_lines;
159+
std::mutex m_stats_lock;
160+
std::condition_variable m_stats_cv;
161+
std::thread m_stats_updater;
155162
};
156163

157164

0 commit comments

Comments
 (0)