Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -221,14 +221,24 @@ void Driver::execute(const Submission& submission) {
continue;
}
if (pipelined && !predicated && (opcode == 0x3c || opcode == 0x93) && header != RenderingWaitPacketHeader && orderedWaits && DrawPipeline::Queue0().Busy()) {
const std::uint64_t awaited = packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u);
if (const auto value = DrawPipeline::Queue0().PendingLabel(awaited, Pm4::WaitAwaitedBytes(packet)); value.has_value() && Pm4::WaitComparesValue(packet, *value)) {
const auto awaitedBytes = Pm4::WaitAwaitedBytes(packet);
const std::uint64_t awaited = (packet[2] & (awaitedBytes == 8 ? ~7u : ~3u)) | (static_cast<std::uint64_t>(packet[3]) << 32u);
const auto value = DrawPipeline::Queue0().PendingLabel(awaited, awaitedBytes);
if (value.has_value() && Pm4::WaitComparesValue(packet, *value)) {
++waitOutcomes().fromRecorderSameQueue;
gateOpened() = true;
recent.Record(cursor);
cursor = nextCursor;
continue;
}
if (!DrawPipeline::Queue0().Overlaps(awaited, awaitedBytes) && Pm4::WaitSatisfiedUnchecked(packet)) {
bumpEpoch(&EpochBumps::waits);
++waitOutcomes().atEntry;
gateOpened() = true;
recent.Record(cursor);
cursor = nextCursor;
continue;
}
}
if (pipelined && DrawPipeline::Queue0().Busy() && !keepsDrawPipeline(packet, header, opcode)) DrawPipeline::Queue0().Drain(DrawPipeline::DrainReason::Packet, header == FlipPacketHeader ? 0xffu : opcode);
if (pipelined && predicated && DrawPipeline::Queue0().Busy() && DrawPipeline::Queue0().Overlaps(queue.predication.address, queue.predication.operation == 3 ? 8 : 4)) DrawPipeline::Queue0().Drain(DrawPipeline::DrainReason::Packet, opcode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void Driver::traceLabel(std::span<const std::uint32_t> packet, std::uint32_t que
const char* kind = nullptr;
if (opcode == 0x49 && packet.size() >= 7) { target = packet[3] | (static_cast<std::uint64_t>(packet[4]) << 32u); kind = "RELEASE_MEM"; }
else if (opcode == 0x37 && packet.size() >= 5) { target = packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u); kind = "WRITE_DATA"; }
else if ((opcode == 0x3c || opcode == 0x93) && packet.size() >= 7) { target = packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u); kind = "WAIT_REG_MEM"; }
else if ((opcode == 0x3c || opcode == 0x93) && packet.size() >= 7) { target = (packet[2] & (Pm4::WaitAwaitedBytes(packet) == 8 ? ~7u : ~3u)) | (static_cast<std::uint64_t>(packet[3]) << 32u); kind = "WAIT_REG_MEM"; }
else if (opcode == 0x40 && packet.size() >= 6) { target = packet[4] | (static_cast<std::uint64_t>(packet[5]) << 32u); kind = "COPY_DATA"; }
std::uint64_t length = 4;
if (opcode == 0x50 && packet.size() >= 7) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,19 +112,21 @@ void Driver::waitMemory(std::span<const std::uint32_t> packet, std::uint32_t que

GuestMemory::TagGpuLockThread(queue);
auto& outcomes = waitOutcomes();
const std::uint64_t awaited = packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u);
const bool wide = ((packet[0] >> 8u) & 0xffu) == 0x93u;
const std::size_t awaitedBytes = Pm4::WaitAwaitedBytes(packet);
const auto alignMask = awaitedBytes == 8 ? ~7ull : ~3ull;
const std::uint64_t awaited = (packet[2] & static_cast<std::uint32_t>(alignMask)) | (static_cast<std::uint64_t>(packet[3]) << 32u);
static const bool traceGpu = std::getenv("APS5_TRACE_GPU") != nullptr;
if (traceGpu) std::fprintf(stderr, "[gpu] %.1f queue 0x%x waits 0x%llx == 0x%x (now 0x%x)\n", TraceMs(), queue, static_cast<unsigned long long>(packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u)), packet[4],
*reinterpret_cast<const volatile std::uint32_t*>(packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u)));
if (traceGpu) std::fprintf(stderr, "[gpu] %.1f queue 0x%x waits 0x%llx == 0x%x (now 0x%x)\n", TraceMs(), queue, static_cast<unsigned long long>(awaited), packet[4],
*reinterpret_cast<const volatile std::uint32_t*>(awaited));
struct WaitTrace {
bool enabled; std::uint32_t queue; std::uint64_t address; std::chrono::steady_clock::time_point begin;
~WaitTrace() {
if (!enabled) return;
const auto ms = std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - begin).count();
if (ms >= 0.5) std::fprintf(stderr, "[gpu] %.1f queue 0x%x wait on 0x%llx done after %.1f ms\n", TraceMs(), queue, static_cast<unsigned long long>(address), ms);
}
} waitTrace{traceGpu, queue, packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u), std::chrono::steady_clock::now()};
} waitTrace{traceGpu, queue, awaited, std::chrono::steady_clock::now()};
bool warned = false;

