Godot: Slow access to getters, setters and node properties

Created on 5 Jul 2017  Â·  9Comments  Â·  Source: godotengine/godot

Operating system or device - Godot version:
Windows 10 Pro 64 - Godot 2.1.3-stable

Issue description:

Analyzing the bunnymark code once again, we found that the use of getters, setters and accessing nodes properties turn the execution of the code much slower.

this is the original bunny.gd code (full project here):

extends Sprite

var velocity = Vector2(0, 0)
var gravity = 3
var max_x = 640
var min_x = 0
var max_y = 480
var min_y = 0


func _ready():
    var tex = preload("res://wabbit_alpha.png")
    set_texture(tex)
    velocity.x = randf() * 10
    velocity.y = rand_range(5, 10)
    set_process(true)

func _process(delta):
    var pos = get_pos()

    pos.x += velocity.x
    pos.y += velocity.y
    velocity.y += gravity

    if (pos.x > max_x):
        velocity.x *= -1
        pos.x = max_x
    elif (pos.x < min_x):
        velocity.x *= -1
        pos.x = min_x

    if (pos.y > max_y):
        velocity.y *= -0.8
        pos.y = max_y
        if (randf() > 0.5):
            velocity.y -= randf() * 12;

    elif (pos.y < min_y):
        velocity.y = 0;
        pos.y = min_y;

set_pos(pos)

Exporting the executable to release mode we get:
Bunnies: 7000
FPS: ~49

Changing it to avoid using Vector2 properties:

extends Sprite
var velocity_x = 0
var velocity_y = 0
var gravity = 3
var max_x = 640
var min_x = 0
var max_y = 480
var min_y = 0

func _ready():
    var tex = preload("res://wabbit_alpha.png")
    set_texture(tex)
    velocity_x= randf() * 10
    velocity_y = rand_range(5, 10)
    set_process(true)

func _process(delta):
    var pos = get_pos()
    var pos_x = pos.x
    var pos_y = pos.y
    pos_x += velocity_x
    pos_y += velocity_y
    velocity_y += gravity
    if (pos_x > max_x):
        velocity_x*= -1
        pos_x = max_x
    elif (pos_x < min_x):
        velocity_x*= -1
        pos_x = min_x
    if (pos_y > max_y):
        velocity_y *= -0.8
        pos_y = max_y
        if (randf() > 0.5):
            velocity_y -= randf() * 12;
    elif (pos_y < min_y):
        velocity_y = 0;
        pos_y = min_y;
    set_pos(Vector2(pos_x, pos_y))

Exporting the executable to release mode we get:
Bunnies: 8000
FPS: ~54
(If we were able to get rid of get_pos and set_pos the results would be even better)

My question is: is that behavior expected? The user _807_ from godotdevelopers forum even adapted the code to use the shower of bullets approach with no notable gain of performance. Here's the full discussion thread.

discussion gdscript

Most helpful comment

