Re: About describe doubt for libev release ..

2020-03-29 Thread CandyMi
My personal reason for replying to your email so late! I am very sorry.

Thank you for pointing out the problem of the mail format. Currently I use a 
browser to send mail. This format is likely to cause special characters to 
escape. I think I will try to improve it.

---

I simulated the ev_once method in my own way, and cached the io watcher and 
timer watcher objects to achieve more efficient (memory) reuse; this can be 
seen from some test cases I wrote for this. The "memory stability" aspect does 
work really well.

The project in my production environment needs to run at least 5000 requests / 
response scenarios per second (single process / single thread). The start and 
stop operations of this frequency are not expensive for an O(log n) operation, 
but In the "Flame Graph", its calling frequency ranks in the forefront. 
Although I haven't encountered any real performance doubts (not encountered 
yet),

At present, I have completely disabled (can enable) the timer watcher, the 
purpose is to reduce the creation of a large number of timers and make it more 
suitable for the connection pooling characteristics of the load balancing 
software.

It is mainly the above-mentioned "foresight" (perhaps stupid), and the analysis 
of the frequency of calls according to the method of "flame graph" makes me 
doubt about its practicality. (Please don't blame it) :)

My idea: if there is no "painless" O(1) complexity operation, then I will try 
to minimize the coexistence of O(log n) complexity operations.

---

Currently, I use ibev as the underlying event driver to drive a scripting 
language (Lua) to complete business logic.

At the beginning, I considered the "minimum heap and time wheel" approach, but 
the actual performance is even worse. The reasons are as follows:

   1. The interaction overhead of the "glue layer" between the two languages 
will increase, making me unable to determine whether it will work better.

   2. The native runtime overhead of the lua language is 30 times slower than 
that of the C language, which makes me not necessarily improve the efficiency 
even when completed in the lua layer;

---

I understand very well that you want to make libev more general, but sometimes 
there are always "choices".

I think this may have a bad impact on your optimization of libev. At the same 
time, I very much hope that libev will often have some "breakthrough" features 
to better give users some "surprises". :)

---

Finally, I have started porting libeio to my web development framework, and I 
have begun to perform stability tests on this "feature" in a test environment. 
I hope you can "clearly" release a stable version of libeio instead of letting 
us get it from "cvs". 

Known issues:

   1. Simultaneously generating a large number of eio_req causes lock 
contention overhead of multiple threads than a single thread to complete 
synchronous I / O operations will aggravate the deterioration of CPU usage; 
(maybe I use it incorrectly)

   2. The file descriptor (fd) created (obtained) by the fileno (FILE * f) 
method cannot complete the "cache" flush of setvbuf to disk using * sync; 
(maybe I used it incorrectly)

   3. In the msys2 (cygwin) simulation environment, libeio fails to control the 
number of threads;
___
libev mailing list
libev@lists.schmorp.de
http://lists.schmorp.de/mailman/listinfo/libev


Re: About describe doubt for libev release ..

2020-03-22 Thread Marc Lehmann
On Mon, Mar 23, 2020 at 02:44:58AM +0800, CandyMi <869646...@qq.com> wrote:
> "While other data structures are possible and I vaguely plan some minor 
> optimisations"
> 
>  I'm very happy to hear what you said! Because every optimization of 
> Timer makes it easy for developers to use without having to hold hands in 
> some cases (I wrote a lot of code for this).
>  I mentioned in my email last year: "About the choice of the data 
> structure of the timer watcher". But I didn't get a reply, I want to 
> communicate with you about this possibility here.

First of all, your mails arrive very garbled here, as if you mailer sent
html instead of text - could you work on improving that= That makes
reading and understanding your mails unnecessarily hard.

As for optimisations, there is a limit to that - libev cannot know how
your timers are used, and trying ti find out will slow it down so much
that it isn't worth optimizing for many important cases. The biggest
savings are to be done on the application side.

>  Of course, there is a simpler "ev_once" available. But when managing 
> more than 100,000 network connections, the overhead of the data structure 
> itself already occupies a very high user space.

That's a very good example - ev_once does a (costly) malloc each time, and
there is no good way aorund that (it could speed up the allocation, but it
will have to allocate). Real savings can be done on the application side,
by arranging its own data structures in a way that avoids extra memory
allocastions altogether.

>  My current solution is the same as what you said: "Once you need to 
> stop the timer, mark it in timer- data!", Wait for the real timeout 
> before calling ev_timer_stop to stop it.

