Merge pull request #2 from reduz/new-benchmarks

Add a benchmarking suite
This commit is contained in:
Juan Linietsky
2020-12-24 00:03:02 -03:00
committed by GitHub
17 changed files with 678 additions and 0 deletions

34
benchmark.gd Normal file
View File

@@ -0,0 +1,34 @@
extends Label
class_name Benchmark
# Declare member variables here. Examples:
# var a = 2
# var b = "text"
@export var test_render_cpu : = false
@export var test_render_gpu : = false
@export var test_idle : = false
@export var test_physics : = false
# Called when the node enters the scene tree for the first time.
func _process(delta):
var txt = ""
if (test_render_cpu):
txt+=str("CPU: ",RenderingServer.viewport_get_measured_render_time_cpu(get_tree().root.get_viewport_rid()) + RenderingServer.get_frame_setup_time_cpu(),"\n")
if (test_render_gpu):
txt+=str("GPU: ",RenderingServer.viewport_get_measured_render_time_gpu(get_tree().root.get_viewport_rid()) ,"\n")
text = txt
func _ready():
add_to_group("bechnmark_config")
if (Manager.is_recording()):
set_process(false)
hide()
add_theme_color_override("font_color",Color(1,1,1))
add_theme_color_override("font_color_shadow",Color(0,0,0))
add_theme_constant_override("outline_size",2)
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

78
main.gd Normal file
View File

@@ -0,0 +1,78 @@
extends Panel
var items = []
func _ready():
$Tree.columns = 5
$Tree.set_column_titles_visible(true)
$Tree.set_column_title(0,"Test Name")
$Tree.set_column_title(1,"Render CPU")
$Tree.set_column_title(2,"Render GPU")
$Tree.set_column_title(3,"Idle")
$Tree.set_column_title(4,"Physics")
var root = $Tree.create_item()
var categories = {}
for i in range(Manager.get_test_count()):
var name = Manager.get_test_name(i)
var category = Manager.get_test_category(i)
var results = Manager.get_test_result(i)
if (not category in categories):
var c = $Tree.create_item(root) as TreeItem
c.set_text(0,category)
categories[category]=c
var item = $Tree.create_item(categories[category]) as TreeItem
item.set_cell_mode(0,TreeItem.CELL_MODE_CHECK)
item.set_text(0,name)
item.set_editable(0,true)
if results:
if (results.render_cpu):
item.set_text(1,str(results.render_cpu," ms"))
if (results.render_gpu):
item.set_text(2,str(results.render_gpu," ms"))
if (results.idle):
item.set_text(3,str(results.idle," ms"))
if (results.physics):
item.set_text(4,str(results.physics," ms"))
items.append(item)
func _on_SelectAll_pressed():
for it in items:
it.set_checked(0,true)
_on_Tree_item_edited()
func _on_SelectNone_pressed():
for it in items:
it.set_checked(0,false)
_on_Tree_item_edited()
func _on_CopyJSON_pressed():
pass # Replace with function body.
func _on_Run_pressed():
if ($Run.disabled):
return
var queue=[]
var idx = 0
for it in items:
if (it.is_checked(0)):
queue.append(idx)
idx+=1
if (idx==0):
return
Manager.benchmark(queue,$TestTime.value,"res://main.tscn")
func _on_Tree_item_edited():
$Run.disabled = true
for it in items:
if (it.is_checked(0)):
$Run.disabled = false
break

119
main.tscn Normal file
View File

