2021-06-02 00:08:00 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "DerivedDataBuildRemoteExecutor.h"
2021-06-07 23:31:40 -04:00
# include "Algo/Find.h"
2021-11-18 14:37:34 -05:00
# include "Containers/Queue.h"
2021-06-02 00:08:00 -04:00
# include "DerivedDataBuild.h"
# include "DerivedDataBuildAction.h"
# include "DerivedDataBuildInputs.h"
# include "DerivedDataBuildOutput.h"
2021-10-20 14:50:22 -04:00
# include "DerivedDataBuildTypes.h"
2021-06-02 00:08:00 -04:00
# include "DerivedDataBuildWorker.h"
2021-08-06 15:50:00 -04:00
# include "DerivedDataRequest.h"
# include "DerivedDataRequestOwner.h"
2022-01-19 00:27:48 -05:00
# include "DerivedDataSharedString.h"
2022-01-06 11:05:57 -05:00
# include "DerivedDataValue.h"
2021-06-02 00:08:00 -04:00
# include "Features/IModularFeatures.h"
2021-07-26 16:18:15 -04:00
# include "HAL/Event.h"
# include "HAL/PlatformProcess.h"
2021-11-18 14:37:34 -05:00
# include "HAL/Runnable.h"
# include "HAL/RunnableThread.h"
2021-06-02 00:08:00 -04:00
# include "Misc/CommandLine.h"
2021-07-13 17:42:10 -04:00
# include "Misc/ConfigCacheIni.h"
2021-06-02 00:08:00 -04:00
# include "Misc/Optional.h"
# include "Misc/PathViews.h"
# include "Modules/ModuleManager.h"
2021-11-18 14:37:34 -05:00
# include "Serialization/CompactBinaryPackage.h"
2021-06-02 00:08:00 -04:00
# include "Serialization/CompactBinaryValidation.h"
# include "Serialization/CompactBinaryWriter.h"
2021-11-18 14:37:34 -05:00
# include "Tasks/Task.h"
# include "Templates/Function.h"
# include "ZenServerHttp.h"
# include "ZenServerInterface.h"
2021-06-07 23:31:40 -04:00
# include <atomic>
2021-06-02 00:08:00 -04:00
2021-11-18 14:37:34 -05:00
# if UE_WITH_ZEN
2021-09-17 11:18:28 -04:00
2021-06-02 00:08:00 -04:00
namespace UE : : DerivedData
{
DEFINE_LOG_CATEGORY_STATIC ( LogDerivedDataBuildRemoteExecutor , Log , All ) ;
2021-07-26 16:18:15 -04:00
class FRemoteBuildWorkerExecutor ;
2021-08-04 18:08:50 -04:00
class FRemoteBuildExecutionRequest final : public FRequestBase
2021-06-02 00:08:00 -04:00
{
public :
2021-07-26 16:18:15 -04:00
FRemoteBuildExecutionRequest (
FRemoteBuildWorkerExecutor & InExecutor ,
const FBuildAction & Action ,
const FOptionalBuildInputs & Inputs ,
2021-10-20 14:50:22 -04:00
const FBuildPolicy & Policy ,
2021-07-26 16:18:15 -04:00
const FBuildWorker & Worker ,
2021-08-04 18:08:50 -04:00
IBuild & BuildSystem ,
IRequestOwner & Owner ,
2021-07-26 16:18:15 -04:00
FOnBuildWorkerActionComplete & & OnComplete ) ;
2021-08-04 18:08:50 -04:00
~ FRemoteBuildExecutionRequest ( ) final ;
2021-07-26 16:18:15 -04:00
// IRequest interface
2021-08-04 18:08:50 -04:00
void SetPriority ( EPriority Priority ) final
2021-06-02 00:08:00 -04:00
{
}
2021-08-04 18:08:50 -04:00
void Cancel ( ) final
2021-06-02 00:08:00 -04:00
{
2021-07-26 16:18:15 -04:00
bCancelPending . store ( true , std : : memory_order_relaxed ) ;
Wait ( ) ;
}
2021-08-04 18:08:50 -04:00
void Wait ( ) final
2021-07-26 16:18:15 -04:00
{
2021-08-04 18:08:50 -04:00
CompletionEvent - > Wait ( ) ;
2021-06-02 00:08:00 -04:00
}
2021-07-26 16:18:15 -04:00
private :
2021-06-02 00:08:00 -04:00
struct FRemoteExecutionState
{
const FBuildAction & BuildAction ;
const FOptionalBuildInputs & BuildInputs ;
const FBuildWorker & BuildWorker ;
2021-08-04 18:08:50 -04:00
IBuild & BuildSystem ;
IRequestOwner & Owner ;
2021-10-20 14:50:22 -04:00
FBuildPolicy BuildPolicy ;
2021-06-02 00:08:00 -04:00
2021-11-18 14:37:34 -05:00
FIoHash WorkerDescriptionId ;
FIoHash ActionId ;
2021-06-02 00:08:00 -04:00
2021-11-18 14:37:34 -05:00
FCbObject WorkerDescriptor ;
FCbObject Action ;
2021-06-02 00:08:00 -04:00
2021-11-18 14:37:34 -05:00
// Step 1: Query if worker exists
// Step 1a: Post Worker object
// Step 1b: Post Worker package which contains missing blobs
// Step 2: Post Action object
// Step 2a: Post Action package which contains missing blobs
// Step 3: Wait for results, return Package
2021-06-02 00:08:00 -04:00
2021-11-18 14:37:34 -05:00
UE : : Zen : : FZenHttpRequest : : Result Result ;
int ResponseCode ;
TSet < FIoHash > NeedHashes ;
FCbPackage ResultPackage ;
2021-06-02 00:08:00 -04:00
} ;
2021-07-26 16:18:15 -04:00
FRemoteExecutionState State ;
FOnBuildWorkerActionComplete CompletionCallback ;
FRemoteBuildWorkerExecutor & Executor ;
FEventRef CompletionEvent { EEventMode : : ManualReset } ;
std : : atomic < bool > bCancelPending ;
bool bHeuristicBuildStarted ;
// General utility methods
2021-11-18 14:37:34 -05:00
static FCbObject BuildWorkerDescriptor ( const FBuildWorker & Worker , const int TimeoutSeconds ) ;
2021-07-26 16:18:15 -04:00
bool ProcessCancellation ( ) ;
2021-11-18 14:37:34 -05:00
bool IsResultOk ( const UE : : Zen : : FZenHttpRequest : : Result & Result , const TCHAR * OperationDesc ) ;
bool IsResponseOk ( const int ResponseCode , const TCHAR * OperationDesc ) ;
2021-07-26 16:18:15 -04:00
// Async steps
2021-11-18 14:37:34 -05:00
void DetermineIfWorkerExists_Async ( ) ;
void PostWorkerObject_Async ( ) ;
void PostWorkerPackage_Async ( ) ;
void PostActionObject_Async ( ) ;
void PostActionPackage_Async ( ) ;
void GetResultPackage_Async ( ) ;
void QueueGetResultPackage ( ) ;
2021-07-26 16:18:15 -04:00
// Post-step flow
2021-11-18 14:37:34 -05:00
void OnWorkerExistsDetermined ( const UE : : Zen : : FZenHttpRequest : : Result & Result ) ;
void OnPostWorkerObjectComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result ) ;
void OnPostWorkerPackageComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result ) ;
void OnPostActionObjectComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result ) ;
void OnPostActionPackageComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result ) ;
void OnGetResultPackageComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result ) ;
2021-07-26 16:18:15 -04:00
} ;
2021-11-18 14:37:34 -05:00
class FRemoteBuildWorkerExecutor final : public IBuildWorkerExecutor , FRunnable
2021-07-26 16:18:15 -04:00
{
public :
FRemoteBuildWorkerExecutor ( )
: GlobalExecutionTimeoutSeconds ( - 1 )
, bEnabled ( false )
2021-06-02 00:08:00 -04:00
{
2021-07-26 16:18:15 -04:00
check ( IsInGameThread ( ) ) ; // initialization from the main thread is expected to allow config reading for the limiting heuristics
check ( GConfig & & GConfig - > IsReadyForUse ( ) ) ;
2021-10-25 20:05:28 -04:00
bool bConfigEnabled = false ;
GConfig - > GetBool ( TEXT ( " DerivedDataBuildRemoteExecutor " ) , TEXT ( " bEnabled " ) , bConfigEnabled , GEngineIni ) ;
2021-07-26 16:18:15 -04:00
GConfig - > GetInt ( TEXT ( " DerivedDataBuildRemoteExecutor " ) , TEXT ( " GlobalExecutionTimeoutSeconds " ) , GlobalExecutionTimeoutSeconds , GEngineIni ) ;
2021-10-25 20:05:28 -04:00
if ( bConfigEnabled | | FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " DDC2RemoteExecution " ) ) )
2021-06-02 00:08:00 -04:00
{
2021-11-18 14:37:34 -05:00
ScopeZenService = MakeUnique < UE : : Zen : : FScopeZenService > ( ) ;
UE : : Zen : : FZenServiceInstance & ZenServiceInstance = ScopeZenService - > GetInstance ( ) ;
if ( ZenServiceInstance . IsServiceRunning ( ) )
2021-06-02 00:08:00 -04:00
{
2021-11-18 14:37:34 -05:00
ProcessingThreadEvent = FPlatformProcess : : GetSynchEventFromPool ( /* bIsManualReset = */ false ) ;
ProcessingThread = TUniquePtr < FRunnableThread > ( FRunnableThread : : Create ( this , TEXT ( " FRemoteBuildWorkerExecutor " ) , 0 , TPri_BelowNormal ) ) ;
bEnabled = ProcessingThread . IsValid ( ) ;
}
if ( bEnabled )
{
RequestPool = MakeUnique < UE : : Zen : : FZenHttpRequestPool > ( ZenServiceInstance . GetURL ( ) ) ;
2022-02-02 06:26:22 -05:00
IModularFeatures : : Get ( ) . RegisterModularFeature ( IBuildWorkerExecutor : : FeatureName , this ) ;
2021-11-18 14:37:34 -05:00
}
else
{
bProcessingThreadRunning = false ;
ProcessingThreadEvent - > Trigger ( ) ;
ProcessingThread - > WaitForCompletion ( ) ;
ScopeZenService . Reset ( ) ;
ProcessingThread . Reset ( ) ;
FPlatformProcess : : ReturnSynchEventToPool ( ProcessingThreadEvent ) ;
2021-06-02 00:08:00 -04:00
}
}
}
2021-07-26 16:18:15 -04:00
virtual ~ FRemoteBuildWorkerExecutor ( )
2021-06-02 00:08:00 -04:00
{
2021-07-26 16:18:15 -04:00
if ( bEnabled )
2021-06-02 00:08:00 -04:00
{
2022-02-02 06:26:22 -05:00
IModularFeatures : : Get ( ) . UnregisterModularFeature ( IBuildWorkerExecutor : : FeatureName , this ) ;
2021-11-18 14:37:34 -05:00
bProcessingThreadRunning = false ;
ProcessingThreadEvent - > Trigger ( ) ;
ProcessingThread - > WaitForCompletion ( ) ;
FPlatformProcess : : ReturnSynchEventToPool ( ProcessingThreadEvent ) ;
2021-06-02 00:08:00 -04:00
}
2021-11-18 14:37:34 -05:00
}
2021-06-02 00:08:00 -04:00
2021-10-20 14:50:22 -04:00
void Build (
2021-06-02 00:08:00 -04:00
const FBuildAction & Action ,
const FOptionalBuildInputs & Inputs ,
2021-10-20 14:50:22 -04:00
const FBuildPolicy & Policy ,
2021-06-02 00:08:00 -04:00
const FBuildWorker & Worker ,
2021-08-04 18:08:50 -04:00
IBuild & BuildSystem ,
IRequestOwner & Owner ,
2021-06-02 00:08:00 -04:00
FOnBuildWorkerActionComplete & & OnComplete ) final
{
2021-06-07 23:31:40 -04:00
{
// TODO: This block forces resolution of inputs before we attempt to determine which
// inputs need to be uploaded. This is required because we can't refer to inputs
// in the Merkle tree by their RawHash/RawSize but instead must send their CompressedHash/
// CompressedSize. Once the remote execution API allows us to represent inputs with RawHash/
// RawSize, this block can be removed and we can find missing CAS inputs without having resolved
// the inputs first.
2022-01-19 00:27:48 -05:00
TArray < FUtf8StringView > MissingInputs ;
2021-07-26 16:18:15 -04:00
uint64 TotalInputSize = 0 ;
uint64 TotalMissingInputSize = 0 ;
2022-01-19 00:27:48 -05:00
Action . IterateInputs ( [ & MissingInputs , & Inputs , & TotalInputSize , & TotalMissingInputSize ] ( FUtf8StringView Key , const FIoHash & RawHash , uint64 RawSize )
2021-06-07 23:31:40 -04:00
{
if ( Inputs . IsNull ( ) | | Inputs . Get ( ) . FindInput ( Key ) . IsNull ( ) )
{
MissingInputs . Emplace ( Key ) ;
2021-07-13 17:42:10 -04:00
TotalMissingInputSize + = RawSize ;
2021-06-07 23:31:40 -04:00
}
2021-07-13 17:42:10 -04:00
TotalInputSize + = RawSize ;
2021-06-07 23:31:40 -04:00
} ) ;
2021-07-13 17:42:10 -04:00
if ( ! LimitingHeuristics . PassesPreResolveRequirements ( TotalInputSize , TotalMissingInputSize ) )
{
OnComplete ( { Action . GetKey ( ) , { } , { } , EStatus : : Error } ) ;
2021-08-04 18:08:50 -04:00
return ;
2021-07-13 17:42:10 -04:00
}
2022-01-19 00:27:48 -05:00
if ( ! MissingInputs . IsEmpty ( ) )
2021-06-07 23:31:40 -04:00
{
2022-01-19 00:27:48 -05:00
OnComplete ( { Action . GetKey ( ) , { } , MissingInputs , EStatus : : Ok } ) ;
2021-08-04 18:08:50 -04:00
return ;
2021-06-07 23:31:40 -04:00
}
}
2021-10-20 14:50:22 -04:00
new FRemoteBuildExecutionRequest ( * this , Action , Inputs , Policy , Worker , BuildSystem , Owner , MoveTemp ( OnComplete ) ) ;
2021-06-02 00:08:00 -04:00
}
TConstArrayView < FStringView > GetHostPlatforms ( ) const final
{
2021-07-23 12:17:08 -04:00
static constexpr FStringView HostPlatforms [ ] { TEXT ( " Win64 " _SV ) , TEXT ( " Linux " _SV ) , TEXT ( " Mac " _SV ) } ;
2021-06-02 00:08:00 -04:00
return HostPlatforms ;
}
2021-07-13 17:42:10 -04:00
void DumpStats ( )
{
if ( Stats . TotalRemoteBuilds . load ( ) = = 0 )
{
return ;
}
Stats . Dump ( ) ;
}
2021-11-18 14:37:34 -05:00
uint32 Run ( ) final
{
bProcessingThreadRunning = true ;
while ( bProcessingThreadRunning )
{
ProcessingThreadEvent - > Wait ( ) ;
TUniqueFunction < void ( bool ) > Function ;
while ( PendingRequests . Dequeue ( Function ) )
{
Function ( true ) ;
}
if ( bProcessingThreadRunning )
{
FPlatformProcess : : Sleep ( 1.0f ) ;
}
}
return 0 ;
}
void Stop ( ) final
{
bProcessingThreadRunning = false ;
}
void Exit ( ) final
{
TUniqueFunction < void ( bool ) > Function ;
while ( PendingRequests . Dequeue ( Function ) )
{
Function ( false ) ;
}
}
void AddResultWaitRequest ( TUniqueFunction < void ( bool ) > & & Function )
{
PendingRequests . Enqueue ( MoveTemp ( Function ) ) ;
ProcessingThreadEvent - > Trigger ( ) ;
}
2021-06-02 00:08:00 -04:00
private :
2021-07-13 17:42:10 -04:00
struct FStats
{
std : : atomic < uint64 > TotalRemoteBuilds { 0 } ;
std : : atomic < uint32 > InFlightRemoteBuilds { 0 } ;
std : : atomic < uint64 > TotalSuccessfulRemoteBuilds { 0 } ;
2021-11-18 14:37:34 -05:00
std : : atomic < uint64 > TotalTimedOutRemoteBuilds { 0 } ;
2021-07-13 17:42:10 -04:00
struct FBlobStat
{
std : : atomic < uint64 > Quantity { 0 } ;
std : : atomic < uint64 > Bytes { 0 } ;
void AddBlob ( uint64 InBytes )
{
Quantity . fetch_add ( 1 , std : : memory_order_relaxed ) ;
Bytes . fetch_add ( InBytes , std : : memory_order_relaxed ) ;
}
} ;
2021-11-18 14:37:34 -05:00
FBlobStat TotalWorkerObjectsUploaded ;
FBlobStat TotalWorkerPackagesUploaded ;
FBlobStat TotalActionObjectsUploaded ;
FBlobStat TotalActionPackagesUploaded ;
FBlobStat TotalObjectsDownloaded ;
FBlobStat TotalPackagesDownloaded ;
2021-07-13 17:42:10 -04:00
void Dump ( )
{
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " " ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " DDC Remote Execution Stats " ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " ========================== " ) ) ;
2021-11-18 14:37:34 -05:00
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Total remote builds " ) , TotalRemoteBuilds . load ( ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Successful remote builds " ) , TotalSuccessfulRemoteBuilds . load ( ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Timed out remote builds " ) , TotalTimedOutRemoteBuilds . load ( ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Uploaded worker objects (quantity) " ) , TotalWorkerObjectsUploaded . Quantity . load ( ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Uploaded worker objects (KB) " ) , TotalWorkerObjectsUploaded . Bytes . load ( ) / 1024 ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Uploaded worker packages (quantity) " ) , TotalWorkerPackagesUploaded . Quantity . load ( ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Uploaded worker packages (KB) " ) , TotalWorkerPackagesUploaded . Bytes . load ( ) / 1024 ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Uploaded action objects (quantity) " ) , TotalActionObjectsUploaded . Quantity . load ( ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Uploaded action objects (KB) " ) , TotalActionObjectsUploaded . Bytes . load ( ) / 1024 ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Uploaded action packages (quantity) " ) , TotalActionPackagesUploaded . Quantity . load ( ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Uploaded action packages (KB) " ) , TotalActionPackagesUploaded . Bytes . load ( ) / 1024 ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Downloaded packages (quantity) " ) , TotalPackagesDownloaded . Quantity . load ( ) ) ;
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Display , TEXT ( " %-36s=%10 " ) UINT64_FMT , TEXT ( " Downloaded packages (KB) " ) , TotalPackagesDownloaded . Bytes . load ( ) / 1024 ) ;
2021-07-13 17:42:10 -04:00
}
} ;
// Temporary heuristics until a scheduler makes higher level decisions about how to limit remote execution of builds
class FLimitingHeuristics
{
public :
FLimitingHeuristics ( )
{
check ( IsInGameThread ( ) ) ; // initialization from the main thread is expected to allow config reading for the limiting heuristics
check ( GConfig & & GConfig - > IsReadyForUse ( ) ) ;
const TCHAR * Section = TEXT ( " DerivedDataBuildRemoteExecutor.LimitingHeuristics " ) ;
GConfig - > GetBool ( Section , TEXT ( " bEnableLimits " ) , bEnableLimits , GEngineIni ) ;
int32 SignedMaxTotalRemoteBuilds { MAX_int32 } ;
GConfig - > GetInt ( Section , TEXT ( " MaxTotalRemoteBuilds " ) , SignedMaxTotalRemoteBuilds , GEngineIni ) ;
if ( ( SignedMaxTotalRemoteBuilds > = 0 ) & & ( SignedMaxTotalRemoteBuilds < MAX_int32 ) )
{
MaxTotalRemoteBuilds = ( uint64 ) SignedMaxTotalRemoteBuilds ;
}
int32 SignedMaxInFlightRemoteBuilds { MAX_int32 } ;
GConfig - > GetInt ( Section , TEXT ( " MaxInFlightRemoteBuilds " ) , SignedMaxInFlightRemoteBuilds , GEngineIni ) ;
if ( ( SignedMaxInFlightRemoteBuilds > = 0 ) & & ( SignedMaxInFlightRemoteBuilds < MAX_int32 ) )
{
MaxInFlightRemoteBuilds = ( uint32 ) SignedMaxInFlightRemoteBuilds ;
}
int32 SignedMinInputSizeForRemoteBuilds { 0 } ;
GConfig - > GetInt ( Section , TEXT ( " MinInputSizeForRemoteBuilds " ) , SignedMinInputSizeForRemoteBuilds , GEngineIni ) ;
if ( ( SignedMinInputSizeForRemoteBuilds > = 0 ) & & ( SignedMinInputSizeForRemoteBuilds < MAX_int32 ) )
{
MinInputSizeForRemoteBuilds = ( uint64 ) SignedMinInputSizeForRemoteBuilds ;
}
2021-12-07 17:22:29 -05:00
int32 SignedMaxInputSizeForRemoteBuilds { MAX_int32 } ;
GConfig - > GetInt ( Section , TEXT ( " MaxInputSizeForRemoteBuilds " ) , SignedMaxInputSizeForRemoteBuilds , GEngineIni ) ;
if ( ( SignedMaxInputSizeForRemoteBuilds > = 0 ) & & ( SignedMaxInputSizeForRemoteBuilds < MAX_int32 ) )
{
MaxInputSizeForRemoteBuilds = ( uint64 ) SignedMaxInputSizeForRemoteBuilds ;
}
2021-07-13 17:42:10 -04:00
int32 SignedMaxMissingInputSizeForRemoteBuilds { MAX_int32 } ;
GConfig - > GetInt ( Section , TEXT ( " MaxMissingInputSizeForRemoteBuilds " ) , SignedMaxMissingInputSizeForRemoteBuilds , GEngineIni ) ;
if ( ( SignedMaxMissingInputSizeForRemoteBuilds > = 0 ) & & ( SignedMaxMissingInputSizeForRemoteBuilds < MAX_int32 ) )
{
MaxMissingInputSizeForRemoteBuilds = ( uint64 ) SignedMaxMissingInputSizeForRemoteBuilds ;
}
}
bool PassesPreResolveRequirements ( uint64 InputSize , uint64 MissingInputSize )
{
if ( ! bEnableLimits )
{
return true ;
}
if ( InputSize < MinInputSizeForRemoteBuilds )
{
return false ;
}
2021-12-07 17:22:29 -05:00
if ( InputSize > MaxInputSizeForRemoteBuilds )
{
return false ;
}
2021-07-13 17:42:10 -04:00
if ( MissingInputSize > MaxMissingInputSizeForRemoteBuilds )
{
return false ;
}
return true ;
}
bool TryStartNewBuild ( FStats & InStats )
{
if ( ( InStats . TotalRemoteBuilds . fetch_add ( 1 , std : : memory_order_relaxed ) > = MaxTotalRemoteBuilds ) & & bEnableLimits )
{
InStats . TotalRemoteBuilds . fetch_sub ( 1 , std : : memory_order_relaxed ) ;
return false ;
}
if ( ( InStats . InFlightRemoteBuilds . fetch_add ( 1 , std : : memory_order_relaxed ) > = MaxInFlightRemoteBuilds ) & & bEnableLimits )
{
InStats . TotalRemoteBuilds . fetch_sub ( 1 , std : : memory_order_relaxed ) ;
InStats . InFlightRemoteBuilds . fetch_sub ( 1 , std : : memory_order_relaxed ) ;
return false ;
}
return true ;
}
void FinishBuild ( FStats & InStats )
{
InStats . InFlightRemoteBuilds . fetch_sub ( 1 , std : : memory_order_relaxed ) ;
}
private :
uint64 MaxTotalRemoteBuilds { MAX_uint64 } ;
uint32 MaxInFlightRemoteBuilds { MAX_uint32 } ;
uint64 MinInputSizeForRemoteBuilds { 0 } ;
2021-12-07 17:22:29 -05:00
uint64 MaxInputSizeForRemoteBuilds { MAX_uint64 } ;
2021-07-13 17:42:10 -04:00
uint64 MaxMissingInputSizeForRemoteBuilds { MAX_uint64 } ;
bool bEnableLimits { false } ;
} ;
2021-07-26 16:18:15 -04:00
friend class FRemoteBuildExecutionRequest ;
2021-07-13 17:42:10 -04:00
FStats Stats ;
FLimitingHeuristics LimitingHeuristics ;
2021-11-18 14:37:34 -05:00
TUniquePtr < FRunnableThread > ProcessingThread ;
FEvent * ProcessingThreadEvent ;
TQueue < TUniqueFunction < void ( bool ) > , EQueueMode : : Mpsc > PendingRequests ;
2021-07-14 17:18:55 -04:00
int GlobalExecutionTimeoutSeconds ;
2021-11-18 14:37:34 -05:00
TUniquePtr < UE : : Zen : : FScopeZenService > ScopeZenService ;
TUniquePtr < UE : : Zen : : FZenHttpRequestPool > RequestPool ;
2021-06-02 00:08:00 -04:00
bool bEnabled ;
2021-11-18 14:37:34 -05:00
std : : atomic < bool > bProcessingThreadRunning ;
2021-06-02 00:08:00 -04:00
} ;
2021-07-26 16:18:15 -04:00
FRemoteBuildExecutionRequest : : FRemoteBuildExecutionRequest (
2021-10-20 14:50:22 -04:00
FRemoteBuildWorkerExecutor & InExecutor ,
const FBuildAction & Action ,
const FOptionalBuildInputs & Inputs ,
const FBuildPolicy & Policy ,
const FBuildWorker & Worker ,
IBuild & BuildSystem ,
IRequestOwner & Owner ,
FOnBuildWorkerActionComplete & & OnComplete )
2021-08-04 18:08:50 -04:00
: State { Action , Inputs , Worker , BuildSystem , Owner , Policy }
2021-07-26 16:18:15 -04:00
, CompletionCallback ( MoveTemp ( OnComplete ) )
, Executor ( InExecutor )
, bCancelPending ( false )
, bHeuristicBuildStarted ( false )
{
2021-08-04 18:08:50 -04:00
Owner . Begin ( this ) ;
2021-11-18 14:37:34 -05:00
if ( ! Executor . LimitingHeuristics . TryStartNewBuild ( Executor . Stats ) )
{
State . Owner . End ( this , [ this ]
{
CompletionCallback ( { State . BuildAction . GetKey ( ) , { } , { } , EStatus : : Error } ) ;
CompletionEvent - > Trigger ( ) ;
} ) ;
return ;
}
bHeuristicBuildStarted = true ;
DetermineIfWorkerExists_Async ( ) ;
2021-07-26 16:18:15 -04:00
}
FRemoteBuildExecutionRequest : : ~ FRemoteBuildExecutionRequest ( )
{
if ( bHeuristicBuildStarted )
{
Executor . LimitingHeuristics . FinishBuild ( Executor . Stats ) ;
2021-10-20 14:50:22 -04:00
}
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
FCbObject FRemoteBuildExecutionRequest : : BuildWorkerDescriptor ( const FBuildWorker & Worker , const int TimeoutSeconds )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
FCbWriter WorkerDescriptor ;
WorkerDescriptor . BeginObject ( ) ;
2021-07-26 16:18:15 -04:00
2021-11-18 14:37:34 -05:00
WorkerDescriptor . AddString ( " name " _ASV , Worker . GetName ( ) ) ;
WorkerDescriptor . AddString ( " path " _ASV , Worker . GetPath ( ) ) ;
WorkerDescriptor . AddString ( " host " _ASV , Worker . GetHostPlatform ( ) ) ;
WorkerDescriptor . AddUuid ( " buildsystem_version " _ASV , Worker . GetBuildSystemVersion ( ) ) ;
WorkerDescriptor . AddInteger ( " timeout " _ASV , TimeoutSeconds ) ;
WorkerDescriptor . AddInteger ( " cores " _ASV , 1 ) ;
//WorkerDescriptor.AddInteger("memory"_ASV, 1 * 1024 * 1024 * 1024);
2021-07-26 16:18:15 -04:00
2021-11-18 14:37:34 -05:00
WorkerDescriptor . BeginArray ( " environment " _ASV ) ;
Worker . IterateEnvironment ( [ & WorkerDescriptor ] ( FStringView Name , FStringView Value )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
WorkerDescriptor . AddString ( WriteToString < 256 > ( Name , " = " , Value ) ) ;
2021-07-26 16:18:15 -04:00
} ) ;
2021-11-18 14:37:34 -05:00
WorkerDescriptor . EndArray ( ) ;
2021-07-26 16:18:15 -04:00
2021-11-18 14:37:34 -05:00
WorkerDescriptor . BeginArray ( " executables " _ASV ) ;
Worker . IterateExecutables ( [ & WorkerDescriptor ] ( FStringView Key , const FIoHash & RawHash , uint64 RawSize )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
WorkerDescriptor . BeginObject ( ) ;
WorkerDescriptor . AddString ( " name " _ASV , Key ) ;
WorkerDescriptor . AddBinaryAttachment ( " hash " _ASV , RawHash ) ;
WorkerDescriptor . AddInteger ( " size " _ASV , RawSize ) ;
WorkerDescriptor . EndObject ( ) ;
2021-07-26 16:18:15 -04:00
} ) ;
2021-11-18 14:37:34 -05:00
WorkerDescriptor . EndArray ( ) ;
2021-07-26 16:18:15 -04:00
2021-11-18 14:37:34 -05:00
WorkerDescriptor . BeginArray ( " files " ) ;
Worker . IterateFiles ( [ & WorkerDescriptor ] ( FStringView Key , const FIoHash & RawHash , uint64 RawSize )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
WorkerDescriptor . BeginObject ( ) ;
WorkerDescriptor . AddString ( " name " _ASV , Key ) ;
WorkerDescriptor . AddBinaryAttachment ( " hash " _ASV , RawHash ) ;
WorkerDescriptor . AddInteger ( " size " _ASV , RawSize ) ;
WorkerDescriptor . EndObject ( ) ;
2021-08-04 18:08:50 -04:00
} ) ;
2021-11-18 14:37:34 -05:00
WorkerDescriptor . EndArray ( ) ;
2021-07-26 16:18:15 -04:00
2021-11-18 14:37:34 -05:00
WorkerDescriptor . BeginArray ( " dirs " _ASV ) ;
WorkerDescriptor . AddString ( WriteToString < 256 > ( " Engine/Binaries/ " , Worker . GetHostPlatform ( ) ) ) ;
WorkerDescriptor . EndArray ( ) ;
WorkerDescriptor . BeginArray ( " functions " _ASV ) ;
2022-01-19 00:27:48 -05:00
Worker . IterateFunctions ( [ & WorkerDescriptor ] ( FUtf8StringView Name , const FGuid & Version )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
WorkerDescriptor . BeginObject ( ) ;
WorkerDescriptor . AddString ( " name " _ASV , Name ) ;
WorkerDescriptor . AddUuid ( " version " _ASV , Version ) ;
WorkerDescriptor . EndObject ( ) ;
2021-07-26 16:18:15 -04:00
} ) ;
2021-11-18 14:37:34 -05:00
WorkerDescriptor . EndArray ( ) ;
2021-07-26 16:18:15 -04:00
2021-11-18 14:37:34 -05:00
WorkerDescriptor . EndObject ( ) ;
2021-07-26 16:18:15 -04:00
2021-11-22 13:17:47 -05:00
return WorkerDescriptor . Save ( ) . AsObject ( ) ;
2021-07-26 16:18:15 -04:00
}
bool FRemoteBuildExecutionRequest : : ProcessCancellation ( )
{
if ( bCancelPending . load ( std : : memory_order_relaxed ) )
{
2021-08-04 18:08:50 -04:00
State . Owner . End ( this , [ this ]
{
CompletionCallback ( { State . BuildAction . GetKey ( ) , { } , { } , EStatus : : Canceled } ) ;
CompletionEvent - > Trigger ( ) ;
} ) ;
2021-07-26 16:18:15 -04:00
return true ;
}
return false ;
}
2021-11-18 14:37:34 -05:00
bool FRemoteBuildExecutionRequest : : IsResultOk ( const UE : : Zen : : FZenHttpRequest : : Result & Result , const TCHAR * OperationDesc )
2021-08-17 10:41:59 -04:00
{
2021-11-18 14:37:34 -05:00
if ( Result = = Zen : : FZenHttpRequest : : Result : : Failed )
2021-08-17 10:41:59 -04:00
{
2021-11-18 14:37:34 -05:00
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Warning , TEXT ( " Remote execution system error: operation '%s' produced an failed result! " ) , OperationDesc ) ;
2021-08-17 10:41:59 -04:00
State . Owner . End ( this , [ this ]
{
CompletionCallback ( { State . BuildAction . GetKey ( ) , { } , { } , EStatus : : Error } ) ;
CompletionEvent - > Trigger ( ) ;
} ) ;
return false ;
}
return true ;
}
2021-11-18 14:37:34 -05:00
bool FRemoteBuildExecutionRequest : : IsResponseOk ( const int ResponseCode , const TCHAR * OperationDesc )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
if ( ! UE : : Zen : : IsSuccessCode ( ResponseCode ) )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Warning , TEXT ( " Remote execution system error: operation '%s' produced an error result (%d)! " ) , OperationDesc , ResponseCode ) ;
State . Owner . End ( this , [ this ]
{
CompletionCallback ( { State . BuildAction . GetKey ( ) , { } , { } , EStatus : : Error } ) ;
CompletionEvent - > Trigger ( ) ;
} ) ;
return false ;
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
return true ;
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
void FRemoteBuildExecutionRequest : : DetermineIfWorkerExists_Async ( )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
UE : : Tasks : : Launch ( TEXT ( " FRemoteBuildExecutionRequest::GetWorkerExists " ) , [ this ]
2021-09-17 11:18:28 -04:00
{
2021-11-18 14:37:34 -05:00
State . WorkerDescriptor = BuildWorkerDescriptor ( State . BuildWorker , Executor . GlobalExecutionTimeoutSeconds ) ;
State . WorkerDescriptionId = State . WorkerDescriptor . GetHash ( ) ;
TStringBuilder < 128 > WorkerUri ;
2022-01-05 15:20:34 -05:00
WorkerUri . Append ( " /apply/workers/ " ) ;
2021-11-18 14:37:34 -05:00
WorkerUri < < State . WorkerDescriptionId ;
2021-12-08 16:24:11 -05:00
UE : : Zen : : FZenScopedRequestPtr Request ( Executor . RequestPool . Get ( ) , false ) ;
2021-11-18 14:37:34 -05:00
State . Result = Request - > PerformBlockingDownload ( WorkerUri , nullptr , Zen : : EContentType : : CbObject ) ;
State . ResponseCode = Request - > GetResponseCode ( ) ;
OnWorkerExistsDetermined ( State . Result ) ;
2021-09-17 11:18:28 -04:00
}
2021-11-18 14:37:34 -05:00
) ;
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
void FRemoteBuildExecutionRequest : : PostWorkerObject_Async ( )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
UE : : Tasks : : Launch ( TEXT ( " FRemoteBuildExecutionRequest::PostWorkerObject " ) , [ this ]
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
TStringBuilder < 128 > WorkerUri ;
2022-01-05 15:20:34 -05:00
WorkerUri . Append ( " /apply/workers/ " ) ;
2021-11-18 14:37:34 -05:00
WorkerUri < < State . WorkerDescriptionId ;
2021-09-17 11:18:28 -04:00
2021-11-18 14:37:34 -05:00
Executor . Stats . TotalWorkerObjectsUploaded . AddBlob ( State . WorkerDescriptor . GetSize ( ) ) ;
State . NeedHashes . Empty ( ) ;
2021-12-08 16:24:11 -05:00
UE : : Zen : : FZenScopedRequestPtr Request ( Executor . RequestPool . Get ( ) , false ) ;
2021-11-18 14:37:34 -05:00
State . Result = Request - > PerformBlockingPost ( WorkerUri , State . WorkerDescriptor ) ;
State . ResponseCode = Request - > GetResponseCode ( ) ;
if ( Request - > GetResponseCode ( ) = = 404 )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
FCbObjectView Response = Request - > GetResponseAsObject ( ) ;
FCbArrayView NeedArray = Response [ " need " ] . AsArrayView ( ) ;
for ( auto & It : NeedArray )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
State . NeedHashes . Add ( It . AsHash ( ) ) ;
}
}
OnPostWorkerObjectComplete ( State . Result ) ;
}
) ;
}
void FRemoteBuildExecutionRequest : : PostWorkerPackage_Async ( )
{
UE : : Tasks : : Launch ( TEXT ( " FRemoteBuildExecutionRequest::PostWorkerPackage " ) , [ this ]
{
TStringBuilder < 128 > WorkerUri ;
2022-01-05 15:20:34 -05:00
WorkerUri . Append ( " /apply/workers/ " ) ;
2021-11-18 14:37:34 -05:00
WorkerUri < < State . WorkerDescriptionId ;
uint64_t AttachmentBytes { } ;
FCbPackage Package ;
{
TSet < FIoHash > WorkerFileHashes ;
State . BuildWorker . IterateExecutables ( [ NeedHashes = State . NeedHashes , & WorkerFileHashes ] ( FStringView Path , const FIoHash & RawHash , uint64 RawSize )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
if ( NeedHashes . Contains ( RawHash ) )
{
WorkerFileHashes . Emplace ( RawHash ) ;
}
} ) ;
State . BuildWorker . IterateFiles ( [ NeedHashes = State . NeedHashes , & WorkerFileHashes ] ( FStringView Path , const FIoHash & RawHash , uint64 RawSize )
{
if ( NeedHashes . Contains ( RawHash ) )
{
WorkerFileHashes . Emplace ( RawHash ) ;
}
} ) ;
if ( State . NeedHashes . Num ( ) ! = WorkerFileHashes . Num ( ) )
{
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Warning , TEXT ( " Remote execution system error: build input file missing! " ) ) ;
State . Result = UE : : Zen : : FZenHttpRequest : : Result : : Failed ;
State . ResponseCode = 0 ;
OnPostWorkerPackageComplete ( State . Result ) ;
return ;
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
FRequestOwner BlockingOwner ( EPriority : : Blocking ) ;
State . BuildWorker . FindFileData ( WorkerFileHashes . Array ( ) , BlockingOwner , [ & Package , & AttachmentBytes ] ( FBuildWorkerFileDataCompleteParams & & Params )
{
for ( const FCompressedBuffer & Buffer : Params . Files )
{
Package . AddAttachment ( FCbAttachment { Buffer } ) ;
AttachmentBytes + = Buffer . GetCompressedSize ( ) ;
}
} ) ;
BlockingOwner . Wait ( ) ;
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
Package . SetObject ( State . WorkerDescriptor ) ;
Executor . Stats . TotalActionPackagesUploaded . AddBlob ( AttachmentBytes + State . WorkerDescriptor . GetSize ( ) ) ;
2021-12-08 16:24:11 -05:00
UE : : Zen : : FZenScopedRequestPtr Request ( Executor . RequestPool . Get ( ) , false ) ;
2021-11-18 14:37:34 -05:00
State . Result = Request - > PerformBlockingPostPackage ( WorkerUri , Package ) ;
State . ResponseCode = Request - > GetResponseCode ( ) ;
OnPostWorkerPackageComplete ( State . Result ) ;
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
) ;
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
void FRemoteBuildExecutionRequest : : PostActionObject_Async ( )
2021-07-26 16:18:15 -04:00
{
2021-11-18 14:37:34 -05:00
UE : : Tasks : : Launch ( TEXT ( " FRemoteBuildExecutionRequest::PostActionObject " ) , [ this ]
2021-09-17 11:18:28 -04:00
{
2021-11-18 14:37:34 -05:00
{
FCbWriter BuildActionWriter ;
State . BuildAction . Save ( BuildActionWriter ) ;
State . Action = BuildActionWriter . Save ( ) . AsObject ( ) ;
State . ActionId = State . Action . GetHash ( ) ;
}
TStringBuilder < 128 > ActionUri ;
2022-01-05 15:20:34 -05:00
ActionUri . Append ( " /apply/jobs/ " ) ;
2021-11-18 14:37:34 -05:00
ActionUri < < State . WorkerDescriptionId ;
State . NeedHashes . Empty ( ) ;
Executor . Stats . TotalActionObjectsUploaded . AddBlob ( State . Action . GetSize ( ) ) ;
2021-12-08 16:24:11 -05:00
UE : : Zen : : FZenScopedRequestPtr Request ( Executor . RequestPool . Get ( ) , false ) ;
2021-11-18 14:37:34 -05:00
State . Result = Request - > PerformBlockingPost ( ActionUri , State . Action ) ;
State . ResponseCode = Request - > GetResponseCode ( ) ;
if ( Request - > GetResponseCode ( ) = = 404 )
{
FCbObjectView Response = Request - > GetResponseAsObject ( ) ;
FCbArrayView NeedArray = Response [ " need " ] . AsArrayView ( ) ;
for ( auto & It : NeedArray )
{
State . NeedHashes . Add ( It . AsHash ( ) ) ;
}
}
OnPostActionObjectComplete ( State . Result ) ;
}
) ;
}
void FRemoteBuildExecutionRequest : : PostActionPackage_Async ( )
{
UE : : Tasks : : Launch ( TEXT ( " FRemoteBuildExecutionRequest::PostActionPackage " ) , [ this ]
{
uint64_t AttachmentBytes { } ;
FCbPackage ActionPackage ;
2022-01-19 00:27:48 -05:00
State . BuildInputs . Get ( ) . IterateInputs ( [ NeedHashes = State . NeedHashes , & ActionPackage , & AttachmentBytes ] ( FUtf8StringView Key , const FCompressedBuffer & Buffer )
2021-11-18 14:37:34 -05:00
{
if ( NeedHashes . Contains ( Buffer . GetRawHash ( ) ) )
{
ActionPackage . AddAttachment ( FCbAttachment { Buffer } ) ;
AttachmentBytes + = Buffer . GetCompressedSize ( ) ;
}
} ) ;
if ( State . NeedHashes . Num ( ) ! = ActionPackage . GetAttachments ( ) . Num ( ) )
{
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Warning , TEXT ( " Remote execution system error: build input attachment missing! " ) ) ;
State . Result = UE : : Zen : : FZenHttpRequest : : Result : : Failed ;
State . ResponseCode = 0 ;
OnPostActionPackageComplete ( State . Result ) ;
return ;
}
ActionPackage . SetObject ( State . Action ) ;
TStringBuilder < 128 > ActionUri ;
2022-01-05 15:20:34 -05:00
ActionUri . Append ( " /apply/jobs/ " ) ;
2021-11-18 14:37:34 -05:00
ActionUri < < State . WorkerDescriptionId ;
Executor . Stats . TotalActionPackagesUploaded . AddBlob ( AttachmentBytes + State . Action . GetSize ( ) ) ;
2021-12-08 16:24:11 -05:00
UE : : Zen : : FZenScopedRequestPtr Request ( Executor . RequestPool . Get ( ) , false ) ;
2021-11-18 14:37:34 -05:00
State . Result = Request - > PerformBlockingPostPackage ( ActionUri , ActionPackage ) ;
State . ResponseCode = Request - > GetResponseCode ( ) ;
OnPostActionPackageComplete ( State . Result ) ;
}
) ;
}
void FRemoteBuildExecutionRequest : : GetResultPackage_Async ( )
{
UE : : Tasks : : Launch ( TEXT ( " FRemoteBuildExecutionRequest::GetResultPackage " ) , [ this ]
{
TStringBuilder < 128 > JobGetUri ;
2022-01-05 15:20:34 -05:00
JobGetUri . Append ( " /apply/jobs/ " ) ;
2021-11-18 14:37:34 -05:00
JobGetUri < < State . WorkerDescriptionId ;
JobGetUri < < " / " ;
JobGetUri < < State . ActionId ;
2021-12-08 16:24:11 -05:00
UE : : Zen : : FZenScopedRequestPtr Request ( Executor . RequestPool . Get ( ) , false ) ;
2021-11-18 14:37:34 -05:00
State . Result = Request - > PerformBlockingDownload ( JobGetUri . ToString ( ) , nullptr , UE : : Zen : : EContentType : : CbPackage ) ;
State . ResponseCode = Request - > GetResponseCode ( ) ;
if ( State . ResponseCode = = 200 )
{
Executor . Stats . TotalPackagesDownloaded . AddBlob ( Request - > GetResponseBuffer ( ) . Num ( ) ) ;
State . ResultPackage = Request - > GetResponseAsPackage ( ) ;
}
else if ( State . ResponseCode = = 404 )
{
Executor . Stats . TotalTimedOutRemoteBuilds . fetch_add ( 1 , std : : memory_order_relaxed ) ;
}
OnGetResultPackageComplete ( State . Result ) ;
}
) ;
}
void FRemoteBuildExecutionRequest : : QueueGetResultPackage ( )
{
auto Callback = [ this ] ( const bool Continue ) mutable
{
if ( ! Continue )
{
State . Owner . End ( this , [ this ]
{
CompletionCallback ( { State . BuildAction . GetKey ( ) , { } , { } , EStatus : : Canceled } ) ;
CompletionEvent - > Trigger ( ) ;
} ) ;
2021-09-17 11:18:28 -04:00
return ;
}
2021-11-18 14:37:34 -05:00
GetResultPackage_Async ( ) ;
} ;
2021-09-17 11:18:28 -04:00
2021-11-18 14:37:34 -05:00
Executor . AddResultWaitRequest ( MoveTemp ( Callback ) ) ;
2021-07-26 16:18:15 -04:00
}
2021-11-18 14:37:34 -05:00
void FRemoteBuildExecutionRequest : : OnWorkerExistsDetermined ( const UE : : Zen : : FZenHttpRequest : : Result & Result )
2021-07-26 16:18:15 -04:00
{
2021-09-17 11:18:28 -04:00
if ( ProcessCancellation ( ) )
2021-07-26 16:18:15 -04:00
{
return ;
}
2021-11-18 14:37:34 -05:00
if ( ! IsResultOk ( Result , TEXT ( " GetWorkerExists " ) ) )
2021-09-17 11:18:28 -04:00
{
2021-11-18 14:37:34 -05:00
return ;
}
if ( State . ResponseCode = = 404 )
{
// Worker missing, proceed to posting Object
PostWorkerObject_Async ( ) ;
return ;
}
if ( ! IsResponseOk ( State . ResponseCode , TEXT ( " GetWorkerExists " ) ) )
{
return ;
}
// Worker exists, proceed to action
PostActionObject_Async ( ) ;
}
void FRemoteBuildExecutionRequest : : OnPostWorkerObjectComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result )
{
if ( ProcessCancellation ( ) )
{
return ;
}
if ( ! IsResultOk ( Result , TEXT ( " PostWorkerObject " ) ) )
{
return ;
}
if ( State . ResponseCode = = 404 )
{
// Worker content missing, proceed to posting Package
PostWorkerPackage_Async ( ) ;
return ;
}
if ( ! IsResponseOk ( State . ResponseCode , TEXT ( " PostWorkerObject " ) ) )
{
return ;
}
// Worker exists and is not missing anything, proceed to action
PostActionObject_Async ( ) ;
}
void FRemoteBuildExecutionRequest : : OnPostWorkerPackageComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result )
{
if ( ProcessCancellation ( ) )
{
return ;
}
if ( ! IsResultOk ( Result , TEXT ( " PostWorkerPackage " ) ) | | ! IsResponseOk ( State . ResponseCode , TEXT ( " PostWorkerPackage " ) ) )
{
return ;
}
// Worker exists and is not missing anything, proceed to action
PostActionObject_Async ( ) ;
}
void FRemoteBuildExecutionRequest : : OnPostActionObjectComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result )
{
if ( ProcessCancellation ( ) )
{
return ;
}
if ( ! IsResultOk ( Result , TEXT ( " PostActionObject " ) ) )
{
return ;
}
if ( State . ResponseCode = = 404 )
{
// Action content missing, proceed to posting Package
PostActionPackage_Async ( ) ;
return ;
}
if ( ! IsResponseOk ( State . ResponseCode , TEXT ( " PostWorkerObject " ) ) )
{
return ;
}
// Action posted, proceed to waiting
QueueGetResultPackage ( ) ;
}
void FRemoteBuildExecutionRequest : : OnPostActionPackageComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result )
{
if ( ProcessCancellation ( ) )
{
return ;
}
if ( ! IsResultOk ( Result , TEXT ( " PostActionPackage " ) ) | | ! IsResponseOk ( State . ResponseCode , TEXT ( " PostActionPackage " ) ) )
{
return ;
}
// Action posted, proceed to waiting
QueueGetResultPackage ( ) ;
}
void FRemoteBuildExecutionRequest : : OnGetResultPackageComplete ( const UE : : Zen : : FZenHttpRequest : : Result & Result )
{
if ( ProcessCancellation ( ) )
{
return ;
}
if ( ! IsResultOk ( Result , TEXT ( " GetResultPackage " ) ) | | ! IsResponseOk ( State . ResponseCode , TEXT ( " GetResultPackage " ) ) )
{
return ;
}
if ( State . ResponseCode = = 202 )
{
QueueGetResultPackage ( ) ;
return ;
}
// We're done!
FOptionalBuildOutput RemoteBuildOutput = FBuildOutput : : Load ( State . BuildAction . GetName ( ) , State . BuildAction . GetFunction ( ) , State . ResultPackage . GetObject ( ) ) ;
if ( RemoteBuildOutput . IsNull ( ) )
{
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Warning , TEXT ( " Remote execution system error: build output blob missing! " ) ) ;
State . Owner . End ( this , [ this ]
{
CompletionCallback ( { State . BuildAction . GetKey ( ) , { } , { } , EStatus : : Error } ) ;
CompletionEvent - > Trigger ( ) ;
} ) ;
return ;
}
FBuildOutputBuilder OutputBuilder = State . BuildSystem . CreateOutput ( State . BuildAction . GetName ( ) , State . BuildAction . GetFunction ( ) ) ;
2021-11-24 13:25:25 -05:00
for ( const FBuildOutputMessage & Message : RemoteBuildOutput . Get ( ) . GetMessages ( ) )
{
OutputBuilder . AddMessage ( Message ) ;
}
for ( const FBuildOutputLog & Log : RemoteBuildOutput . Get ( ) . GetLogs ( ) )
{
OutputBuilder . AddLog ( Log ) ;
}
2021-11-18 14:37:34 -05:00
2022-01-06 11:05:57 -05:00
for ( const FValueWithId & Value : RemoteBuildOutput . Get ( ) . GetValues ( ) )
2021-11-18 14:37:34 -05:00
{
2022-01-06 11:05:57 -05:00
FCompressedBuffer BufferForValue ;
2021-11-18 14:37:34 -05:00
2022-01-06 11:05:57 -05:00
if ( const FCbAttachment * Attachment = State . ResultPackage . FindAttachment ( Value . GetRawHash ( ) ) )
2021-11-18 14:37:34 -05:00
{
2022-01-06 11:05:57 -05:00
BufferForValue = Attachment - > AsCompressedBinary ( ) ;
2021-11-18 14:37:34 -05:00
}
2022-01-06 11:05:57 -05:00
if ( BufferForValue . IsNull ( ) )
2021-11-18 14:37:34 -05:00
{
UE_LOG ( LogDerivedDataBuildRemoteExecutor , Warning , TEXT ( " Remote execution system error: payload blob missing! " ) ) ;
State . Owner . End ( this , [ this ]
{
CompletionCallback ( { State . BuildAction . GetKey ( ) , { } , { } , EStatus : : Error } ) ;
CompletionEvent - > Trigger ( ) ;
} ) ;
2021-09-17 11:18:28 -04:00
return ;
}
2021-11-18 14:37:34 -05:00
2022-01-06 11:05:57 -05:00
OutputBuilder . AddValue ( Value . GetId ( ) , FValue ( MoveTemp ( BufferForValue ) ) ) ;
2021-09-17 11:18:28 -04:00
}
2021-11-18 14:37:34 -05:00
FBuildOutput BuildOutput = OutputBuilder . Build ( ) ;
Executor . Stats . TotalSuccessfulRemoteBuilds . fetch_add ( 1 , std : : memory_order_relaxed ) ;
State . Owner . End ( this , [ this , & BuildOutput ] ( ) mutable
2021-08-04 18:08:50 -04:00
{
2021-11-18 14:37:34 -05:00
CompletionCallback ( { State . BuildAction . GetKey ( ) , MoveTemp ( BuildOutput ) , { } , EStatus : : Ok } ) ;
2021-08-04 18:08:50 -04:00
} ) ;
2022-01-06 11:05:57 -05:00
CompletionEvent - > Trigger ( ) ;
2021-07-26 16:18:15 -04:00
}
2021-06-02 00:08:00 -04:00
} // namespace UE::DerivedData
2021-07-13 17:42:10 -04:00
TOptional < UE : : DerivedData : : FRemoteBuildWorkerExecutor > GRemoteBuildWorkerExecutor ;
2021-06-02 00:08:00 -04:00
void InitDerivedDataBuildRemoteExecutor ( )
{
2021-07-13 17:42:10 -04:00
if ( ! GRemoteBuildWorkerExecutor . IsSet ( ) )
{
GRemoteBuildWorkerExecutor . Emplace ( ) ;
}
}
void DumpDerivedDataBuildRemoteExecutorStats ( )
{
static bool bHasRun = false ;
if ( GRemoteBuildWorkerExecutor . IsSet ( ) & & ! bHasRun )
{
bHasRun = true ;
GRemoteBuildWorkerExecutor - > DumpStats ( ) ;
}
2021-06-02 00:08:00 -04:00
}
2021-11-18 14:37:34 -05:00
# else
void InitDerivedDataBuildRemoteExecutor ( )
{
}
void DumpDerivedDataBuildRemoteExecutorStats ( )
{
}
# endif // #if UE_WITH_ZEN