[UE5] "aqProf.dll" "VtuneApi.dll" "VtuneApi32e.dll"을 찾을 수 없다는 오류에 대한 삽질 기록

sanghoon·2023년 11월 2일
0

끝끝내 왜 발생했는지는 알아내지 못했지만, 어떤 방식을 시도해봤는지 적어보았다.
발생 환경 : UE5.2, Windows10


오류 발생!

포폴용 게임을 개발하던 어느날 아주 이상한 오류가 났다...

오류가 난 상황을 설명하기 전에 어떤 게임을 만드려고 시도하는 중인지 말해보자면,
리슨서버로 멀티플레이 게임을 구현하려고 하는 중이었다.
ServerTravel을 하기 전에 TCP 통신을 사용해 호스트의 LAN ip주소를 입력하면 해당 호스트의 서버에서 게임을 할 수 있도록 구현하는 중이었다.

void ULobbyUI::TryHost(FString IP, FString NickName)
{
	// wait until all players join
	auto GameInstance = Cast<UMSBGameInstance>(GetGameInstance());
	AsyncTask(ENamedThreads::AnyBackgroundHiPriTask, [this, GameInstance]()->void
       	{
       		if(nullptr == ServerManager) ServerManager = NewObject<UTCPServer>();
       		ServerManager->OnPlayerCountUpdate.AddUObject(this, &ULobbyUI::UpdatePlayerCount);
			check(GameInstance);
			ServerManager->OnMaxPlayerJoined.AddDynamic(GameInstance, &UMSBGameInstance::EnterGameOnServer); // 서버트래블 수행위치
       		ServerManager->StartHost(); // maxPlayer가 채워질 때까지 클라이언트의 연결을 대기
       	});
}


void ULobbyUI::TryJoin(FString ServerIP, FString NickName)
{
	MSB_LOG(Warning, TEXT("try join"));
	Text_HostIP->SetText(FText::FromString(ServerIP));
	// wait until all players join
	auto GameInstance = Cast<UMSBGameInstance>(GetGameInstance());
	AsyncTask(ENamedThreads::AnyBackgroundHiPriTask, [this, ServerIP, GameInstance]()->void
		   {
			   if(nullptr == ClientManager) ClientManager = NewObject<UTCPClient>();
		       ClientManager->OnPlayerCountUpdate.AddUObject(this, &ULobbyUI::UpdatePlayerCount);
		       ClientManager->OnMaxPlayerJoined.AddDynamic(GameInstance, &UMSBGameInstance::EnterGameOnClient); // 클라이언트트래블 수행위치
			   ClientManager->Join(ServerIP); // ServerIP로 참가 요청 보내기
		   });
}

위 코드에서는 문제가 나지 않았다. 다만 뷰포트에서 게임 종료를 누르더라도 소켓이 닫아지지 않아, 다음 플레이 시 호스트와 클라이언트 모두 무한대기하고 있는 상황이 벌어져서 각각의 람다에 아래 두 줄을 추가하였다.

ServerManager->OnMaxPlayerJoined.AddDynamic(ServerManager, &UTCPServer::CloseSocket);

ClientManager->OnMaxPlayerJoined.AddDynamic(ClientManager, &UTCPClient::CloseSocket);

(물론 각각의 인스턴스 소멸자에 소켓을 닫는 코드를 넣기는 했지만, 가비지컬렉터가 수거하기 전에 강제 종료되서 생기는 문제인지 제대로 닫히지 않는 모양이었다)

그런데 생전 처음보는 오류가 발생했다!

크래시 리포트 스택을 살펴봐도 아래와 같은 문구만 나올 뿐 어느 코드에서 오류가 발생했는지 나와있지 않았다.

UE5Editor_Core
UE5Editor_RenderCore
UE5Editor_RenderCore
UE5Editor_RenderCore
UE5Editor_Engine 
등등(시도할 때마다 비슷한 형식의 다른 스택이 보임)

디버깅모드를 통해 오류가 날법한 곳에 브레이크포인트를 걸어놓고 돌려봐도