@@ -0,0 +1,119 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://main.gd" type="Script" id=1]
[node name="Main" type="Panel"]
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="."]
offset_left = 24.0
offset_top = 16.0
offset_right = 146.0
offset_bottom = 56.0
text = "Available Benchmarks:"
structured_text_bidi_override_options = [ ]
script = null
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Tree" type="Tree" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 24.0
offset_top = 40.0
offset_right = -18.0
offset_bottom = -45.0
script = null
[node name="SelectAll" type="Button" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -520.0
offset_top = -32.0
offset_right = -438.0
offset_bottom = -12.0
rect_pivot_offset = Vector2( 41, 20 )
text = "Select All"
script = null
[node name="SelectNone" type="Button" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -424.0
offset_top = -32.0
offset_right = -335.0
offset_bottom = -12.0
rect_pivot_offset = Vector2( 41, 20 )
text = "Select None"
script = null
[node name="CopyJSON" type="Button" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -320.0
offset_top = -32.0
offset_right = -162.0
offset_bottom = -12.0
rect_pivot_offset = Vector2( 41, 20 )
text = "Copy JSON to clipboard"
script = null
[node name="Run" type="Button" parent="."]
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -104.0
offset_top = -32.0
offset_right = -22.0
offset_bottom = -12.0
rect_pivot_offset = Vector2( 41, 20 )
disabled = true
text = "Run
"
script = null
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label2" type="Label" parent="."]
offset_left = 35.1181
offset_top = 572.436
offset_right = 132.118
offset_bottom = 612.436
text = "Test Time (sec)"
structured_text_bidi_override_options = [ ]
script = null
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TestTime" type="SpinBox" parent="."]
offset_left = 144.0
offset_top = 568.0
offset_right = 326.0
offset_bottom = 592.0
min_value = 1.0
value = 8.0
script = null
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="item_edited" from="Tree" to="." method="_on_Tree_item_edited"]
[connection signal="pressed" from="SelectAll" to="." method="_on_SelectAll_pressed"]
[connection signal="pressed" from="SelectNone" to="." method="_on_SelectNone_pressed"]
[connection signal="pressed" from="CopyJSON" to="." method="_on_CopyJSON_pressed"]
[connection signal="pressed" from="Run" to="." method="_on_Run_pressed"]

144
manager.gd Normal file
View File

@@ -0,0 +1,144 @@
extends Node
# Declare member variables here. Examples:
# var a = 2
# var b = "text"
class Results:
var render_cpu := 0.0
var render_gpu := 0.0
var idle := 0.0
var physics := 0.0
var frames_captured := 0
class Test:
var name : String
var category : String
var path : String
var results : Results = null
func _init(p_name : String,p_category: String,p_path : String):
name = p_name
category = p_category
path = p_path
var results : Results = null
var tests=[
Test.new("Static Cull","Culling","res://rendering/culling/basic_cull.tscn"),
Test.new("Dynamic Cull","Culling","res://rendering/culling/dynamic_cull.tscn"),
Test.new("Static Lights Cull","Culling","res://rendering/culling/static_light_cull.tscn"),
Test.new("Dynamic Lights Cull","Culling","res://rendering/culling/dynamic_light_cull.tscn"),
Test.new("Directional Light Cull","Culling","res://rendering/culling/directional_light_cull.tscn"),
]
var recording := false
var remaining_time := 5.0
func is_recording():
return recording
func get_test_count() -> int:
return tests.size()
func get_test_name(idx) -> String:
return tests[idx].name
func get_test_category(idx) -> String:
return tests[idx].category
func get_test_result(idx) -> Results:
return tests[idx].results
var tests_queue = []
var test_time := 5.0
var return_to_scene : = ""
var skip_first := false
func benchmark(queue : Array,time : float,return_path : String):
tests_queue = queue
if (tests_queue.size() == 0):
return
test_time = time
return_to_scene = return_path
begin_test()
var record_render_gpu := false
var record_render_cpu := false
var record_idle := false
var record_physics := false
func begin_test():
results = Results.new()
recording = true
results = Results.new()
remaining_time = test_time
set_process(true)
get_tree().change_scene(tests[tests_queue[0]].path)
var bmgroup = get_tree().get_nodes_in_group("bechnmark_config")
if (bmgroup.size()):
var bm = bmgroup[0]
record_render_cpu = bm.test_render_cpu
record_render_gpu = bm.test_render_gpu
record_idle = bm.test_idle
record_physics = bm.test_physics
else:
record_render_cpu = true
record_render_gpu = true
record_idle = true
record_physics = true
skip_first = true
frames_captured = 0
func end_test():
recording = false
results.render_cpu /= float(frames_captured)
results.render_gpu /= float(frames_captured)
results.idle /= float(frames_captured)
results.physics /= float(frames_captured)
tests[tests_queue[0]].results = results
results = null
tests_queue.pop_front()
if (tests_queue.size() > 0):
begin_test() #tests pending? goto next
else:
get_tree().change_scene(return_to_scene)
return_to_scene=""
func _process(delta):
if (not recording):
return
if (skip_first):
skip_first=false
return
if (record_render_cpu):
results.render_cpu += RenderingServer.viewport_get_measured_render_time_cpu(get_tree().root.get_viewport_rid()) + RenderingServer.get_frame_setup_time_cpu()
if (record_render_gpu):
results.render_gpu += RenderingServer.viewport_get_measured_render_time_gpu(get_tree().root.get_viewport_rid())
if (record_idle):
results.idle += 0.0
if (record_physics):
results.physics += 0.0
frames_captured += 1
remaining_time -= delta
if (remaining_time < 0.0):
end_test()
func report_time(delta,render_cpu,render_gpu,idle_cpu,physics_cpu):
if (not recording):
return
# Called when the node enters the scene tree for the first time.
func _ready():
RenderingServer.viewport_set_measure_render_time(get_tree().root.get_viewport_rid(),true)
set_process(false)
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

View File

@@ -1 +1,27 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=4
_global_script_classes=[ {
"base": "Label",
"class": @"Benchmark",
"language": @"GDScript",
"path": "res://benchmark.gd"
} ]
_global_script_class_icons={
@"Benchmark": ""
}
[application]
run/main_scene="res://main.tscn"
[autoload]
Manager="*res://manager.gd"

View File

@@ -0,0 +1,4 @@
extends "res://rendering/culling/culling_base.gd"
func _ready():
fill_with_objects(10000,true)

View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://rendering/culling/basic_cull.gd" type="Script" id=1]
[ext_resource path="res://benchmark.gd" type="Script" id=2]
[node name="Node3D" type="Node3D"]
script = ExtResource( 1 )
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.873609 )
current = true
far = 200.0
script = null
[node name="Benchmark" type="Label" parent="."]
offset_right = 40.0
offset_bottom = 40.0
structured_text_bidi_override_options = [ ]
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
test_render_cpu = true

View File

@@ -0,0 +1,89 @@
extends Node3D
var objects = []
var object_xforms = []
var lights = []
var light_instances = []
var light_instance_xforms = []
var meshes = []
func fill_with_objects(object_amount,unshaded = false):
var m = BoxMesh.new()
meshes.append(m)
m = SphereMesh.new()
meshes.append(m)
m = CapsuleMesh.new()
meshes.append(m)
m = CylinderMesh.new()
meshes.append(m)
m = PrismMesh.new()
meshes.append(m)
for m in meshes:
var s = Shader.new()
var st = "shader_type spatial; "+("render_mode unshaded;" if unshaded else "")+"void fragment() { ALBEDO = vec3("+str(randf(),",",randf(),",",randf())+"); }"
print(st)
s.code = st
var mat = ShaderMaterial.new()
mat.shader = s;
m.material = mat
var cam := ($Camera3D as Camera3D)
var zn = 2
var zextent = cam.far - zn
var ss = get_tree().root.size
var from = cam.project_position(Vector2(0,ss.y),zextent)
var extents = cam.project_position(Vector2(ss.x,0),zextent) - from
for i in range(object_amount):
var xf = Transform()
xf.origin = Vector3(from.x + randf() * extents.x,from.y + randf() * extents.y, - (zn + zextent * randf()))
var ins = RenderingServer.instance_create()
RenderingServer.instance_set_base(ins,meshes[i % meshes.size()].get_rid())
RenderingServer.instance_set_scenario(ins,get_world_3d().scenario)
RenderingServer.instance_set_transform(ins,xf)
objects.append(ins)
object_xforms.append(xf)
func fill_with_omni_lights(amount,use_shadows=true):
var cam := ($Camera3D as Camera3D)
var zn = 2
var zextent = cam.far - zn
var ss = get_tree().root.size
var from = cam.project_position(Vector2(0,ss.y),zextent)
var extents = cam.project_position(Vector2(ss.x,0),zextent) - from
var l = RenderingServer.omni_light_create()
RenderingServer.light_set_param(l,RenderingServer.LIGHT_PARAM_RANGE,10)
RenderingServer.light_set_shadow(l,use_shadows)
RenderingServer.light_omni_set_shadow_mode(l,RenderingServer.LIGHT_OMNI_SHADOW_DUAL_PARABOLOID) # faster
lights.append(l)
for i in range(amount):
var xf = Transform()
xf.origin = Vector3(from.x + randf() * extents.x,from.y + randf() * extents.y, - (zn + zextent * randf()))
var ins = RenderingServer.instance_create()
RenderingServer.instance_set_base(ins,l)
RenderingServer.instance_set_scenario(ins,get_world_3d().scenario)
RenderingServer.instance_set_transform(ins,xf)
light_instances.append(ins)
light_instance_xforms.append(xf)
func _exit_tree():
for o in objects:
RenderingServer.free_rid(o)
for l in lights:
RenderingServer.free_rid(l)
for l in light_instances:
RenderingServer.free_rid(l)
meshes.clear()

View File

@@ -0,0 +1,6 @@
extends "res://rendering/culling/culling_base.gd"
func _ready():
fill_with_objects(10000)

View File

@@ -0,0 +1,28 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://rendering/culling/directional_light_cull.gd" type="Script" id=1]
[ext_resource path="res://benchmark.gd" type="Script" id=2]
[node name="Node3D" type="Node3D"]
script = ExtResource( 1 )
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.873609 )
current = true
far = 200.0
script = null
[node name="Benchmark" type="Label" parent="."]
offset_right = 40.0
offset_bottom = 40.0
structured_text_bidi_override_options = [ ]
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
test_render_cpu = true
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform( 0.933154, 0, 0.359476, -0.242196, 0.738961, 0.628711, -0.265639, -0.673748, 0.689565, 2.09069, 0, 0 )
shadow_enabled = true
script = null

