On Fri, 3 Feb 2017 08:42:58 -0200 Gustavo Sverzut Barbieri <[email protected]> said:
> On Fri, Feb 3, 2017 at 4:01 AM, Carsten Haitzler <[email protected]> wrote: > > raster pushed a commit to branch master. > > > > http://git.enlightenment.org/core/efl.git/commit/?id=eab798c753e72eece526ceccf3c9beb441b5f5ff > > > > commit eab798c753e72eece526ceccf3c9beb441b5f5ff > > Author: Carsten Haitzler (Rasterman) <[email protected]> > > Date: Fri Feb 3 14:57:49 2017 +0900 > > > > ecore_con/efl_net - dedicated threads for network i/o not from the pool > > > > so ecore_con/efl_net were using the standard ecore_thread thread pool > > for doing things like dns lookups > > this is true > > > (that can take multiple minutes until timeouts) > > this is unlikely but possible. :) > > and actual http transactions. > > this is false. CURL itself does the HTTP transactions using our main > loop by calling back efl_net_dialer_http.c to > register/unregister/modify the fd that is being modified. my bad - the proxy lookups were in the thread pool for http stuff. also the ip resolves were too. these CAN take a long time to timeout if you have a bad network... :) > > > similarly they can block > > thread workers for long periods or indefinitely thus basically > > blocking the whole eocre_thread pool and stopping others from sharing > > it. > > how big is the thread pool? I hope it's a dynamic size and will not > simply serialize everything into one/two threads. by default the MAX # of threads is number of cpu cores detected. it's settable though. _ecore_thread_count_max = eina_cpu_count(); if (_ecore_thread_count_max <= 0) _ecore_thread_count_max = 1; but it actually uses that + 1 * 16 if (_ecore_thread_worker_count > ((_ecore_thread_count_max + 1) * 16)) { _ecore_thread_worker_count--; free(worker); return; } for shutting down, but startup up it's limited. i think there's something a bit wrong here... :/ > > the best solution we have right now is to bypass the thread pool > > queue and have dedicated threads for these actions. what we should > > have is a dedicated thread pool with each thread taking on N > > connections (via select etc.) and the ability to create and destroy > > thread pools for specific tasks so you can separate the work out from > > other work. but that is basically a redesign of our thread pool infra > > so let's do the quick solution here until that day comes. > > not sure about this. If I go and try to use that in efl_net, it will > always go wrong: > > - If I hope the guy is doing regular desktop app that randomly need > 1-2 remote resources, that's like 1-2 lookups for the whole lifetime, > so likely a single thread for the whole application is good enough. > > - if I think that's going to be used by multi tab browser doing > prefetch and parallel resources, that's like 100's lookups for each > tab, then 50+ threads would be desirable. > > - If I think the guy is writing a server utility that may execute > hundreds of thousands transactions per second, then it's closer to > that order. > > That said, my bet is that EFL would dynamically grow and shrink the > pool using some heuristic, like: > - queue at most 1-2 requests in a thread, then spawn a new thread; > - if thread is idle for X seconds, exit. it doesn't though. the queue and pool is pretty basic. it's a single pool for everyone. once it hits the max # of workers work is queued and picked up by the next available worker. this actually makes sense, you do not want 3 of workers to grow "indefinitely" even if you are doing 100,000's of transactions. otherwise you just use far more resoruces in kernel space with whole thread instances instead of far cheaper queues in userspace. you probably want a heuristic that detects a stuck pool and then expands a bit to unstick it (or allow "fast and simple operations to keep going through while slow blocked ones hang about). we don't have anything like that. my thoughts above in the log were something like 1 thread handles 10 connections with its own select and read/write to/from buffers (and this will then message the mainloop with the results already sitting in a buffer). if you have 100 connections you might have 10 threads each handling 10 connections... or something like this (numbers can be adjusted). i'm thinking specifically network i/o connections here. this would have its own pool fo thread workers that expands and contracts as needed (maybe keeping 1 or 2 spares around for a while if they become idle just in case to avoid creation of threads). what we do need is a rethink and redesign of thread pool infra so it can "cache" worker threads and re-use them (maybe the pools share a central cache of spare threads? and pull a worker thread out of the shared global pool when they need one). they would need some kind of pool manager that detects "pool is stuck and queue has not had an item worked on for > 0.3 seconds so we need to expand the pool out now by 1) and then as the queue empties hand workers back tot he global pool where up to N float about for a while then voluntarily die off if they have nothing to do for maybe 1.0 seconds or something... > It would be even better if the requests could be migrated from threads > (or pop'ed from a common queue), so in the case one job/func takes too > much to execute we don't wait for queued funcs if we have other idle > threads. yeah. similar to the above for sure. but all in all this is a rethink-redesign of ecore_thread. or at least the core code behind it. ecore_thread could be layered on top. ecore_thread also suffers another major issue. it handles thread -> mainloop event marshalling nicely (especially with feedback) BUT it has nothing to go in reverse (mainloop -> thread). you ONLY get to provide work at the start. you cant have an input queue and feed input to the thread (and it sits polling/sleeping on that queue). yes i know you can use a pipe or eina_thread_queue for this separately. then the design smells asymmetric. and this brings up then the whole discussion of threads and mainloops. once threads can send output back to the mainloop (or maybe another thread with a loop) and then also process incoming requests/events... wouldnt they run a "mainloop" of their own. or just a loop (main loop being the loop that happens or run from main()). now our design looks really clean and symmetric. every "higher level thread" (not talking eina_thread) has an event loop. any thread can send stuff to any other thread (messages/data/results, functions to execute) ... and this is where promises/futures look nice and you can have 2 threads chat back and forth with nice sequencing of the discussion via promises. anyway... it's kind of interrelated. > > this partially addresses D4640 > > > > a dedicated thread per image load though is going to be a lot nastier... > > --- > > src/lib/ecore_con/ecore_con.c | 9 +++++---- > > src/lib/ecore_con/efl_net_dialer_http.c | 9 +++++---- > > 2 files changed, 10 insertions(+), 8 deletions(-) > > > > diff --git a/src/lib/ecore_con/ecore_con.c b/src/lib/ecore_con/ecore_con.c > > index dd641da..35eb4d0 100644 > > --- a/src/lib/ecore_con/ecore_con.c > > +++ b/src/lib/ecore_con/ecore_con.c > > @@ -703,10 +703,11 @@ efl_net_ip_resolve_async_new(const char *host, const > > char *port, const struct ad > > > > d->result = NULL; > > > > - return ecore_thread_run(_efl_net_ip_resolve_async_run, > > - _efl_net_ip_resolve_async_end, > > - _efl_net_ip_resolve_async_cancel, > > - d); > > + return ecore_thread_feedback_run(_efl_net_ip_resolve_async_run, > > + NULL, > > + _efl_net_ip_resolve_async_end, > > + _efl_net_ip_resolve_async_cancel, > > + d, EINA_TRUE); > > > > failed_hints: > > free(d->port); > > diff --git a/src/lib/ecore_con/efl_net_dialer_http.c > > b/src/lib/ecore_con/efl_net_dialer_http.c index 2454c72..6c4a463 100644 > > --- a/src/lib/ecore_con/efl_net_dialer_http.c > > +++ b/src/lib/ecore_con/efl_net_dialer_http.c > > @@ -1407,10 +1407,11 @@ _efl_net_dialer_http_efl_net_dialer_dial(Eo *o, > > Efl_Net_Dialer_Http_Data *pd, co > > > > ctx->o = o; > > > > - pd->libproxy_thread = ecore_thread_run > > (_efl_net_dialer_http_libproxy_run, > > - > > _efl_net_dialer_http_libproxy_end, > > - > > _efl_net_dialer_http_libproxy_cancel, > > - ctx); > > + pd->libproxy_thread = ecore_thread_feedback_run > > (_efl_net_dialer_http_libproxy_run, > > + NULL, > > + > > _efl_net_dialer_http_libproxy_end, > > + > > _efl_net_dialer_http_libproxy_cancel, > > + ctx, EINA_TRUE); > > this needs to go, I said to Cedric I'll work on it. > > the libproxy thread had a reason to exist when it was using libproxy > directly. Now that it uses another process, then the reason ceases and > we can be async directly on top of ecore_exe. > > > > -- > Gustavo Sverzut Barbieri > -------------------------------------- > Mobile: +55 (16) 99354-9890 > > ------------------------------------------------------------------------------ > Check out the vibrant tech community on one of the world's most > engaging tech sites, SlashDot.org! http://sdm.link/slashdot > _______________________________________________ > enlightenment-devel mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/enlightenment-devel > -- ------------- Codito, ergo sum - "I code, therefore I am" -------------- The Rasterman (Carsten Haitzler) [email protected] ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, SlashDot.org! http://sdm.link/slashdot _______________________________________________ enlightenment-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/enlightenment-devel
