Skip to content

Commit 70649ef

Browse files
author
Unity Technologies
committed
com.unity.test-framework.performance@2.1.0-preview
## [2.1.0] - 2020-05-14 Add flexible horizontal splitter for report window Fix date format ## [2.0.9] - 2020-03-23 Fix profiler measurements for method measurements Throw exceptions when measuring NaN
1 parent ec61028 commit 70649ef

File tree

10 files changed

+187
-15
lines changed

10 files changed

+187
-15
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## [2.1.0] - 2020-05-14
4+
5+
Add flexible horizontal splitter for report window
6+
Fix date format
7+
38
## [2.0.9] - 2020-03-23
49

510
Fix profiler measurements for method measurements
16.6 KB
Loading
59.1 KB
Loading
149 KB
Loading

Documentation~/index.md

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The Performance Testing Extension is intended to be used with, and complement, t
1111

1212
To install the Performance Testing Extension package
1313
1. Open the `manifest.json` file for your Unity project (located in the YourProject/Packages directory) in a text editor
14-
2. Add `"com.unity.test-framework.performance": "2.0.9-preview",` to the dependencies
14+
2. Add `"com.unity.test-framework.performance": "2.1.0-preview",` to the dependencies
1515
3. Save the manifest.json file
1616
4. Verify the Performance Testing Extension is now installed opening the Unity Package Manager window
1717