View File

@@ -0,0 +1,13 @@
extends "res://rendering/culling/culling_base.gd"
var time_accum = 0.0
func _process(delta):
time_accum += delta * 4.0
for i in range(objects.size()):
var xf = object_xforms[i]
var angle = i * PI * 2.0 / objects.size()
xf.origin += Vector3(sin(angle),cos(angle),0.0) * sin(time_accum) * 2.0
RenderingServer.instance_set_transform(objects[i],xf)
func _ready():
fill_with_objects(10000)

View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://rendering/culling/dynamic_cull.gd" type="Script" id=1]
[ext_resource path="res://benchmark.gd" type="Script" id=2]
[node name="Node3D" type="Node3D"]
script = ExtResource( 1 )
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.873609 )
current = true
far = 200.0
script = null
[node name="Benchmark" type="Label" parent="."]
offset_right = 40.0
offset_bottom = 40.0
structured_text_bidi_override_options = [ ]
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
test_render_cpu = true

View File

@@ -0,0 +1,15 @@
extends "res://rendering/culling/culling_base.gd"
@export var use_shadows := false
var time_accum = 0.0
func _process(delta):
time_accum += delta * 4.0
for i in range(light_instances.size()):
var xf = light_instance_xforms[i]
var angle = i * PI * 2.0 / light_instances.size()
xf.origin += Vector3(sin(angle),cos(angle),0.0) * sin(time_accum) * 2.0
RenderingServer.instance_set_transform(light_instances[i],xf)
func _ready():
fill_with_objects(10000)
fill_with_omni_lights(100,use_shadows)

