Files
UnrealEngineUWP/Engine/Source/Programs/AutomationTool/Scripts/BenchmarkBuild/BenchmarkRunEditorTask.cs
Andrew Grant 5087ea59ea TL;DR
Improved behavior of PIE automation to deal with extremly long hitches and better represet the time a user is going to wait before the editor is usable.
Improved usability of BenchmarkBuild script


Changes

+ Added new automation command for waiting until average fps reaches a specified value. Using this with a conservative value is a better way of checking for interactivity than looping at shader compiles etc.
+ When Errors are added to a test as a result of logging, this itself is now logged as an error. This makes it clearer why a test may have failed despite its own checks having passed.
+ BenchmarkBuild can now just specify empty arguments for PIE/Cook tests (e.g. -PIE1_Args="") to allow comparisons between default/other.
+ Project.Maps.PIE can now take a "-maps" argument on the command line for the list of maps to test
+ Turned on AutomationController.SuppresLogErrors for Frosty to prevent errors causing errors to fail
+ Cleaned up naming for mulltiple-variations of PIE/Cook tests in BenchmarkBuild. Now use -PIE1Args, -PIE2Args etc

Fixes -

* Fixed issue in AutomationControllerManager where extreme hitching resulted in an editor test timing out due to outstanding pings being given a "TimeSince" that would exceed a timeout
* Fixed issue where bTreatLogErrorsAsTestErrors was (strangely) causing the editor to exit with a zero-error code when tests failed.
* Made FWaitForShadersToFinishCompiling automation task non-blocking to prevent timeouts. (It also checks texture compilation as the blocking version used to)
* Fixed BenchmarkBuild using the old System.Maps.PIE test that isn't enabled by default in projects
* Removed flush of shaders/textures in Project.Maps.PIE since this doesn't represent when the level is playable. Measuring this will be added as a separate test.
* Fixed issue where a user specifying a map with an extension would cause Project.Maps.PIE not to recognize the level had loaded

#rb swarm
#jira nojira

[CL 15426493 by Andrew Grant in ue5-main branch]
2021-02-16 20:13:40 -04:00

136 lines
3.8 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using EpicGames.Core;
using UnrealBuildTool;
namespace AutomationTool.Benchmark
{
class BenchmarkRunEditorTask : BenchmarkEditorTaskBase
{
public BenchmarkRunEditorTask(FileReference InProjectFile, DDCTaskOptions InOptions, string InEditorArgs="")
: base(InProjectFile, InOptions, InEditorArgs)
{
TaskName = string.Format("{0} PIE", ProjectName, BuildHostPlatform.Current.Platform);
}
protected override bool PerformPrequisites()
{
// build editor
BuildTarget Command = new BuildTarget();
Command.ProjectName = ProjectFile != null ? ProjectFile.GetFileNameWithoutAnyExtensions() : null;
Command.Platforms = BuildHostPlatform.Current.Platform.ToString();
Command.Targets = "Editor";
Command.NoTools = false;
if (Command.Execute() != ExitCode.Success)
{
return false;
}
// if they want a hot DDC then do the test one time with no timing
if (TaskOptions.HasFlag(DDCTaskOptions.HotDDC))
{
RunEditorAndWaitForMapLoad(true);
}
base.PerformPrequisites();
return true;
}
static IProcessResult CurrentProcess = null;
static DateTime LastStdOutTime = DateTime.Now;
//static bool TestCompleted = false;
/// <summary>
/// A filter that suppresses all output od stdout/stderr
/// </summary>
/// <param name="Message"></param>
/// <returns></returns>
static string EndOnMapCheckFilter(string Message)
{
if (CurrentProcess != null)
{
lock (CurrentProcess)
{
if (Message.Contains("TEST COMPLETE"))
{
Log.TraceInformation("Automation test reported as complete.");
//TestCompleted = true;
}
LastStdOutTime = DateTime.Now;
}
}
return Message;
}
private static string MakeValidFileName(string name)
{
string invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars()));
string invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars);
return System.Text.RegularExpressions.Regex.Replace(name, invalidRegStr, "_");
}
protected bool RunEditorAndWaitForMapLoad(bool bIsWarming)
{
string ProjectArg = ProjectFile != null ? ProjectFile.ToString() : "";
string EditorPath = HostPlatform.Current.GetUE4ExePath("UnrealEditor.exe");
string LogArg = string.Format("-log={0}.log", MakeValidFileName(GetFullTaskName()).Replace(" ", "_"));
string Arguments = string.Format("{0} -execcmds=\"automation runtest Project.Maps.PIE;Quit\" {1} -stdout -FullStdOutLogOutput -unattended {2}", ProjectArg, EditorArgs, LogArg);
if (!bIsWarming && TaskOptions.HasFlag(DDCTaskOptions.NoShaderDDC))
{
Arguments += (" -noshaderddc");
}
if (TaskOptions.HasFlag(DDCTaskOptions.NoXGE))
{
Arguments += (" -noxgeshadercompile");
}
var RunOptions = CommandUtils.ERunOptions.AllowSpew | CommandUtils.ERunOptions.NoWaitForExit;
var SpewDelegate = new ProcessResult.SpewFilterCallbackType(EndOnMapCheckFilter);
//TestCompleted = false;
LastStdOutTime = DateTime.Now;
CurrentProcess = CommandUtils.Run(EditorPath, Arguments, Options: RunOptions, SpewFilterCallback: SpewDelegate);
int TimeoutMins = 15;
while (!CurrentProcess.HasExited)
{
Thread.Sleep(5 * 1000);
lock (CurrentProcess)
{
if ((DateTime.Now - LastStdOutTime).TotalMinutes >= TimeoutMins)
{
Log.TraceError("Gave up waiting for task after {0} minutes of no output", TimeoutMins);
CurrentProcess.ProcessObject.Kill();
}
}
}
int ExitCode = CurrentProcess.ExitCode;
CurrentProcess = null;
return ExitCode == 0;
}
protected override bool PerformTask()
{
return RunEditorAndWaitForMapLoad(false);
}
}
}