@@ -334,6 +334,131 @@ public static string GetScenePath(string name)
334334
}
335335
```
336336

337+
## Writing a simple test
338+
339+
As an example, to measure the performance of Vector2 operations you can use `Measure.Method`. This executes the provided method and samples performance. You can increase `MeasurementCount` from the default of 7 to 20 to achieve better performance test stability. You can execute a `Vector2.MoveTowards` test in Edit or Play mode.
340+
341+
``` csharp
342+
[Test, Performance]
343+
public void Vector2_operations()
344+
{
345+
var a = Vector2.one;
346+
var b = Vector2.zero;
347+
348+
Measure.Method(() =>
349+
{
350+
Vector2.MoveTowards(a, b, 0.5f);
351+
Vector2.ClampMagnitude(a, 0.5f);
352+
Vector2.Reflect(a, b);
353+
Vector2.SignedAngle(a, b);
354+
})
355+
.MeasurementCount(20)
356+
.Run();
357+
}
358+
```
359+
360+
To view the results, go to **Window > Analysis > Performance Test Report**.
361+
362+
![Performance test example01](images/example01.png)
363+
364+
In this example, the results show that the first method execution took five times longer than the subsequent methods, and those subsequent method executions were unstable. Also, you can’t tell from these test results how long it took for each Vector2 operation to execute.
365+
366+
### Improving test stability
367+
368+
You can improve this test in several ways. First, try to improve test stability. Test instability at the beginning of a test can occur for several reasons, such as entering Play mode or method initialization, because the tested method is quite fast and more sensitive to other running background processes. To improve this, add `WarmupCount(n)`. This allows you to execute methods before you start to record data, so Unity doesn’t record method initialization. The simplest way to increase test execution time is to repeat the method in a loop.
369+
Avoid having measurements that are less than 1ms because they are usually more sensitive to unstable environments.
370+
To help you track each operation's execution times, split the Vector2 operations into several tests. Usually, when writing a test, you use setup and clean up methods to isolate the test environment. However, in this case, methods are isolated and do not affect other methods, therefore they do not need a cleanup or setup.
371+
The following code example shows a performance test for the `Vector2.MoveTowards` operation. Other Vector2 performance tests are identical.
372+
373+
``` csharp
374+
[Test, Performance]
375+
public void Vector2_MoveTowards()
376+
{
377+
378+
Measure.Method(() =>
379+
{
380+
Vector2.MoveTowards(Vector2.one, Vector2.zero, 0.5f);
381+
})
382+
.WarmupCount(5)
383+
.IterationsPerMeasurement(10000)
384+
.MeasurementCount(20)
385+
.Run();
386+
}
387+
```
388+
389+
With 100000 iterations in this test, there is a small fluctuation in method execution time, but the standard deviation is low, which means the test is reasonably stable.
390+
391+
![Performance test example02](images/example02.png)
392+
393+
As an example, if you want to measure a method that only runs in Play mode (for example `Physics.Raycast`), you can use `Measure.Frames()`, which records time per frame by default. To only measure `Physics.Raycast` time, you can disable frame time measurements with `DontRecordFrametime` and just measure the `Physics.Raycast` profiler marker.
394+
This test creates objects that you need to dispose of at the end of each test, because multiple unnecessary objects can affect the next test results. Use the SetUp method to create GameObjects, and the TearDown method to destroy the created GameObjects after each test.
395+
396+
``` csharp
397+
[SetUp]
398+
public void SetUp()
399+
{
400+
for (int i = 0; i < 100; ++i)
401+
{
402+
GameObject raycaster = new GameObject("raycast", typeof(Raycast));
403+
raycaster.transform.SetParent(_parent.transform);
404+
}
405+
}
406+
407+
[UnityTest, Performance]
408+
public IEnumerator Physics_RaycastTests()
409+
{
410+
string profilierMarker = "Physics.Raycast";
411+
412+
yield return Measure.Frames()
413+
.WarmupCount(3)
414+
.DontRecordFrametime()
415+
.MeasurementCount(10)
416+
.ProfilerMarkers(profilierMarker)
417+
.Run();
418+
}
419+
420+
public class Raycast : MonoBehaviour
421+
{
422+
private void Update()
423+
{
424+
RaycastHit hit;
425+
bool ray = Physics.Raycast(
426+
transform.position,
427+
Vector3.forward,
428+
out hit,
429+
Mathf.Infinity);
430+
}
431+
}
432+
433+
[TearDown]
434+
public void TearDown()
435+
{
436+
GameObject.DestroyImmediate(_parent);
437+
}
438+
```
439+
440+
To record your own measurements, create a new sample group and record a custom metric. The following examples measures `Allocated` and `Reserved` memory.
441+
442+
``` csharp
443+
[Test, Performance]
444+
public void Empty()
445+
{
446+
var allocated = new SampleGroup("TotalAllocatedMemory", SampleUnit.Megabyte);
447+
var reserved = new SampleGroup("TotalReservedMemory", SampleUnit.Megabyte);
448+
449+
using (Measure.Scope())
450+
{
451+
Measure.Custom(allocated, Profiler.GetTotalAllocatedMemoryLong() / 1048576f);
452+
Measure.Custom(reserved, Profiler.GetTotalReservedMemoryLong() / 1048576f);
453+
}
454+
}
455+
```
456+
457+
Before you start to collect package performance data, make sure that the tests you run locally are stable (the data set deviation is <5%). In the **Performance Test Report** window check whether the test isn’t fluctuating and that the results between runs are similar.
458+
459+
Performance test results run on a local machine can be significantly different compared to previous test runs because there could be other applications running in the background, or CPU overheating or CPU boosting is enabled. Make sure that CPU intensive applications are turned off where possible. You can disable CPU boost in the BIOS or by using third-parties software, such as Real Temp.
460+
461+
For compairing performance data between runs use [Unity Performance Benchmark Reporter](https://github.com/Unity-Technologies/PerformanceBenchmarkReporter/wiki). Unity Performance Benchmark Reporter provides you with a graphical HTML report that enables you to compare performance metric baselines and subsequent performance metrics.
337462

338463
## More Examples
339464

Editor/TestReportGraph/TestReportWindow.cs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ public class TestReportWindow : EditorWindow
3737
private bool m_showSamples = true;
3838
private int[] m_columnWidth = new int[4];
3939

40+
private bool m_isResizing;
41+
private float m_testListHeight = s_windowHeight / 4;
42+
private Rect m_splitterRect;
43+
private float m_windowHeight;
44+
4045
[SerializeField]
4146
TreeViewState m_testListTreeViewState;
4247
[SerializeField]
@@ -260,9 +265,10 @@ private void Draw()
260265
{
261266
if (m_testListTable != null)
262267
{
263-
Rect r = GUILayoutUtility.GetRect(position.width, s_windowHeight / 4, GUI.skin.box,
268+
Rect r = GUILayoutUtility.GetRect(position.width, m_testListHeight, GUI.skin.box,
264269
GUILayout.ExpandWidth(true));
265270
m_testListTable.OnGUI(r);
271+
Resize(r.y);
266272
}
267273
}
268274

@@ -350,6 +356,41 @@ private void Draw()
350356
}
351357
}
352358

359+
private void Resize(float headerHeight)
360+
{
361+
m_splitterRect = new Rect(0, headerHeight + m_testListHeight, position.width, 5f);
362+
363+
EditorGUIUtility.AddCursorRect(m_splitterRect, MouseCursor.ResizeVertical);
364+
365+
if (Event.current.type == EventType.MouseDown)
366+
m_isResizing = m_splitterRect.Contains(Event.current.mousePosition);
367+
368+
const float minListHeight = 80f;
369+
var maxListHeight = position.height - 240f;
370+
var needMoveSplitterAndRepaint = false;
371+
372+
if (m_isResizing && Event.current.type == EventType.MouseDrag)
373+
{
374+
m_testListHeight = Mathf.Clamp(Event.current.mousePosition.y - headerHeight, minListHeight, maxListHeight);
375+
needMoveSplitterAndRepaint = true;
376+
}
377+
else if (Math.Abs(m_windowHeight - position.height) > float.Epsilon)
378+
{
379+
m_windowHeight = position.height;
380+
m_testListHeight = Mathf.Clamp(m_testListHeight, minListHeight, maxListHeight);
381+
needMoveSplitterAndRepaint = true;
382+
}
383+
384+
if (needMoveSplitterAndRepaint)
385+
{
386+
m_splitterRect.Set(m_splitterRect.x, m_testListHeight, m_splitterRect.width, m_splitterRect.height);
387+
Repaint();
388+
}
389+
390+
if (Event.current.type == EventType.MouseUp)
391+
m_isResizing = false;
392+
}
393+
353394
private void DrawBarGraph(float width, float height, List<double> samples, float min, float max, float median)
354395
{
355396
if (DrawStart(width, height))
@@ -395,7 +436,7 @@ private void DrawBarGraph(float width, float height, List<double> samples, float
395436
{
396437
float sample = (float)samples[i];
397438

398-
string tooltip = string.Format("{0} (at sample {1} of {2})", sample, i, samples.Count);
439+
string tooltip = string.Format("{0} (at sample {1} of {2})", sample, i+1, samples.Count);
399440

400441
GUI.Label(new Rect(rect.x + x, rect.y + y, xAxisInc, height), new GUIContent("", tooltip));
401442

Editor/TestRunBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public void Setup()
2727
run.Dependencies = GetPackageDependencies();
2828
SetBuildSettings(run);
2929

30-
run.Date = (int)Utils.ConvertToUnixTimestamp(DateTime.Now);
30+
run.Date = Utils.ConvertToUnixTimestamp(DateTime.Now);
3131

3232
CreateResourcesFolder();
3333
CreatePerformanceTestRunJson(run);

Runtime/Data/Run.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Unity.PerformanceTesting.Data
88
public class Run
99
{
1010
public string TestSuite;
11-
public int Date;
11+
public long Date;
1212
public Player Player;
1313
public Hardware Hardware;
1414
public Editor Editor;

Runtime/Utils.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@ public static class Utils
1313
public const string TestRunInfo = "PerformanceTestRunInfo.json";
1414
public const string PlayerPrefKeyRunJSON = "PT_Run";
1515

16-
public static DateTime ConvertFromUnixTimestamp(int timestamp)
16+
public static DateTime ConvertFromUnixTimestamp(long timestamp)
1717
{
18-
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
19-
return origin.AddSeconds(timestamp);
18+
var offset = DateTimeOffset.FromUnixTimeMilliseconds(timestamp);
19+
return offset.UtcDateTime;
2020
}
2121

22-
public static int ConvertToUnixTimestamp(DateTime date)
22+
public static long ConvertToUnixTimestamp(DateTime date)
2323
{
24-
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
25-
TimeSpan diff = date.ToUniversalTime() - origin;
26-
return (int)Math.Floor(diff.TotalSeconds);
24+
var offset = new DateTimeOffset(date);
25+
return offset.ToUnixTimeMilliseconds();
2726
}
2827

2928
public class RatioUnit

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "com.unity.test-framework.performance",
33
"displayName": "Performance testing API",
4-
"version": "2.0.9-preview",
4+
"version": "2.1.0-preview",
55
"unity": "2019.3",
66
"unityRelease": "0a10",
77
"description": "Extension to the Unity Test framework package. Adds performance testing capabilities and collects configuration metadata.",
@@ -13,10 +13,12 @@
1313
"com.unity.test-framework": "1.1.0",
1414
"com.unity.nuget.newtonsoft-json": "2.0.0-preview"
1515
},
16+
"upmCi": {
17+
"footprint": "bffa451d2d70421572fe14efb2acbaa69f80eeff"
18+
},
1619
"repository": {
17-
"footprint": "ad9c5c26d28dc49453310f158baf84c774e4f333",
1820
"type": "git",
1921
"url": "https://github.cds.internal.unity3d.com/unity/com.unity.test-framework.performance.git",
20-
"revision": "2c45c9785265b08de6329a51eee72914b21b4be8"
22+
"revision": "4fcf08c79385aef3efa6862e69754565792ef757"
2123
}
2224
}

0 commit comments

Comments
 (0)