View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://benchmark.gd" type="Script" id=1]
[ext_resource path="res://rendering/culling/dynamic_light_cull.gd" type="Script" id=2]
[node name="Node3D" type="Node3D"]
script = ExtResource( 2 )
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.873609 )
current = true
far = 200.0
script = null
[node name="Benchmark" type="Label" parent="."]
offset_right = 40.0
offset_bottom = 40.0
structured_text_bidi_override_options = [ ]
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
test_render_cpu = true

View File

@@ -0,0 +1,24 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://benchmark.gd" type="Script" id=1]
[ext_resource path="res://rendering/culling/dynamic_light_cull.gd" type="Script" id=2]
[node name="Node3D" type="Node3D"]
script = ExtResource( 2 )
use_shadows = true
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.873609 )
current = true
far = 200.0
script = null
[node name="Benchmark" type="Label" parent="."]
offset_right = 40.0
offset_bottom = 40.0
structured_text_bidi_override_options = [ ]
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
test_render_cpu = true

View File

@@ -0,0 +1,6 @@
extends "res://rendering/culling/culling_base.gd"
func _ready():
fill_with_objects(10000)
fill_with_omni_lights(100)

View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://rendering/culling/static_light_cull.gd" type="Script" id=1]
[ext_resource path="res://benchmark.gd" type="Script" id=2]
[node name="Node3D" type="Node3D"]
script = ExtResource( 1 )
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.873609 )
current = true
far = 200.0
script = null
[node name="Benchmark" type="Label" parent="."]
offset_right = 40.0
offset_bottom = 40.0
structured_text_bidi_override_options = [ ]
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
test_render_cpu = true