struct EpochPoint {
Expand Down Expand Up @@ -373,15 +375,15 @@ void Driver::waitMemory(std::span<const std::uint32_t> packet, std::uint32_t que
static std::uint64_t timeouts = 0;
const std::lock_guard lock(reportedMutex);
if (++timeouts % 20 == 0) std::fprintf(stderr, "[gpu] %llu GPU waits have timed out\n", static_cast<unsigned long long>(timeouts));
if (!reported.insert(packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u)).second) continue;
if (!reported.insert(awaited).second) continue;
}
const bool wide = ((packet[0] >> 8u) & 0xffu) == 0x93u;
const std::uint64_t reference = wide ? packet[4] | (static_cast<std::uint64_t>(packet[5]) << 32u) : packet[4];
const std::uint64_t mask = wide ? packet[6] | (static_cast<std::uint64_t>(packet[7]) << 32u) : packet[5];
const std::uint64_t current = wide ? *reinterpret_cast<const volatile std::uint64_t*>(awaited) : *reinterpret_cast<const volatile std::uint32_t*>(awaited);
const std::uint64_t current = awaitedBytes == 8 ? *reinterpret_cast<const volatile std::uint64_t*>(awaited) : *reinterpret_cast<const volatile std::uint32_t*>(awaited);
std::fprintf(stderr, "[gpu] queue 0x%x WAIT_REG_MEM%s%s at 0x%llx timed out after %dms (function %u ref 0x%llx mask 0x%llx value 0x%llx)\n", queue, wide ? "_64" : "", requireMemory ? " (landing)" : "",
static_cast<unsigned long long>(awaited), waitTimeoutMs(), packet[1] & 7u, static_cast<unsigned long long>(reference), static_cast<unsigned long long>(mask), static_cast<unsigned long long>(current));
const auto address = packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u);
const auto address = awaited;
for (const auto& record : writeHistory()) {
if (record.length != 0 && record.target <= address && address < record.target + std::max<std::uint64_t>(record.length, 4))
std::fprintf(stderr, "[gpu] earlier write by queue 0x%x opcode 0x%x at 0x%llx+0x%llx\n", record.queue, record.opcode, static_cast<unsigned long long>(record.target), static_cast<unsigned long long>(record.length));
Expand Down
26 changes: 14 additions & 12 deletions core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,6 @@ void Validate(std::span<const std::uint32_t> packet, std::uint32_t queue) {
size(opcode == 0x3c ? 7 : 9);
require((packet[1] & 0x10u) != 0, "register-space WAIT_REG_MEM is not implemented");
require((packet[1] & 7u) <= 6u, "invalid WAIT_REG_MEM compare function");
require((packet[2] & (opcode == 0x3c ? 3u : 7u)) == 0, "misaligned WAIT_REG_MEM address");
break;
}
case 0x45: {
Expand Down Expand Up @@ -553,20 +552,27 @@ bool waitCompares(std::span<const std::uint32_t> packet, bool wide, std::uint64_

}

std::size_t WaitAwaitedBytes(std::span<const std::uint32_t> packet) {
const bool wide = ((packet[0] >> 8u) & 0xffu) == 0x93u;
return wide && (packet.size() < 8 || packet[7] != 0) ? 8 : 4;
}

bool WaitSatisfied(std::span<const std::uint32_t> packet) {
const bool wide = ((packet[0] >> 8u) & 0xffu) == 0x93u;
const auto source = address(packet[2], packet[3]);
const auto awaitedBytes = WaitAwaitedBytes(packet);
const auto source = address(packet[2] & (awaitedBytes == 8 ? ~7u : ~3u), packet[3]);
std::uint64_t value = 0;
// Named for the [hooksync] attribution (the read goes through the flush hook).
const GuestMemory::ReadSiteScope site(GuestMemory::ReadSite::Wait);
GuestMemory::Read(source, std::as_writable_bytes(std::span(&value, 1)).first(wide ? 8 : 4), wide ? 8 : 4);
GuestMemory::Read(source, std::as_writable_bytes(std::span(&value, 1)).first(awaitedBytes), awaitedBytes);
return waitCompares(packet, wide, value);
}

bool WaitSatisfiedUnchecked(std::span<const std::uint32_t> packet) {
const bool wide = ((packet[0] >> 8u) & 0xffu) == 0x93u;
const auto source = address(packet[2], packet[3]);
const std::uint64_t value = wide ? *reinterpret_cast<const volatile std::uint64_t*>(source) : *reinterpret_cast<const volatile std::uint32_t*>(source);
const auto awaitedBytes = WaitAwaitedBytes(packet);
const auto source = address(packet[2] & (awaitedBytes == 8 ? ~7u : ~3u), packet[3]);
const std::uint64_t value = awaitedBytes == 8 ? *reinterpret_cast<const volatile std::uint64_t*>(source) : *reinterpret_cast<const volatile std::uint32_t*>(source);
return waitCompares(packet, wide, value);
}

Expand All @@ -575,11 +581,6 @@ bool WaitComparesValue(std::span<const std::uint32_t> packet, std::uint64_t valu
return waitCompares(packet, wide, value);
}

std::size_t WaitAwaitedBytes(std::span<const std::uint32_t> packet) {
const bool wide = ((packet[0] >> 8u) & 0xffu) == 0x93u;
return wide && (packet.size() < 8 || packet[7] != 0) ? 8 : 4;
}

std::size_t ConditionalWords(std::span<const std::uint32_t> packet) {
require(packet.size() == 5 && ((packet[0] >> 8u) & 0xffu) == 0x22u, "expected COND_EXEC packet");
return packet[4] & ConditionalWordsMask;
Expand Down Expand Up @@ -676,7 +677,8 @@ WaitFields DecodeWait(std::span<const std::uint32_t> packet) {
const auto opcode = packet.empty() ? 0u : (packet[0] >> 8u) & 0xffu;
require((opcode == 0x3cu && packet.size() == 7) || (opcode == 0x93u && packet.size() == 9), "expected WAIT_REG_MEM or WAIT_REG_MEM_64 packet");
const bool wide = opcode == 0x93u;
return {packet[1] & 7u, address(packet[2], packet[3]), wide ? address(packet[4], packet[5]) : packet[4], wide ? address(packet[6], packet[7]) : packet[5], wide ? packet[8] : packet[6], WaitAwaitedBytes(packet)};
const auto awaitedBytes = WaitAwaitedBytes(packet);
return {packet[1] & 7u, address(packet[2] & (awaitedBytes == 8 ? ~7u : ~3u), packet[3]), wide ? address(packet[4], packet[5]) : packet[4], wide ? address(packet[6], packet[7]) : packet[5], wide ? packet[8] : packet[6], awaitedBytes};
}

ConditionalWrite DecodeConditionalWrite(std::span<const std::uint32_t> packet) {
Expand Down Expand Up @@ -1049,7 +1051,7 @@ void Execute(std::span<const std::uint32_t> packet, QueueState& queue) {
if (!warned && std::chrono::steady_clock::now() - start > std::chrono::seconds(5)) {
warned = true;
std::fprintf(stderr, "[gpu] WAIT_REG_MEM at 0x%llx still waiting after 5s (function %u ref 0x%x mask 0x%x)\n",
static_cast<unsigned long long>(address(packet[2], packet[3])), packet[1] & 7u, packet[4], packet[5]);
static_cast<unsigned long long>(address(packet[2] & (WaitAwaitedBytes(packet) == 8 ? ~7u : ~3u), packet[3])), packet[1] & 7u, packet[4], packet[5]);
}
}
return;
Expand Down
Loading
Loading