That's not what I said (in fact, I personally do not use the data field
very often, and wish there was a nice way to get rid of it, but there
isn't, unless you compile libev yourself).

What I meant is more clearly explained in
http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Be_smart_about_timeouts,
part 3 (Let the timer time out, but then re-arm it as required.) - basically,
if you have an inactivity timeout of, say, 60 seconds, you can have a timer
that runs at least every 60 seconds, and then calculates the real timeout.
That way, when there is activity (typically much more often than once per
minute), you only need to do a single assignment instead of rearming the
timer.

And that needs to be done on the application side.

If you have many sockets with identical timeouts, you can be much more
efficient. For example, you could have a list sorted by activity and a single
timer for all connections.

And if you don't need super-exact timeout, but have lots of connections, you
could have a timer that runs every n seconds and reaps connections.

A generic event library can't know this and/or do this for you.

I did play with the thought of having many more watcher types, such as a
watcher type that has it's own container in which all timers have the same
timeout, which could be used for that, but that was when I was under the
influence of Perl's Event module API, and in the end, the more minimal
libevent way of doing things won over.

Most importantly, libev tries to allow applications to do all of this
themselves without forcing them into a particular style, which isd what I
learned from other event loops which aren't as generic.

>   if (timer-data-closed == 1) {
>ev_timer_again(...); // only need to stop timer.
>return ;
>   }
> 
>   timer-data-closed = 1; // now

That doesn't seem like an advantage - if you know the timer is no longer
needed, it should be cheaper to stop it directly and be done with it.

>  Can libev provide a "painless" way for developers to use 
> "ev_timer_start" at will without having to consider using "trick" to simplify 
> the complexity of the algorithm?

I think it already does, to the extent possible. I think your specific
trick is actually malking it worse, but I could be convinced on the
opposite by a benchmark :) But I suspect the conditions under which it
could be better would have to be very specific.

The reason why it is likely worse is that a lot of timers increase the
timer heap size, and effectively the same work has to be done as when
calling ev_io_stop, plus extra work because the heap is larger and the
operations likely have worse cache locality.

>  I have observed that a timer called "Timer-wheel" is provided in the 
> Linux kernel, and its algorithm complexity is currently constant. This may be 
> a good reference.

I know how the kernel does it - however, while it suits the kernel, it
cannot emulate libev timers, and just because it might be O(1) on some
operations does not mean it is faster than a good heap.

And most importantly, you can't have both a timer wheel (which requires your
application to design aorund it) and a timer implementation that just works
for every application (as in libev), i.e. your goal of being generic and easy
to use directly 

Re: About describe doubt for libev release ..

2020-03-22 Thread CandyMi
"While other data structures are possible and I vaguely plan some minor 
optimisations"


 I'm very happy to hear what you said! Because every optimization of 
Timer makes it easy for developers to use without having to hold hands in some 
cases (I wrote a lot of code for this).


 I mentioned in my email last year: "About the choice of the data 
structure of the timer watcher". But I didn't get a reply, I want to 
communicate with you about this possibility here.


 In general, we will use the following code to reflect when a network 
connection should be closed:


 static void timer_cb(...) {


  ev_io_stop(...);


 }




 static void io_cb(...) {


  ev_timer_stop(...);


 }


 static void listet_socket (int sock, int events, int timeout, int 
repeats, void* data) {


  io-data = data;
  ev_io_init(io, sock, io_cb, READ or write);
  ev_io_start(loop, io);


  timer-data = data;
  ev_timer_init(timer, timer_cb, timeout, repeats);
  ev_timer_start(loop, io);


  


 }


 Of course, there is a simpler "ev_once" available. But when managing 
more than 100,000 network connections, the overhead of the data structure 
itself already occupies a very high user space.


 My current solution is the same as what you said: "Once you need to stop 
the timer, mark it in timer- data!", Wait for the real timeout before 
calling ev_timer_stop to stop it.


 The modified code looks like this:


 static void timer_cb(...) {


  if (timer-data-closed == 1) {
   ev_timer_again(...); // only need to stop timer.
   return ;
  }


  ev_timer_again(...);


  ev_io_stop(...);


  ...


 }


 static void io_cb(...) {


  // ev_timer_stop(...); before


  timer-data-closed = 1; // now


  ..


 }


 But obviously, this makes the code we write gradually less and less 
readable.


 Can libev provide a "painless" way for developers to use 
