Skip to content

Deleting multiple children is slow due to eager layout updates #4908

Closed
@niklasf

Description

Perform all steps below and tick them with [x]

  • Read the FAQ
  • Check the related part of the Documentation
  • Update lvgl to the latest version
  • Reproduce the issue in a Simulator

Describe the bug

lv_obj_del() eagerly calls lv_obj_update_layout():

lv_obj_update_layout(par);

This was introduced in #3210.

Eagerly updating the layout can be very expensive when deleting many children of an object. lv_obj_clean() does not have the same problem, but not always all children have to be deleted.

To Reproduce

Run the following example for results like:

0 ms for 1 labels
0 ms for 10 labels
3 ms for 100 labels
229 ms for 1000 labels
18168 ms for 10000 labels

Note that these numbers were created on a relatively powerful desktop machine. On low powered devices there's a noticable delay even for moderate numbers of deleted objects.

#include "lvgl.h"

#include <unistd.h>
#include <time.h>
#include <stdio.h>

static uint32_t tick_cb()
{
    struct timespec ts = { 0 };
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec * 1000 + ts.tv_nsec / 1000 / 1000;
}

static void repro(unsigned int num_children)
{
    lv_obj_t * screen = lv_obj_create(NULL);
    lv_obj_set_flex_flow(screen, LV_FLEX_FLOW_COLUMN);

    lv_obj_t * label[num_children];

    // Create many children
    for(unsigned int i = 0; i < num_children; i++) {
        label[i] = lv_label_create(screen);
        lv_label_set_text_fmt(label[i], "Label %d", i);
    }

    lv_display_load_scr(screen);

    // Delete some of them
    uint32_t begin = tick_cb();
    for(unsigned int i = 0; i < num_children; i++) {
        if(i % 10 != 0) {
            lv_obj_del(label[i]);
        }
    }
    uint32_t end = tick_cb();
    printf("%u ms for %u labels\n", end - begin, num_children);
}

int main()
{
    lv_init();
    lv_tick_set_cb(tick_cb);

    lv_sdl_window_create(1024, 600);

    repro(1);
    repro(10);
    repro(100);
    repro(1000);
    repro(10000);

    while(true) {
        uint32_t delay = lv_timer_handler();
        usleep(delay * 1000);
    }

    return 0;
}

Expected behavior

Better practical performance (even if complexity remains quadratic).

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions