GSRunner: Dump/compare stats

This commit is contained in:
Stenzek 2023-07-20 18:37:36 +10:00 committed by Connor McLaughlin
parent c59ea602c5
commit d5776e8946
4 changed files with 77 additions and 2 deletions

View File

@ -13,6 +13,7 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <atomic>
#include <chrono>
#include <csignal>
#include <cstdlib>
@ -39,6 +40,7 @@
#include "pcsx2/Achievements.h"
#include "pcsx2/CDVD/CDVD.h"
#include "pcsx2/GS.h"
#include "pcsx2/GS/GSPerfMon.h"
#include "pcsx2/GSDumpReplayer.h"
#include "pcsx2/Host.h"
#include "pcsx2/INISettingsInterface.h"
@ -57,6 +59,7 @@ namespace GSRunner
static void InitializeConsole();
static bool InitializeConfig();
static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params);
static void DumpStats();
static bool CreatePlatformWindow();
static void DestroyPlatformWindow();
@ -77,6 +80,12 @@ static bool s_no_console = false;
// Owned by the GS thread.
static u32 s_dump_frame_number = 0;
static u32 s_loop_number = s_loop_count;
static u64 s_total_draws = 0;
static u64 s_total_render_passes = 0;
static u64 s_total_barriers = 0;
static u64 s_total_copies = 0;
static u64 s_total_uploads = 0;
static u32 s_total_frames = 0;
bool GSRunner::InitializeConfig()
{
@ -265,6 +274,17 @@ void Host::BeginPresentFrame()
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
GSQueueSnapshot(dump_path);
}
if (GSConfig.UseHardwareRenderer())
{
s_total_draws += static_cast<u64>(g_perfmon.GetCounter(GSPerfMon::DrawCalls));
s_total_render_passes += static_cast<u64>(g_perfmon.GetCounter(GSPerfMon::RenderPasses));
s_total_barriers += static_cast<u64>(g_perfmon.GetCounter(GSPerfMon::Barriers));
s_total_copies += static_cast<u64>(g_perfmon.GetCounter(GSPerfMon::TextureCopies));
s_total_uploads += static_cast<u64>(g_perfmon.GetCounter(GSPerfMon::TextureUploads));
s_total_frames++;
std::atomic_thread_fence(std::memory_order_release);
}
}
void Host::RequestResizeHostDisplay(s32 width, s32 height)
@ -601,6 +621,18 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
return true;
}
void GSRunner::DumpStats()
{
std::atomic_thread_fence(std::memory_order_acquire);
Console.WriteLn(fmt::format("======= HW STATISTICS FOR {} FRAMES ========", s_total_frames));
Console.WriteLn(fmt::format("@HWSTAT@ Draw Calls: {} (avg {})", s_total_draws, static_cast<u64>(std::ceil(s_total_draws / static_cast<double>(s_total_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Render Passes: {} (avg {})", s_total_render_passes, static_cast<u64>(std::ceil(s_total_render_passes / static_cast<double>(s_total_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Barriers: {} (avg {})", s_total_barriers, static_cast<u64>(std::ceil(s_total_barriers / static_cast<double>(s_total_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Copies: {} (avg {})", s_total_copies, static_cast<u64>(std::ceil(s_total_copies / static_cast<double>(s_total_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Uploads: {} (avg {})", s_total_uploads, static_cast<u64>(std::ceil(s_total_uploads / static_cast<double>(s_total_frames)))));
Console.WriteLn("============================================");
}
int main(int argc, char* argv[])
{
GSRunner::InitializeConsole();
@ -636,6 +668,7 @@ int main(int argc, char* argv[])
while (VMManager::GetState() == VMState::Running)
VMManager::Execute();
VMManager::Shutdown(false);
GSRunner::DumpStats();
}
VMManager::Internal::CPUThreadShutdown();

View File

@ -39,6 +39,36 @@ def compare_frames(path1, path2):
return False
def extract_stats(file):
stats = {}
try:
with open(file, "r") as f:
for line in f.readlines():
m = re.match(".*@HWSTAT@ ([^:]+): (.*) \(avg ([^)]+)\)$", line)
if m is None:
continue
stats[m[1]] = int(m[3])
except FileNotFoundError:
pass
except IOError:
pass
return stats
def compare_stats(baselinedir, testdir):
stats1 = extract_stats(os.path.join(baselinedir, "emulog.txt"))
stats2 = extract_stats(os.path.join(testdir, "emulog.txt"))
res = []
for statname in stats1.keys():
if statname not in stats2 or stats1[statname] == stats2[statname]:
continue
v2 = stats2[statname]
v1 = stats1[statname]
delta = v2 - v1
res.append("%s: %s%d [%d=>%d]" % (statname, "+" if delta > 0 else "", delta, v1, v2))
return res
def check_regression_test(baselinedir, testdir, name):
#print("Checking '%s'..." % name)
@ -51,6 +81,7 @@ def check_regression_test(baselinedir, testdir, name):
images = glob.glob(os.path.join(dir1, "*_frame*.png"))
diff_frames = []
first_fail = True
stats = compare_stats(dir1, dir2)
for imagepath in images:
imagename = Path(imagepath).name
@ -85,9 +116,15 @@ def check_regression_test(baselinedir, testdir, name):
write("</table>")
write("<pre>Difference in frames [%s] for %s</pre>" % (",".join(map(str, diff_frames)), name))
print("*** Difference in frames [%s] for %s" % (",".join(map(str, diff_frames)), name))
return False
if len(stats) > 0:
write("<pre>%s</pre>" % "\n".join(stats))
print(stats)
elif len(stats) > 0:
write("<h1>{}</h1>".format(name))
write("<pre>%s</pre>" % "\n".join(stats))
print(name, stats)
return True
return len(diff_frames) == 0
def check_regression_tests(baselinedir, testdir):
@ -103,6 +140,8 @@ def check_regression_tests(baselinedir, testdir):
else:
failure += 1
print("%d dumps unchanged" % success)
print("%d dumps changed" % failure)
return (failure == 0)

View File

@ -24,6 +24,8 @@ def run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, paralle
real_dumpdir = os.path.join(dumpdir, gsname).strip()
if not os.path.exists(real_dumpdir):
os.mkdir(real_dumpdir)
else:
return
if renderer is not None:
args.extend(["-renderer", renderer])

View File

@ -55,6 +55,7 @@ public:
void EndFrame();
void Put(counter_t c, double val) { m_counters[c] += val; }
double GetCounter(counter_t c) { return m_counters[c]; }
double Get(counter_t c) { return m_stats[c]; }
void Update();