One of my associates suggested this patch. The idea is to reduce loop_sleep if we had to spawn a lot of children last time through the loop. This way on restart (since $created_children is initialized to $idle_children), and on sudden concurrency spikes, we loop quickly enough to spawn the children we need very quickly; whereas under normal conditions, we don't bother. I still decreased loop_sleep by half in our own version, so that the longest wait clients will experience during a drastic concurrency increase would be just slightly above 15 seconds.

Would there be any interest in accepting this if I tested it and put it in my git?

-Jared

On 06/02/2009 08:09 AM, Jared Johnson wrote:
Why not set --idle-children at start-up to something higher (or just 0
to disable)?

Setting it higher is a bit bothersome because our QP children use too
much memory right now (mainly from using DBIx::Class), so it would be a
bit unfortunate to have more memory-consuming kids around that aren't
needed.  As for disabling idle-children.. what exactly would the
behavior be with disabled idle children?  In a situation where
concurrency is saturated, it seems that QP spawns $idle_children
processes every $loop_wait seconds.  Would QP instead spawn a new child
_immediately_ when a new connection attempt came in?  Or if it still
waits $loop_wait seconds, how many children does it spawn when it sees
some are needed?

-Jared

--- a/qpsmtpd-prefork
+++ b/qpsmtpd-prefork
@@ -75,7 +75,7 @@ my $max_children    = 15;   # max number of child processes to spawn
 my $idle_children   = 5;    # number of idle child processes to spawn
 my $maxconnip       = 10;
 my $child_lifetime  = 100;  # number of times a child may be reused
-my $loop_sleep      = 30;   # seconds main_loop sleeps before checking children
+my $loop_sleep      = 15;   # seconds main_loop sleeps before checking children
 my $re_nice         = 5;    # substracted from parents current nice level
 my $d_start         = 0;
 my $quiet           = 0;
@@ -339,10 +339,11 @@ sub reaper {
 #arg0: void
 #ret0: void
 sub main_loop {
+    my $created_children = $idle_children;
     while (1) {
         # if there is no child death to process, then sleep EXPR seconds
         # or until signal (i.e. child death) is received
-        sleep $loop_sleep unless @children_term;
+        sleep $loop_sleep / ($created_children * 2 + 1) unless @children_term;
 
         # block CHLD signals to avoid race
         my $sigset = block_signal(SIGCHLD);
@@ -379,9 +380,9 @@ sub main_loop {
         }
 
         # spawn children
-        for (my $i = scalar(keys %children) ; $i < $chld_pool ; $i++) {
-            new_child();    # add to the child pool
-        }
+        $created_children = $chld_pool - keys %children;
+        $created_children = 0 if $created_children < 0;
+        new_child() for 1..$created_children;
 
         # unblock signals
         unblock_signal($sigset);

Reply via email to