위와 같이 모든 브레이크포인트에서는 문제가 발생하지 않았고, 브레이크 포인트들을 다 통과한 후 GameThread가 아닌 처음보는 스레드에서(디버깅 할때마다 다른 스레드에서 오류가 났다) 알 수 없는 오류가 났다... 오류가 난 코드의 위치를 알 수도 없으니 참 막막했다.

그 다음으로는 로그파일을 뒤져보았다.

Log file open, 11/02/23 16:05:05
LogWindows: Failed to load 'aqProf.dll' (GetLastError=126)
LogWindows: File 'aqProf.dll' does not exist
LogProfilingDebugging: Loading WinPixEventRuntime.dll for PIX profiling (from ../../../Engine/Binaries/ThirdParty/Windows/WinPixEventRuntime/x64).
LogWindows: Failed to load 'VtuneApi.dll' (GetLastError=126)
LogWindows: File 'VtuneApi.dll' does not exist
LogWindows: Failed to load 'VtuneApi32e.dll' (GetLastError=126)
LogWindows: File 'VtuneApi32e.dll' does not exist
LogWindows: Started CrashReportClient (pid=12524)
LogWindows: Custom abort handler registered for crash reporting.
...
LogWindows: Failed to load 'WinPixGpuCapturer.dll' (GetLastError=126)
LogWindows: File 'WinPixGpuCapturer.dll' does not exist
PixWinPlugin: PIX capture plugin failed to initialize! Check that the process is launched from PIX.
...

아무리 봐도 알 수 없어서, 'aqProf.dll', 'VtuneApi.dll', 'VtuneApi32e.dll', 'WinPixGpuCapturer.dll'을 키워드로 에픽게임즈 커뮤니티를 찾아보았다.

놀랍게도 나와 비슷한 오류가 났다는 사람은 많은데 해결했다는 사람은 극소수였다. 질문 글에 달린 해결방법들은 아래와 같다.

시도했던 방법들

내 경우도 그렇고 특정 레벨을 Open할 때 오류가 나는 사람이 많았어서 그런지 렌더링 쪽에 관련된 해결방법들이 많이 있었다.

그래픽 드라이버를 업데이트해보세요

나의 경우 Nvidia RTX 3080 ti를 사용하고 있는데 업데이트를 해도 소용이 없었다.

DirectX 버전을 12에서 11로 낮춰보세요

Project Settings > Platforms - Windows > Targeted RHIs > Default RHI에 할당된 값을 DX 12에서 DX 11로 낮춰보라는 방법이었다.
해당 글의 질문자는 해결이 되었지만, 나는 같은 오류가 계속 나왔다..

에디터에서 변경하는 것이 아닌, DefaultEngine.ini 파일에서 직접 수정해도 된다.

DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
-> DefaultGraphicsRHI=DefaultGraphicsRHI_DX11

PIX를 설치하세요

다운로드 후 설치해보았지만, 해결 X

PIX for Windows GPU Capture Plugin을 import하세요

Edit > Plugins에서 해당 플러그인을 임포트시켜봤지만 해결 X

닷넷 sdk 버전 문제

.NET core sdk 3.1을 깔라는 내용의 댓글이 있었다. 1년 전 댓글이라 터무니없이 낮은 버전이긴 했지만 지푸라기라도 잡는 심정으로 설치했으나 해결 X (3.1버전 말고 현재 지원 중인 버전; 6.0 ~ 8.0을 깔아봐도 해결되지 않았다.)

특정 폴더 삭제 후 재빌드하세요

  • 프로젝트 디렉토리 안에 있는 Intermediate/Saved/DerivedDataCache 폴더 삭제
  • C:\Users\유저명\AppData\Local\UnrealEngine\5.2\Saved 삭제

두 방법 모두 X

깃허브 풀리퀘스트

언리얼 엔진 공식 레포지토리에 Pull Request가 하나 올라와 있다.(private repo이기 때문에 깃헙계정과 언리얼 계정을 먼저 연결하셔야합니당)

대충 이것과 비슷한 케이스의 오류가 나는 경우가 많은데, 이를 그냥 로깅할 때 무시하면 되지 않느냐는 내용이다. 답변은 (2023. 11. 02 기준) 현재 제약사항이 많아 당장 확인 및 반영이 어렵다는 입장.

pr 기록을 참고하여 바꿔보았지만 여전히 비슷한 오류가 났다(약간 다르긴 했다). 바꿨는데도 비슷한 오류가 나는 걸로 봐서는 한두줄 바꾼다고 해결될 문제가 아닌 듯 했다.

언리얼 공식 네이버 카페

네이버 카페에도 역시나 비슷한 오류 때문에 고생하신 분들이 많았다. 그러나 해결했다는 분은 한명도 없었다....

그래서 어떻게 할 것이냐?

내 경우에는 오류의 원인이 뭐가 되었든 간에 소켓을 닫는 코드를 작성함에 따라 발생한 문제였기 때문에
일단 소켓 닫는 코드 이전으로 커밋을 되돌려 놓았다.

소켓 연결을 담당하는 두 클래스를 싱글톤으로 만들면 소켓을 닫는 메서드를 굳이 델리게이트에 바인딩시키지 않고도
이미 바인딩되어 있는 다른 메서드에서 잠글 수 있지 않을까 생각 중이다.


이후의 기록

  1. 소켓 클래스를 싱글톤으로 만들어도 Fatal Error가 나면서 게임이 강제종료되고 같은 로그가 띄워졌다.

  2. 소켓통신을 버리고 기본 OnlineSubsystem을 이용해도 같은 현상이 발생했다.(Fatal Error 나면서 강제종료되는 현상, 그리고 'aqProf.dll' (GetLastError=126))

    • 에디터 로그를 확인해본 결과 특정 델리게이트들에 바인딩된 메서드들이 2번씩 불리는 경우가 있어서 바인딩하기 전 RemoveAll()을 각각 진행해주었다.
    • 디버그모드로 패키징한 후 로그파일에서 오류난 부분을 한줄씩 확인해봤더니 이전과는 다른 오류 라인을 확인할 수 있었다!
    // Character.cpp 코드에서 난 에러
    [2023.11.14-11.27.39:748][356]LogWindows: Error: Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000000

나의 경우 해당 오류가 났던 줄에서 Delegate를 Execute하고 있었는데, 이 부분에서 위의 오류가 났었다.

델리게이트에 바인딩하는 부분은 PostInitializeComponents였는데, 다음과 같이 게임모드 클래스의 인스턴스를 얻어와 게임모드 클래스의 메서드를 바인딩해주었다.

auto GameMode = Cast<ACustomGameModeBase>(UGameplayStatics::GetGameMode(GetWorld()));
CustomDelegate.BindUObject(GameMode, &ACustomGameModeBase::DoSth);

ServerTravel을 하게되면서 local에 있는 게임모드 클래스가 잠시 파괴되고 서버의 게임모드클래스의 인스턴스화가 진행되면서 해당 오류가 난다고 생각했었다.
그래서 Execute하기 전 바로 바인딩을 진행하였더니 오류가 해결되었다!

그럼에도 불구하고 로그파일을 확인해보니 '그 오류'는 여전히 나는 것으로 확인했다.

Log file open, 11/14/23 21:07:24
LogWindows: Failed to load 'aqProf.dll' (GetLastError=126)
LogWindows: File 'aqProf.dll' does not exist
LogProfilingDebugging: Loading WinPixEventRuntime.dll for PIX profiling (from ../../../Engine/Binaries/ThirdParty/Windows/WinPixEventRuntime/x64).
LogWindows: Failed to load 'VtuneApi.dll' (GetLastError=126)
LogWindows: File 'VtuneApi.dll' does not exist
LogWindows: Failed to load 'VtuneApi32e.dll' (GetLastError=126)
LogWindows: File 'VtuneApi32e.dll' does not exist

결론

aqProf.dll이 존재하지 않는다는 로그는 오류가 나지 않는 상황에도 로그에 띄워지기 때문에, 일단은 무시해도 될 것 같다.

그렇다면 왜 이전에는 EXCEPTION_ACCESS_VIOLATION오류가 뜨지 않았는가? <- shipping모드로 패키징하는 경우, 디버그모드로 패키징하는 것보다 적게 로깅된다.

아무튼 나를 1달도 넘게 고생시킨 에러가 해결되니까 기분은 좋다..
이 글을 보고있는 분들께도 나의 기록이 도움이 되었으면 좋겠다.

0개의 댓글