mirror of
https://github.com/godotengine/godot-benchmarks.git
synced 2026-01-04 06:10:04 +03:00
Added support for C# benchmarks (#46)
This commit is contained in:
9
Benchmark.cs
Normal file
9
Benchmark.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Godot;
|
||||
|
||||
public partial class Benchmark : RefCounted
|
||||
{
|
||||
public bool test_render_cpu = false;
|
||||
public bool test_render_gpu = false;
|
||||
public bool test_idle = false;
|
||||
public bool test_physics = false;
|
||||
}
|
||||
@@ -5,7 +5,8 @@ Thank you for your interest in contributing!
|
||||
> **Note**
|
||||
>
|
||||
> This project only supports Godot's `master` branch (4.0's development branch),
|
||||
> not Godot 3.x. Attempting to open this project in Godot 3.x will result in errors.
|
||||
> not Godot 3.x.
|
||||
> Attempting to open this project in Godot 3.x will result in errors.
|
||||
|
||||
## Adding new benchmarks
|
||||
|
||||
@@ -23,14 +24,15 @@ you can also create a new folder in the repository's root folder.
|
||||
In the `_init()` function of your script, configure your benchmark by
|
||||
initializing any desired `Benchmark` variables to true:
|
||||
|
||||
- **test_render_cpu:** Enable this for rendering benchmarks.
|
||||
- `test_render_cpu`: Enable this for rendering benchmarks.
|
||||
Leave it disabled for other benchmarks.
|
||||
- **test_render_gpu:** Enable this for rendering benchmarks.
|
||||
- `test_render_gpu`: Enable this for rendering benchmarks.
|
||||
Leave it disabled for other benchmarks.
|
||||
- **test_idle:** Enable this for non-rendering CPU-intensive benchmarks.
|
||||
- `test_idle`: Enable this for non-rendering CPU-intensive benchmarks.
|
||||
Leave it disabled for other benchmarks.
|
||||
- **test_physics:** Enable this for physics benchmarks.
|
||||
- `test_physics`: Enable this for physics benchmarks.
|
||||
Leave it disabled for other benchmarks.
|
||||
- > Leaving all of these disabled will only time the initial call to your `benchmark_` function (see below).
|
||||
|
||||
### Implement the benchmark
|
||||
|
||||
@@ -57,6 +59,9 @@ Remember to follow the
|
||||
when writing new scripts. Adding type hints is recommended whenever possible,
|
||||
unless you are specifically benchmarking non-typed scripts.
|
||||
|
||||
> C# benchmark functions must begin with `Benchmark`, instead of `benchmark_`.
|
||||
> For C# benchmarks to be available, you must use the .NET version of the engine.
|
||||
|
||||
### Test the benchmark
|
||||
|
||||
1. Run the project in the editor.
|
||||
|
||||
9
Godot Benchmarks.csproj
Normal file
9
Godot Benchmarks.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Godot.NET.Sdk/4.3.0-dev.2">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
|
||||
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<RootNamespace>GodotBenchmarks</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
19
Godot Benchmarks.sln
Normal file
19
Godot Benchmarks.sln
Normal file
@@ -0,0 +1,19 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot Benchmarks", "Godot Benchmarks.csproj", "{A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
ExportDebug|Any CPU = ExportDebug|Any CPU
|
||||
ExportRelease|Any CPU = ExportRelease|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
|
||||
{A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
|
||||
{A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
|
||||
{A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,92 +1,76 @@
|
||||
extends Benchmark
|
||||
|
||||
const ITERATIONS = 10_000_000
|
||||
const RANDOM_SEED = preload("res://main.gd").RANDOM_SEED
|
||||
|
||||
var rng := RandomNumberGenerator.new()
|
||||
|
||||
func benchmark_global_scope_randi() -> void:
|
||||
# Reset the random seed to improve reproducibility of this benchmark.
|
||||
seed(RANDOM_SEED)
|
||||
seed(Manager.RANDOM_SEED)
|
||||
for i in ITERATIONS:
|
||||
randi()
|
||||
|
||||
# Reset the random seed again to improve reproducibility of other benchmarks.
|
||||
seed(RANDOM_SEED)
|
||||
|
||||
|
||||
func benchmark_randi() -> void:
|
||||
rng.seed = RANDOM_SEED
|
||||
rng.seed = Manager.RANDOM_SEED
|
||||
for i in ITERATIONS:
|
||||
rng.randi()
|
||||
rng.seed = RANDOM_SEED
|
||||
|
||||
|
||||
func benchmark_global_scope_randf() -> void:
|
||||
seed(RANDOM_SEED)
|
||||
seed(Manager.RANDOM_SEED)
|
||||
for i in ITERATIONS:
|
||||
randf()
|
||||
seed(RANDOM_SEED)
|
||||
|
||||
|
||||
func benchmark_randf() -> void:
|
||||
rng.seed = RANDOM_SEED
|
||||
rng.seed = Manager.RANDOM_SEED
|
||||
for i in ITERATIONS:
|
||||
rng.randf()
|
||||
rng.seed = RANDOM_SEED
|
||||
|
||||
|
||||
func benchmark_global_scope_randi_range() -> void:
|
||||
seed(RANDOM_SEED)
|
||||
seed(Manager.RANDOM_SEED)
|
||||
for i in ITERATIONS:
|
||||
randi_range(1234, 5678)
|
||||
seed(RANDOM_SEED)
|
||||
|
||||
|
||||
func benchmark_randi_range() -> void:
|
||||
rng.seed = RANDOM_SEED
|
||||
rng.seed = Manager.RANDOM_SEED
|
||||
for i in ITERATIONS:
|
||||
rng.randi_range(1234, 5678)
|
||||
rng.seed = RANDOM_SEED
|
||||
|
||||
|
||||
func benchmark_global_scope_randf_range() -> void:
|
||||
seed(RANDOM_SEED)
|
||||
seed(Manager.RANDOM_SEED)
|
||||
for i in ITERATIONS:
|
||||
randf_range(1234.0, 5678.0)
|
||||
seed(RANDOM_SEED)
|
||||
|
||||
|
||||
func benchmark_randf_range() -> void:
|
||||
rng.seed = RANDOM_SEED
|
||||
rng.seed = Manager.RANDOM_SEED
|
||||
for i in ITERATIONS:
|
||||
rng.randf_range(1234.0, 5678.0)
|
||||
rng.seed = RANDOM_SEED
|
||||
|
||||
|
||||
func benchmark_global_scope_randfn() -> void:
|
||||
seed(RANDOM_SEED)
|
||||
seed(Manager.RANDOM_SEED)
|
||||
for i in ITERATIONS:
|
||||
randfn(10.0, 2.0)
|
||||
seed(RANDOM_SEED)
|
||||
|
||||
|
||||
func benchmark_randfn() -> void:
|
||||
rng.seed = RANDOM_SEED
|
||||
rng.seed = Manager.RANDOM_SEED
|
||||
for i in ITERATIONS:
|
||||
rng.randfn(10.0, 2.0)
|
||||
rng.seed = RANDOM_SEED
|
||||
|
||||
|
||||
func benchmark_global_scope_randomize() -> void:
|
||||
seed(RANDOM_SEED)
|
||||
seed(Manager.RANDOM_SEED)
|
||||
for i in ITERATIONS:
|
||||
randomize()
|
||||
seed(RANDOM_SEED)
|
||||
|
||||
|
||||
func benchmark_randomize() -> void:
|
||||
rng.seed = RANDOM_SEED
|
||||
rng.seed = Manager.RANDOM_SEED
|
||||
for i in ITERATIONS:
|
||||
rng.randomize()
|
||||
rng.seed = RANDOM_SEED
|
||||
|
||||
18
benchmarks/csharp/Array.cs
Normal file
18
benchmarks/csharp/Array.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Similar to GDScript Array benchmarks, but using C# Array instead
|
||||
|
||||
public partial class Array : Benchmark
|
||||
{
|
||||
public void BenchmarkFillLoop()
|
||||
{
|
||||
int[] array = new int[10_000_000];
|
||||
|
||||
for(int i = 0; i < array.Length; i++)
|
||||
{ array[i] = 1234; }
|
||||
}
|
||||
|
||||
public void BenchmarkFillMethod()
|
||||
{
|
||||
int[] array = new int[10_000_000];
|
||||
System.Array.Fill(array, 1234);
|
||||
}
|
||||
}
|
||||
7
benchmarks/csharp/Control.cs
Normal file
7
benchmarks/csharp/Control.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
public partial class Control : Benchmark
|
||||
{
|
||||
public void BenchmarkControl()
|
||||
{
|
||||
// An empty test, to act as a control
|
||||
}
|
||||
}
|
||||
26
benchmarks/csharp/ForLoop.cs
Normal file
26
benchmarks/csharp/ForLoop.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
// Similar to GDScript for_loop benchmarks, but using C#
|
||||
|
||||
public partial class ForLoop : Benchmark
|
||||
{
|
||||
private const int ITERATIONS = 1_000_000;
|
||||
|
||||
private int number = 0;
|
||||
|
||||
public void BenchmarkLoopAdd()
|
||||
{
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{
|
||||
number += 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void BenchmarkLoopCall()
|
||||
{
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{
|
||||
Function();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Function(){}
|
||||
}
|
||||
120
benchmarks/csharp/List.cs
Normal file
120
benchmarks/csharp/List.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
// Similar to GDScript Array benchmarks, but using C# List instead
|
||||
|
||||
public partial class List : Benchmark
|
||||
{
|
||||
private const int ITERATIONS = 2_000_000;
|
||||
|
||||
public void BenchmarkInt32List()
|
||||
{
|
||||
List<int> list = new List<int>();
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.Add(i); }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list[i] = 0; }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.RemoveAt(list.Count - 1); }
|
||||
}
|
||||
|
||||
public void BenchmarkInt64List()
|
||||
{
|
||||
List<long> list = new List<long>();
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.Add(i); }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list[i] = 0; }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.RemoveAt(list.Count - 1); }
|
||||
}
|
||||
|
||||
public void BenchmarkFloat32List()
|
||||
{
|
||||
List<float> list = new List<float>();
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.Add(i); }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list[i] = 0; }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.RemoveAt(list.Count - 1); }
|
||||
}
|
||||
|
||||
public void BenchmarkFloat64List()
|
||||
{
|
||||
List<double> list = new List<double>();
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.Add(i); }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list[i] = 0; }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.RemoveAt(list.Count - 1); }
|
||||
}
|
||||
|
||||
public void BenchmarkVector2List()
|
||||
{
|
||||
List<Godot.Vector2> list = new List<Godot.Vector2>();
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.Add(new Godot.Vector2(i, i)); }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list[i] = Godot.Vector2.Zero; }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.RemoveAt(list.Count - 1); }
|
||||
}
|
||||
|
||||
public void BenchmarkVector3List()
|
||||
{
|
||||
List<Godot.Vector3> list = new List<Godot.Vector3>();
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.Add(new Godot.Vector3(i, i, i)); }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list[i] = Godot.Vector3.Zero; }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.RemoveAt(list.Count - 1); }
|
||||
}
|
||||
|
||||
public void BenchmarkColorList()
|
||||
{
|
||||
List<Godot.Color> list = new List<Godot.Color>();
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.Add(new Godot.Color(i, i, i, 1.0f)); }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list[i] = Godot.Colors.Black; }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.RemoveAt(list.Count - 1); }
|
||||
}
|
||||
|
||||
public void BenchmarkStringList()
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.Add("Godot " + i.ToString()); }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list[i] = ""; }
|
||||
|
||||
for(int i = 0; i < ITERATIONS; i++)
|
||||
{ list.RemoveAt(list.Count - 1); }
|
||||
}
|
||||
}
|
||||
128
benchmarks/csharp/physics/RigidBody2D.cs
Normal file
128
benchmarks/csharp/physics/RigidBody2D.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
// Identical benchmark to "rigid_body_2d.gd" but written in C#
|
||||
|
||||
public partial class RigidBody2D : Benchmark
|
||||
{
|
||||
const bool VISUALIZE = true;
|
||||
const double SPREAD_H = 1600.0f;
|
||||
const double SPREAD_V = 800.0f;
|
||||
|
||||
private WorldBoundaryShape2D boundary_shape = new WorldBoundaryShape2D();
|
||||
private RectangleShape2D SquareShape = new RectangleShape2D();
|
||||
private CircleShape2D CircleShape = new CircleShape2D();
|
||||
private QuadMesh SquareMesh = new QuadMesh();
|
||||
private SphereMesh CircleMesh = new SphereMesh();
|
||||
|
||||
public RigidBody2D()
|
||||
{
|
||||
SquareMesh.Size = new Vector2(20.0f, 20.0f);
|
||||
CircleMesh.Radius = 10.0f;
|
||||
CircleMesh.Height = 20.0f;
|
||||
test_physics = true;
|
||||
test_idle = true;
|
||||
}
|
||||
|
||||
public Node2D SetupScene(Func<bool, Godot.RigidBody2D.CcdMode, Godot.RigidBody2D> create_body_func, bool unique_shape, Godot.RigidBody2D.CcdMode ccd_mode, bool boundary, int num_shapes)
|
||||
{
|
||||
Node2D scene_root = new Node2D();
|
||||
|
||||
if(VISUALIZE)
|
||||
{
|
||||
Camera2D camera = new Camera2D() { Position = new Vector2(0.0f, -100.0f), Zoom = new Vector2(0.5f, 0.5f) };
|
||||
scene_root.AddChild(camera);
|
||||
}
|
||||
|
||||
if (boundary)
|
||||
{
|
||||
StaticBody2D pit = new StaticBody2D();
|
||||
pit.AddChild(CreateWall(new Vector2((float)SPREAD_H, 0.0f), -0.1f));
|
||||
pit.AddChild(CreateWall(new Vector2(-(float)SPREAD_H, 0.0f), 0.1f));
|
||||
scene_root.AddChild(pit);
|
||||
}
|
||||
|
||||
for(int i = 0; i < num_shapes; i++)
|
||||
{
|
||||
Godot.RigidBody2D body = create_body_func(unique_shape, ccd_mode);
|
||||
body.Position = new Vector2((float)GD.RandRange(-SPREAD_H, SPREAD_H), (float)GD.RandRange(0.0d, -SPREAD_V));
|
||||
scene_root.AddChild(body);
|
||||
}
|
||||
|
||||
return scene_root;
|
||||
}
|
||||
|
||||
public CollisionShape2D CreateWall(Vector2 position, float rotation)
|
||||
{
|
||||
return new CollisionShape2D() {Shape = boundary_shape, Position = position, Rotation = rotation };
|
||||
}
|
||||
|
||||
public Godot.RigidBody2D CreateRandomShape(bool unique_shape, Godot.RigidBody2D.CcdMode ccd_mode)
|
||||
{
|
||||
switch(GD.RandRange(0,1))
|
||||
{
|
||||
case 0: return CreateSquare(unique_shape, ccd_mode);
|
||||
default: return CreateCircle(unique_shape, ccd_mode);
|
||||
}
|
||||
}
|
||||
|
||||
public Godot.RigidBody2D CreateSquare(bool unique_shape, Godot.RigidBody2D.CcdMode ccd_mode)
|
||||
{
|
||||
Godot.RigidBody2D rigid_body = new Godot.RigidBody2D();
|
||||
CollisionShape2D collision_shape = new CollisionShape2D();
|
||||
rigid_body.ContinuousCd = ccd_mode;
|
||||
|
||||
if(VISUALIZE) { rigid_body.AddChild(new MeshInstance2D(){ Mesh = SquareMesh }); }
|
||||
|
||||
if (unique_shape) { collision_shape.Shape = new RectangleShape2D(); }
|
||||
else { collision_shape.Shape = SquareShape; }
|
||||
|
||||
rigid_body.AddChild(collision_shape);
|
||||
return rigid_body;
|
||||
}
|
||||
|
||||
public Godot.RigidBody2D CreateCircle(bool unique_shape, Godot.RigidBody2D.CcdMode ccd_mode)
|
||||
{
|
||||
Godot.RigidBody2D rigid_body = new Godot.RigidBody2D();
|
||||
CollisionShape2D collision_shape = new CollisionShape2D();
|
||||
rigid_body.ContinuousCd = ccd_mode;
|
||||
|
||||
if(VISUALIZE) { rigid_body.AddChild(new MeshInstance2D(){ Mesh = CircleMesh }); }
|
||||
|
||||
if (unique_shape) { collision_shape.Shape = new CircleShape2D(); }
|
||||
else { collision_shape.Shape = CircleShape; }
|
||||
|
||||
rigid_body.AddChild(collision_shape);
|
||||
return rigid_body;
|
||||
}
|
||||
|
||||
public Node2D Benchmark2000RigidBody2DSquares()
|
||||
{
|
||||
return SetupScene(CreateSquare, false, Godot.RigidBody2D.CcdMode.Disabled, true, 2000);
|
||||
}
|
||||
|
||||
public Node2D Benchmark2000RigidBody2DCircles()
|
||||
{
|
||||
return SetupScene(CreateCircle, false, Godot.RigidBody2D.CcdMode.Disabled, true, 2000);
|
||||
}
|
||||
|
||||
public Node2D Benchmark2000RigidBody2DMixed()
|
||||
{
|
||||
return SetupScene(CreateRandomShape, false, Godot.RigidBody2D.CcdMode.Disabled, true, 2000);
|
||||
}
|
||||
|
||||
public Node2D Benchmark2000RigidBody2DUnique()
|
||||
{
|
||||
return SetupScene(CreateRandomShape, true, Godot.RigidBody2D.CcdMode.Disabled, true, 2000);
|
||||
}
|
||||
|
||||
public Node2D Benchmark2000RigidBody2DContinuous()
|
||||
{
|
||||
return SetupScene(CreateRandomShape, false, Godot.RigidBody2D.CcdMode.CastShape, true, 2000);
|
||||
}
|
||||
|
||||
public Node2D Benchmark2000RigidBody2DUnbound()
|
||||
{
|
||||
return SetupScene(CreateRandomShape, false, Godot.RigidBody2D.CcdMode.Disabled, false, 2000);
|
||||
}
|
||||
}
|
||||
128
benchmarks/csharp/physics/RigidBody3D.cs
Normal file
128
benchmarks/csharp/physics/RigidBody3D.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
// Identical benchmark to "rigid_body_3d.gd" but written in C#
|
||||
|
||||
public partial class RigidBody3D : Benchmark
|
||||
{
|
||||
const bool VISUALIZE = true;
|
||||
const double SPREAD_H = 20.0f;
|
||||
const double SPREAD_V = 10.0f;
|
||||
|
||||
private WorldBoundaryShape3D boundary_shape = new WorldBoundaryShape3D();
|
||||
private BoxShape3D BoxShape = new BoxShape3D();
|
||||
private SphereShape3D SphereShape = new SphereShape3D();
|
||||
private BoxMesh BoxMesh = new BoxMesh();
|
||||
private SphereMesh SphereMesh = new SphereMesh();
|
||||
|
||||
public RigidBody3D()
|
||||
{
|
||||
test_physics = true;
|
||||
test_idle = true;
|
||||
}
|
||||
|
||||
public Node3D SetupScene(Func<bool, bool, Godot.RigidBody3D> create_body_func, bool unique_shape, bool ccd_mode, bool boundary, int num_shapes)
|
||||
{
|
||||
Node3D scene_root = new Node3D();
|
||||
|
||||
if(VISUALIZE)
|
||||
{
|
||||
Camera3D camera = new Camera3D() { Position = new Vector3(0.0f, 20.0f, 20.0f) };
|
||||
camera.RotateX(-0.8f);
|
||||
scene_root.AddChild(camera);
|
||||
}
|
||||
|
||||
if (boundary)
|
||||
{
|
||||
StaticBody3D pit = new StaticBody3D();
|
||||
pit.AddChild(CreateWall(new Vector3((float)SPREAD_H, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 0.2f)));
|
||||
pit.AddChild(CreateWall(new Vector3(0.0f, 0.0f, (float)SPREAD_H), new Vector3(-0.2f, 0.0f, 0.0f)));
|
||||
pit.AddChild(CreateWall(new Vector3(-(float)SPREAD_H, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, -0.2f)));
|
||||
pit.AddChild(CreateWall(new Vector3(0.0f, 0.0f, -(float)SPREAD_H), new Vector3(0.2f, 0.0f, 0.0f)));
|
||||
scene_root.AddChild(pit);
|
||||
}
|
||||
|
||||
for(int i = 0; i < num_shapes; i++)
|
||||
{
|
||||
Godot.RigidBody3D body = create_body_func(unique_shape, ccd_mode);
|
||||
body.Position = new Vector3((float)GD.RandRange(-SPREAD_H, SPREAD_H), (float)GD.RandRange(0.0d, SPREAD_V), (float)GD.RandRange(-SPREAD_H, SPREAD_H));
|
||||
scene_root.AddChild(body);
|
||||
}
|
||||
|
||||
return scene_root;
|
||||
}
|
||||
|
||||
public CollisionShape3D CreateWall(Vector3 position, Vector3 rotation)
|
||||
{
|
||||
return new CollisionShape3D() {Shape = boundary_shape, Position = position, Rotation = rotation };
|
||||
}
|
||||
|
||||
public Godot.RigidBody3D CreateRandomShape(bool unique_shape, bool ccd_mode)
|
||||
{
|
||||
switch(GD.RandRange(0,1))
|
||||
{
|
||||
case 0: return CreateBox(unique_shape, ccd_mode);
|
||||
default: return CreateSphere(unique_shape, ccd_mode);
|
||||
}
|
||||
}
|
||||
|
||||
public Godot.RigidBody3D CreateBox(bool unique_shape, bool ccd_mode)
|
||||
{
|
||||
Godot.RigidBody3D rigid_body = new Godot.RigidBody3D();
|
||||
CollisionShape3D collision_shape = new CollisionShape3D();
|
||||
rigid_body.ContinuousCd = ccd_mode;
|
||||
|
||||
if(VISUALIZE) { rigid_body.AddChild(new MeshInstance3D(){ Mesh = BoxMesh }); }
|
||||
|
||||
if (unique_shape) { collision_shape.Shape = new BoxShape3D(); }
|
||||
else { collision_shape.Shape = BoxShape; }
|
||||
|
||||
rigid_body.AddChild(collision_shape);
|
||||
return rigid_body;
|
||||
}
|
||||
|
||||
public Godot.RigidBody3D CreateSphere(bool unique_shape, bool ccd_mode)
|
||||
{
|
||||
Godot.RigidBody3D rigid_body = new Godot.RigidBody3D();
|
||||
CollisionShape3D collision_shape = new CollisionShape3D();
|
||||
rigid_body.ContinuousCd = ccd_mode;
|
||||
|
||||
if(VISUALIZE) { rigid_body.AddChild(new MeshInstance3D(){ Mesh = SphereMesh }); }
|
||||
|
||||
if (unique_shape) { collision_shape.Shape = new SphereShape3D(); }
|
||||
else { collision_shape.Shape = SphereShape; }
|
||||
|
||||
rigid_body.AddChild(collision_shape);
|
||||
return rigid_body;
|
||||
}
|
||||
|
||||
public Node3D Benchmark2000RigidBody3DSquares()
|
||||
{
|
||||
return SetupScene(CreateBox, false, false, true, 2000);
|
||||
}
|
||||
|
||||
public Node3D Benchmark2000RigidBody3DCircles()
|
||||
{
|
||||
return SetupScene(CreateSphere, false, false, true, 2000);
|
||||
}
|
||||
|
||||
public Node3D Benchmark2000RigidBody3DMixed()
|
||||
{
|
||||
return SetupScene(CreateRandomShape, false, false, true, 2000);
|
||||
}
|
||||
|
||||
public Node3D Benchmark2000RigidBody3DUnique()
|
||||
{
|
||||
return SetupScene(CreateRandomShape, true, false, true, 2000);
|
||||
}
|
||||
|
||||
public Node3D Benchmark2000RigidBody3DContinuous()
|
||||
{
|
||||
return SetupScene(CreateRandomShape, false, true, true, 2000);
|
||||
}
|
||||
|
||||
public Node3D Benchmark2000RigidBody3DUnbound()
|
||||
{
|
||||
return SetupScene(CreateRandomShape, false, false, false, 2000);
|
||||
}
|
||||
}
|
||||
6
benchmarks/gdscript/control.gd
Normal file
6
benchmarks/gdscript/control.gd
Normal file
@@ -0,0 +1,6 @@
|
||||
extends Benchmark
|
||||
|
||||
# An empty test, to act as a control
|
||||
|
||||
func benchmark_control():
|
||||
pass
|
||||
119
benchmarks/physics/rigid_body_2d.gd
Normal file
119
benchmarks/physics/rigid_body_2d.gd
Normal file
@@ -0,0 +1,119 @@
|
||||
extends Benchmark
|
||||
|
||||
const VISUALIZE := true
|
||||
const SPREAD_H := 1600.0;
|
||||
const SPREAD_V := 800.0;
|
||||
|
||||
var boundary_shape := WorldBoundaryShape2D.new()
|
||||
var square_shape := RectangleShape2D.new()
|
||||
var circle_shape := CircleShape2D.new()
|
||||
var square_mesh := QuadMesh.new()
|
||||
var circle_mesh := SphereMesh.new()
|
||||
|
||||
func _init() -> void:
|
||||
square_mesh.size = Vector2(20.0, 20.0);
|
||||
circle_mesh.radius = 10.0;
|
||||
circle_mesh.height = 20.0;
|
||||
test_physics = true
|
||||
test_idle = true
|
||||
|
||||
|
||||
func setup_scene(create_body_func: Callable, unique_shape: bool, ccd_mode: RigidBody2D.CCDMode, boundary: bool, num_shapes: int) -> Node2D:
|
||||
var scene_root := Node2D.new()
|
||||
|
||||
if VISUALIZE:
|
||||
var camera := Camera2D.new()
|
||||
camera.position = Vector2(0.0, -100.0)
|
||||
camera.zoom = Vector2(0.5, 0.5)
|
||||
scene_root.add_child(camera)
|
||||
|
||||
if boundary:
|
||||
var pit := StaticBody2D.new();
|
||||
pit.add_child(create_wall(Vector2(SPREAD_H, 0.0), -0.1))
|
||||
pit.add_child(create_wall(Vector2(-SPREAD_H, 0.0), 0.1))
|
||||
scene_root.add_child(pit);
|
||||
|
||||
for _i in num_shapes:
|
||||
var body: RigidBody2D = create_body_func.call(unique_shape, ccd_mode)
|
||||
body.position = Vector2(randf_range(-SPREAD_H, SPREAD_H), randf_range(0.0, -SPREAD_V))
|
||||
scene_root.add_child(body)
|
||||
|
||||
return scene_root
|
||||
|
||||
|
||||
func create_wall(position: Vector2, rotation: float) -> CollisionShape2D:
|
||||
var wall := CollisionShape2D.new()
|
||||
wall.shape = boundary_shape
|
||||
wall.position = position
|
||||
wall.rotation = rotation
|
||||
return wall
|
||||
|
||||
|
||||
func create_random_shape(unique_shape: bool, ccd_mode: RigidBody2D.CCDMode) -> RigidBody2D:
|
||||
match randi_range(0, 1):
|
||||
0: return create_square(unique_shape, ccd_mode)
|
||||
_: return create_circle(unique_shape, ccd_mode)
|
||||
|
||||
|
||||
func create_square(unique_shape: bool, ccd_mode: RigidBody2D.CCDMode) -> RigidBody2D:
|
||||
var rigid_body := RigidBody2D.new()
|
||||
var collision_shape := CollisionShape2D.new()
|
||||
rigid_body.continuous_cd = ccd_mode
|
||||
|
||||
if VISUALIZE:
|
||||
var mesh_instance := MeshInstance2D.new()
|
||||
mesh_instance.mesh = square_mesh
|
||||
rigid_body.add_child(mesh_instance)
|
||||
|
||||
if unique_shape:
|
||||
collision_shape.shape = RectangleShape2D.new()
|
||||
else:
|
||||
# Reuse existing shape.
|
||||
collision_shape.shape = square_shape
|
||||
rigid_body.add_child(collision_shape)
|
||||
|
||||
return rigid_body
|
||||
|
||||
|
||||
func create_circle(unique_shape: bool, ccd_mode: RigidBody2D.CCDMode) -> RigidBody2D:
|
||||
var rigid_body := RigidBody2D.new()
|
||||
var collision_shape := CollisionShape2D.new()
|
||||
rigid_body.continuous_cd = ccd_mode
|
||||
|
||||
if VISUALIZE:
|
||||
var mesh_instance := MeshInstance2D.new()
|
||||
mesh_instance.mesh = circle_mesh
|
||||
rigid_body.add_child(mesh_instance)
|
||||
|
||||
if unique_shape:
|
||||
collision_shape.shape = CircleShape2D.new()
|
||||
else:
|
||||
# Reuse existing shape.
|
||||
collision_shape.shape = circle_shape
|
||||
rigid_body.add_child(collision_shape)
|
||||
|
||||
return rigid_body
|
||||
|
||||
|
||||
func benchmark_2000_rigid_body_2d_squares() -> Node2D:
|
||||
return setup_scene(create_square, false, RigidBody2D.CCD_MODE_DISABLED, true, 2000)
|
||||
|
||||
|
||||
func benchmark_2000_rigid_body_2d_circles() -> Node2D:
|
||||
return setup_scene(create_circle, false, RigidBody2D.CCD_MODE_DISABLED, true, 2000)
|
||||
|
||||
|
||||
func benchmark_2000_rigid_body_2d_mixed() -> Node2D:
|
||||
return setup_scene(create_random_shape, false, RigidBody2D.CCD_MODE_DISABLED, true, 2000)
|
||||
|
||||
|
||||
func benchmark_2000_rigid_body_2d_unique() -> Node2D:
|
||||
return setup_scene(create_random_shape, true, RigidBody2D.CCD_MODE_DISABLED, true, 2000)
|
||||
|
||||
|
||||
func benchmark_2000_rigid_body_2d_continuous() -> Node2D:
|
||||
return setup_scene(create_random_shape, false, RigidBody2D.CCD_MODE_CAST_SHAPE, true, 2000)
|
||||
|
||||
|
||||
func benchmark_2000_rigid_body_2d_unbound() -> Node2D:
|
||||
return setup_scene(create_random_shape, false, RigidBody2D.CCD_MODE_DISABLED, false, 2000)
|
||||
@@ -1,34 +1,69 @@
|
||||
extends Benchmark
|
||||
|
||||
const VISUALIZE := true
|
||||
const SPREAD_H := 20.0;
|
||||
const SPREAD_V := 10.0;
|
||||
|
||||
var boundary_shape := WorldBoundaryShape3D.new()
|
||||
var box_shape := BoxShape3D.new()
|
||||
var sphere_shape := SphereShape3D.new()
|
||||
var box_mesh := BoxMesh.new()
|
||||
var sphere_mesh := SphereMesh.new()
|
||||
|
||||
func _init() -> void:
|
||||
test_physics = true
|
||||
test_idle = true
|
||||
|
||||
|
||||
func setup_scene(create_body_func: Callable, unique_shape: bool, num_shapes: int) -> Node3D:
|
||||
func setup_scene(create_body_func: Callable, unique_shape: bool, ccd_mode: bool, boundary: bool, num_shapes: int) -> Node3D:
|
||||
var scene_root := Node3D.new()
|
||||
var camera := Camera3D.new()
|
||||
camera.position.y = 0.3
|
||||
camera.position.z = 1.0
|
||||
camera.rotate_x(-0.8)
|
||||
scene_root.add_child(camera)
|
||||
|
||||
if VISUALIZE:
|
||||
var camera := Camera3D.new()
|
||||
camera.position = Vector3(0.0, 20.0, 20.0)
|
||||
camera.rotate_x(-0.8)
|
||||
scene_root.add_child(camera)
|
||||
|
||||
if boundary:
|
||||
var pit := StaticBody3D.new();
|
||||
pit.add_child(create_wall(Vector3(SPREAD_H, 0.0, 0.0), Vector3(0.0, 0.0, 0.2)))
|
||||
pit.add_child(create_wall(Vector3(0.0, 0.0, SPREAD_H), Vector3(-0.2, 0.0, 0.0)))
|
||||
pit.add_child(create_wall(Vector3(-SPREAD_H, 0.0, 0.0), Vector3(0.0, 0.0, -0.2)))
|
||||
pit.add_child(create_wall(Vector3(0.0, 0.0, -SPREAD_H), Vector3(0.2, 0.0, 0.0)))
|
||||
scene_root.add_child(pit);
|
||||
|
||||
for _i in num_shapes:
|
||||
var box: RigidBody3D = create_body_func.call(unique_shape)
|
||||
box.position.x = randf_range(-50, 50)
|
||||
box.position.z = randf_range(-50, 50)
|
||||
scene_root.add_child(box)
|
||||
var body: RigidBody3D = create_body_func.call(unique_shape, ccd_mode)
|
||||
body.position = Vector3(randf_range(-SPREAD_H, SPREAD_H), randf_range(0.0, SPREAD_V), randf_range(-SPREAD_H, SPREAD_H))
|
||||
scene_root.add_child(body)
|
||||
|
||||
return scene_root
|
||||
|
||||
|
||||
func create_box(unique_shape: bool) -> RigidBody3D:
|
||||
var rigid_body := RigidBody3D.new()
|
||||
func create_wall(position: Vector3, rotation: Vector3) -> CollisionShape3D:
|
||||
var wall := CollisionShape3D.new()
|
||||
wall.shape = boundary_shape
|
||||
wall.position = position
|
||||
wall.rotation = rotation
|
||||
return wall
|
||||
|
||||
|
||||
func create_random_shape(unique_shape: bool, ccd_mode: bool) -> RigidBody3D:
|
||||
match randi_range(0, 1):
|
||||
0: return create_box(unique_shape, ccd_mode)
|
||||
_: return create_sphere(unique_shape, ccd_mode)
|
||||
|
||||
|
||||
func create_box(unique_shape: bool, ccd_mode: bool) -> RigidBody3D:
|
||||
var rigid_body := RigidBody3D.new()
|
||||
var collision_shape := CollisionShape3D.new()
|
||||
rigid_body.continuous_cd = ccd_mode
|
||||
|
||||
if VISUALIZE:
|
||||
var mesh_instance := MeshInstance3D.new()
|
||||
mesh_instance.mesh = box_mesh
|
||||
rigid_body.add_child(mesh_instance)
|
||||
|
||||
if unique_shape:
|
||||
collision_shape.shape = BoxShape3D.new()
|
||||
else:
|
||||
@@ -39,10 +74,16 @@ func create_box(unique_shape: bool) -> RigidBody3D:
|
||||
return rigid_body
|
||||
|
||||
|
||||
func create_sphere(unique_shape: bool) -> RigidBody3D:
|
||||
func create_sphere(unique_shape: bool, ccd_mode: bool) -> RigidBody3D:
|
||||
var rigid_body := RigidBody3D.new()
|
||||
|
||||
var collision_shape := CollisionShape3D.new()
|
||||
rigid_body.continuous_cd = ccd_mode
|
||||
|
||||
if VISUALIZE:
|
||||
var mesh_instance := MeshInstance3D.new()
|
||||
mesh_instance.mesh = sphere_mesh
|
||||
rigid_body.add_child(mesh_instance)
|
||||
|
||||
if unique_shape:
|
||||
collision_shape.shape = SphereShape3D.new()
|
||||
else:
|
||||
@@ -53,17 +94,25 @@ func create_sphere(unique_shape: bool) -> RigidBody3D:
|
||||
return rigid_body
|
||||
|
||||
|
||||
func benchmark_7500_rigid_body_3d_shared_box_shape() -> Node3D:
|
||||
return setup_scene(create_box, false, 7500)
|
||||
func benchmark_2000_rigid_body_3d_boxes() -> Node3D:
|
||||
return setup_scene(create_box, false, false, true, 2000)
|
||||
|
||||
|
||||
func benchmark_7500_rigid_body_3d_unique_box_shape() -> Node3D:
|
||||
return setup_scene(create_box, true, 7500)
|
||||
func benchmark_2000_rigid_body_3d_spheres() -> Node3D:
|
||||
return setup_scene(create_sphere, false, false, true, 2000)
|
||||
|
||||
|
||||
func benchmark_7500_rigid_body_3d_shared_sphere_shape() -> Node3D:
|
||||
return setup_scene(create_sphere, false, 7500)
|
||||
func benchmark_2000_rigid_body_3d_mixed() -> Node3D:
|
||||
return setup_scene(create_random_shape, false, false, true, 2000)
|
||||
|
||||
|
||||
func benchmark_7500_rigid_body_3d_unique_sphere_shape() -> Node3D:
|
||||
return setup_scene(create_sphere, true, 7500)
|
||||
func benchmark_2000_rigid_body_3d_unique() -> Node3D:
|
||||
return setup_scene(create_random_shape, true, false, true, 2000)
|
||||
|
||||
|
||||
func benchmark_2000_rigid_body_3d_continuous() -> Node3D:
|
||||
return setup_scene(create_random_shape, false, true, true, 2000)
|
||||
|
||||
|
||||
func benchmark_2000_rigid_body_3d_unbound() -> Node3D:
|
||||
return setup_scene(create_random_shape, false, false, false, 2000)
|
||||
|
||||
@@ -7,7 +7,7 @@ func _init():
|
||||
|
||||
class TestScene extends Node3D:
|
||||
|
||||
var scene = preload("res://benchmarks/rendering/very_large_scene.tscn")
|
||||
var scene = preload("res://supplemental/very_large_scene.tscn")
|
||||
var instance
|
||||
var world_env: WorldEnvironment = null
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ func _init():
|
||||
|
||||
class TestScene extends Node3D:
|
||||
|
||||
var sponza_scene = preload("res://benchmarks/rendering/sponza.tscn")
|
||||
var sponza_scene = preload("res://supplemental/sponza.tscn")
|
||||
var sponza
|
||||
var world_env: WorldEnvironment = null
|
||||
|
||||
|
||||
15
main.gd
15
main.gd
@@ -1,7 +1,5 @@
|
||||
extends Panel
|
||||
|
||||
const RANDOM_SEED = 0x60d07
|
||||
|
||||
var items := []
|
||||
|
||||
# Prefix variables with `arg_` to have them automatically be parsed from command line arguments
|
||||
@@ -11,11 +9,9 @@ var arg_save_json := ""
|
||||
var arg_run_benchmarks := false
|
||||
|
||||
@onready var tree := $Tree as Tree
|
||||
var categories := {}
|
||||
|
||||
func _ready() -> void:
|
||||
# Use a fixed random seed to improve reproducibility of results.
|
||||
seed(RANDOM_SEED)
|
||||
|
||||
# Parse valid command-line arguments of the form `--key=value` into member variables.
|
||||
for argument in OS.get_cmdline_user_args():
|
||||
if not argument.begins_with("--"):
|
||||
@@ -50,7 +46,6 @@ func _ready() -> void:
|
||||
tree.set_column_title(5, "Main Thread Time")
|
||||
|
||||
var root := tree.create_item()
|
||||
var categories := {}
|
||||
|
||||
for test_id in Manager.get_test_ids():
|
||||
var test_name := test_id.pretty_name()
|
||||
@@ -75,10 +70,10 @@ func _ready() -> void:
|
||||
# from the interface after the fact.
|
||||
item.set_checked(0, true)
|
||||
if arg_include_benchmarks:
|
||||
if not path.match(arg_include_benchmarks):
|
||||
if not path.matchn(arg_include_benchmarks):
|
||||
item.set_checked(0, false)
|
||||
if arg_exclude_benchmarks:
|
||||
if path.match(arg_exclude_benchmarks):
|
||||
if path.matchn(arg_exclude_benchmarks):
|
||||
item.set_checked(0, false)
|
||||
|
||||
var results := Manager.get_test_result_as_dict(test_id)
|
||||
@@ -100,12 +95,16 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _on_SelectAll_pressed() -> void:
|
||||
for category in categories.values():
|
||||
category.collapsed = false
|
||||
for item in items:
|
||||
item.set_checked(0, true)
|
||||
_on_Tree_item_edited()
|
||||
|
||||
|
||||
func _on_SelectNone_pressed() -> void:
|
||||
for category in categories.values():
|
||||
category.collapsed = true
|
||||
for item in items:
|
||||
item.set_checked(0, false)
|
||||
_on_Tree_item_edited()
|
||||
|
||||
63
manager.gd
63
manager.gd
@@ -1,5 +1,7 @@
|
||||
extends Node
|
||||
|
||||
const RANDOM_SEED = 0x60d07
|
||||
|
||||
class Results:
|
||||
var render_cpu := 0.0
|
||||
var render_gpu := 0.0
|
||||
@@ -10,6 +12,7 @@ class Results:
|
||||
class TestID:
|
||||
var name : String
|
||||
var category : String
|
||||
var language : String
|
||||
|
||||
func pretty_name() -> String:
|
||||
return name.capitalize()
|
||||
@@ -24,24 +27,29 @@ class TestID:
|
||||
|
||||
func test_ids_from_path(path: String) -> Array[TestID]:
|
||||
var rv : Array[TestID] = []
|
||||
if not path.ends_with(".gd"):
|
||||
return rv
|
||||
|
||||
var script = load(path).new()
|
||||
if not (script is Benchmark):
|
||||
return rv
|
||||
|
||||
var bench_script : Benchmark = script
|
||||
for method in bench_script.get_method_list():
|
||||
if not method.name.begins_with("benchmark_"):
|
||||
# Check for runnable tests.
|
||||
for extension in languages.keys():
|
||||
if not path.ends_with(extension):
|
||||
continue
|
||||
|
||||
var test_id := TestID.new()
|
||||
test_id.name = method.name.trim_prefix("benchmark_")
|
||||
test_id.category = path.trim_prefix("res://benchmarks/").trim_suffix(".gd")
|
||||
rv.push_back(test_id)
|
||||
return rv
|
||||
var bench_script = load(path).new()
|
||||
for method in bench_script.get_method_list():
|
||||
if not method.name.begins_with(languages[extension]["test_prefix"]):
|
||||
continue
|
||||
|
||||
# This method is a runnable test. Push it onto the result
|
||||
var test_id := TestID.new()
|
||||
test_id.name = method.name.trim_prefix(languages[extension]["test_prefix"])
|
||||
test_id.category = path.trim_prefix("res://benchmarks/").trim_suffix(extension)
|
||||
test_id.language = extension
|
||||
rv.push_back(test_id)
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
# List of supported languages and their styles.
|
||||
var languages := {".gd": {"test_prefix": "benchmark_"}}
|
||||
|
||||
# List of benchmarks populated in `_ready()`.
|
||||
var test_results := {}
|
||||
@@ -72,6 +80,10 @@ func _ready():
|
||||
RenderingServer.viewport_set_measure_render_time(get_tree().root.get_viewport_rid(),true)
|
||||
set_process(false)
|
||||
|
||||
# Register script language compatibility
|
||||
if Engine.has_singleton("GodotSharp"):
|
||||
languages[".cs"] = {"test_prefix": "Benchmark"}
|
||||
|
||||
# Register contents of `benchmarks/` folder automatically.
|
||||
for benchmark_path in dir_contents("res://benchmarks/"):
|
||||
for test_id in test_ids_from_path(benchmark_path):
|
||||
@@ -93,7 +105,9 @@ func benchmark(test_ids: Array[TestID], return_path: String) -> void:
|
||||
for i in range(test_ids.size()):
|
||||
DisplayServer.window_set_title("%d/%d - Running %s" % [i + 1, test_ids.size(), test_ids[i].pretty()])
|
||||
print("Running benchmark %d of %d: %s" % [i + 1, test_ids.size(), test_ids[i]])
|
||||
seed(RANDOM_SEED)
|
||||
await run_test(test_ids[i])
|
||||
print("Result: %s\n" % get_result_as_string(test_ids[i]))
|
||||
|
||||
DisplayServer.window_set_title("[DONE] %d benchmarks - Godot Benchmarks" % test_ids.size())
|
||||
print_rich("[color=green][b]Done running %d benchmarks.[/b] Results JSON:[/color]\n" % test_ids.size())
|
||||
@@ -111,6 +125,7 @@ func benchmark(test_ids: Array[TestID], return_path: String) -> void:
|
||||
if return_path:
|
||||
get_tree().change_scene_to_file(return_path)
|
||||
else:
|
||||
get_tree().queue_delete(get_tree())
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
@@ -128,13 +143,15 @@ func run_test(test_id: TestID) -> void:
|
||||
# Add a dummy child so that the above check works for subsequent reloads
|
||||
get_tree().current_scene.add_child(Node.new())
|
||||
|
||||
var benchmark_script : Benchmark = load("res://benchmarks/%s.gd" % test_id.category).new()
|
||||
|
||||
var bench_script = load("res://benchmarks/%s%s" % [test_id.category, test_id.language]).new()
|
||||
var results := Results.new()
|
||||
|
||||
# Call and time the function to be tested
|
||||
var begin_time := Time.get_ticks_usec()
|
||||
var bench_node = benchmark_script.call("benchmark_" + test_id.name)
|
||||
var bench_node = bench_script.call(languages[test_id.language]["test_prefix"] + test_id.name)
|
||||
results.time = (Time.get_ticks_usec() - begin_time) * 0.001
|
||||
|
||||
# Continue benchmarking if the function call has returned a node
|
||||
var frames_captured := 0
|
||||
if bench_node:
|
||||
get_tree().current_scene.add_child(bench_node)
|
||||
@@ -166,11 +183,21 @@ func run_test(test_id: TestID) -> void:
|
||||
# metrics calculated on a per-second basis.
|
||||
|
||||
for metric in results.get_property_list():
|
||||
if benchmark_script.get("test_" + metric.name) == false: # account for null
|
||||
if bench_script.get("test_" + metric.name) == false: # account for null
|
||||
results.set(metric.name, 0.0)
|
||||
|
||||
test_results[test_id] = results
|
||||
|
||||
func get_result_as_string(test_id: TestID) -> String:
|
||||
# Returns all non-zero metrics formatted as a string
|
||||
var rd := get_test_result_as_dict(test_id)
|
||||
|
||||
for key in rd.keys():
|
||||
if rd[key] == 0.0:
|
||||
rd.erase(key)
|
||||
|
||||
return JSON.stringify(rd)
|
||||
|
||||
func get_test_result_as_dict(test_id: TestID) -> Dictionary:
|
||||
var result : Results = test_results[test_id]
|
||||
var rv := {}
|
||||
|
||||
@@ -29,6 +29,10 @@ window/size/viewport_width=1920
|
||||
window/size/viewport_height=1080
|
||||
window/stretch/mode="viewport"
|
||||
|
||||
[dotnet]
|
||||
|
||||
project/assembly_name="Godot Benchmarks"
|
||||
|
||||
[gui]
|
||||
|
||||
theme/default_theme_scale=1.5
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[gd_scene load_steps=6 format=3 uid="uid://33dqw5jcha0h"]
|
||||
|
||||
[ext_resource type="Script" path="res://benchmarks/rendering/camera_move.gd" id="1_vqkte"]
|
||||
[ext_resource type="Script" path="res://supplemental/camera_move.gd" id="1_vqkte"]
|
||||
|
||||
|
||||
[sub_resource type="Environment" id="Environment_itcjv"]
|
||||
|
||||
Reference in New Issue
Block a user