Performance degradation when increasing number of children

The following example creates an object which contains one label - which shows the current number of children - and an increasing number of objects which keep getting created:10 every 5 seconds.
The whole thing keeps getting animated back and forth.

What I can see is that the performance degradation is very very obvious as the number of object increases.This is very noticable in windows but even more on the target hardware - to the point in which it may even mean we need to drop LVGL for our project - other than that everything seems to be going fine actually.

void demo_widgets()
{
auto s = lv_obj_create(nullptr);
lv_scr_load(s);

auto wrapper = lv_obj_create(s);
lv_obj_set_size(wrapper, SCREEN_WIDTH, SCREEN_HEIGHT);

auto l = lv_label_create(wrapper);
int n = 0;

lv_anim_t animation;
lv_anim_init(&animation);
lv_anim_set_var(&animation, wrapper);
lv_anim_set_exec_cb(&animation, (lv_anim_exec_xcb_t)lv_obj_set_x);
lv_anim_set_time(&animation, 300);
lv_anim_set_playback_time(&animation, 300);
lv_anim_set_repeat_count(&animation, 0xffff);
lv_anim_set_path_cb(&animation, lv_anim_path_bounce);
lv_anim_set_values(&animation, 0, 500);
lv_anim_start(&animation);

for (int i = 0 ; i < 100 ; i++)
{
    for (; n < i * 10; n++)
    {
        auto l = lv_obj_create(wrapper);
        lv_obj_set_y(l, 100);
    }

    std::stringstream ss;
    ss << n;
    
    lv_label_set_text(l, ss.str().c_str());

    auto c = std::chrono::steady_clock::now();

    while (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::duration(std::chrono::steady_clock::now() - c)).count() < 5000)
    {
        auto cc = std::chrono::steady_clock::now();
        lv_task_handler();
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        lv_tick_inc(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::duration(std::chrono::steady_clock::now() - cc)).count());
    }
}

}

I guess the question is if this makes sense or if there is something fundamentally wrong with this example - which obviously is an extreme simplification of what we actually want to do.

Of course one could probably take a snapshot of whatever we want to animate and animate that instead. Didn’t try it yet but I guess it would do the trick performance-wise. The reason why I still ask if anyone has any ideas is because this seems really too dramatic to be true and I therefore think there must be something wrong somewhere.

Any thoughts?

Thanks in advance.

Hi,

I’v rewritten your example in C with a few changes:


void obj_create_timer(lv_timer_t * t)
{
    static int i = 1;
    lv_obj_t * cont = t->user_data;

    for (int n = 0; n < i * 10; n++)
    {
        lv_obj_t * obj = lv_obj_create(cont);
        lv_obj_set_y(obj, 100);
    }
    i++;

    uint32_t cnt = lv_obj_get_child_cnt(cont);
    lv_label_set_text_fmt(lv_obj_get_child(cont, 0), "%d", cnt);
    printf("Widget count: %d\n", cnt);
}


void demo_widgets(void)
{
    lv_obj_t * s = lv_obj_create(NULL);
    lv_scr_load(s);

    lv_obj_t * wrapper = lv_obj_create(s);
    lv_obj_set_size(wrapper, lv_pct(100), lv_pct(100));

    lv_obj_t * l = lv_label_create(wrapper);

    lv_anim_t animation;
    lv_anim_init(&animation);
    lv_anim_set_var(&animation, wrapper);
    lv_anim_set_exec_cb(&animation, (lv_anim_exec_xcb_t)lv_obj_set_x);
    lv_anim_set_time(&animation, 300);
    lv_anim_set_playback_time(&animation, 300);
    lv_anim_set_repeat_count(&animation, 0xffff);
    lv_anim_set_path_cb(&animation, lv_anim_path_bounce);
    lv_anim_set_values(&animation, 0, 500);
    lv_anim_start(&animation);

    lv_timer_create(obj_create_timer, 3000, wrapper);
}

Some notes:

  • Be sure LV_USE_ASSERT_OBJ and LV_USE_ASSERT_MEM_INTEGRITY are disabled in lv_conf.h
  • For recurring tasks I suggest creating an lv_timer and call lv_tick_inc() from an a separate thread or set a custom tick source.
  • If you place hundreds of objects on top of each other it will be slow to redraw. LVGL cannot filter out the objects in the background if the top objects has rounded corner. If you place the objects out of the screen (e.g. lv_obj_set_y(l, 2000);) there shouldn’t be significant performance drop even with thousands of objects. With a layout (e.g. lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN);) it should be lightning fast too. So the reason fro slowdown shouldn’t be the fact that there are many object, but the fact that all these needs to be drawn too.
  • How many object do you actually need? For 100+ similar objects probably there is a more effective way, instead of creating 100 real objects. So what is your exact use case?

Hi, thanks for your answer.

Yes, I’ve tried disabling the asserts and putting the tick in another thread.
It improved quite a lot - I actually wanted to answer myself just for future reference but it seems you were faster :slight_smile:
And yes, out of the screen and invisible objects seem fine - and that is quite useful for what we want do to.

It also seems one easily gets to 100 objects or so but now - without the assertions - 100 seems very ok.
I agree that probably there are ways to simplify the structure and stuff like that but I see that as a sort of an optimization. This just seemed a bit too extreme and therefore scary.

Things look promising at the moment but we’ll explore a bit more.
Thanks once again.

Glad to hear that you issue is resolved :slight_smile:

Let us know if you have any other questions. If it’s a professional project our services might be interesting too.