2021-07-19 13:09:47 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Async/ParallelFor.h"
# include "DerivedDataBackendInterface.h"
2022-01-10 13:43:40 -05:00
# include "DerivedDataCacheKey.h"
# include "DerivedDataCacheRecord.h"
# include "DerivedDataRequestOwner.h"
# include "DerivedDataValue.h"
# include "DerivedDataValueId.h"
2022-02-23 13:13:43 -05:00
# include "HAL/FileManager.h"
2022-01-10 13:43:40 -05:00
# include "Memory/CompositeBuffer.h"
2021-07-19 13:09:47 -04:00
# include "Misc/AutomationTest.h"
2022-01-10 13:43:40 -05:00
# include "Misc/Paths.h"
2021-07-19 13:09:47 -04:00
# include "Misc/SecureHash.h"
2022-01-10 13:43:40 -05:00
# include "Serialization/CompactBinaryWriter.h"
2022-01-11 11:57:38 -05:00
# include "ZenServerInterface.h"
2021-07-19 13:09:47 -04:00
// Test is targeted at HttpDerivedDataBackend but with some backend test interface it could be generalized
// to function against all backends.
# if WITH_DEV_AUTOMATION_TESTS && WITH_HTTP_DDC_BACKEND
Fix thread starvation for request in http backend by using a FIFO for thread waiting for a connection to be freed
Replace the sleep by a wait on an event triggered by the thread freeing the connection
Improve the test to output stats seen below and use the proper amount of threads on low core systems
Automation RunTests System.DerivedDataCache.HttpDerivedDataBackend.ConcurrentCachedDataProbablyExistsBatch
Before
RPS: 238, AvgLatency: 90.09 ms, MaxLatency: 7.77 s
RPS: 231, AvgLatency: 87.66 ms, MaxLatency: 7.77 s
RPS: 245, AvgLatency: 139.07 ms, MaxLatency: 10.08 s
After
RPS: 634, AvgLatency: 102.97 ms, MaxLatency: 0.26 s
RPS: 653, AvgLatency: 102.51 ms, MaxLatency: 0.26 s
RPS: 630, AvgLatency: 102.29 ms, MaxLatency: 0.26 s
#rnx
#rb Zousar.Shaker, Francis.Hurteau
#preflight 60ffe8317f21c90001f6116a
#ROBOMERGE-SOURCE: CL 16968010 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16968015 by danny couture in ue5-release-engine-test branch]
2021-07-27 09:26:42 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogHttpDerivedDataBackendTests , Log , All ) ;
2021-07-19 13:09:47 -04:00
# define TEST_NAME_ROOT TEXT("System.DerivedDataCache.HttpDerivedDataBackend")
# define IMPLEMENT_HTTPDERIVEDDATA_AUTOMATION_TEST( TClass, PrettyName, TFlags ) \
2022-02-14 14:43:39 -05:00
IMPLEMENT_CUSTOM_COMPLEX_AUTOMATION_TEST ( TClass , FHttpCacheStoreTestBase , TEST_NAME_ROOT PrettyName , TFlags ) \
2021-07-19 13:09:47 -04:00
void TClass : : GetTests ( TArray < FString > & OutBeautifiedNames , TArray < FString > & OutTestCommands ) const \
{ \
if ( CheckPrequisites ( ) ) \
{ \
OutBeautifiedNames . Add ( TEST_NAME_ROOT PrettyName ) ; \
OutTestCommands . Add ( FString ( ) ) ; \
} \
}
2022-02-14 14:43:39 -05:00
namespace UE : : DerivedData
2022-01-11 11:57:38 -05:00
{
2022-02-14 14:43:39 -05:00
FDerivedDataBackendInterface * GetAnyHttpCacheStore (
2022-01-11 11:57:38 -05:00
FString & OutDomain ,
FString & OutOAuthProvider ,
FString & OutOAuthClientId ,
FString & OutOAuthSecret ,
2022-03-23 18:05:53 -04:00
FString & OutOAuthScope ,
2022-01-11 11:57:38 -05:00
FString & OutNamespace ,
FString & OutStructuredNamespace ) ;
2022-02-14 14:43:39 -05:00
ILegacyCacheStore * CreateZenCacheStore ( const TCHAR * NodeName , const TCHAR * ServiceUrl , const TCHAR * Namespace ) ;
2022-01-11 11:57:38 -05:00
2022-02-14 14:43:39 -05:00
class FHttpCacheStoreTestBase : public FAutomationTestBase
2021-07-19 13:09:47 -04:00
{
public :
2022-02-14 14:43:39 -05:00
FHttpCacheStoreTestBase ( const FString & InName , const bool bInComplexTask )
2021-07-19 13:09:47 -04:00
: FAutomationTestBase ( InName , bInComplexTask )
{
}
bool CheckPrequisites ( ) const
{
2022-01-11 11:57:38 -05:00
if ( FDerivedDataBackendInterface * Backend = GetTestBackend ( ) )
2021-07-19 13:09:47 -04:00
{
2022-01-11 11:57:38 -05:00
return true ;
2021-07-19 13:09:47 -04:00
}
return false ;
}
protected :
2022-01-10 13:43:40 -05:00
Fix thread starvation for request in http backend by using a FIFO for thread waiting for a connection to be freed
Replace the sleep by a wait on an event triggered by the thread freeing the connection
Improve the test to output stats seen below and use the proper amount of threads on low core systems
Automation RunTests System.DerivedDataCache.HttpDerivedDataBackend.ConcurrentCachedDataProbablyExistsBatch
Before
RPS: 238, AvgLatency: 90.09 ms, MaxLatency: 7.77 s
RPS: 231, AvgLatency: 87.66 ms, MaxLatency: 7.77 s
RPS: 245, AvgLatency: 139.07 ms, MaxLatency: 10.08 s
After
RPS: 634, AvgLatency: 102.97 ms, MaxLatency: 0.26 s
RPS: 653, AvgLatency: 102.51 ms, MaxLatency: 0.26 s
RPS: 630, AvgLatency: 102.29 ms, MaxLatency: 0.26 s
#rnx
#rb Zousar.Shaker, Francis.Hurteau
#preflight 60ffe8317f21c90001f6116a
#ROBOMERGE-SOURCE: CL 16968010 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16968015 by danny couture in ue5-release-engine-test branch]
2021-07-27 09:26:42 -04:00
void ConcurrentTestWithStats ( TFunctionRef < void ( ) > TestFunction , int32 ThreadCount , double Duration )
{
std : : atomic < uint64 > Requests { 0 } ;
std : : atomic < uint64 > MaxLatency { 0 } ;
std : : atomic < uint64 > TotalMS { 0 } ;
std : : atomic < uint64 > TotalRequests { 0 } ;
FEvent * StartEvent = FPlatformProcess : : GetSynchEventFromPool ( true ) ;
FEvent * LastEvent = FPlatformProcess : : GetSynchEventFromPool ( true ) ;
std : : atomic < double > StopTime { 0.0 } ;
std : : atomic < uint64 > ActiveCount { 0 } ;
for ( int32 ThreadIndex = 0 ; ThreadIndex < ThreadCount ; + + ThreadIndex )
{
ActiveCount + + ;
Async (
ThreadIndex < FTaskGraphInterface : : Get ( ) . GetNumWorkerThreads ( ) ? EAsyncExecution : : TaskGraph : EAsyncExecution : : Thread ,
[ & ] ( )
{
// No false start, wait until everyone is ready before starting the test
StartEvent - > Wait ( ) ;
while ( FPlatformTime : : Seconds ( ) < StopTime . load ( std : : memory_order_relaxed ) )
{
uint64 Before = FPlatformTime : : Cycles64 ( ) ;
TestFunction ( ) ;
uint64 Delta = FPlatformTime : : Cycles64 ( ) - Before ;
Requests + + ;
TotalMS + = FPlatformTime : : ToMilliseconds64 ( Delta ) ;
TotalRequests + + ;
// Compare exchange loop until we either succeed to set the maximum value
// or we bail out because we don't have the maximum value anymore.
while ( true )
{
uint64 Snapshot = MaxLatency . load ( ) ;
if ( Delta > Snapshot )
{
// Only do the exchange if the value has not changed since we confirmed
// we had a bigger one.
if ( MaxLatency . compare_exchange_strong ( Snapshot , Delta ) )
{
// Exchange succeeded
break ;
}
}
else
{
// We don't have the maximum
break ;
}
}
}
if ( - - ActiveCount = = 0 )
{
LastEvent - > Trigger ( ) ;
}
}
) ;
}
StopTime = FPlatformTime : : Seconds ( ) + Duration ;
// GO!
StartEvent - > Trigger ( ) ;
while ( FPlatformTime : : Seconds ( ) < StopTime )
{
FPlatformProcess : : Sleep ( 1.0f ) ;
if ( TotalRequests )
{
UE_LOG ( LogHttpDerivedDataBackendTests , Display , TEXT ( " RPS: %llu, AvgLatency: %.02f ms, MaxLatency: %.02f s " ) , Requests . exchange ( 0 ) , double ( TotalMS ) / TotalRequests , FPlatformTime : : ToSeconds ( MaxLatency ) ) ;
}
else
{
UE_LOG ( LogHttpDerivedDataBackendTests , Display , TEXT ( " RPS: %llu, AvgLatency: N/A, MaxLatency: %.02f s " ) , Requests . exchange ( 0 ) , FPlatformTime : : ToSeconds ( MaxLatency ) ) ;
}
}
LastEvent - > Wait ( ) ;
FPlatformProcess : : ReturnSynchEventToPool ( StartEvent ) ;
FPlatformProcess : : ReturnSynchEventToPool ( LastEvent ) ;
}
2022-02-23 13:13:43 -05:00
static FDerivedDataBackendInterface * GetTestBackend ( )
2021-07-19 13:09:47 -04:00
{
2022-02-14 14:43:39 -05:00
static FDerivedDataBackendInterface * CachedBackend = GetAnyHttpCacheStore (
2022-03-23 18:05:53 -04:00
TestDomain , TestOAuthProvider , TestOAuthClientId , TestOAuthSecret , TestOAuthScope , TestNamespace , TestStructuredNamespace ) ;
2021-07-19 13:09:47 -04:00
return CachedBackend ;
}
2022-02-14 14:43:39 -05:00
bool GetRecords ( TConstArrayView < FCacheRecord > Records , FCacheRecordPolicy Policy , TArray < FCacheRecord > & OutRecords )
2022-01-10 13:43:40 -05:00
{
using namespace UE : : DerivedData ;
2022-02-14 14:43:39 -05:00
ICacheStore * TestBackend = GetTestBackend ( ) ;
2022-01-10 13:43:40 -05:00
TArray < FCacheGetRequest > Requests ;
Requests . Reserve ( Records . Num ( ) ) ;
for ( int32 RecordIndex = 0 ; RecordIndex < Records . Num ( ) ; + + RecordIndex )
{
const FCacheRecord & Record = Records [ RecordIndex ] ;
2022-02-14 14:43:39 -05:00
Requests . Add ( { { TEXT ( " FHttpCacheStoreTestBase " ) } , Record . GetKey ( ) , Policy , static_cast < uint64 > ( RecordIndex ) } ) ;
2022-01-10 13:43:40 -05:00
}
struct FGetOutput
{
FCacheRecord Record ;
EStatus Status = EStatus : : Error ;
} ;
TArray < TOptional < FGetOutput > > GetOutputs ;
GetOutputs . SetNum ( Records . Num ( ) ) ;
FRequestOwner RequestOwner ( EPriority : : Blocking ) ;
2022-01-11 17:09:20 -05:00
TestBackend - > Get ( Requests , RequestOwner , [ & GetOutputs ] ( FCacheGetResponse & & Response )
2022-01-10 13:43:40 -05:00
{
2022-01-11 17:09:20 -05:00
FCacheRecordBuilder RecordBuilder ( Response . Record . GetKey ( ) ) ;
2022-01-10 13:43:40 -05:00
2022-01-11 17:09:20 -05:00
if ( Response . Record . GetMeta ( ) )
2022-01-10 13:43:40 -05:00
{
2022-01-11 17:09:20 -05:00
RecordBuilder . SetMeta ( FCbObject : : Clone ( Response . Record . GetMeta ( ) ) ) ;
2022-01-10 13:43:40 -05:00
}
2022-01-11 17:09:20 -05:00
for ( const FValueWithId & Value : Response . Record . GetValues ( ) )
2022-01-10 13:43:40 -05:00
{
if ( Value )
{
RecordBuilder . AddValue ( Value ) ;
}
}
2022-01-11 17:09:20 -05:00
GetOutputs [ Response . UserData ] . Emplace ( FGetOutput { RecordBuilder . Build ( ) , Response . Status } ) ;
2022-01-10 13:43:40 -05:00
} ) ;
RequestOwner . Wait ( ) ;
for ( int32 RecordIndex = 0 ; RecordIndex < Records . Num ( ) ; + + RecordIndex )
{
FGetOutput & ReceivedOutput = GetOutputs [ RecordIndex ] . GetValue ( ) ;
if ( ReceivedOutput . Status ! = EStatus : : Ok )
{
return false ;
}
OutRecords . Add ( MoveTemp ( ReceivedOutput . Record ) ) ;
}
return true ;
}
2022-01-14 10:53:17 -05:00
2022-02-23 13:13:43 -05:00
bool GetValues ( TConstArrayView < FValue > Values , ECachePolicy Policy , TArray < FValue > & OutValues , const char * BucketName = nullptr , ICacheStore * CacheStore = GetTestBackend ( ) )
2022-02-02 07:35:19 -05:00
{
using namespace UE : : DerivedData ;
2022-02-23 13:13:43 -05:00
ICacheStore * TestBackend = CacheStore ;
2022-02-02 07:35:19 -05:00
FCacheBucket TestCacheBucket ( BucketName ? BucketName : " AutoTestDummy " ) ;
TArray < FCacheGetValueRequest > Requests ;
Requests . Reserve ( Values . Num ( ) ) ;
for ( int32 ValueIndex = 0 ; ValueIndex < Values . Num ( ) ; + + ValueIndex )
{
const FValue & Value = Values [ ValueIndex ] ;
FCacheKey Key ;
Key . Bucket = TestCacheBucket ;
Key . Hash = Value . GetRawHash ( ) ;
2022-02-14 14:43:39 -05:00
Requests . Add ( { { TEXT ( " FHttpCacheStoreTestBase " ) } , Key , Policy , static_cast < uint64 > ( ValueIndex ) } ) ;
2022-02-02 07:35:19 -05:00
}
struct FGetValueOutput
{
FValue Value ;
EStatus Status = EStatus : : Error ;
} ;
TArray < TOptional < FGetValueOutput > > GetValueOutputs ;
GetValueOutputs . SetNum ( Values . Num ( ) ) ;
FRequestOwner RequestOwner ( EPriority : : Blocking ) ;
TestBackend - > GetValue ( Requests , RequestOwner , [ & GetValueOutputs ] ( FCacheGetValueResponse & & Response )
{
GetValueOutputs [ Response . UserData ] . Emplace ( FGetValueOutput { Response . Value , Response . Status } ) ;
} ) ;
RequestOwner . Wait ( ) ;
for ( int32 ValueIndex = 0 ; ValueIndex < Values . Num ( ) ; + + ValueIndex )
{
FGetValueOutput & ReceivedOutput = GetValueOutputs [ ValueIndex ] . GetValue ( ) ;
if ( ReceivedOutput . Status ! = EStatus : : Ok )
{
return false ;
}
OutValues . Add ( MoveTemp ( ReceivedOutput . Value ) ) ;
}
return true ;
}
2022-02-14 14:43:39 -05:00
bool GetRecordChunks ( TConstArrayView < FCacheRecord > Records , FCacheRecordPolicy Policy , uint64 Offset , uint64 Size , TArray < FSharedBuffer > & OutChunks )
2022-01-14 10:53:17 -05:00
{
using namespace UE : : DerivedData ;
2022-02-14 14:43:39 -05:00
ICacheStore * TestBackend = GetTestBackend ( ) ;
2022-01-14 10:53:17 -05:00
2022-01-18 04:47:59 -05:00
TArray < FCacheGetChunkRequest > Requests ;
2022-01-14 10:53:17 -05:00
int32 OverallIndex = 0 ;
for ( int32 RecordIndex = 0 ; RecordIndex < Records . Num ( ) ; + + RecordIndex )
{
const FCacheRecord & Record = Records [ RecordIndex ] ;
TConstArrayView < FValueWithId > Values = Record . GetValues ( ) ;
for ( int32 ValueIndex = 0 ; ValueIndex < Values . Num ( ) ; + + ValueIndex )
{
const FValueWithId & Value = Values [ ValueIndex ] ;
2022-02-14 14:43:39 -05:00
Requests . Add ( { { TEXT ( " FHttpCacheStoreTestBase " ) } , Record . GetKey ( ) , Value . GetId ( ) , Offset , Size , Value . GetRawHash ( ) , Policy . GetValuePolicy ( Value . GetId ( ) ) , static_cast < uint64 > ( OverallIndex ) } ) ;
2022-01-14 10:53:17 -05:00
+ + OverallIndex ;
}
}
struct FGetChunksOutput
{
FSharedBuffer Chunk ;
EStatus Status = EStatus : : Error ;
} ;
TArray < TOptional < FGetChunksOutput > > GetOutputs ;
GetOutputs . SetNum ( Requests . Num ( ) ) ;
FRequestOwner RequestOwner ( EPriority : : Blocking ) ;
2022-01-18 04:47:59 -05:00
TestBackend - > GetChunks ( Requests , RequestOwner , [ & GetOutputs ] ( FCacheGetChunkResponse & & Response )
2022-01-14 10:53:17 -05:00
{
GetOutputs [ Response . UserData ] . Emplace ( FGetChunksOutput { Response . RawData , Response . Status } ) ;
} ) ;
RequestOwner . Wait ( ) ;
for ( int32 RequestIndex = 0 ; RequestIndex < Requests . Num ( ) ; + + RequestIndex )
{
FGetChunksOutput & ReceivedOutput = GetOutputs [ RequestIndex ] . GetValue ( ) ;
if ( ReceivedOutput . Status ! = EStatus : : Ok )
{
return false ;
}
OutChunks . Add ( MoveTemp ( ReceivedOutput . Chunk ) ) ;
}
return true ;
}
2022-01-10 13:43:40 -05:00
2022-02-14 14:43:39 -05:00
void ValidateRecords ( const TCHAR * Name , TConstArrayView < FCacheRecord > RecordsToTest , TConstArrayView < FCacheRecord > ReferenceRecords , FCacheRecordPolicy Policy )
2022-01-10 13:43:40 -05:00
{
using namespace UE : : DerivedData ;
if ( ! TestEqual ( FString : : Printf ( TEXT ( " %s::Record quantity " ) , Name ) , RecordsToTest . Num ( ) , ReferenceRecords . Num ( ) ) )
{
return ;
}
for ( int32 RecordIndex = 0 ; RecordIndex < RecordsToTest . Num ( ) ; + + RecordIndex )
{
const FCacheRecord & ExpectedRecord = ReferenceRecords [ RecordIndex ] ;
const FCacheRecord & RecordToTest = RecordsToTest [ RecordIndex ] ;
if ( EnumHasAnyFlags ( Policy . GetRecordPolicy ( ) , ECachePolicy : : SkipMeta ) )
{
TestTrue ( FString : : Printf ( TEXT ( " %s::Get meta null " ) , Name ) , ! RecordToTest . GetMeta ( ) ) ;
}
else
{
TestTrue ( FString : : Printf ( TEXT ( " %s::Get meta equality " ) , Name ) , ExpectedRecord . GetMeta ( ) . Equals ( RecordToTest . GetMeta ( ) ) ) ;
}
TestEqual ( FString : : Printf ( TEXT ( " %s::Get value quantity " ) , Name ) , ExpectedRecord . GetValues ( ) . Num ( ) , RecordToTest . GetValues ( ) . Num ( ) ) ;
const TConstArrayView < FValueWithId > ExpectedValues = ExpectedRecord . GetValues ( ) ;
const TConstArrayView < FValueWithId > ReceivedValues = RecordToTest . GetValues ( ) ;
for ( int32 ValueIndex = 0 ; ValueIndex < ExpectedValues . Num ( ) ; + + ValueIndex )
{
if ( EnumHasAnyFlags ( Policy . GetRecordPolicy ( ) , ECachePolicy : : SkipData ) )
{
TestTrue ( FString : : Printf ( TEXT ( " %s::Get value[%d] !HasData " ) , Name , ValueIndex ) , ! ReceivedValues [ ValueIndex ] . HasData ( ) ) ;
}
else
{
TestTrue ( FString : : Printf ( TEXT ( " %s::Get value[%d] HasData " ) , Name , ValueIndex ) , ReceivedValues [ ValueIndex ] . HasData ( ) ) ;
TestTrue ( FString : : Printf ( TEXT ( " %s::Get value[%d] equality " ) , Name , ValueIndex ) , ExpectedValues [ ValueIndex ] = = ReceivedValues [ ValueIndex ] ) ;
TestTrue ( FString : : Printf ( TEXT ( " %s::Get value[%d] data equality " ) , Name , ValueIndex ) , FIoHash : : HashBuffer ( ReceivedValues [ ValueIndex ] . GetData ( ) . GetCompressed ( ) ) = = FIoHash : : HashBuffer ( ExpectedValues [ ValueIndex ] . GetData ( ) . GetCompressed ( ) ) ) ;
}
}
}
}
2022-02-14 14:43:39 -05:00
void ValidateValues ( const TCHAR * Name , TConstArrayView < FValue > ValuesToTest , TConstArrayView < FValue > ReferenceValues , ECachePolicy Policy )
2022-02-02 07:35:19 -05:00
{
using namespace UE : : DerivedData ;
if ( ! TestEqual ( FString : : Printf ( TEXT ( " %s::Value quantity " ) , Name ) , ValuesToTest . Num ( ) , ReferenceValues . Num ( ) ) )
{
return ;
}
for ( int32 ValueIndex = 0 ; ValueIndex < ValuesToTest . Num ( ) ; + + ValueIndex )
{
const FValue & ExpectedValue = ReferenceValues [ ValueIndex ] ;
const FValue & ValueToTest = ValuesToTest [ ValueIndex ] ;
if ( EnumHasAnyFlags ( Policy , ECachePolicy : : SkipData ) )
{
TestTrue ( FString : : Printf ( TEXT ( " %s::Get value[%d] !HasData " ) , Name , ValueIndex ) , ! ValueToTest . HasData ( ) ) ;
}
else
{
TestTrue ( FString : : Printf ( TEXT ( " %s::Get value[%d] HasData " ) , Name , ValueIndex ) , ValueToTest . HasData ( ) ) ;
TestTrue ( FString : : Printf ( TEXT ( " %s::Get value[%d] equality " ) , Name , ValueIndex ) , ExpectedValue = = ValueToTest ) ;
TestTrue ( FString : : Printf ( TEXT ( " %s::Get value[%d] data equality " ) , Name , ValueIndex ) , FIoHash : : HashBuffer ( ValueToTest . GetData ( ) . GetCompressed ( ) ) = = FIoHash : : HashBuffer ( ExpectedValue . GetData ( ) . GetCompressed ( ) ) ) ;
}
}
}
2022-02-14 14:43:39 -05:00
void ValidateRecordChunks ( const TCHAR * Name , TConstArrayView < FSharedBuffer > RecordChunksToTest , TConstArrayView < FCacheRecord > ReferenceRecords , FCacheRecordPolicy Policy , uint64 Offset , uint64 Size )
2022-01-14 10:53:17 -05:00
{
using namespace UE : : DerivedData ;
int32 TotalChunks = 0 ;
for ( int32 RecordIndex = 0 ; RecordIndex < ReferenceRecords . Num ( ) ; + + RecordIndex )
{
const FCacheRecord & Record = ReferenceRecords [ RecordIndex ] ;
TConstArrayView < FValueWithId > Values = Record . GetValues ( ) ;
for ( int32 ValueIndex = 0 ; ValueIndex < Values . Num ( ) ; + + ValueIndex )
{
+ + TotalChunks ;
}
}
if ( ! TestEqual ( FString : : Printf ( TEXT ( " %s::Chunk quantity " ) , Name ) , RecordChunksToTest . Num ( ) , TotalChunks ) )
{
return ;
}
int32 ChunkIndex = 0 ;
for ( int32 RecordIndex = 0 ; RecordIndex < ReferenceRecords . Num ( ) ; + + RecordIndex )
{
const FCacheRecord & ExpectedRecord = ReferenceRecords [ RecordIndex ] ;
const TConstArrayView < FValueWithId > ExpectedValues = ExpectedRecord . GetValues ( ) ;
for ( int32 ValueIndex = 0 ; ValueIndex < ExpectedValues . Num ( ) ; + + ValueIndex )
{
const FSharedBuffer & ChunkToTest = RecordChunksToTest [ ChunkIndex ] ;
if ( EnumHasAnyFlags ( Policy . GetRecordPolicy ( ) , ECachePolicy : : SkipData ) )
{
TestTrue ( FString : : Printf ( TEXT ( " %s::Get chunk[%d] IsNull " ) , Name , ChunkIndex ) , ChunkToTest . IsNull ( ) ) ;
}
else
{
FSharedBuffer ReferenceBuffer = ExpectedValues [ ValueIndex ] . GetData ( ) . Decompress ( ) ;
FMemoryView ReferenceView = ReferenceBuffer . GetView ( ) . Mid ( Offset , Size ) ;
TestTrue ( FString : : Printf ( TEXT ( " %s::Get chunk[%d] data equality " ) , Name , ChunkIndex ) , ReferenceView . EqualBytes ( ChunkToTest . GetView ( ) ) ) ;
}
+ + ChunkIndex ;
}
}
}
2022-02-14 14:43:39 -05:00
TArray < FCacheRecord > GetAndValidateRecords ( const TCHAR * Name , TConstArrayView < FCacheRecord > Records , FCacheRecordPolicy Policy )
2022-01-10 13:43:40 -05:00
{
using namespace UE : : DerivedData ;
TArray < FCacheRecord > ReceivedRecords ;
bool bGetSuccessful = GetRecords ( Records , Policy , ReceivedRecords ) ;
TestTrue ( FString : : Printf ( TEXT ( " %s::Get status " ) , Name ) , bGetSuccessful ) ;
if ( ! bGetSuccessful )
{
return TArray < FCacheRecord > ( ) ;
}
ValidateRecords ( Name , ReceivedRecords , Records , Policy ) ;
return ReceivedRecords ;
}
2022-02-23 13:13:43 -05:00
TArray < FValue > GetAndValidateValues ( const TCHAR * Name , TConstArrayView < FValue > Values , ECachePolicy Policy , ICacheStore * CacheStore = GetTestBackend ( ) )
2022-02-02 07:35:19 -05:00
{
using namespace UE : : DerivedData ;
TArray < FValue > ReceivedValues ;
2022-02-23 13:13:43 -05:00
bool bGetSuccessful = GetValues ( Values , Policy , ReceivedValues , nullptr , CacheStore ) ;
2022-02-02 07:35:19 -05:00
TestTrue ( FString : : Printf ( TEXT ( " %s::Get status " ) , Name ) , bGetSuccessful ) ;
if ( ! bGetSuccessful )
{
return TArray < FValue > ( ) ;
}
ValidateValues ( Name , ReceivedValues , Values , Policy ) ;
return ReceivedValues ;
}
2022-02-14 14:43:39 -05:00
TArray < FSharedBuffer > GetAndValidateRecordChunks ( const TCHAR * Name , TConstArrayView < FCacheRecord > Records , FCacheRecordPolicy Policy , uint64 Offset , uint64 Size )
2022-01-14 10:53:17 -05:00
{
using namespace UE : : DerivedData ;
TArray < FSharedBuffer > ReceivedChunks ;
bool bGetSuccessful = GetRecordChunks ( Records , Policy , Offset , Size , ReceivedChunks ) ;
TestTrue ( FString : : Printf ( TEXT ( " %s::GetChunks status " ) , Name ) , bGetSuccessful ) ;
if ( ! bGetSuccessful )
{
return TArray < FSharedBuffer > ( ) ;
}
ValidateRecordChunks ( Name , ReceivedChunks , Records , Policy , Offset , Size ) ;
return ReceivedChunks ;
}
2022-02-14 14:43:39 -05:00
TArray < FCacheRecord > GetAndValidateRecordsAndChunks ( const TCHAR * Name , TConstArrayView < FCacheRecord > Records , FCacheRecordPolicy Policy )
2022-01-14 10:53:17 -05:00
{
GetAndValidateRecordChunks ( Name , Records , Policy , 5 , 5 ) ;
return GetAndValidateRecords ( Name , Records , Policy ) ;
}
2022-01-11 11:57:38 -05:00
protected :
static inline FString TestDomain ;
static inline FString TestOAuthProvider ;
static inline FString TestOAuthClientId ;
static inline FString TestOAuthSecret ;
2022-03-23 18:05:53 -04:00
static inline FString TestOAuthScope ;
2022-01-11 11:57:38 -05:00
static inline FString TestNamespace ;
static inline FString TestStructuredNamespace ;
2021-07-19 13:09:47 -04:00
} ;
2021-07-27 15:25:39 -04:00
// Helper function to create a number of dummy cache keys for testing
2022-01-11 11:57:38 -05:00
TArray < FString > CreateTestCacheKeys ( FDerivedDataBackendInterface * InTestBackend , uint32 InNumKeys )
2021-07-19 13:09:47 -04:00
{
TArray < FString > Keys ;
TArray < uint8 > KeyContents ;
KeyContents . Add ( 42 ) ;
FSHA1 HashState ;
HashState . Update ( KeyContents . GetData ( ) , KeyContents . Num ( ) ) ;
HashState . Final ( ) ;
uint8 Hash [ FSHA1 : : DigestSize ] ;
HashState . GetHash ( Hash ) ;
const FString HashString = BytesToHex ( Hash , FSHA1 : : DigestSize ) ;
2021-07-27 15:25:39 -04:00
for ( uint32 KeyIndex = 0 ; KeyIndex < InNumKeys ; + + KeyIndex )
2021-07-19 13:09:47 -04:00
{
FString NewKey = FString : : Printf ( TEXT ( " __AutoTest_Dummy_%u__%s " ) , KeyIndex , * HashString ) ;
Keys . Add ( NewKey ) ;
2021-07-27 15:25:39 -04:00
InTestBackend - > PutCachedData ( * NewKey , KeyContents , false ) ;
2021-07-19 13:09:47 -04:00
}
2021-07-27 15:25:39 -04:00
return Keys ;
}
2022-02-14 14:43:39 -05:00
TArray < FCacheRecord > CreateTestCacheRecords ( ICacheStore * InTestBackend , uint32 InNumKeys , uint32 InNumValues , FCbObject MetaContents = FCbObject ( ) , const char * BucketName = nullptr )
2022-01-10 13:43:40 -05:00
{
using namespace UE : : DerivedData ;
FCacheBucket TestCacheBucket ( BucketName ? BucketName : " AutoTestDummy " ) ;
TArray < FCacheRecord > CacheRecords ;
TArray < FCachePutRequest > PutRequests ;
PutRequests . Reserve ( InNumKeys ) ;
for ( uint32 KeyIndex = 0 ; KeyIndex < InNumKeys ; + + KeyIndex )
{
FIoHashBuilder HashBuilder ;
TArray < FSharedBuffer > Values ;
for ( uint32 ValueIndex = 0 ; ValueIndex < InNumValues ; + + ValueIndex )
{
TArray < uint8 > ValueContents ;
2022-01-14 10:53:17 -05:00
// Add N zeroed bytes where N corresponds to the value index times 10.
const int32 NumBytes = ( ValueIndex + 1 ) * 10 ;
ValueContents . AddUninitialized ( NumBytes ) ;
for ( int32 ContentIndex = 0 ; ContentIndex < NumBytes ; + + ContentIndex )
2022-01-10 13:43:40 -05:00
{
2022-01-14 10:53:17 -05:00
ValueContents [ ContentIndex ] = ( uint8 ) ( KeyIndex + ContentIndex ) ;
2022-01-10 13:43:40 -05:00
}
Values . Emplace ( MakeSharedBufferFromArray ( MoveTemp ( ValueContents ) ) ) ;
HashBuilder . Update ( Values . Last ( ) . GetView ( ) ) ;
}
FCacheKey Key ;
Key . Bucket = TestCacheBucket ;
Key . Hash = HashBuilder . Finalize ( ) ;
FCacheRecordBuilder RecordBuilder ( Key ) ;
for ( const FSharedBuffer & ValueBuffer : Values )
{
FIoHash ValueHash ( FIoHash : : HashBuffer ( ValueBuffer ) ) ;
RecordBuilder . AddValue ( FValueId : : FromHash ( ValueHash ) , ValueBuffer ) ;
}
if ( MetaContents )
{
RecordBuilder . SetMeta ( MoveTemp ( MetaContents ) ) ;
}
PutRequests . Add ( { { TEXT ( " AutoTest " ) } , RecordBuilder . Build ( ) , ECachePolicy : : Default , KeyIndex } ) ;
}
FRequestOwner Owner ( EPriority : : Blocking ) ;
2022-01-11 17:09:20 -05:00
InTestBackend - > Put ( PutRequests , Owner , [ & CacheRecords , & PutRequests ] ( FCachePutResponse & & Response )
2022-01-10 13:43:40 -05:00
{
2022-01-11 17:09:20 -05:00
check ( Response . Status = = EStatus : : Ok ) ;
CacheRecords . Add ( PutRequests [ Response . UserData ] . Record ) ;
2022-01-10 13:43:40 -05:00
} ) ;
Owner . Wait ( ) ;
return CacheRecords ;
}
2022-02-14 14:43:39 -05:00
TArray < FValue > CreateTestCacheValues ( ICacheStore * InTestBackend , uint32 InNumValues , const char * BucketName = nullptr )
2022-02-02 07:35:19 -05:00
{
using namespace UE : : DerivedData ;
FCacheBucket TestCacheBucket ( BucketName ? BucketName : " AutoTestDummy " ) ;
TArray < FCachePutValueRequest > PutValueRequests ;
PutValueRequests . Reserve ( InNumValues ) ;
TArray < FSharedBuffer > ValueBuffers ;
for ( uint32 ValueIndex = 0 ; ValueIndex < InNumValues ; + + ValueIndex )
{
TArray < uint8 > ValueContents ;
// Add N zeroed bytes where N corresponds to the value index times 10.
const int32 NumBytes = ( ValueIndex + 1 ) * 10 ;
ValueContents . AddUninitialized ( NumBytes ) ;
for ( int32 ContentIndex = 0 ; ContentIndex < NumBytes ; + + ContentIndex )
{
2022-02-15 12:34:29 -05:00
ValueContents [ ContentIndex ] = ( uint8 ) ( ValueIndex + ContentIndex + 52 ) ; // offset of 52 to keep the contents distinct from record test data
2022-02-02 07:35:19 -05:00
}
ValueBuffers . Emplace ( MakeSharedBufferFromArray ( MoveTemp ( ValueContents ) ) ) ;
}
uint64 KeyIndex = 0 ;
for ( const FSharedBuffer & ValueBuffer : ValueBuffers )
{
FIoHash ValueHash ( FIoHash : : HashBuffer ( ValueBuffer ) ) ;
FCacheKey Key ;
Key . Bucket = TestCacheBucket ;
Key . Hash = ValueHash ;
PutValueRequests . Add ( { { TEXT ( " AutoTest " ) } , Key , FValue : : Compress ( ValueBuffer ) , ECachePolicy : : Default , KeyIndex + + } ) ;
}
TArray < FValue > Values ;
FRequestOwner Owner ( EPriority : : Blocking ) ;
InTestBackend - > PutValue ( PutValueRequests , Owner , [ & Values , & PutValueRequests ] ( FCachePutValueResponse & & Response )
{
check ( Response . Status = = EStatus : : Ok ) ;
Values . Add ( PutValueRequests [ Response . UserData ] . Value ) ;
} ) ;
Owner . Wait ( ) ;
return Values ;
}
2021-07-27 15:25:39 -04:00
IMPLEMENT_HTTPDERIVEDDATA_AUTOMATION_TEST ( FConcurrentCachedDataProbablyExistsBatch , TEXT ( " .FConcurrentCachedDataProbablyExistsBatch " ) , EAutomationTestFlags : : EditorContext | EAutomationTestFlags : : ProductFilter )
bool FConcurrentCachedDataProbablyExistsBatch : : RunTest ( const FString & Parameters )
{
2022-01-11 11:57:38 -05:00
FDerivedDataBackendInterface * TestBackend = GetTestBackend ( ) ;
2021-07-27 15:25:39 -04:00
const int32 ThreadCount = 64 ;
const double Duration = 10 ;
const uint32 KeysInBatch = 4 ;
TArray < FString > Keys = CreateTestCacheKeys ( TestBackend , KeysInBatch ) ;
2021-07-19 13:09:47 -04:00
std : : atomic < uint32 > MismatchedResults = 0 ;
Fix thread starvation for request in http backend by using a FIFO for thread waiting for a connection to be freed
Replace the sleep by a wait on an event triggered by the thread freeing the connection
Improve the test to output stats seen below and use the proper amount of threads on low core systems
Automation RunTests System.DerivedDataCache.HttpDerivedDataBackend.ConcurrentCachedDataProbablyExistsBatch
Before
RPS: 238, AvgLatency: 90.09 ms, MaxLatency: 7.77 s
RPS: 231, AvgLatency: 87.66 ms, MaxLatency: 7.77 s
RPS: 245, AvgLatency: 139.07 ms, MaxLatency: 10.08 s
After
RPS: 634, AvgLatency: 102.97 ms, MaxLatency: 0.26 s
RPS: 653, AvgLatency: 102.51 ms, MaxLatency: 0.26 s
RPS: 630, AvgLatency: 102.29 ms, MaxLatency: 0.26 s
#rnx
#rb Zousar.Shaker, Francis.Hurteau
#preflight 60ffe8317f21c90001f6116a
#ROBOMERGE-SOURCE: CL 16968010 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16968015 by danny couture in ue5-release-engine-test branch]
2021-07-27 09:26:42 -04:00
ConcurrentTestWithStats (
[ & ] ( )
2021-07-19 13:09:47 -04:00
{
Fix thread starvation for request in http backend by using a FIFO for thread waiting for a connection to be freed
Replace the sleep by a wait on an event triggered by the thread freeing the connection
Improve the test to output stats seen below and use the proper amount of threads on low core systems
Automation RunTests System.DerivedDataCache.HttpDerivedDataBackend.ConcurrentCachedDataProbablyExistsBatch
Before
RPS: 238, AvgLatency: 90.09 ms, MaxLatency: 7.77 s
RPS: 231, AvgLatency: 87.66 ms, MaxLatency: 7.77 s
RPS: 245, AvgLatency: 139.07 ms, MaxLatency: 10.08 s
After
RPS: 634, AvgLatency: 102.97 ms, MaxLatency: 0.26 s
RPS: 653, AvgLatency: 102.51 ms, MaxLatency: 0.26 s
RPS: 630, AvgLatency: 102.29 ms, MaxLatency: 0.26 s
#rnx
#rb Zousar.Shaker, Francis.Hurteau
#preflight 60ffe8317f21c90001f6116a
#ROBOMERGE-SOURCE: CL 16968010 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16968015 by danny couture in ue5-release-engine-test branch]
2021-07-27 09:26:42 -04:00
TConstArrayView < FString > BatchView = MakeArrayView ( Keys . GetData ( ) , KeysInBatch ) ;
TBitArray < > Result = TestBackend - > CachedDataProbablyExistsBatch ( BatchView ) ;
if ( Result . CountSetBits ( ) ! = BatchView . Num ( ) )
2021-07-19 13:09:47 -04:00
{
Fix thread starvation for request in http backend by using a FIFO for thread waiting for a connection to be freed
Replace the sleep by a wait on an event triggered by the thread freeing the connection
Improve the test to output stats seen below and use the proper amount of threads on low core systems
Automation RunTests System.DerivedDataCache.HttpDerivedDataBackend.ConcurrentCachedDataProbablyExistsBatch
Before
RPS: 238, AvgLatency: 90.09 ms, MaxLatency: 7.77 s
RPS: 231, AvgLatency: 87.66 ms, MaxLatency: 7.77 s
RPS: 245, AvgLatency: 139.07 ms, MaxLatency: 10.08 s
After
RPS: 634, AvgLatency: 102.97 ms, MaxLatency: 0.26 s
RPS: 653, AvgLatency: 102.51 ms, MaxLatency: 0.26 s
RPS: 630, AvgLatency: 102.29 ms, MaxLatency: 0.26 s
#rnx
#rb Zousar.Shaker, Francis.Hurteau
#preflight 60ffe8317f21c90001f6116a
#ROBOMERGE-SOURCE: CL 16968010 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16968015 by danny couture in ue5-release-engine-test branch]
2021-07-27 09:26:42 -04:00
MismatchedResults . fetch_add ( BatchView . Num ( ) - Result . CountSetBits ( ) , std : : memory_order_relaxed ) ;
2021-07-19 13:09:47 -04:00
}
Fix thread starvation for request in http backend by using a FIFO for thread waiting for a connection to be freed
Replace the sleep by a wait on an event triggered by the thread freeing the connection
Improve the test to output stats seen below and use the proper amount of threads on low core systems
Automation RunTests System.DerivedDataCache.HttpDerivedDataBackend.ConcurrentCachedDataProbablyExistsBatch
Before
RPS: 238, AvgLatency: 90.09 ms, MaxLatency: 7.77 s
RPS: 231, AvgLatency: 87.66 ms, MaxLatency: 7.77 s
RPS: 245, AvgLatency: 139.07 ms, MaxLatency: 10.08 s
After
RPS: 634, AvgLatency: 102.97 ms, MaxLatency: 0.26 s
RPS: 653, AvgLatency: 102.51 ms, MaxLatency: 0.26 s
RPS: 630, AvgLatency: 102.29 ms, MaxLatency: 0.26 s
#rnx
#rb Zousar.Shaker, Francis.Hurteau
#preflight 60ffe8317f21c90001f6116a
#ROBOMERGE-SOURCE: CL 16968010 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16968015 by danny couture in ue5-release-engine-test branch]
2021-07-27 09:26:42 -04:00
} ,
ThreadCount ,
Duration
2021-07-19 13:09:47 -04:00
) ;
Fix thread starvation for request in http backend by using a FIFO for thread waiting for a connection to be freed
Replace the sleep by a wait on an event triggered by the thread freeing the connection
Improve the test to output stats seen below and use the proper amount of threads on low core systems
Automation RunTests System.DerivedDataCache.HttpDerivedDataBackend.ConcurrentCachedDataProbablyExistsBatch
Before
RPS: 238, AvgLatency: 90.09 ms, MaxLatency: 7.77 s
RPS: 231, AvgLatency: 87.66 ms, MaxLatency: 7.77 s
RPS: 245, AvgLatency: 139.07 ms, MaxLatency: 10.08 s
After
RPS: 634, AvgLatency: 102.97 ms, MaxLatency: 0.26 s
RPS: 653, AvgLatency: 102.51 ms, MaxLatency: 0.26 s
RPS: 630, AvgLatency: 102.29 ms, MaxLatency: 0.26 s
#rnx
#rb Zousar.Shaker, Francis.Hurteau
#preflight 60ffe8317f21c90001f6116a
#ROBOMERGE-SOURCE: CL 16968010 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16968015 by danny couture in ue5-release-engine-test branch]
2021-07-27 09:26:42 -04:00
2021-07-19 13:09:47 -04:00
TestEqual ( TEXT ( " Concurrent calls to CachedDataProbablyExistsBatch for a batch of keys that were put are not reliably found " ) , MismatchedResults , 0 ) ;
return true ;
}
2021-07-27 15:25:39 -04:00
// This test validate that batch requests wont mismatch head and get request for the same keys in the same batch
IMPLEMENT_HTTPDERIVEDDATA_AUTOMATION_TEST ( FConcurrentExistsAndGetForSameKeyBatch , TEXT ( " .FConcurrentExistsAndGetForSameKeyBatch " ) , EAutomationTestFlags : : EditorContext | EAutomationTestFlags : : ProductFilter )
bool FConcurrentExistsAndGetForSameKeyBatch : : RunTest ( const FString & Parameters )
{
2022-01-11 11:57:38 -05:00
FDerivedDataBackendInterface * TestBackend = GetTestBackend ( ) ;
2021-07-27 15:25:39 -04:00
const int32 ParallelTasks = 32 ;
const uint32 Iterations = 20 ;
const uint32 KeysInBatch = 4 ;
TArray < FString > Keys = CreateTestCacheKeys ( TestBackend , KeysInBatch ) ;
// Add some non valid keys by just using guids
for ( int32 Index = 0 ; Index < KeysInBatch ; + + Index )
{
Keys . Add ( FGuid : : NewGuid ( ) . ToString ( ) ) ;
}
ParallelFor ( ParallelTasks ,
[ & ] ( int32 TaskIndex )
{
for ( uint32 Iteration = 0 ; Iteration < Iterations ; + + Iteration )
{
for ( int32 KeyIndex = 0 ; KeyIndex < Keys . Num ( ) ; + + KeyIndex )
{
if ( ( Iteration % 2 ) ^ ( KeyIndex % 2 ) )
{
TestBackend - > CachedDataProbablyExists ( * Keys [ KeyIndex ] ) ;
}
else
{
TArray < uint8 > OutData ;
TestBackend - > GetCachedData ( * Keys [ KeyIndex ] , OutData ) ;
}
}
}
}
) ;
return true ;
}
2022-01-10 13:43:40 -05:00
// Tests basic functionality for structured cache operations
IMPLEMENT_HTTPDERIVEDDATA_AUTOMATION_TEST ( CacheStore , TEXT ( " .CacheStore " ) , EAutomationTestFlags : : EditorContext | EAutomationTestFlags : : ProductFilter )
bool CacheStore : : RunTest ( const FString & Parameters )
{
using namespace UE : : DerivedData ;
2022-01-11 11:57:38 -05:00
FDerivedDataBackendInterface * TestBackend = GetTestBackend ( ) ;
2022-01-10 13:43:40 -05:00
2022-01-11 11:57:38 -05:00
# if UE_WITH_ZEN
2022-01-10 13:43:40 -05:00
using namespace UE : : Zen ;
2022-02-15 12:34:29 -05:00
FServiceSettings ZenUpstreamTestServiceSettings ;
FServiceAutoLaunchSettings & ZenUpstreamTestAutoLaunchSettings = ZenUpstreamTestServiceSettings . SettingsVariant . Get < FServiceAutoLaunchSettings > ( ) ;
ZenUpstreamTestAutoLaunchSettings . DataPath = FPaths : : ConvertRelativePathToFull ( FPaths : : Combine ( FPaths : : EngineSavedDir ( ) , " ZenUpstreamUnitTest " ) ) ;
ZenUpstreamTestAutoLaunchSettings . ExtraArgs = FString : : Printf ( TEXT ( " --http asio --upstream-jupiter-url \" %s \" --upstream-jupiter-oauth-url \" %s \" --upstream-jupiter-oauth-clientid \" %s \" --upstream-jupiter-oauth-clientsecret \" %s \" --upstream-jupiter-namespace-ddc \" %s \" --upstream-jupiter-namespace \" %s \" " ) ,
2022-01-11 11:57:38 -05:00
* TestDomain ,
* TestOAuthProvider ,
* TestOAuthClientId ,
* TestOAuthSecret ,
* TestNamespace ,
* TestStructuredNamespace
2022-01-10 13:43:40 -05:00
) ;
2022-02-15 12:34:29 -05:00
ZenUpstreamTestAutoLaunchSettings . DesiredPort = 23337 ; // Avoid the normal default port
ZenUpstreamTestAutoLaunchSettings . bShowConsole = true ;
ZenUpstreamTestAutoLaunchSettings . bLimitProcessLifetime = true ;
FScopeZenService ScopeZenUpstreamService ( MoveTemp ( ZenUpstreamTestServiceSettings ) ) ;
2022-02-23 13:13:43 -05:00
IFileManager : : Get ( ) . DeleteDirectory ( * FPaths : : Combine ( FPaths : : EngineSavedDir ( ) , " ZenUpstreamSiblingUnitTest " ) , false , true ) ;
FServiceSettings ZenUpstreamSiblingTestServiceSettings ;
FServiceAutoLaunchSettings & ZenUpstreamSiblingTestAutoLaunchSettings = ZenUpstreamSiblingTestServiceSettings . SettingsVariant . Get < FServiceAutoLaunchSettings > ( ) ;
ZenUpstreamSiblingTestAutoLaunchSettings . DataPath = FPaths : : ConvertRelativePathToFull ( FPaths : : Combine ( FPaths : : EngineSavedDir ( ) , " ZenUpstreamSiblingUnitTest " ) ) ;
ZenUpstreamSiblingTestAutoLaunchSettings . ExtraArgs = FString : : Printf ( TEXT ( " --http asio --upstream-jupiter-url \" %s \" --upstream-jupiter-oauth-url \" %s \" --upstream-jupiter-oauth-clientid \" %s \" --upstream-jupiter-oauth-clientsecret \" %s \" --upstream-jupiter-namespace-ddc \" %s \" --upstream-jupiter-namespace \" %s \" " ) ,
* TestDomain ,
* TestOAuthProvider ,
* TestOAuthClientId ,
* TestOAuthSecret ,
* TestNamespace ,
* TestStructuredNamespace
) ;
ZenUpstreamSiblingTestAutoLaunchSettings . DesiredPort = 23338 ; // Avoid the normal default port
ZenUpstreamSiblingTestAutoLaunchSettings . bShowConsole = true ;
ZenUpstreamSiblingTestAutoLaunchSettings . bLimitProcessLifetime = true ;
FScopeZenService ScopeZenUpstreamSiblingService ( MoveTemp ( ZenUpstreamSiblingTestServiceSettings ) ) ;
2022-02-15 12:34:29 -05:00
FServiceSettings ZenTestServiceSettings ;
FServiceAutoLaunchSettings & ZenTestAutoLaunchSettings = ZenTestServiceSettings . SettingsVariant . Get < FServiceAutoLaunchSettings > ( ) ;
ZenTestAutoLaunchSettings . DataPath = FPaths : : ConvertRelativePathToFull ( FPaths : : Combine ( FPaths : : EngineSavedDir ( ) , " ZenUnitTest " ) ) ;
ZenTestAutoLaunchSettings . ExtraArgs = FString : : Printf ( TEXT ( " --http asio --upstream-zen-url \" http://localhost:%d \" " ) ,
ScopeZenUpstreamService . GetInstance ( ) . GetPort ( )
) ;
2022-01-10 13:43:40 -05:00
ZenTestAutoLaunchSettings . DesiredPort = 13337 ; // Avoid the normal default port
ZenTestAutoLaunchSettings . bShowConsole = true ;
ZenTestAutoLaunchSettings . bLimitProcessLifetime = true ;
2022-02-23 13:13:43 -05:00
IFileManager : : Get ( ) . DeleteDirectory ( * FPaths : : Combine ( FPaths : : EngineSavedDir ( ) , " ZenUnitTestSibling " ) , false , true ) ;
FServiceSettings ZenTestServiceSiblingSettings ;
FServiceAutoLaunchSettings & ZenTestSiblingAutoLaunchSettings = ZenTestServiceSiblingSettings . SettingsVariant . Get < FServiceAutoLaunchSettings > ( ) ;
ZenTestSiblingAutoLaunchSettings . DataPath = FPaths : : ConvertRelativePathToFull ( FPaths : : Combine ( FPaths : : EngineSavedDir ( ) , " ZenUnitTestSibling " ) ) ;
ZenTestSiblingAutoLaunchSettings . ExtraArgs = FString : : Printf ( TEXT ( " --http asio --upstream-zen-url \" http://localhost:%d \" " ) ,
ScopeZenUpstreamSiblingService . GetInstance ( ) . GetPort ( )
) ;
ZenTestSiblingAutoLaunchSettings . DesiredPort = 13338 ; // Avoid the normal default port
ZenTestSiblingAutoLaunchSettings . bShowConsole = true ;
ZenTestSiblingAutoLaunchSettings . bLimitProcessLifetime = true ;
FScopeZenService ScopeZenSiblingService ( MoveTemp ( ZenTestServiceSiblingSettings ) ) ;
TUniquePtr < ILegacyCacheStore > ZenIntermediarySiblingBackend ( CreateZenCacheStore ( TEXT ( " TestSibling " ) , ScopeZenSiblingService . GetInstance ( ) . GetURL ( ) , * TestNamespace ) ) ;
2022-01-10 13:43:40 -05:00
FScopeZenService ScopeZenService ( MoveTemp ( ZenTestServiceSettings ) ) ;
2022-02-14 14:43:39 -05:00
TUniquePtr < ILegacyCacheStore > ZenIntermediaryBackend ( CreateZenCacheStore ( TEXT ( " Test " ) , ScopeZenService . GetInstance ( ) . GetURL ( ) , * TestNamespace ) ) ;
auto WaitForZenPushToUpstream = [ ] ( ILegacyCacheStore * ZenBackend , TConstArrayView < FCacheRecord > Records )
2022-01-10 13:43:40 -05:00
{
// TODO: Expecting a legitimate means to wait for zen to finish pushing records to its upstream in the future
FPlatformProcess : : Sleep ( 1.0f ) ;
} ;
2022-02-15 12:34:29 -05:00
auto WaitForZenPushValuesToUpstream = [ ] ( ILegacyCacheStore * ZenBackend , TConstArrayView < FValue > Values )
{
// TODO: Expecting a legitimate means to wait for zen to finish pushing records to its upstream in the future
FPlatformProcess : : Sleep ( 1.0f ) ;
} ;
2022-01-11 11:57:38 -05:00
# endif // UE_WITH_ZEN
2022-01-10 13:43:40 -05:00
const uint32 RecordsInBatch = 3 ;
2022-02-02 07:35:19 -05:00
const uint32 ValuesInBatch = RecordsInBatch ;
2022-01-10 13:43:40 -05:00
{
TArray < FCacheRecord > PutRecords = CreateTestCacheRecords ( TestBackend , RecordsInBatch , 1 ) ;
2022-01-14 10:53:17 -05:00
TArray < FCacheRecord > RecievedRecords = GetAndValidateRecordsAndChunks ( TEXT ( " SimpleValue " ) , PutRecords , ECachePolicy : : Default ) ;
TArray < FCacheRecord > RecievedRecordsSkipMeta = GetAndValidateRecordsAndChunks ( TEXT ( " SimpleValueSkipMeta " ) , PutRecords , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) ;
TArray < FCacheRecord > RecievedRecordsSkipData = GetAndValidateRecordsAndChunks ( TEXT ( " SimpleValueSkipData " ) , PutRecords , ECachePolicy : : Default | ECachePolicy : : SkipData ) ;
2022-01-10 13:43:40 -05:00
2022-01-11 11:57:38 -05:00
# if UE_WITH_ZEN
if ( ZenIntermediaryBackend )
{
TArray < FCacheRecord > PutRecordsZen = CreateTestCacheRecords ( ZenIntermediaryBackend . Get ( ) , RecordsInBatch , 1 , FCbObject ( ) , " AutoTestDummyZen " ) ;
WaitForZenPushToUpstream ( ZenIntermediaryBackend . Get ( ) , PutRecordsZen ) ;
ValidateRecords ( TEXT ( " SimpleValueZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " SimpleValueZen " ) , PutRecordsZen , ECachePolicy : : Default ) , RecievedRecords , ECachePolicy : : Default ) ;
ValidateRecords ( TEXT ( " SimpleValueSkipMetaZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " SimpleValueSkipMetaZen " ) , PutRecordsZen , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) , RecievedRecordsSkipMeta , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) ;
ValidateRecords ( TEXT ( " SimpleValueSkipDataZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " SimpleValueSkipDataZen " ) , PutRecordsZen , ECachePolicy : : Default | ECachePolicy : : SkipData ) , RecievedRecordsSkipData , ECachePolicy : : Default | ECachePolicy : : SkipData ) ;
}
# endif // UE_WITH_ZEN
2022-01-10 13:43:40 -05:00
}
{
TCbWriter < 64 > MetaWriter ;
MetaWriter . BeginObject ( ) ;
2022-04-25 11:31:36 -04:00
MetaWriter . AddInteger ( ANSITEXTVIEW ( " MetaKey " ) , 42 ) ;
2022-01-10 13:43:40 -05:00
MetaWriter . EndObject ( ) ;
FCbObject MetaObject = MetaWriter . Save ( ) . AsObject ( ) ;
TArray < FCacheRecord > PutRecords = CreateTestCacheRecords ( TestBackend , RecordsInBatch , 1 , MetaObject ) ;
2022-01-14 10:53:17 -05:00
TArray < FCacheRecord > RecievedRecords = GetAndValidateRecordsAndChunks ( TEXT ( " SimpleValueWithMeta " ) , PutRecords , ECachePolicy : : Default ) ;
TArray < FCacheRecord > RecievedRecordsSkipMeta = GetAndValidateRecordsAndChunks ( TEXT ( " SimpleValueWithMetaSkipMeta " ) , PutRecords , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) ;
TArray < FCacheRecord > RecievedRecordsSkipData = GetAndValidateRecordsAndChunks ( TEXT ( " SimpleValueWithMetaSkipData " ) , PutRecords , ECachePolicy : : Default | ECachePolicy : : SkipData ) ;
2022-01-10 13:43:40 -05:00
2022-01-11 11:57:38 -05:00
# if UE_WITH_ZEN
if ( ZenIntermediaryBackend )
{
TArray < FCacheRecord > PutRecordsZen = CreateTestCacheRecords ( ZenIntermediaryBackend . Get ( ) , RecordsInBatch , 1 , MetaObject , " AutoTestDummyZen " ) ;
WaitForZenPushToUpstream ( ZenIntermediaryBackend . Get ( ) , PutRecordsZen ) ;
ValidateRecords ( TEXT ( " SimpleValueWithMetaZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " SimpleValueWithMetaZen " ) , PutRecordsZen , ECachePolicy : : Default ) , RecievedRecords , ECachePolicy : : Default ) ;
ValidateRecords ( TEXT ( " SimpleValueWithMetaSkipMetaZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " SimpleValueWithMetaSkipMetaZen " ) , PutRecordsZen , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) , RecievedRecordsSkipMeta , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) ;
ValidateRecords ( TEXT ( " SimpleValueWithMetaSkipDataZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " SimpleValueWithMetaSkipDataZen " ) , PutRecordsZen , ECachePolicy : : Default | ECachePolicy : : SkipData ) , RecievedRecordsSkipData , ECachePolicy : : Default | ECachePolicy : : SkipData ) ;
}
# endif // UE_WITH_ZEN
2022-01-10 13:43:40 -05:00
}
{
TArray < FCacheRecord > PutRecords = CreateTestCacheRecords ( TestBackend , RecordsInBatch , 5 ) ;
2022-01-14 10:53:17 -05:00
TArray < FCacheRecord > RecievedRecords = GetAndValidateRecordsAndChunks ( TEXT ( " MultiValue " ) , PutRecords , ECachePolicy : : Default ) ;
TArray < FCacheRecord > RecievedRecordsSkipMeta = GetAndValidateRecordsAndChunks ( TEXT ( " MultiValueSkipMeta " ) , PutRecords , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) ;
TArray < FCacheRecord > RecievedRecordsSkipData = GetAndValidateRecordsAndChunks ( TEXT ( " MultiValueSkipData " ) , PutRecords , ECachePolicy : : Default | ECachePolicy : : SkipData ) ;
2022-01-10 13:43:40 -05:00
2022-01-11 11:57:38 -05:00
# if UE_WITH_ZEN
if ( ZenIntermediaryBackend )
{
TArray < FCacheRecord > PutRecordsZen = CreateTestCacheRecords ( ZenIntermediaryBackend . Get ( ) , RecordsInBatch , 5 , FCbObject ( ) , " AutoTestDummyZen " ) ;
WaitForZenPushToUpstream ( ZenIntermediaryBackend . Get ( ) , PutRecordsZen ) ;
ValidateRecords ( TEXT ( " MultiValueZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " MultiValueZen " ) , PutRecordsZen , ECachePolicy : : Default ) , RecievedRecords , ECachePolicy : : Default ) ;
ValidateRecords ( TEXT ( " MultiValueSkipMetaZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " MultiValueSkipMetaZen " ) , PutRecordsZen , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) , RecievedRecordsSkipMeta , ECachePolicy : : Default | ECachePolicy : : SkipMeta ) ;
ValidateRecords ( TEXT ( " MultiValueSkipDataZenAndDirect " ) , GetAndValidateRecords ( TEXT ( " MultiValueSkipDataZen " ) , PutRecordsZen , ECachePolicy : : Default | ECachePolicy : : SkipData ) , RecievedRecordsSkipData , ECachePolicy : : Default | ECachePolicy : : SkipData ) ;
}
# endif // UE_WITH_ZEN
2022-01-10 13:43:40 -05:00
}
2022-02-02 07:35:19 -05:00
{
TArray < FValue > PutValues = CreateTestCacheValues ( TestBackend , ValuesInBatch ) ;
2022-02-15 12:34:29 -05:00
TArray < FValue > ReceivedValues = GetAndValidateValues ( TEXT ( " SimpleValue " ) , PutValues , ECachePolicy : : Default ) ;
TArray < FValue > ReceivedValuesSkipData = GetAndValidateValues ( TEXT ( " SimpleValueSkipData " ) , PutValues , ECachePolicy : : Default | ECachePolicy : : SkipData ) ;
# if UE_WITH_ZEN
if ( ZenIntermediaryBackend )
{
TArray < FValue > PutValuesZen = CreateTestCacheValues ( ZenIntermediaryBackend . Get ( ) , ValuesInBatch ) ;
WaitForZenPushValuesToUpstream ( ZenIntermediaryBackend . Get ( ) , PutValuesZen ) ;
ValidateValues ( TEXT ( " SimpleValueZenAndDirect " ) , GetAndValidateValues ( TEXT ( " SimpleValueZen " ) , PutValuesZen , ECachePolicy : : Default ) , ReceivedValues , ECachePolicy : : Default ) ;
ValidateValues ( TEXT ( " SimpleValueSkipDataZenAndDirect " ) , GetAndValidateValues ( TEXT ( " SimpleValueSkipDataZen " ) , PutValuesZen , ECachePolicy : : Default | ECachePolicy : : SkipData ) , ReceivedValuesSkipData , ECachePolicy : : Default | ECachePolicy : : SkipData ) ;
}
2022-02-23 13:13:43 -05:00
if ( ZenIntermediarySiblingBackend )
{
GetAndValidateValues ( TEXT ( " SimpleValueZen " ) , PutValues , ECachePolicy : : Default , ZenIntermediarySiblingBackend . Get ( ) ) ;
GetAndValidateValues ( TEXT ( " SimpleValueSkipDataZen " ) , PutValues , ECachePolicy : : Default | ECachePolicy : : SkipData , ZenIntermediarySiblingBackend . Get ( ) ) ;
}
2022-02-15 12:34:29 -05:00
# endif // UE_WITH_ZEN
2022-02-02 07:35:19 -05:00
}
2022-01-10 13:43:40 -05:00
return true ;
}
2022-02-14 14:43:39 -05:00
} // UE::DerivedData
2022-01-13 11:09:29 -05:00
Fix thread starvation for request in http backend by using a FIFO for thread waiting for a connection to be freed
Replace the sleep by a wait on an event triggered by the thread freeing the connection
Improve the test to output stats seen below and use the proper amount of threads on low core systems
Automation RunTests System.DerivedDataCache.HttpDerivedDataBackend.ConcurrentCachedDataProbablyExistsBatch
Before
RPS: 238, AvgLatency: 90.09 ms, MaxLatency: 7.77 s
RPS: 231, AvgLatency: 87.66 ms, MaxLatency: 7.77 s
RPS: 245, AvgLatency: 139.07 ms, MaxLatency: 10.08 s
After
RPS: 634, AvgLatency: 102.97 ms, MaxLatency: 0.26 s
RPS: 653, AvgLatency: 102.51 ms, MaxLatency: 0.26 s
RPS: 630, AvgLatency: 102.29 ms, MaxLatency: 0.26 s
#rnx
#rb Zousar.Shaker, Francis.Hurteau
#preflight 60ffe8317f21c90001f6116a
#ROBOMERGE-SOURCE: CL 16968010 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v838-16927207)
[CL 16968015 by danny couture in ue5-release-engine-test branch]
2021-07-27 09:26:42 -04:00
# endif // #if WITH_DEV_AUTOMATION_TESTS && WITH_HTTP_DDC_BACKEND