I noticed too that access to Vector2 and Vector3 properties was really slowing down operations in my own GDScript benchmark batch, in general using vector math as much as possible is faster (even if it's only about updating one of the components, it's an interpreted language remember, slow things aren't always what we think^^).

All 9 comments

indexing is supposed to be slower, not that it couldn't be optimized a bit
eventually.
it could be interesting to test using GDNative C++ and C# in comparison in
Godot 3.0

On Wed, Jul 5, 2017 at 8:22 AM, Shin-NiL notifications@github.com wrote:

Operating system or device - Godot version:
Windows 10 Pro 64 - Godot 2.1.3-stable

Issue description:

Analyzing the bunnymark code once again, we found that the use of getters,
setters and accessing nodes properties turn the execution of the code much
slower.

this is the original bunny.gd code (full project here
https://github.com/Shin-NiL/Godot-BunnyMark-CPP/tree/master/projects/godot-bunnymark-gdscript
):

extends Sprite

var velocity = Vector2(0, 0)
var gravity = 3
var max_x = 640
var min_x = 0
var max_y = 480
var min_y = 0

func _ready():
var tex = preload("res://wabbit_alpha.png")
set_texture(tex)
velocity.x = randf() * 10
velocity.y = rand_range(5, 10)
set_process(true)

func _process(delta):
var pos = get_pos()

pos.x += velocity.x
pos.y += velocity.y
velocity.y += gravity

if (pos.x > max_x):
velocity.x *= -1
pos.x = max_x
elif (pos.x < min_x):
velocity.x *= -1
pos.x = min_x

if (pos.y > max_y):
velocity.y *= -0.8
pos.y = max_y
if (randf() > 0.5):
velocity.y -= randf() * 12;

elif (pos.y < min_y):
velocity.y = 0;
pos.y = min_y;

set_pos(pos)

Exporting the executable to release mode we get:
Bunnies: 7000
FPS: ~49

Changing it to avoid using Vector2 properties:

extends Sprite
var velocity_x = 0
var velocity_y = 0
var gravity = 3
var max_x = 640
var min_x = 0
var max_y = 480
var min_y = 0

func _ready():
var tex = preload("res://wabbit_alpha.png")
set_texture(tex)
velocity_x= randf() * 10
velocity_y = rand_range(5, 10)
set_process(true)

func _process(delta):
var pos = get_pos()
var pos_x = pos.x
var pos_y = pos.y
pos_x += velocity_x
pos_y += velocity_y
velocity_y += gravity
if (pos_x > max_x):
velocity_x= -1
pos_x = max_x
elif (pos_x < min_x):
velocity_x
= -1
pos_x = min_x
if (pos_y > max_y):
velocity_y *= -0.8
pos_y = max_y
if (randf() > 0.5):
velocity_y -= randf() * 12;
elif (pos_y < min_y):
velocity_y = 0;
pos_y = min_y;
set_pos(Vector2(pos_x, pos_y))

Exporting the executable to release mode we get:
Bunnies: 8000
FPS: ~54
(If we were able to get rid of get_pos and set_pos the results would be
even better)

My question is: is that behavior expected? The user 807 from
godotdevelopers forum even adapted the code to use the shower of bullets
approach with no notable gain of performance. Here's the full discussion
thread.
https://godotdevelopers.org/forum/discussion/18435/bunny-mark-performance

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/godotengine/godot/issues/9506, or mute the thread
https://github.com/notifications/unsubscribe-auth/AF-Z25Mv_N2OIKN7ig8D2pO0DamJPrnqks5sK3IBgaJpZM4OOM70
.

I noticed too that access to Vector2 and Vector3 properties was really slowing down operations in my own GDScript benchmark batch, in general using vector math as much as possible is faster (even if it's only about updating one of the components, it's an interpreted language remember, slow things aren't always what we think^^).

@reduz what I did was change my C++ Bunnymark module (Godot 2.1.3) to not access the Vector2 properties (as I did with the GDScript version). But I didn't see any performance gain doing that.

@Zylann thanks, nice tip :)

@Shin-NiL Can you still reproduce this in Godot 3.2.1 or the master branch?

@Calinou
Here's the results running on Windows 10 Pro 64 (new machine), Godot 3.2.1-stable, release mode:

Vector2 version
Bunnies: 12000
FPS: ~55

Non Vector2 version
Bunnies: 17000
FPS: ~55

@Shin-NiL Do you have an updated test project for 3.2.x to check those Vector2 and non Vector2 variants?

@akien-mga
I did a new test with 3.2.2-stable, running on the same machine I got the same results as before with 3.1.1-stable.

What I meant is: can we have the test project?

It's useful to have benchmark results, but it's better to have access to the benchmark to actually debug what makes things slower :)

@akien-mga ok, I got it :P

It's not beautiful, but I think it works.

nonvector_bunny_mark.zip

Was this page helpful?
0 / 5 - 0 ratings