softgpu: Expose flush reasons/times in debug stats.
This commit is contained in:
parent
d6d3bf360c
commit
d95475e021
5 changed files with 65 additions and 8 deletions
|
@ -20,6 +20,8 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "Common/Profiler/Profiler.h"
|
#include "Common/Profiler/Profiler.h"
|
||||||
#include "Common/Thread/ThreadManager.h"
|
#include "Common/Thread/ThreadManager.h"
|
||||||
|
#include "Common/TimeUtil.h"
|
||||||
|
#include "Core/System.h"
|
||||||
#include "GPU/Software/BinManager.h"
|
#include "GPU/Software/BinManager.h"
|
||||||
#include "GPU/Software/Rasterizer.h"
|
#include "GPU/Software/Rasterizer.h"
|
||||||
#include "GPU/Software/RasterizerRectangle.h"
|
#include "GPU/Software/RasterizerRectangle.h"
|
||||||
|
@ -136,7 +138,7 @@ BinManager::~BinManager() {
|
||||||
void BinManager::UpdateState() {
|
void BinManager::UpdateState() {
|
||||||
PROFILE_THIS_SCOPE("bin_state");
|
PROFILE_THIS_SCOPE("bin_state");
|
||||||
if (states_.Full())
|
if (states_.Full())
|
||||||
Flush();
|
Flush("states");
|
||||||
stateIndex_ = (int)states_.Push(RasterizerState());
|
stateIndex_ = (int)states_.Push(RasterizerState());
|
||||||
ComputeRasterizerState(&states_[stateIndex_]);
|
ComputeRasterizerState(&states_[stateIndex_]);
|
||||||
states_[stateIndex_].samplerID.cached.clut = cluts_[clutIndex_].readable;
|
states_[stateIndex_].samplerID.cached.clut = cluts_[clutIndex_].readable;
|
||||||
|
@ -165,12 +167,12 @@ void BinManager::UpdateState() {
|
||||||
// We don't want to overlap wrong, so flush any pending.
|
// We don't want to overlap wrong, so flush any pending.
|
||||||
if (maxTasks_ != newMaxTasks) {
|
if (maxTasks_ != newMaxTasks) {
|
||||||
maxTasks_ = newMaxTasks;
|
maxTasks_ = newMaxTasks;
|
||||||
Flush();
|
Flush("selfrender");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our bin sizes are based on offset, so if that changes we have to flush.
|
// Our bin sizes are based on offset, so if that changes we have to flush.
|
||||||
if (queueOffsetX_ != gstate.getOffsetX16() || queueOffsetY_ != gstate.getOffsetY16()) {
|
if (queueOffsetX_ != gstate.getOffsetX16() || queueOffsetY_ != gstate.getOffsetY16()) {
|
||||||
Flush();
|
Flush("offset");
|
||||||
queueOffsetX_ = gstate.getOffsetX16();
|
queueOffsetX_ = gstate.getOffsetX16();
|
||||||
queueOffsetY_ = gstate.getOffsetY16();
|
queueOffsetY_ = gstate.getOffsetY16();
|
||||||
}
|
}
|
||||||
|
@ -179,7 +181,7 @@ void BinManager::UpdateState() {
|
||||||
void BinManager::UpdateClut(const void *src) {
|
void BinManager::UpdateClut(const void *src) {
|
||||||
PROFILE_THIS_SCOPE("bin_clut");
|
PROFILE_THIS_SCOPE("bin_clut");
|
||||||
if (cluts_.Full())
|
if (cluts_.Full())
|
||||||
Flush();
|
Flush("cluts");
|
||||||
clutIndex_ = (int)cluts_.Push(BinClut());
|
clutIndex_ = (int)cluts_.Push(BinClut());
|
||||||
memcpy(cluts_[clutIndex_].readable, src, sizeof(BinClut));
|
memcpy(cluts_[clutIndex_].readable, src, sizeof(BinClut));
|
||||||
}
|
}
|
||||||
|
@ -323,7 +325,10 @@ void BinManager::Drain() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinManager::Flush() {
|
void BinManager::Flush(const char *reason) {
|
||||||
|
double st;
|
||||||
|
if (coreCollectDebugStats)
|
||||||
|
st = time_now_d();
|
||||||
Drain();
|
Drain();
|
||||||
waitable_->Wait();
|
waitable_->Wait();
|
||||||
taskRanges_.clear();
|
taskRanges_.clear();
|
||||||
|
@ -341,6 +346,42 @@ void BinManager::Flush() {
|
||||||
queueRange_.y2 = 0;
|
queueRange_.y2 = 0;
|
||||||
queueOffsetX_ = -1;
|
queueOffsetX_ = -1;
|
||||||
queueOffsetY_ = -1;
|
queueOffsetY_ = -1;
|
||||||
|
|
||||||
|
if (coreCollectDebugStats) {
|
||||||
|
double et = time_now_d();
|
||||||
|
flushReasonTimes_[reason] += et - st;
|
||||||
|
if (et - st > slowestFlushTime_) {
|
||||||
|
slowestFlushTime_ = et - st;
|
||||||
|
slowestFlushReason_ = reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinManager::GetStats(char *buffer, size_t bufsize) {
|
||||||
|
double allTotal = 0.0;
|
||||||
|
double slowestTotalTime = 0.0;
|
||||||
|
const char *slowestTotalReason = nullptr;
|
||||||
|
for (auto &it : flushReasonTimes_) {
|
||||||
|
if (it.second > slowestTotalTime) {
|
||||||
|
slowestTotalTime = it.second;
|
||||||
|
slowestTotalReason = it.first;
|
||||||
|
}
|
||||||
|
allTotal += it.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buffer, bufsize,
|
||||||
|
"Slowest individual flush: %s (%0.4f)\n"
|
||||||
|
"Slowest total flush: %s (%0.4f)\n"
|
||||||
|
"Total flush time: %0.4f\n",
|
||||||
|
slowestFlushReason_, slowestFlushTime_,
|
||||||
|
slowestTotalReason, slowestTotalTime,
|
||||||
|
allTotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinManager::ResetStats() {
|
||||||
|
flushReasonTimes_.clear();
|
||||||
|
slowestFlushReason_ = nullptr;
|
||||||
|
slowestFlushTime_ = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BinCoords BinCoords::Intersect(const BinCoords &range) const {
|
inline BinCoords BinCoords::Intersect(const BinCoords &range) const {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <unordered_map>
|
||||||
#include "Common/Log.h"
|
#include "Common/Log.h"
|
||||||
#include "GPU/Software/Rasterizer.h"
|
#include "GPU/Software/Rasterizer.h"
|
||||||
|
|
||||||
|
@ -166,7 +167,10 @@ public:
|
||||||
void AddPoint(const VertexData &v0);
|
void AddPoint(const VertexData &v0);
|
||||||
|
|
||||||
void Drain();
|
void Drain();
|
||||||
void Flush();
|
void Flush(const char *reason);
|
||||||
|
|
||||||
|
void GetStats(char *buffer, size_t bufsize);
|
||||||
|
void ResetStats();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr int MAX_POSSIBLE_TASKS = 64;
|
static constexpr int MAX_POSSIBLE_TASKS = 64;
|
||||||
|
@ -188,6 +192,10 @@ private:
|
||||||
std::atomic<bool> taskStatus_[MAX_POSSIBLE_TASKS];
|
std::atomic<bool> taskStatus_[MAX_POSSIBLE_TASKS];
|
||||||
BinWaitable *waitable_ = nullptr;
|
BinWaitable *waitable_ = nullptr;
|
||||||
|
|
||||||
|
std::unordered_map<const char *, double> flushReasonTimes_;
|
||||||
|
const char *slowestFlushReason_ = nullptr;
|
||||||
|
double slowestFlushTime_ = 0.0;
|
||||||
|
|
||||||
BinCoords Scissor(BinCoords range);
|
BinCoords Scissor(BinCoords range);
|
||||||
BinCoords Range(const VertexData &v0, const VertexData &v1, const VertexData &v2);
|
BinCoords Range(const VertexData &v0, const VertexData &v1, const VertexData &v2);
|
||||||
BinCoords Range(const VertexData &v0, const VertexData &v1);
|
BinCoords Range(const VertexData &v0, const VertexData &v1);
|
||||||
|
|
|
@ -900,7 +900,7 @@ void SoftGPU::FinishDeferred() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftGPU::GetStats(char *buffer, size_t bufsize) {
|
void SoftGPU::GetStats(char *buffer, size_t bufsize) {
|
||||||
snprintf(buffer, bufsize, "SoftGPU: (N/A)");
|
drawEngine_->transformUnit.GetStats(buffer, bufsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftGPU::InvalidateCache(u32 addr, int size, GPUInvalidationType type)
|
void SoftGPU::InvalidateCache(u32 addr, int size, GPUInvalidationType type)
|
||||||
|
|
|
@ -609,10 +609,16 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransformUnit::Flush(const char *reason) {
|
void TransformUnit::Flush(const char *reason) {
|
||||||
binner_->Flush();
|
binner_->Flush(reason);
|
||||||
GPUDebug::NotifyDraw();
|
GPUDebug::NotifyDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TransformUnit::GetStats(char *buffer, size_t bufsize) {
|
||||||
|
// TODO: More stats?
|
||||||
|
binner_->GetStats(buffer, bufsize);
|
||||||
|
binner_->ResetStats();
|
||||||
|
}
|
||||||
|
|
||||||
void TransformUnit::FlushIfOverlap(const char *reason, uint32_t addr, uint32_t sz) {
|
void TransformUnit::FlushIfOverlap(const char *reason, uint32_t addr, uint32_t sz) {
|
||||||
if (!Memory::IsVRAMAddress(addr))
|
if (!Memory::IsVRAMAddress(addr))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -123,6 +123,8 @@ public:
|
||||||
void FlushIfOverlap(const char *reason, uint32_t addr, uint32_t sz);
|
void FlushIfOverlap(const char *reason, uint32_t addr, uint32_t sz);
|
||||||
void NotifyClutUpdate(const void *src);
|
void NotifyClutUpdate(const void *src);
|
||||||
|
|
||||||
|
void GetStats(char *buffer, size_t bufsize);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VertexData ReadVertex(VertexReader &vreader, bool &outside_range_flag);
|
VertexData ReadVertex(VertexReader &vreader, bool &outside_range_flag);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue