2020-02-18 17:19:54 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
using AutomationTool ;
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Text ;
using System.Threading ;
using System.Threading.Tasks ;
2020-12-21 23:07:37 -04:00
using EpicGames.Core ;
2020-02-18 17:19:54 -05:00
using UnrealBuildTool ;
2021-06-11 18:21:35 -04:00
using UnrealBuildBase ;
2020-02-18 17:19:54 -05:00
namespace AutomationTool.Benchmark
{
[Help("Runs benchmarks and reports overall results")]
2022-01-06 14:16:53 -05:00
[Help("Example1: RunUAT BenchmarkBuild -all -project=Unreal")]
[Help("Example2: RunUAT BenchmarkBuild -allcompile -project=Unreal+EngineTest -platform=PS4")]
[Help("Example3: RunUAT BenchmarkBuild -editor -client -cook -cooknoshaderddc -cooknoddc -xge -noxge -singlecompile -nopcompile -project=Unreal+QAGame+EngineTest -platform=Win64+PS4+XboxOne+Switch -iterations=3")]
2020-02-18 17:19:54 -05:00
[Help("preview", "List everything that will run but don't do it")]
2022-01-06 14:16:53 -05:00
[Help("project=<name>", "Do tests on the specified projec(s)t. E.g. -project=UE+FortniteGame+QAGame")]
2020-02-18 17:19:54 -05:00
[Help("all", "Run all the things (except noddc)")]
[Help("allcompile", "Run all the compile things")]
2020-02-21 13:09:10 -05:00
[Help("editor", "Build an editor for compile tests")]
2022-01-06 14:16:53 -05:00
[Help("client", "Build a client for compile tests (see -platform)")]
2020-02-21 13:09:10 -05:00
[Help("platform=<p1+p2>", "Specify the platform(s) to use for client compilation/cooking, if empty the local platform be used if -client or -cook is specified")]
[Help("xge", "Do a compile with XGE / FASTBuild")]
[Help("noxge", "Do a compile without XGE / FASTBuild")]
[Help("singlecompile", "Do a single-file compile")]
[Help("nopcompile", "Do a nothing-needs-compiled compile")]
2020-03-02 15:50:41 -05:00
[Help("cores=X+Y+Z", "Do noxge builds with these processor counts (default is Environment.ProcessorCount)")]
2020-02-18 17:19:54 -05:00
[Help("cook", "Do a cook for the specified platform")]
2020-03-07 05:47:20 -05:00
[Help("pie", "Launch the editor (only valid when -project is specified")]
2021-02-16 20:13:40 -04:00
[Help("maps", "Map to PIE with (only valid when using a single project")]
2020-03-09 17:03:55 -04:00
[Help("warmddc", "Cook / PIE with a warm DDC")]
[Help("hotddc", "Cook / PIE with a hot local DDC (an untimed pre-run is performed)")]
[Help("coldddc", "Cook / PIE with a cold local DDC (a temporary folder is used)")]
[Help("noshaderddc", "Cook / PIE with no shaders in the DDC")]
2020-02-21 13:09:10 -05:00
[Help("iterations=<n>", "How many times to perform each test)")]
[Help("wait=<n>", "How many seconds to wait between each test)")]
[Help("filename", "Name/path of file to write CSV results to. If empty the local machine name will be used")]
2020-03-05 13:50:48 -05:00
[Help("noclean", "Don't build from clean. (Mostly just to speed things up when testing)")]
2021-02-16 20:13:40 -04:00
[Help("Cook[N] Args = ", " Extra args to use when cooking . - Cook1Args = \ "-foo\" -Cook2Args=\"-bar\" will run two cooks with each argument set. Use -CookArgs for a single cook" ) ]
[Help("PIE[N] Args = ", " Extra args to use when running the editor . - PIE1Args = \ "-foo\" -PIE2Args=\"-bar\" will run three PIE tests with each argument set. Use -PIEArgs for a single PIE" ) ]
2020-02-18 17:19:54 -05:00
class BenchmarkBuild : BuildCommand
{
2020-03-05 13:50:48 -05:00
class BenchmarkOptions : BuildCommand
{
public bool Preview = false ;
2020-02-18 17:19:54 -05:00
2022-01-06 14:16:53 -05:00
public bool DoUETests = false ;
2020-03-05 13:50:48 -05:00
public IEnumerable < string > ProjectsToTest = Enumerable . Empty < string > ( ) ;
public IEnumerable < UnrealTargetPlatform > PlatformsToTest = Enumerable . Empty < UnrealTargetPlatform > ( ) ;
// building
public bool DoBuildEditorTests = false ;
public bool DoBuildClientTests = false ;
public bool DoNoCompileTests = false ;
public bool DoSingleCompileTests = false ;
public bool DoAcceleratedCompileTests = false ;
public bool DoNoAcceleratedCompileTests = false ;
public IEnumerable < int > CoresForLocalJobs = new [ ] { Environment . ProcessorCount } ;
// cooking
public bool DoCookTests = false ;
2020-03-11 15:17:54 -04:00
2020-03-05 13:50:48 -05:00
// editor startup tests
2020-03-07 05:47:20 -05:00
public bool DoPIETests = false ;
2020-03-05 13:50:48 -05:00
2021-02-16 20:13:40 -04:00
public IEnumerable < string > PIEMapList = Enumerable . Empty < string > ( ) ;
2020-03-11 13:02:02 -04:00
2020-03-05 13:50:48 -05:00
// misc
public int Iterations = 1 ;
public bool NoClean = false ;
public int TimeBetweenTasks = 0 ;
2020-10-29 13:38:15 -04:00
public List < string > CookArgs = new List < string > ( ) ;
public List < string > PIEArgs = new List < string > ( ) ;
2020-03-05 13:50:48 -05:00
public string FileName = string . Format ( "{0}_Results.csv" , Environment . MachineName ) ;
2020-03-09 17:03:55 -04:00
public DDCTaskOptions DDCOptions = DDCTaskOptions . None ;
2020-03-05 13:50:48 -05:00
public void ParseParams ( string [ ] InParams )
{
this . Params = InParams ;
bool AllThings = ParseParam ( "all" ) ;
bool AllCompile = AllThings | ParseParam ( "allcompile" ) ;
Preview = ParseParam ( "preview" ) ;
2022-01-06 14:16:53 -05:00
DoUETests = AllThings | | ParseParam ( "Unreal" ) ;
NoClean = ParseParam ( "NoClean" ) ;
2020-03-05 13:50:48 -05:00
// compilation
2022-01-06 14:16:53 -05:00
DoBuildEditorTests = AllCompile | | ParseParam ( "editor" ) ;
DoBuildClientTests = AllCompile | | ParseParam ( "client" ) ;
DoNoCompileTests = AllCompile | | ParseParam ( "nopcompile" ) ;
DoSingleCompileTests = AllCompile | | ParseParam ( "singlecompile" ) ;
DoAcceleratedCompileTests = AllCompile | | ParseParam ( "xge" ) | | ParseParam ( "fastbuild" ) ;
// if the user didn't specify -xge then we do noxge by default so they get something with minimal steps
DoNoAcceleratedCompileTests = ( AllCompile | | ! DoAcceleratedCompileTests ) | | ParseParam ( "noxge" ) | | ParseParam ( "nofastbuild" ) ;
2020-03-05 13:50:48 -05:00
// cooking
DoCookTests = AllThings | ParseParam ( "cook" ) ;
2020-03-11 15:17:54 -04:00
2020-03-05 13:50:48 -05:00
// editor startup tests
2020-03-07 05:47:20 -05:00
DoPIETests = AllThings | ParseParam ( "pie" ) ;
2020-03-30 12:14:01 -04:00
2020-03-09 17:03:55 -04:00
// DDC options
DDCOptions | = ParseParam ( "warmddc" ) ? DDCTaskOptions . WarmDDC : DDCTaskOptions . None ;
DDCOptions | = ParseParam ( "hotddc" ) ? DDCTaskOptions . HotDDC : DDCTaskOptions . None ;
DDCOptions | = ParseParam ( "coldddc" ) ? DDCTaskOptions . ColdDDC : DDCTaskOptions . None ;
DDCOptions | = ParseParam ( "noshaderddc" ) ? DDCTaskOptions . NoShaderDDC : DDCTaskOptions . None ;
2020-03-30 12:14:01 -04:00
DDCOptions | = ParseParam ( "noxge" ) ? DDCTaskOptions . NoXGE : DDCTaskOptions . None ;
2020-03-05 13:50:48 -05:00
// sanity
DoAcceleratedCompileTests = DoAcceleratedCompileTests & & BenchmarkBuildTask . SupportsAcceleration ;
Preview = ParseParam ( "Preview" ) ;
Iterations = ParseParamInt ( "Iterations" , Iterations ) ;
TimeBetweenTasks = ParseParamInt ( "Wait" , TimeBetweenTasks ) ;
2021-02-16 20:13:40 -04:00
// allow up to 10 cook & PIE variations. -Cook1_Args=etc -Cook2_Args=etc2 etc
2020-10-29 13:38:15 -04:00
for ( int i = 0 ; i < 10 ; i + + )
{
string PostFix = i = = 0 ? "" : i . ToString ( ) ;
2021-02-16 20:13:40 -04:00
string CookParam = ParseParamValue ( "Cook" + PostFix + "Args" , null ) ;
2020-03-05 13:50:48 -05:00
2021-02-16 20:13:40 -04:00
if ( CookParam ! = null )
2020-10-29 13:38:15 -04:00
{
CookArgs . Add ( CookParam ) ;
}
2021-02-16 20:13:40 -04:00
string PIEParam = ParseParamValue ( "PIE" + PostFix + "Args" , null ) ;
2020-10-29 13:38:15 -04:00
2021-02-16 20:13:40 -04:00
if ( PIEParam ! = null )
2020-10-29 13:38:15 -04:00
{
PIEArgs . Add ( PIEParam ) ;
}
}
2021-02-16 20:13:40 -04:00
2020-10-29 13:38:15 -04:00
FileName = ParseParamValue ( "filename" , FileName ) ;
2020-03-05 13:50:48 -05:00
// Parse the project arg
{
string ProjectsArg = ParseParamValue ( "project" , null ) ;
ProjectsArg = ParseParamValue ( "projects" , ProjectsArg ) ;
// Look at the project argument and verify it's a valid uproject
if ( ! string . IsNullOrEmpty ( ProjectsArg ) )
{
2020-03-09 17:03:55 -04:00
ProjectsToTest = ProjectsArg . Split ( new [ ] { '+' , ',' } , StringSplitOptions . RemoveEmptyEntries ) ;
2020-03-05 13:50:48 -05:00
}
}
// Parse and validate platform list from arguments
{
string PlatformArg = ParseParamValue ( "platform" , "" ) ;
PlatformArg = ParseParamValue ( "platforms" , PlatformArg ) ;
if ( ! string . IsNullOrEmpty ( PlatformArg ) )
{
List < UnrealTargetPlatform > ClientPlatforms = new List < UnrealTargetPlatform > ( ) ;
var PlatformList = PlatformArg . Split ( new [ ] { '+' , ',' } , StringSplitOptions . RemoveEmptyEntries ) ;
foreach ( var Platform in PlatformList )
{
UnrealTargetPlatform PlatformEnum ;
if ( ! UnrealTargetPlatform . TryParse ( Platform , out PlatformEnum ) )
{
throw new AutomationException ( "{0} is not a valid Unreal Platform" , Platform ) ;
}
ClientPlatforms . Add ( PlatformEnum ) ;
}
PlatformsToTest = ClientPlatforms ;
}
else
{
PlatformsToTest = new [ ] { BuildHostPlatform . Current . Platform } ;
}
}
// parse processor args
{
string ProcessorArg = ParseParamValue ( "cores" , "" ) ;
if ( ! string . IsNullOrEmpty ( ProcessorArg ) )
{
var ProcessorList = ProcessorArg . Split ( new [ ] { '+' , ',' } , StringSplitOptions . RemoveEmptyEntries ) ;
CoresForLocalJobs = ProcessorList . Select ( P = > Convert . ToInt32 ( P ) ) ;
}
2020-03-11 15:17:54 -04:00
}
2020-03-30 12:14:01 -04:00
// parse map args
{
2021-02-16 20:13:40 -04:00
string Arg = ParseParamValue ( "maps" , "" ) ;
Arg = ParseParamValue ( "map" , Arg ) ;
2020-03-30 12:14:01 -04:00
if ( ! string . IsNullOrEmpty ( Arg ) )
{
2021-02-16 20:13:40 -04:00
PIEMapList = Arg . Split ( new [ ] { '+' , ',' } , StringSplitOptions . RemoveEmptyEntries ) ;
2020-03-30 12:14:01 -04:00
}
}
2020-03-05 13:50:48 -05:00
}
}
2020-02-18 17:19:54 -05:00
2021-08-09 18:24:52 -04:00
struct BenchmarkResult
{
public TimeSpan TaskTime { get ; set ; }
public bool Failed { get ; set ; }
}
2020-02-18 17:19:54 -05:00
public BenchmarkBuild ( )
2020-03-11 15:17:54 -04:00
{
2020-02-18 17:19:54 -05:00
}
public override ExitCode Execute ( )
{
2020-03-05 13:50:48 -05:00
BenchmarkOptions Options = new BenchmarkOptions ( ) ;
Options . ParseParams ( this . Params ) ;
2020-02-18 17:19:54 -05:00
2020-03-05 13:50:48 -05:00
List < BenchmarkTaskBase > Tasks = new List < BenchmarkTaskBase > ( ) ;
2020-02-18 17:19:54 -05:00
2021-08-09 18:24:52 -04:00
Dictionary < BenchmarkTaskBase , List < BenchmarkResult > > Results = new Dictionary < BenchmarkTaskBase , List < BenchmarkResult > > ( ) ;
2020-02-18 17:19:54 -05:00
2020-03-11 15:17:54 -04:00
for ( int ProjectIndex = 0 ; ProjectIndex < Options . ProjectsToTest . Count ( ) ; ProjectIndex + + )
2020-02-18 17:19:54 -05:00
{
2020-03-05 13:50:48 -05:00
string Project = Options . ProjectsToTest . ElementAt ( ProjectIndex ) ;
2020-02-18 17:19:54 -05:00
2020-03-09 17:03:55 -04:00
FileReference ProjectFile = ProjectUtils . FindProjectFileFromName ( Project ) ;
2022-01-06 14:16:53 -05:00
if ( ProjectFile = = null & & ! Project . Equals ( "Unreal" , StringComparison . OrdinalIgnoreCase ) )
2020-03-09 17:03:55 -04:00
{
throw new AutomationException ( "Could not find project file for {0}" , Project ) ;
}
2020-03-05 13:50:48 -05:00
if ( Options . DoBuildEditorTests )
2020-02-18 17:19:54 -05:00
{
2020-03-09 17:03:55 -04:00
Tasks . AddRange ( AddBuildTests ( ProjectFile , BuildHostPlatform . Current . Platform , "Editor" , Options ) ) ;
2020-02-18 17:19:54 -05:00
}
2020-03-05 13:50:48 -05:00
// do startup tests
2020-03-11 13:02:02 -04:00
if ( Options . DoPIETests )
{
Tasks . AddRange ( AddPIETests ( ProjectFile , Options ) ) ;
}
2020-03-05 13:50:48 -05:00
foreach ( var ClientPlatform in Options . PlatformsToTest )
2020-02-18 17:19:54 -05:00
{
// build a client if the project supports it
2020-03-09 17:03:55 -04:00
string TargetName = ProjectSupportsClientBuild ( ProjectFile ) ? "Client" : "Game" ;
2020-02-18 17:19:54 -05:00
2020-03-11 13:02:02 -04:00
if ( Options . DoBuildClientTests )
{
// do build tests
Tasks . AddRange ( AddBuildTests ( ProjectFile , ClientPlatform , TargetName , Options ) ) ;
}
2020-02-21 13:09:10 -05:00
2020-03-05 13:50:48 -05:00
// do cook tests
2020-03-11 13:02:02 -04:00
if ( Options . DoCookTests )
{
Tasks . AddRange ( AddCookTests ( ProjectFile , ClientPlatform , Options ) ) ;
}
2020-02-18 17:19:54 -05:00
}
}
Log . TraceInformation ( "Will execute tests:" ) ;
foreach ( var Task in Tasks )
{
2020-02-21 13:09:10 -05:00
Log . TraceInformation ( "{0}" , Task . GetFullTaskName ( ) ) ;
2020-02-18 17:19:54 -05:00
}
2020-03-05 13:50:48 -05:00
if ( ! Options . Preview )
2020-02-18 17:19:54 -05:00
{
// create results lists
foreach ( var Task in Tasks )
{
2021-08-09 18:24:52 -04:00
Results . Add ( Task , new List < BenchmarkResult > ( ) ) ;
2020-02-18 17:19:54 -05:00
}
DateTime StartTime = DateTime . Now ;
2020-03-05 13:50:48 -05:00
for ( int i = 0 ; i < Options . Iterations ; i + + )
2020-02-18 17:19:54 -05:00
{
foreach ( var Task in Tasks )
{
2020-03-11 15:17:54 -04:00
Log . TraceInformation ( "Starting task {0} (Pass {1})" , Task . GetFullTaskName ( ) , i + 1 ) ;
2020-02-18 17:19:54 -05:00
Task . Run ( ) ;
2020-02-21 13:09:10 -05:00
Log . TraceInformation ( "Task {0} took {1}" , Task . GetFullTaskName ( ) , Task . TaskTime . ToString ( @"hh\:mm\:ss" ) ) ;
2020-02-18 17:19:54 -05:00
2021-08-09 18:24:52 -04:00
if ( Task . Failed )
{
Log . TraceError ( "Task failed! Benchmark time may be inaccurate." ) ;
}
Results [ Task ] . Add ( new BenchmarkResult
{
TaskTime = Task . TaskTime ,
Failed = Task . Failed
} ) ;
2020-02-18 17:19:54 -05:00
2020-03-05 13:50:48 -05:00
// write results so far
WriteCSVResults ( Options . FileName , Tasks , Results ) ;
2020-02-18 17:19:54 -05:00
2020-03-05 13:50:48 -05:00
Log . TraceInformation ( "Waiting {0} secs until next task" , Options . TimeBetweenTasks ) ;
Thread . Sleep ( Options . TimeBetweenTasks * 1000 ) ;
2020-02-18 17:19:54 -05:00
}
}
Log . TraceInformation ( "**********************************************************************" ) ;
Log . TraceInformation ( "Test Results:" ) ;
foreach ( var Task in Tasks )
{
string TimeString = "" ;
2021-08-09 18:24:52 -04:00
IEnumerable < BenchmarkResult > TaskResults = Results [ Task ] ;
2020-02-18 17:19:54 -05:00
2021-08-09 18:24:52 -04:00
foreach ( var Result in TaskResults )
2020-02-18 17:19:54 -05:00
{
if ( TimeString . Length > 0 )
{
TimeString + = ", " ;
}
2021-08-09 18:24:52 -04:00
if ( Result . Failed )
2020-02-18 17:19:54 -05:00
{
2021-08-09 18:24:52 -04:00
TimeString + = "Failed " ;
2020-02-18 17:19:54 -05:00
}
2021-08-09 18:24:52 -04:00
TimeString + = Result . TaskTime . ToString ( @"hh\:mm\:ss" ) ;
2020-02-18 17:19:54 -05:00
}
var AvgTimeString = "" ;
2021-08-09 18:24:52 -04:00
if ( TaskResults . Count ( ) > 1 )
2020-02-18 17:19:54 -05:00
{
2021-08-09 18:24:52 -04:00
var AvgTime = new TimeSpan ( TaskResults . Select ( R = > R . TaskTime ) . Sum ( T = > T . Ticks ) / TaskResults . Count ( ) ) ;
2020-02-18 17:19:54 -05:00
AvgTimeString = string . Format ( " (Avg: {0})" , AvgTime . ToString ( @"hh\:mm\:ss" ) ) ;
2020-03-11 15:17:54 -04:00
}
2020-02-18 17:19:54 -05:00
2020-02-21 13:09:10 -05:00
Log . TraceInformation ( "Task {0}:\t{1}{2}" , Task . GetFullTaskName ( ) , TimeString , AvgTimeString ) ;
2020-02-18 17:19:54 -05:00
}
Log . TraceInformation ( "**********************************************************************" ) ;
TimeSpan Elapsed = DateTime . Now - StartTime ;
2020-03-11 15:17:54 -04:00
Log . TraceInformation ( "Total benchmark time: {0}" , Elapsed . ToString ( @"hh\:mm\:ss" ) ) ;
2020-02-18 17:19:54 -05:00
2020-03-05 13:50:48 -05:00
WriteCSVResults ( Options . FileName , Tasks , Results ) ;
2020-02-18 17:19:54 -05:00
}
return ExitCode . Success ;
}
2020-03-09 17:03:55 -04:00
IEnumerable < BenchmarkTaskBase > AddBuildTests ( FileReference InProjectFile , UnrealTargetPlatform InPlatform , string InTargetName , BenchmarkOptions InOptions )
2020-03-05 13:50:48 -05:00
{
BuildOptions CleanFlag = InOptions . NoClean ? BuildOptions . None : BuildOptions . Clean ;
BuildOptions NoAndSingleCompileOptions = BuildOptions . None ;
List < BenchmarkTaskBase > NewTasks = new List < BenchmarkTaskBase > ( ) ;
if ( InOptions . DoAcceleratedCompileTests )
{
2020-03-09 17:03:55 -04:00
NewTasks . Add ( new BenchmarkBuildTask ( InProjectFile , InTargetName , InPlatform , CleanFlag ) ) ;
2020-03-05 13:50:48 -05:00
}
if ( InOptions . DoNoAcceleratedCompileTests )
{
foreach ( int ProcessorCount in InOptions . CoresForLocalJobs )
{
2020-03-09 17:03:55 -04:00
NewTasks . Add ( new BenchmarkBuildTask ( InProjectFile , InTargetName , InPlatform , CleanFlag | BuildOptions . NoAcceleration , "" , ProcessorCount ) ) ;
2020-03-05 13:50:48 -05:00
}
// do single compilation with these results
NoAndSingleCompileOptions | = BuildOptions . NoAcceleration ;
}
if ( InOptions . DoNoCompileTests )
{
// note, don't clean since we build normally then build a single file
2020-03-09 17:03:55 -04:00
NewTasks . Add ( new BenchmarkNopCompileTask ( InProjectFile , InTargetName , InPlatform , NoAndSingleCompileOptions ) ) ;
2020-03-05 13:50:48 -05:00
}
if ( InOptions . DoSingleCompileTests )
{
2020-03-09 17:03:55 -04:00
FileReference SourceFile = FindProjectSourceFile ( InProjectFile ) ;
2020-03-05 13:50:48 -05:00
// note, don't clean since we build normally then build again
2020-03-09 17:03:55 -04:00
NewTasks . Add ( new BenchmarkSingleCompileTask ( InProjectFile , InTargetName , InPlatform , SourceFile , NoAndSingleCompileOptions ) ) ;
2020-03-05 13:50:48 -05:00
}
return NewTasks ;
}
2020-03-09 17:03:55 -04:00
IEnumerable < BenchmarkTaskBase > AddCookTests ( FileReference InProjectFile , UnrealTargetPlatform InPlatform , BenchmarkOptions InOptions )
2020-03-05 13:50:48 -05:00
{
2020-03-09 17:03:55 -04:00
if ( InProjectFile = = null )
2020-03-05 13:50:48 -05:00
{
return Enumerable . Empty < BenchmarkTaskBase > ( ) ;
}
List < BenchmarkTaskBase > NewTasks = new List < BenchmarkTaskBase > ( ) ;
// Cook a client if the project supports i
2020-03-09 17:03:55 -04:00
bool CookClient = ProjectSupportsClientBuild ( InProjectFile ) ;
2020-03-05 13:50:48 -05:00
if ( InOptions . DoCookTests )
{
2020-03-09 17:03:55 -04:00
2020-10-29 13:38:15 -04:00
IEnumerable < string > CookVariations = InOptions . CookArgs . Any ( ) ? InOptions . CookArgs : new List < string > { "" } ;
2020-03-09 17:03:55 -04:00
2020-10-29 13:38:15 -04:00
foreach ( string CookArgs in CookVariations )
2020-03-09 17:03:55 -04:00
{
2022-01-06 14:16:53 -05:00
bool DoWarmCook = InOptions . DDCOptions . HasFlag ( DDCTaskOptions . WarmDDC ) | |
( ! InOptions . DDCOptions . HasFlag ( DDCTaskOptions . HotDDC ) & & ! InOptions . DDCOptions . HasFlag ( DDCTaskOptions . ColdDDC ) ) ;
2020-10-29 13:38:15 -04:00
// no/warm options
2022-01-06 14:16:53 -05:00
if ( DoWarmCook )
2020-10-29 13:38:15 -04:00
{
NewTasks . Add ( new BenchmarkCookTask ( InProjectFile , InPlatform , CookClient , DDCTaskOptions . WarmDDC , CookArgs ) ) ;
}
2020-03-09 17:03:55 -04:00
2020-10-29 13:38:15 -04:00
if ( InOptions . DDCOptions . HasFlag ( DDCTaskOptions . HotDDC ) )
{
NewTasks . Add ( new BenchmarkCookTask ( InProjectFile , InPlatform , CookClient , DDCTaskOptions . HotDDC , CookArgs ) ) ;
}
2020-03-09 17:03:55 -04:00
2020-10-29 13:38:15 -04:00
if ( InOptions . DDCOptions . HasFlag ( DDCTaskOptions . ColdDDC ) )
{
NewTasks . Add ( new BenchmarkCookTask ( InProjectFile , InPlatform , CookClient , DDCTaskOptions . ColdDDC , CookArgs ) ) ;
}
if ( InOptions . DDCOptions . HasFlag ( DDCTaskOptions . NoShaderDDC ) )
{
NewTasks . Add ( new BenchmarkCookTask ( InProjectFile , InPlatform , CookClient , DDCTaskOptions . NoShaderDDC , CookArgs ) ) ;
}
2020-03-09 17:03:55 -04:00
}
2020-03-05 13:50:48 -05:00
}
return NewTasks ;
}
2020-03-09 17:03:55 -04:00
IEnumerable < BenchmarkTaskBase > AddPIETests ( FileReference InProjectFile , BenchmarkOptions InOptions )
2020-03-05 13:50:48 -05:00
{
2020-03-30 12:14:01 -04:00
if ( InProjectFile = = null | | ! InOptions . DoPIETests )
2020-03-05 13:50:48 -05:00
{
return Enumerable . Empty < BenchmarkTaskBase > ( ) ;
}
List < BenchmarkTaskBase > NewTasks = new List < BenchmarkTaskBase > ( ) ;
2021-02-16 20:13:40 -04:00
string PIEArgs = "" ;
2020-03-30 12:14:01 -04:00
2021-02-16 20:13:40 -04:00
if ( InOptions . PIEMapList . Any ( ) )
2020-03-09 17:03:55 -04:00
{
2021-02-16 20:13:40 -04:00
PIEArgs + = string . Format ( "-map=\"{0}\"" , string . Join ( "+" , InOptions . PIEMapList ) ) ;
2020-03-09 17:03:55 -04:00
}
2021-02-16 20:13:40 -04:00
2020-10-29 13:38:15 -04:00
IEnumerable < string > PIEVariations = InOptions . PIEArgs . Any ( ) ? InOptions . PIEArgs : new List < string > { "" } ;
2020-03-11 15:17:54 -04:00
2021-02-16 20:13:40 -04:00
foreach ( string VariationArgs in PIEVariations )
2020-03-05 13:50:48 -05:00
{
2021-02-16 20:13:40 -04:00
string FinalArgs = PIEArgs + " " + VariationArgs ;
// if no options assume warm
if ( InOptions . DDCOptions = = DDCTaskOptions . None | | InOptions . DDCOptions . HasFlag ( DDCTaskOptions . WarmDDC ) )
2020-03-09 17:03:55 -04:00
{
2021-02-16 20:13:40 -04:00
NewTasks . Add ( new BenchmarkRunEditorTask ( InProjectFile , DDCTaskOptions . WarmDDC , FinalArgs ) ) ;
}
2020-03-09 17:03:55 -04:00
2021-02-16 20:13:40 -04:00
// hot ddc
if ( InOptions . DDCOptions . HasFlag ( DDCTaskOptions . HotDDC ) )
{
NewTasks . Add ( new BenchmarkRunEditorTask ( InProjectFile , DDCTaskOptions . HotDDC , FinalArgs ) ) ;
}
2020-03-09 17:03:55 -04:00
2021-02-16 20:13:40 -04:00
// cold ddc
if ( InOptions . DDCOptions . HasFlag ( DDCTaskOptions . ColdDDC ) )
{
NewTasks . Add ( new BenchmarkRunEditorTask ( InProjectFile , DDCTaskOptions . ColdDDC , FinalArgs ) ) ;
}
2020-03-09 17:03:55 -04:00
2021-02-16 20:13:40 -04:00
// no shaders in the ddc
if ( InOptions . DDCOptions . HasFlag ( DDCTaskOptions . NoShaderDDC ) )
{
NewTasks . Add ( new BenchmarkRunEditorTask ( InProjectFile , DDCTaskOptions . NoShaderDDC , FinalArgs ) ) ;
2020-03-09 17:03:55 -04:00
}
2020-03-05 13:50:48 -05:00
}
2020-03-30 12:14:01 -04:00
2020-03-05 13:50:48 -05:00
return NewTasks ;
}
2020-02-18 17:19:54 -05:00
/// <summary>
/// Writes our current result to a CSV file. It's expected that this function is called multiple times so results are
/// updated as we go
/// </summary>
2021-08-09 18:24:52 -04:00
void WriteCSVResults ( string InFileName , List < BenchmarkTaskBase > InTasks , Dictionary < BenchmarkTaskBase , List < BenchmarkResult > > InResults )
2020-02-18 17:19:54 -05:00
{
2020-03-05 13:50:48 -05:00
Log . TraceInformation ( "Writing results to {0}" , InFileName ) ;
2020-02-18 17:19:54 -05:00
try
{
List < string > Lines = new List < string > ( ) ;
2020-02-21 13:09:10 -05:00
// first line is machine name,CPU count,Iteration 1, Iteration 2 etc
string FirstLine = string . Format ( "{0},{1}" , Environment . MachineName , Environment . ProcessorCount ) ;
2020-02-18 17:19:54 -05:00
2020-03-05 13:50:48 -05:00
if ( InTasks . Count ( ) > 0 )
2020-02-18 17:19:54 -05:00
{
2020-03-05 13:50:48 -05:00
int Iterations = InResults [ InTasks . First ( ) ] . Count ( ) ;
2020-02-18 17:19:54 -05:00
if ( Iterations > 0 )
{
for ( int i = 0 ; i < Iterations ; i + + )
{
FirstLine + = "," ;
FirstLine + = string . Format ( "Iteration {0}" , i + 1 ) ;
}
}
}
Lines . Add ( FirstLine ) ;
2020-03-05 13:50:48 -05:00
foreach ( var Task in InTasks )
2020-02-18 17:19:54 -05:00
{
// start with Name, StartTime
2020-02-21 13:09:10 -05:00
string Line = string . Format ( "{0},{1}" , Task . GetFullTaskName ( ) , Task . StartTime . ToString ( "yyyy-dd-MM HH:mm:ss" ) ) ;
2020-02-18 17:19:54 -05:00
// now append all iteration times
2021-08-09 18:24:52 -04:00
foreach ( BenchmarkResult Result in InResults [ Task ] )
2020-02-18 17:19:54 -05:00
{
Line + = "," ;
2021-08-09 18:24:52 -04:00
if ( Result . Failed )
2020-02-18 17:19:54 -05:00
{
2021-08-09 18:24:52 -04:00
Line + = "FAILED " ;
2020-02-18 17:19:54 -05:00
}
2021-08-09 18:24:52 -04:00
Line + = Result . TaskTime . ToString ( @"hh\:mm\:ss" ) ;
2020-02-18 17:19:54 -05:00
}
Lines . Add ( Line ) ;
}
2020-03-05 13:50:48 -05:00
File . WriteAllLines ( InFileName , Lines . ToArray ( ) ) ;
2020-02-18 17:19:54 -05:00
}
catch ( Exception Ex )
{
2020-03-05 13:50:48 -05:00
Log . TraceError ( "Failed to write CSV to {0}. {1}" , InFileName , Ex ) ;
2020-02-18 17:19:54 -05:00
}
}
/// <summary>
/// Returns true/false based on whether the project supports a client configuration
/// </summary>
/// <param name="ProjectName"></param>
/// <returns></returns>
2020-03-09 17:03:55 -04:00
bool ProjectSupportsClientBuild ( FileReference InProjectFile )
2020-02-18 17:19:54 -05:00
{
2020-03-09 17:03:55 -04:00
if ( InProjectFile = = null )
2020-02-18 17:19:54 -05:00
{
2022-01-06 14:16:53 -05:00
// UE
2020-02-18 17:19:54 -05:00
return true ;
}
2020-03-09 17:03:55 -04:00
ProjectProperties Properties = ProjectUtils . GetProjectProperties ( InProjectFile ) ;
2020-02-18 17:19:54 -05:00
2022-01-06 14:16:53 -05:00
return Properties . Targets . Where ( T = > T . Rules . Type = = TargetType . Client ) . Any ( ) ;
2020-02-18 17:19:54 -05:00
}
/// <summary>
/// Returns true/false based on whether the project supports a client configuration
/// </summary>
/// <param name="ProjectName"></param>
/// <returns></returns>
2020-03-09 17:03:55 -04:00
FileReference FindProjectSourceFile ( FileReference InProjectFile )
2020-02-18 17:19:54 -05:00
{
FileReference SourceFile = null ;
2020-03-09 17:03:55 -04:00
if ( InProjectFile ! = null )
2020-02-18 17:19:54 -05:00
{
2020-03-09 17:03:55 -04:00
DirectoryReference SourceDir = DirectoryReference . Combine ( InProjectFile . Directory , "Source" , InProjectFile . GetFileNameWithoutAnyExtensions ( ) ) ;
2020-02-18 17:19:54 -05:00
var Files = DirectoryReference . EnumerateFiles ( SourceDir , "*.cpp" , System . IO . SearchOption . AllDirectories ) ;
SourceFile = Files . FirstOrDefault ( ) ;
}
if ( SourceFile = = null )
{
// touch the write time on a file, first making it writable since it may be under P4
2021-06-11 18:21:35 -04:00
SourceFile = FileReference . Combine ( Unreal . EngineDirectory , "Source/Runtime/Engine/Private/UnrealEngine.cpp" ) ;
2020-02-18 17:19:54 -05:00
}
2020-03-09 17:03:55 -04:00
Log . TraceVerbose ( "Will compile {0} for single-file compilation test for {1}" , SourceFile , InProjectFile . GetFileNameWithoutAnyExtensions ( ) ) ;
2020-02-18 17:19:54 -05:00
return SourceFile ;
}
}
}