修复 性能测试竞态bug

This commit is contained in:
2026-07-23 13:54:06 +08:00
parent 6ece8054ac
commit 94bb3d4f89
3 changed files with 173 additions and 139 deletions
+53 -92
View File
@@ -1,106 +1,67 @@
#include "PerformanceShower_p.h" #include "PerformanceShower_p.h"
#include <QPainter>
#include <QVBoxLayout>
namespace YSG { namespace YSG {
PerformanceShower::PerformanceShower(QWidget *parent) : QWidget(parent) { PerformanceShower::PerformanceShower() {
setAttribute(Qt::WA_OpaquePaintEvent, true); dPtr = new PerformanceShowerPrivate;
auto layout = new QVBoxLayout(this); mObjectName = "PerformanceShower";
layout->setSpacing(0); }
PerformanceShowerPrivate* PerformanceShower::d() {
return reinterpret_cast<PerformanceShowerPrivate*>(dPtr);
}
RenderData* PerformanceShower::createRenderData() {
return new PerformanceShowerPrivate;
}
RenderState* PerformanceShower::createRenderState() {
return new PerformanceShowerRenderState;
}
InputData* PerformanceShower::createInputData() {
return new PerformanceShowerInputData;
}
void PerformanceShower::setEnabled(bool enabled) {
mEnabled.store(enabled, std::memory_order_release);
if(enabled) {
appendEvent({PerformanceEventType::Clear});
}
markRenderDirty();
}
bool PerformanceShower::enabled() const {
return mEnabled.load(std::memory_order_acquire);
} }
void PerformanceShower::refreshCounter() { void PerformanceShower::refreshCounter() {
std::lock_guard<std::mutex> lock(mMutex); appendEvent({PerformanceEventType::Clear});
for(CounterLine& value : mCounter) {
value.mStatistics.clear();
}
} }
void PerformanceShower::counterIncrease(const QString& counterName) { void PerformanceShower::counterIncrease(const QString& counterName) {
std::lock_guard<std::mutex> lock(mMutex); PerformanceEvent event;
if(!mCounter.contains(counterName)) { event.type = PerformanceEventType::Counter;
mCounter[counterName].mName = counterName; event.key = counterName;
} appendEvent(event);
mCounter[counterName].mStatistics.update(1);
} }
void PerformanceShower::setPerformanceLine(const QString& key, const PerformanceLine& line) { void PerformanceShower::setPerformanceLine(const QString& key, const PerformanceLine& line) {
std::lock_guard<std::mutex> lock(mMutex); PerformanceEvent event;
mInfoMap[key] = line; event.type = PerformanceEventType::Line;
event.key = key;
event.line = line;
appendEvent(event);
} }
void PerformanceShower::setInfo(const QString& key, const QString& value) { void PerformanceShower::setInfo(const QString& key, const QString& value) {
std::lock_guard<std::mutex> lock(mMutex); PerformanceEvent event;
mInfos[key] = value; event.type = PerformanceEventType::Info;
event.key = key;
event.value = value;
appendEvent(event);
} }
void PerformanceShower::paintEvent(QPaintEvent *event) { void PerformanceShower::recordCost(const QString& key, double value) {
QPainter painter(this); PerformanceEvent event;
QPoint topLeft = rect().topLeft(); event.type = PerformanceEventType::Cost;
int x = topLeft.x() + mLeftMargin; event.key = key;
int y = topLeft.y() + mTopMargin; event.number = value;
painter.fillRect(rect(), Qt::white); appendEvent(event);
painter.setFont(mFont);
{
std::lock_guard<std::mutex> lock(mMutex);
QFontMetrics fm(mFont);
int n = mAllInfo.size();
for(int i = 0; i < n; i++) {
painter.drawText(topLeft + QPointF(x, y + i * fm.lineSpacing() + fm.lineSpacing()), mAllInfo[i]);
}
}
painter.end();
} }
void PerformanceShower::appendEvent(const PerformanceEvent& event) {
void PerformanceShower::mousePressEvent(QMouseEvent *event) { if(!enabled() && event.type != PerformanceEventType::Clear) return;
if(mMoving) return; auto pd = d();
if(event->button() == Qt::LeftButton) { Triple_Buffer_Lease inputLease = pd->mInputControl.wait_mark_use_role(Input_Edit);
mMoving = true; auto input = reinterpret_cast<PerformanceShowerInputData*>(pd->inputDataByIndex(inputLease.index));
mStartPos = pos(); input->events.append(event);
mStartGlobalPos = event->globalPos(); RenderInputGuard inputGuard(pd, inputLease);
}
event->accept();
}
void PerformanceShower::mouseMoveEvent(QMouseEvent *event) {
if(!mMoving) return;
move(mStartPos + event->globalPos() - mStartGlobalPos);
event->accept();
}
void PerformanceShower::mouseReleaseEvent(QMouseEvent *event) {
if(!mMoving) return;
mMoving = false;
event->accept();
}
QVector<QString> PerformanceShower::all() {
std::lock_guard<std::mutex> lock(mMutex);
QVector<QString> infoList = mFixedInfo;
for(PerformanceLine& l : mInfoMap) infoList.append(l.toString());
for(CounterLine& c : mCounter) infoList.append(c.toString());
for(auto it = mInfos.cbegin(); it != mInfos.cend(); ++it) {
infoList.append(QString("%1: %2").arg(it.key(), it.value()));
}
return infoList;
}
void PerformanceShower::refresh() {
QVector<QString> infoList = all();
{
std::lock_guard<std::mutex> lock(mMutex);
mAllInfo = infoList;
int n = mAllInfo.size();
if(mOldSize != n) {
int maxWidth = 0;
QFontMetrics fm(mFont);
for(int i = 0; i < n; i++) maxWidth = qMax(maxWidth, fm.horizontalAdvance(mAllInfo[i]));
int w = maxWidth + mLeftMargin + mRightMargin;
int h = fm.lineSpacing() * n + mTopMargin + mBottomMargin;
QMetaObject::invokeMethod(this, "firstResize", Q_ARG(int, w), Q_ARG(int, h));
}
mOldSize = n;
}
QMetaObject::invokeMethod(this, "update");
}
void PerformanceShower::firstResize(int w, int h) {
resize(w, h);
}
void PerformanceShower::resizeEvent(QResizeEvent *event) {
event->accept();
} }
} }
+113 -37
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "Core/Statistics/Statistics.h" #include "Core/Statistics/Statistics.h"
#include "../RenderAble.h" #include "../RenderAble.h"
#include <mutex> #include <atomic>
namespace YSG { namespace YSG {
struct PerformanceLine { struct PerformanceLine {
PerformanceLine() = default; PerformanceLine() = default;
@@ -37,65 +37,141 @@ namespace YSG {
struct CounterLine { struct CounterLine {
QString mName; QString mName;
Psc::Speed_Statistics mStatistics; Psc::Speed_Statistics mStatistics;
[[nodiscard]] double getRate() const {
return mStatistics.instant_speed;
}
[[nodiscard]] QString toString() const { [[nodiscard]] QString toString() const {
return QString("%1 :%2 avg:%3 (次/s)") return QString("%1 :%2 avg:%3 (次/s)")
.arg(mName, QString::number(mStatistics.instant_speed, 'f', 2), QString::number(mStatistics.average_speed, 'f', 2)); .arg(mName, QString::number(mStatistics.instant_speed, 'f', 2), QString::number(mStatistics.average_speed, 'f', 2));
} }
}; };
class PerformanceShower : public QWidget { enum class PerformanceEventType : std::uint8_t {
Q_OBJECT Clear,
Counter,
Line,
Info,
Cost
};
struct PerformanceEvent {
PerformanceEventType type = PerformanceEventType::Clear;
QString key;
QString value;
PerformanceLine line;
double number{};
};
struct PerformanceShowerRenderState : RenderState {
QFont font;
int topMargin = 4;
int leftMargin = 4;
int rightMargin = 28;
int bottomMargin = 8;
QColor background = Qt::white;
QColor foreground = Qt::black;
};
struct PerformanceShowerInputData : InputData {
QVector<PerformanceEvent> events;
void clear() override {
events.clear();
}
};
struct PerformanceShowerPrivate;
class PerformanceShower : public RenderAble {
public: public:
explicit PerformanceShower(QWidget *parent = nullptr); PerformanceShower();
QFont mFont; PerformanceShowerPrivate* d();
int mTopMargin = 4, mLeftMargin = 4, mRightMargin = 28, mBottomMargin = 8; RenderData* createRenderData() override;
int mOldSize = -1; RenderState* createRenderState() override;
QVector<QString> mAllInfo; InputData* createInputData() override;
Q_INVOKABLE void firstResize(int w, int h); void setEnabled(bool enabled);
void refresh(); bool enabled() const;
QVector<QString> all();
std::mutex mMutex;
QMap<QString, PerformanceLine> mInfoMap;
QMap<QString, CounterLine> mCounter;
QVector<QString> mFixedInfo;
QMap<QString, QString> mInfos;
void refreshCounter(); void refreshCounter();
void counterIncrease(const QString& counterName); void counterIncrease(const QString& counterName);
void setPerformanceLine(const QString& key, const PerformanceLine& line); void setPerformanceLine(const QString& key, const PerformanceLine& line);
void setInfo(const QString& key, const QString& value); void setInfo(const QString& key, const QString& value);
protected: void recordCost(const QString& key, double value);
void paintEvent(QPaintEvent *event) override; private:
bool mMoving = false; void appendEvent(const PerformanceEvent& event);
QPoint mStartPos, mStartGlobalPos; std::atomic_bool mEnabled{false};
void mousePressEvent(QMouseEvent *event) override; };
void mouseMoveEvent(QMouseEvent *event) override; struct PerformanceShowerPrivate : RenderData {
void mouseReleaseEvent(QMouseEvent *event) override; D_Ptr(PerformanceShower)
void resizeEvent(QResizeEvent *event) override; QMap<QString, PerformanceLine> mInfoMap;
QMap<QString, CounterLine> mCounter;
QMap<QString, QString> mInfos;
QVector<QString> mAllInfo;
void prepareData() override {
syncStatePipeline();
auto input = renderInputData();
for(const PerformanceEvent& event : input->events) {
applyEvent(event);
}
clearRenderInput();
rebuildLines();
}
void draw(QPainter* painter) override {
if(!q()->enabled() || mAllInfo.isEmpty()) return;
auto s = renderState();
painter->save();
painter->setFont(s->font);
QFontMetrics fm(s->font);
int maxWidth = 0;
for(const QString& line : mAllInfo) maxWidth = qMax(maxWidth, fm.horizontalAdvance(line));
int width = maxWidth + s->leftMargin + s->rightMargin;
int height = fm.lineSpacing() * mAllInfo.size() + s->topMargin + s->bottomMargin;
QRect rect(0, 0, width, height);
painter->fillRect(rect, s->background);
painter->setPen(s->foreground);
for(int i = 0; i < mAllInfo.size(); ++i) {
painter->drawText(QPointF(s->leftMargin, s->topMargin + i * fm.lineSpacing() + fm.lineSpacing()), mAllInfo[i]);
}
painter->restore();
}
void applyEvent(const PerformanceEvent& event) {
switch(event.type) {
case PerformanceEventType::Clear:
mInfoMap.clear();
mCounter.clear();
mInfos.clear();
mAllInfo.clear();
break;
case PerformanceEventType::Counter:
if(!mCounter.contains(event.key)) mCounter[event.key].mName = event.key;
mCounter[event.key].mStatistics.update(1);
break;
case PerformanceEventType::Line:
mInfoMap[event.key] = event.line;
break;
case PerformanceEventType::Info:
mInfos[event.key] = event.value;
break;
case PerformanceEventType::Cost:
if(!mInfoMap.contains(event.key)) mInfoMap[event.key] = PerformanceLine(event.key);
mInfoMap[event.key].update(event.number);
break;
}
}
void rebuildLines() {
QVector<QString> lines;
for(PerformanceLine& line : mInfoMap) lines.append(line.toString());
for(CounterLine& counter : mCounter) lines.append(counter.toString());
for(auto it = mInfos.cbegin(); it != mInfos.cend(); ++it) {
lines.append(QString("%1: %2").arg(it.key(), it.value()));
}
mAllInfo = lines;
}
}; };
class Cacl { class Cacl {
public: public:
std::chrono::system_clock::time_point mStart; std::chrono::system_clock::time_point mStart;
QString mName; QString mName;
PerformanceShower *mPerformanceShower{}; PerformanceShower *mPerformanceShower{};
Cacl(const QString& name, PerformanceShower* performanceShower) { Cacl(const QString& name, PerformanceShower* performanceShower) {
if(!performanceShower) return; if(!performanceShower || !performanceShower->enabled()) return;
mStart = std::chrono::system_clock::now(); mStart = std::chrono::system_clock::now();
mName = name; mName = name;
mPerformanceShower = performanceShower; mPerformanceShower = performanceShower;
} }
~Cacl() { ~Cacl() {
if(!mPerformanceShower) return; if(!mPerformanceShower || !mPerformanceShower->enabled()) return;
double useTime = std::chrono::duration<double>(std::chrono::system_clock::now() - mStart).count() * 1000; double useTime = std::chrono::duration<double>(std::chrono::system_clock::now() - mStart).count() * 1000;
std::lock_guard<std::mutex> lock(mPerformanceShower->mMutex); mPerformanceShower->recordCost(mName, useTime);
if(!mPerformanceShower->mInfoMap.contains(mName)) {
mPerformanceShower->mInfoMap[mName] = PerformanceLine(mName);
}
PerformanceLine& data = mPerformanceShower->mInfoMap[mName];
data.update(useTime);
} }
}; };
} }
+7 -10
View File
@@ -20,18 +20,14 @@ namespace YSG {
Global::instance()->renderScheduler().registerPlot(this); Global::instance()->renderScheduler().registerPlot(this);
} }
bool Plot::usePerformanceShower() { bool Plot::usePerformanceShower() {
return d->mShower; return d->mShower && d->mShower->enabled();
} }
void Plot::set_usePerformanceShower(bool use) { void Plot::set_usePerformanceShower(bool use) {
if(!use) { if(!d->mShower) {
PerformanceShower* t = d->mShower; d->mShower = new PerformanceShower;
d->mShower = nullptr; d->mShower->init(this, "legend");
delete t;
} else {
if(d->mShower) return;
d->mShower = new PerformanceShower(this);
d->mShower->show();
} }
d->mShower->setEnabled(use);
} }
Plot::~Plot() { Plot::~Plot() {
@@ -44,6 +40,8 @@ namespace YSG {
return d->mActiveRenderTasks.load(std::memory_order_acquire) == 0; return d->mActiveRenderTasks.load(std::memory_order_acquire) == 0;
}); });
} }
delete d->mShower;
d->mShower = nullptr;
delete d; delete d;
} }
@@ -195,7 +193,6 @@ namespace YSG {
QRegion updateRegion = pipeline.publishRenderColor(); QRegion updateRegion = pipeline.publishRenderColor();
pipeline.jobState = RenderAble::JobState::Idle; pipeline.jobState = RenderAble::JobState::Idle;
if(!updateRegion.isEmpty()) requestUpdate(updateRegion); if(!updateRegion.isEmpty()) requestUpdate(updateRegion);
if(d->mShower) d->mShower->refresh();
if(pipeline.hasNewState()) submitRender(); if(pipeline.hasNewState()) submitRender();
} }
void Plot::renderColor(RenderAble::ColorBuffer* color, QSize size, QColor background, std::uint64_t version) { void Plot::renderColor(RenderAble::ColorBuffer* color, QSize size, QColor background, std::uint64_t version) {