mirror of https://github.com/PCSX2/pcsx2.git
GSRunner: Dump/compare stats
This commit is contained in:
parent
c59ea602c5
commit
d5776e8946
|
@ -13,6 +13,7 @@
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -39,6 +40,7 @@
|
||||||
#include "pcsx2/Achievements.h"
|
#include "pcsx2/Achievements.h"
|
||||||
#include "pcsx2/CDVD/CDVD.h"
|
#include "pcsx2/CDVD/CDVD.h"
|
||||||
#include "pcsx2/GS.h"
|
#include "pcsx2/GS.h"
|
||||||
|
#include "pcsx2/GS/GSPerfMon.h"
|
||||||
#include "pcsx2/GSDumpReplayer.h"
|
#include "pcsx2/GSDumpReplayer.h"
|
||||||
#include "pcsx2/Host.h"
|
#include "pcsx2/Host.h"
|
||||||
#include "pcsx2/INISettingsInterface.h"
|
#include "pcsx2/INISettingsInterface.h"
|
||||||
|
@ -57,6 +59,7 @@ namespace GSRunner
|
||||||
static void InitializeConsole();
|
static void InitializeConsole();
|
||||||
static bool InitializeConfig();
|
static bool InitializeConfig();
|
||||||
static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params);
|
static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params);
|
||||||
|
static void DumpStats();
|
||||||
|
|
||||||
static bool CreatePlatformWindow();
|
static bool CreatePlatformWindow();
|
||||||
static void DestroyPlatformWindow();
|
static void DestroyPlatformWindow();
|
||||||
|
@ -77,6 +80,12 @@ static bool s_no_console = false;
|
||||||
// Owned by the GS thread.
|
// Owned by the GS thread.
|
||||||
static u32 s_dump_frame_number = 0;
|
static u32 s_dump_frame_number = 0;
|
||||||
static u32 s_loop_number = s_loop_count;
|
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()
|
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));
|
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
|
||||||
GSQueueSnapshot(dump_path);
|
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)
|
void Host::RequestResizeHostDisplay(s32 width, s32 height)
|
||||||
|
@ -601,6 +621,18 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||||
return true;
|
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[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
GSRunner::InitializeConsole();
|
GSRunner::InitializeConsole();
|
||||||
|
@ -636,6 +668,7 @@ int main(int argc, char* argv[])
|
||||||
while (VMManager::GetState() == VMState::Running)
|
while (VMManager::GetState() == VMState::Running)
|
||||||
VMManager::Execute();
|
VMManager::Execute();
|
||||||
VMManager::Shutdown(false);
|
VMManager::Shutdown(false);
|
||||||
|
GSRunner::DumpStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
VMManager::Internal::CPUThreadShutdown();
|
VMManager::Internal::CPUThreadShutdown();
|
||||||
|
|
|
@ -39,6 +39,36 @@ def compare_frames(path1, path2):
|
||||||
return False
|
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):
|
def check_regression_test(baselinedir, testdir, name):
|
||||||
#print("Checking '%s'..." % 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"))
|
images = glob.glob(os.path.join(dir1, "*_frame*.png"))
|
||||||
diff_frames = []
|
diff_frames = []
|
||||||
first_fail = True
|
first_fail = True
|
||||||
|
stats = compare_stats(dir1, dir2)
|
||||||
|
|
||||||
for imagepath in images:
|
for imagepath in images:
|
||||||
imagename = Path(imagepath).name
|
imagename = Path(imagepath).name
|
||||||
|
@ -85,9 +116,15 @@ def check_regression_test(baselinedir, testdir, name):
|
||||||
write("</table>")
|
write("</table>")
|
||||||
write("<pre>Difference in frames [%s] for %s</pre>" % (",".join(map(str, diff_frames)), name))
|
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))
|
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):
|
def check_regression_tests(baselinedir, testdir):
|
||||||
|
@ -103,6 +140,8 @@ def check_regression_tests(baselinedir, testdir):
|
||||||
else:
|
else:
|
||||||
failure += 1
|
failure += 1
|
||||||
|
|
||||||
|
print("%d dumps unchanged" % success)
|
||||||
|
print("%d dumps changed" % failure)
|
||||||
return (failure == 0)
|
return (failure == 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ def run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, paralle
|
||||||
real_dumpdir = os.path.join(dumpdir, gsname).strip()
|
real_dumpdir = os.path.join(dumpdir, gsname).strip()
|
||||||
if not os.path.exists(real_dumpdir):
|
if not os.path.exists(real_dumpdir):
|
||||||
os.mkdir(real_dumpdir)
|
os.mkdir(real_dumpdir)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
if renderer is not None:
|
if renderer is not None:
|
||||||
args.extend(["-renderer", renderer])
|
args.extend(["-renderer", renderer])
|
||||||
|
|
|
@ -55,6 +55,7 @@ public:
|
||||||
void EndFrame();
|
void EndFrame();
|
||||||
|
|
||||||
void Put(counter_t c, double val) { m_counters[c] += val; }
|
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]; }
|
double Get(counter_t c) { return m_stats[c]; }
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue