perf(agc): write each skip report in one call and cap its request dumps

mingw's fprintf writes an unbuffered stderr a character at a time: a title skipping many draws
spent seconds per frame printing 17 KB RecompileRequest dumps (GTA V ran at 0.1 fps). Reports are
built into one string and written once; dumps stop after 8 per reason (APS5_SKIP_REQUEST_DUMPS,
-1 for all).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michon 2026-09-29 18:50:23 +02:00
parent 75a8668b5e
commit 8cf2f65806
1 changed files with 37 additions and 5 deletions

View File

@ -1640,15 +1640,47 @@ private:
}
// A draw or dispatch the translator cannot handle is skipped so the rest of the frame still runs;
// each distinct failure is reported once.
static void reportSkip(const char* kind, const std::string& what) {
static std::mutex reportedMutex;
static std::set<std::string> reported;
std::lock_guard lock(reportedMutex);
static std::set<std::size_t> reported;
static std::map<std::string, int> requestDumps;
// APS5_TRACE_SKIPS reports every skip (shortened), not only the first per reason.
static const bool traceSkips = std::getenv("APS5_TRACE_SKIPS") != nullptr;
if (reported.insert(what).second) std::fprintf(stderr, "[gpu] skipped %s: %s\n", kind, what.c_str());
else if (traceSkips) std::fprintf(stderr, "[gpu] skipped %s again: %.100s\n", kind, what.c_str());
static const int dumpLimit = [] { const char* text = std::getenv("APS5_SKIP_REQUEST_DUMPS"); return text ? std::atoi(text) : 8; }();
static constexpr std::string_view marker = "\nRecompileRequest:\n";
std::lock_guard lock(reportedMutex);
std::string line;
static bool announced = false;
if (!announced) {
announced = true;
char text[160];
std::snprintf(text, sizeof(text), "[gpu] skip reports: one write each, RecompileRequest dumps capped at %d per reason (APS5_SKIP_REQUEST_DUMPS)\n", dumpLimit);
line = text;
}
const std::string prefix = "[gpu] skipped " + std::string(kind);
if (reported.insert(std::hash<std::string>{}(what)).second) {
const auto request = what.find(marker);
if (request == std::string::npos) {
line += prefix + ": " + what + "\n";
} else {
const auto reason = what.substr(0, request);
const auto suffix = what.find(' ', request + marker.size());
auto& dumps = requestDumps[reason];
if (dumpLimit < 0 || dumps < dumpLimit) {
++dumps;
line += prefix + ": " + what + "\n";
} else {
if (dumps == dumpLimit) {
++dumps;
line += prefix + ": further RecompileRequest dumps for \"" + reason + "\" are left out\n";
}
line += prefix + ": " + reason + " (request left out)" + (suffix == std::string::npos ? std::string() : what.substr(suffix)) + "\n";
}
}
} else if (traceSkips) {
line += prefix + " again: " + what.substr(0, 100) + "\n";
}
if (!line.empty()) std::fwrite(line.data(), 1, line.size(), stderr);
}
template <typename Work>
void tolerate(const char* kind, Work&& work) {