Page MenuHome

Python API: Huge performance degradation in Blender 2.8
Open, Confirmed, MediumPublic

Description

System Information
Operating system: Windows 7, 64bit
Graphics card:

Blender Version
Broken: (example: 2.80, edc1b0167518)
Worked: (optional) 2.79b

Short description of error

I'm using Blender as a 3D live view controlled from an external application (see https://developer.blender.org/T62051 for more details).

I just noticed that, compared to Blender 2.79, some operations are up to 20x slower in 2.80!

Here is an example:

import time

import bpy


def add_cylinder():
    window = bpy.context.window_manager.windows[0]
    ctx = {'window': window, 'screen': window.screen}
    start = time.clock()
    bpy.ops.mesh.primitive_cylinder_add(
        ctx,
        radius=1, depth=1,
        location=(1.5, 0.0, 1),
        enter_editmode=False,
    )
    print(time.clock() - start)
    print()
    return 1


bpy.app.timers.register(add_cylinder)

Interestingly, these operations are only slow when I have loaded my 3D model (stats: Verts ~120.000, Faces ~200.000, Tris: ~250.000, Objects: ~1000).

When I run this example in an empty Blender file with 2.80 it is always fast (max 4ms, usually faster). In Blender 2.79 (code attached) with my model loaded it performs still very good (4ms to 8ms). However, running this on 2.80 with my model loaded it takes 60 to 85 ms!

I guess this is related to the new renderer. For a workaround it would be perfectly fine if I could disable rendering during my timer callbacks (if that helps), but I couldn't find anything in the API docs.

Details

Type
Bug

Event Timeline

This is in an almost empty scene.

In your case, almost all time is spent in BKE_scene_graph_update_tagged. This is triggered by the newly created object.
Not sure if there is any way to avoid this currently.

Please note this is unrelated to application timers. The issue also shows if the add_cylinder is called directly without a custom context:

def add_cylinder():
    start = time.clock()
    bpy.ops.mesh.primitive_cylinder_add(
        radius=1, depth=1,
        location=(1.5, 0.0, 1),
    )
    print(time.clock() - start)
    print()


add_cylinder()

So I assume all Python plugins are affected by this performance regression!

You can reproduce this for example with the classroom demo (https://download.blender.org/demo/test/classroom.zip). With this example primitive_cylinder_add is ~10x slower on 2.80.

I'm not sure if I read your performance graph correctly, but isn't the scene update called before the execution of the operator?

Running the script multiple times in an empty scene, performance gets worse for every new object. Starting with ~2ms for the first object, duration with 100 added cylinders is ~12ms.

Sebastian Parborg (zeddb) triaged this task as Confirmed, Medium priority.

Any updates here? I think this is a high priority issue for the 2.80 release.

It looks like this is an exponential performance degradation, so with very high detailed models with a lot of objects Python plugins could be even unusable.