Page MenuHomePhabricator

evas async image load has been broken somewhere during efl 1.23 dev
Closed, ResolvedPublic


This is really bad. evas_object_image_load_head_skip_set() no longer pushes file I/O off to the preload threads. The mainloop will open the file. In fact it loads and opens EVERY file you do a file_set on. The whole point of this was to unblock the mainloop from doing file IO. It's not being done by the main loop thread instead of the worker threads as it was before.

I know it used to before because I especially wrote this to do just that and have been relying on it in many places to speed up things like loading icons in e's menus, loading thumbnails and icons in efm, in rage, etc. etc. and now it's doing the actual open()s in the mainloop causing major stalls where there should be none.

Sample test below. Pass it like 500 images to load. You'll see it's doing syscalls/file IO between ZERO and GO1. It should not be. Certainly not in the mainloop.

Extra bonus points if you now notice that EFL code is totally broken If i add 1000 images on the cmdline. Why? We hit max FD count because we open a file per file_set and keep it around... thus hitting the default 1024 max fd limit easily. So this isn't just a performance drop but a fundamental break in functionality.

gcc show.c -o show `pkg-config --cflags --libs elementary`
#include <Elementary.h>

static Evas_Object *win, *img;

static double t0, t;

static void
win_del(void *data, Evas_Object *obj, void *event_info)

static void
preload(void *data, Evas *e, Evas_Object *obj, void *info)
   int iw, ih;
   const char *f;
   double t;

   t = ecore_time_get();
   evas_object_image_file_get(obj, &f, NULL);
   evas_object_image_size_get(obj, &iw, &ih);
   if (!evas_object_image_load_error_get(obj))
     printf("P> %1.5f %s %ix%i\n", t - t0, f, iw, ih);
     printf("E> %1.5f %s\n", t - t0, f);
   if ((iw <= 0) || (ih <= 0)) elm_exit();
   evas_object_resize(obj, iw, ih);

main(int argc, char **argv)
   int i;

   if (argc < 2)
        printf("Args: file.png [preload and head skip]\n");
        return -1;
   elm_init(argc, argv);
   win = elm_win_add(NULL, "show", ELM_WIN_BASIC);
   elm_win_alpha_set(win, EINA_TRUE);
   elm_win_title_set(win, argv[1]);
   evas_object_smart_callback_add(win, "delete,request", win_del, NULL);

   evas_object_resize(img, 320, 320);
   evas_object_resize(win, 320, 320);

   t0 = ecore_time_get();
   t = ecore_time_get();
   printf("ZERO: %1.5f\n", t - t0);
   for (i = 1; i < argc; i++)
        img = evas_object_image_filled_add(evas_object_evas_get(win));
        evas_object_image_load_head_skip_set(img, EINA_TRUE);
        evas_object_event_callback_add(img, EVAS_CALLBACK_IMAGE_PRELOADED,
                                       preload, NULL);
        evas_object_image_file_set(img, argv[i], NULL);
        evas_object_image_preload(img, EINA_FALSE);
   t = ecore_time_get();
   printf("GO1: %1.5f\n", t - t0);

   t = ecore_time_get();
   printf("GO2: %1.5f\n", t - t0);
   return 0;
raster created this task.Oct 16 2019, 8:05 AM
raster triaged this task as Showstopper Issues priority.
raster updated the task description. (Show Details)Oct 16 2019, 12:08 PM
zmike added a subscriber: zmike.Feb 13 2020, 8:08 AM

I spent some time looking into this. During the 1.21 cycle, it appears that all the functionality required for this feature was removed (e.g., rEFL7672d1050ea9e1050c27ce2eda68718ea054b638 and rEFLc8c4572d7005d19cf50f8c53bb7408606cf3ee40).

I've created a patchset which reverts the related patches and then adds some simple handling which (appears to) resolve the issue cited here as well as a small test to avoid similar issues in the future.

@zmike - awesome! :) fantastic man. i'll look at it tonight

zmike added a comment.Feb 13 2020, 8:36 AM

No rush. This series lacks code to handle correctly determining the loaded property for image objects when skip_head is used, but that can be added once it's verified that the functionality works as intended.