Files
UnrealEngine/Engine/Source/Runtime/PakFile/Private/GenericPlatformIoDispatcher.cpp
2025-05-18 13:04:45 +08:00

184 lines
4.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "GenericPlatformIoDispatcher.h"
#include "IoDispatcherFileBackend.h"
#include "Async/AsyncFileHandle.h"
#include "HAL/Event.h"
#include "HAL/PlatformFileManager.h"
#include "HAL/RunnableThread.h"
#include "HAL/IConsoleManager.h"
#include "Misc/ScopeLock.h"
//PRAGMA_DISABLE_OPTIMIZATION
bool GIoDispatcherCullCancelledReadRequests = true;
static FAutoConsoleVariableRef CVar_IoDispatcherCullCancelledReadRequests(
TEXT("s.IoDispatcherCullCancelledReadRequests"),
GIoDispatcherCullCancelledReadRequests,
TEXT("Process cancelled file read requests before starting I/O.")
TEXT("This can prevent the I/O dispatcher thread to stall due to the request queue getting too big.")
);
TRACE_DECLARE_INT_COUNTER_EXTERN(IoDispatcherFileBackendSequentialReads);
TRACE_DECLARE_INT_COUNTER_EXTERN(IoDispatcherFileBackendForwardSeeks);
TRACE_DECLARE_INT_COUNTER_EXTERN(IoDispatcherFileBackendBackwardSeeks);
TRACE_DECLARE_INT_COUNTER_EXTERN(IoDispatcherFileBackendSwitchContainerSeeks);
TRACE_DECLARE_MEMORY_COUNTER_EXTERN(IoDispatcherFileBackendTotalSeekDistance);
TRACE_DECLARE_INT_COUNTER_EXTERN(IoDispatcherFileBackendFileSystemRequests);
TRACE_DECLARE_MEMORY_COUNTER_EXTERN(IoDispatcherFileBackendFileSystemTotalBytesRead);
FGenericFileIoStoreEventQueue::FGenericFileIoStoreEventQueue()
: ServiceEvent(FPlatformProcess::GetSynchEventFromPool())
{
}
FGenericFileIoStoreEventQueue::~FGenericFileIoStoreEventQueue()
{
FPlatformProcess::ReturnSynchEventToPool(ServiceEvent);
}
void FGenericFileIoStoreEventQueue::ServiceNotify()
{
ServiceEvent->Trigger();
}
void FGenericFileIoStoreEventQueue::ServiceWait()
{
ServiceEvent->Wait();
}
FGenericFileIoStoreImpl::FGenericFileIoStoreImpl()
{
}
FGenericFileIoStoreImpl::~FGenericFileIoStoreImpl()
{
}
bool FGenericFileIoStoreImpl::OpenContainer(const TCHAR* ContainerFilePath, uint64& ContainerFileHandle, uint64& ContainerFileSize)
{
IPlatformFile* Ipf = nullptr;
if (UE::IsUsingZenPakFileStreaming())
{
Ipf = &FPlatformFileManager::Get().GetPlatformFile();
}
else
{
Ipf = &IPlatformFile::GetPlatformPhysical();
}
const int64 FileSize = Ipf->FileSize(ContainerFilePath);
if (FileSize < 0)
{
return false;
}
IFileHandle* FileHandle = Ipf->OpenReadNoBuffering(ContainerFilePath);
if (!FileHandle)
{
return false;
}
ContainerFileHandle = reinterpret_cast<UPTRINT>(FileHandle);
ContainerFileSize = uint64(FileSize);
return true;
}
void FGenericFileIoStoreImpl::CloseContainer(uint64 ContainerFileHandle)
{
check(ContainerFileHandle);
IFileHandle* FileHandle = reinterpret_cast<IFileHandle*>(ContainerFileHandle);
delete FileHandle;
}
bool FGenericFileIoStoreImpl::StartRequests(FFileIoStoreRequestQueue& RequestQueue)
{
if (GIoDispatcherCullCancelledReadRequests)
{
TArray<FFileIoStoreReadRequest*> Cancelled;
RequestQueue.PopCancelled(Cancelled);
if (!Cancelled.IsEmpty())
{
{
FScopeLock _(&CompletedRequestsCritical);
for (FFileIoStoreReadRequest* Request : Cancelled)
{
CompletedRequests.Add(Request);
}
}
WakeUpDispatcherThreadDelegate->Execute();
}
}
if (!AcquiredBuffer)
{
AcquiredBuffer = BufferAllocator->AllocBuffer();
if (!AcquiredBuffer)
{
return false;
}
}
FFileIoStoreReadRequest* NextRequest = RequestQueue.Pop();
if (!NextRequest)
{
return false;
}
if (NextRequest->bCancelled | NextRequest->bFailed)
{
{
FScopeLock _(&CompletedRequestsCritical);
CompletedRequests.Add(NextRequest);
}
WakeUpDispatcherThreadDelegate->Execute();
return true;
}
uint8* Dest;
check(!NextRequest->ImmediateScatter.Request);
NextRequest->Buffer = AcquiredBuffer;
AcquiredBuffer = nullptr;
Dest = NextRequest->Buffer->Memory;
if (!BlockCache->Read(NextRequest))
{
IFileHandle* FileHandle = reinterpret_cast<IFileHandle*>(static_cast<UPTRINT>(NextRequest->ContainerFilePartition->FileHandle));
Stats->OnFilesystemReadStarted(NextRequest);
{
TRACE_CPUPROFILER_EVENT_SCOPE(ReadBlockFromFile);
NextRequest->bFailed = true;
int32 RetryCount = 0;
while (RetryCount++ < 10)
{
if (!FileHandle->Seek(NextRequest->Offset))
{
UE_LOG(LogIoDispatcher, Warning, TEXT("Failed seeking to offset %lld (Retries: %d)"), NextRequest->Offset, (RetryCount - 1));
continue;
}
if (!FileHandle->Read(Dest, NextRequest->Size))
{
UE_LOG(LogIoDispatcher, Warning, TEXT("Failed reading %lld bytes at offset %lld (Retries: %d)"), NextRequest->Size, NextRequest->Offset, (RetryCount - 1));
continue;
}
NextRequest->bFailed = false;
Stats->OnFilesystemReadCompleted(NextRequest);
BlockCache->Store(NextRequest);
break;
}
}
}
{
FScopeLock _(&CompletedRequestsCritical);
CompletedRequests.Add(NextRequest);
}
WakeUpDispatcherThreadDelegate->Execute();
return true;
}
void FGenericFileIoStoreImpl::GetCompletedRequests(FFileIoStoreReadRequestList& OutRequests)
{
FScopeLock _(&CompletedRequestsCritical);
OutRequests.AppendSteal(CompletedRequests);
}