"ev_timer_start" at will without having to consider using "trick" to simplify 
the complexity of the algorithm?


 I have observed that a timer called "Timer-wheel" is provided in the 
Linux kernel, and its algorithm complexity is currently constant. This may be a 
good reference.


 Have you considered optimizing by changing the data structure, or do you 
still have other "killer" ways to optimize? Will this affect the stability?


___
libev mailing list
libev@lists.schmorp.de
http://lists.schmorp.de/mailman/listinfo/libev


Re: About describe doubt for libev release ..

2020-03-22 Thread Marc Lehmann
On Sun, Mar 22, 2020 at 12:56:16PM +0800, CandyMi <869646...@qq.com> wrote:
> I have the same opinion about Linux aio and io_uring. The performance of aio 
> is not as good and problematic as described, but the use of io_uring may be 
> limited by the version of the Linux kernel and it makes me hesitant.
> 
> There may be very few people who follow up on Linux 4.x / 5.x aggressively, 
> that is to say, there will be very few people who actually use it! And I also 
> have to maintain the old 2.6.32 kernel project).

Actually, I would assume most people are now on a 4.x kernel, but of
course, select and poll keep being supported and lubev will fall back to
these if required.

> The following code is my implementation of the IO watcher wrapper. The only 
> difference is: "the IO watcher passed to the core IO init method may have 
> called the core IO stop multiple times (object reuse). Such behavior is to 
> reduce the frequent creation or destruction of IO watcher."

This got rather garbled, but I have one comment:

> core_io_stop(core_loop *loop, core_io *io){
>   if (io-events || io-fd){

If you want to check whether a watche ris active (strated), you could use
ev_is_active(w).

Your current if has the disadvantage of not stopping all acive watchers,
as 0 is a valid value for both fd and events.

>   io-fd = io-events = 0x0;

Also, after stopping, you can reuse the watche rmemory in any way you like,
but you then cannot start it again without calling ev_io_init.

> It is worth mentioning the use of the ev_timer_again method: "The consequence 
> of modifying timer- repeat is that it will cause the min-heap to be 
> adjusted every time. Will frequent use have a certain impact or even worse 
> performance?", Because The implementation of ev_timer_again is this (v4.25):

While other data structures are possible, and I vaguely plan some minor
optimisations, when you use ev_timer_again, libev of course has to adjust the
heap to reflect the new reality. ev_timer_again is typically faster than a
stop/start though, which is why it exists.

Depending on your needs, you may be able to further optimize timers by not
updating them at all on every change (e.g. for network timeouts, letting
them expire and reschedule to the real timeout in the callback), or by
creating your own data structure, e.g. if you have a lot of timers with
the same timeout, you can put them into a linked list and only create a
real timer for the next timer in that list, adding new timers to th end
and so on.

> Recently, I was watching the code of libeio. When will libeio be ready to 
> release the official version?

I can call it an official version right now and create a CVS tag if that
helps you. The main blocking issue is probably the lack of documentation,
and some doubts on whether this is really the right API.

And of course, libeio might profit most from io_uring.

In terms of stability, libeio is pretty much stable and in maintenance for
a decade now.

-- 
The choice of a   Deliantra, the free code+content MORPG
  -==- _GNU_  http://www.deliantra.net
  ==-- _   generation
  ---==---(_)__  __   __  Marc Lehmann
  --==---/ / _ \/ // /\ \/ /  schm...@schmorp.de
  -=/_/_//_/\_,_/ /_/\_\

___
libev mailing list
libev@lists.schmorp.de
http://lists.schmorp.de/mailman/listinfo/libev


Re: About describe doubt for libev release ..

2020-03-21 Thread CandyMi
thank you for your reply.


I have the same opinion about Linux aio and io_uring. The performance of aio is 
not as good and problematic as described, but the use of io_uring may be 
limited by the version of the Linux kernel and it makes me hesitant.


There may be very few people who follow up on Linux 4.x / 5.x aggressively, 
that is to say, there will be very few people who actually use it! And I also 
have to maintain the old 2.6.32 kernel project).



...


The following code is my implementation of the IO watcher wrapper. The only 
difference is: "the IO watcher passed to the core IO init method may have 
called the core IO stop multiple times (object reuse). Such behavior is to 
reduce the frequent creation or destruction of IO watcher."



#define CORE_LOOP core_default_loop()


/* === Timer === */
void
core_timer_init(core_timer *timer, _TIMER_CB cb){


timer-repeat = timer-at = 0x0;


ev_init(timer, cb);


}


void
core_timer_start(core_loop *loop, core_timer *timer, ev_tstamp timeout){


timer-repeat = timeout;


ev_timer_again(loop ? loop : CORE_LOOP, timer);


}


void
core_timer_stop(core_loop *loop, core_timer *timer){


timer-repeat = timer-at = 0x0;


ev_timer_again(loop ? loop : CORE_LOOP, timer);


}
/* === Timer === */




/* === IO === */
void
core_io_init(core_io *io, _IO_CB cb, int fd, int events){


ev_io_init(io, cb, fd, events);


}


void
core_io_start(core_loop *loop, core_io *io){


ev_io_start(loop ? loop : CORE_LOOP, io);


}


void
core_io_stop(core_loop *loop, core_io *io){


if (io-events || io-fd){


ev_io_stop(loop ? loop : CORE_LOOP, io);


io-fd = io-events = 0x0;


}


}
/* === IO === */




Even though I don't think they will adversely affect what you said, for 
security reasons I will put the code up to discuss with you and ask if there is 
an optimization solution.


It is worth mentioning the use of the ev_timer_again method: "The consequence 
of modifying timer- repeat is that it will cause the min-heap to be 
adjusted every time. Will frequent use have a certain impact or even worse 
performance?", Because The implementation of ev_timer_again is this (v4.25):


noinline void ev_timer_again (EV_P_ ev_timer *w)
EV_NOEXCEPT
{
 EV_FREQUENT_CHECK;


 clear_pending (EV_A_ (W)w);


 if (ev_is_active (w))
  {
   if (w-repeat)
{
 ev_at (w) = mn_now + w-repeat;
 ANHE_at_cache (timers [ev_active (w)]);
 adjustheap (timers, timercnt, ev_active (w));
}
   else
ev_timer_stop (EV_A_ w);
  }
 else if (w-repeat)
  {
   ev_at (w) = w-repeat;
   ev_timer_start (EV_A_ w);
  }


 EV_FREQUENT_CHECK;
}



The core_timer_* is packaged so that it is suitable for one-time / cyclic 
"timer", and it does not need to apply for and release memory again and reuse 
it until the program ends(Like core_io_*).


Recently, I was watching the code of libeio. When will libeio be ready to 
release the official version?___
libev mailing list
libev@lists.schmorp.de
http://lists.schmorp.de/mailman/listinfo/libev


Re: About describe doubt for libev release ..

2020-03-21 Thread Marc Lehmann
>  1. "the documentation wrongly claimed that user may modify fd 
> and eventsmembers in io watchers when the watcher was stopped." means: 
> Can't modify internal members even if I/O watcher has been stopped?

Yes - you have to use ev_io_set or the new ev_io_modify, direct
modification does not work properly as the io watcher caches some kernel
state info. If you modified these members directly, it might or might not
work correctly, even in old versions.

To be specific, in most versions of libev, I/O watchers assume that if the
fd wasn't changed via ev_io_set, it will refer to the same underlying file
description, unless you use ev_io_set. If you modify the fd directly, you
might not receive events for it, and you might even receive events for fds
that are no longer open (mostly due to the braindamage that is epoll).

>  2. What is the scenario where timerfd checks "Time Jump" cannot 
> wake up? why a minute?

I don't know of any scenarion where timerfds fail - I assume you refer
to something in the Changes file, but what exactly? The only thing that
changed is that libev does not wake up roughly every minute when it is
sure it can keep the time without it.

>  3. What are the special reasons why Linux AIO is no longer the 
> default backend?

It never was the default backend, it merely was available for use by default.
This is no longer the case - compiled libev versions no longer support the
aio backend by default.

The reasons are not that special: linux aio is buggy, extremely slow
and suffers from a multitude of arbitrary limitations, which is why it
couldn't be a default backend. It is expected that the io_uring interface
will eventually replace the epoll backend, although at the moment it's not
there yet. So basically, it is useless dead code that is of little to no
use to anybody, and would only bloat the binary.

-- 
The choice of a   Deliantra, the free code+content MORPG
  -==- _GNU_  http://www.deliantra.net
  ==-- _   generation
  ---==---(_)__  __   __  Marc Lehmann
  --==---/ / _ \/ // /\ \/ /  schm...@schmorp.de
  -=/_/_//_/\_,_/ /_/\_\

___
libev mailing list
libev@lists.schmorp.de
http://lists.schmorp.de/mailman/listinfo/libev