httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bri...@apache.org
Subject cvs commit: httpd-2.0/docs/manual/misc perf-tuning.html
Date Sun, 16 Jun 2002 22:55:11 GMT
brianp      2002/06/16 15:55:11

  Modified:    docs/manual/misc perf-tuning.html
  Log:
  More changes to bring the performance tuning guide closer to compatibility
  with httpd-2.0:
   - Updated the sample system call trace with a 2.0/worker example
   - Removed the section on the preforking model
  
  Revision  Changes    Path
  1.35      +144 -352  httpd-2.0/docs/manual/misc/perf-tuning.html
  
  Index: perf-tuning.html
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/docs/manual/misc/perf-tuning.html,v
  retrieving revision 1.34
  retrieving revision 1.35
  diff -u -r1.34 -r1.35
  --- perf-tuning.html	2 Jun 2002 05:29:14 -0000	1.34
  +++ perf-tuning.html	16 Jun 2002 22:55:11 -0000	1.35
  @@ -41,8 +41,6 @@
           <ul>
             <li><a href="#trace">Detailed Analysis of a
             Trace</a></li>
  -
  -          <li><a href="#preforking">The Pre-Forking Model</a></li>
           </ul>
         </li>
       </ul>
  @@ -705,358 +703,152 @@
   
       <h3><a id="trace" name="trace">Appendix: Detailed Analysis of a
       Trace</a></h3>
  -    Here is a system call trace of Apache 1.3 running on Linux. The
  -    run-time configuration file is essentially the default plus: 
  -
  -    <blockquote>
  -<pre>
  -&lt;Directory /&gt;
  -    AllowOverride none
  -    Options FollowSymLinks
  -&lt;/Directory&gt;
  -</pre>
  -    </blockquote>
  -    The file being requested is a static 6K file of no particular
  -    content. Traces of non-static requests or requests with content
  -    negotiation look wildly different (and quite ugly in some
  -    cases). First the entire trace, then we'll examine details.
  -    (This was generated by the <code>strace</code> program, other
  -    similar programs include <code>truss</code>,
  -    <code>ktrace</code>, and <code>par</code>.) 
  -
  -    <blockquote>
  -<pre>
  -accept(15, {sin_family=AF_INET, sin_port=htons(22283), sin_addr=inet_addr("127.0.0.1")},
[16]) = 3
  -flock(18, LOCK_UN)                      = 0
  -sigaction(SIGUSR1, {SIG_IGN}, {0x8059954, [], SA_INTERRUPT}) = 0
  -getsockname(3, {sin_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("127.0.0.1")},
[16]) = 0
  -setsockopt(3, IPPROTO_TCP1, [1], 4)     = 0
  -read(3, "GET /6k HTTP/1.0\r\nUser-Agent: "..., 4096) = 60
  -sigaction(SIGUSR1, {SIG_IGN}, {SIG_IGN}) = 0
  -time(NULL)                              = 873959960
  -gettimeofday({873959960, 404935}, NULL) = 0
  -stat("/home/dgaudet/ap/apachen/htdocs/6k", {st_mode=S_IFREG|0644, st_size=6144, ...}) =
0
  -open("/home/dgaudet/ap/apachen/htdocs/6k", O_RDONLY) = 4
  -mmap(0, 6144, PROT_READ, MAP_PRIVATE, 4, 0) = 0x400ee000
  -writev(3, [{"HTTP/1.1 200 OK\r\nDate: Thu, 11"..., 245}, {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
6144}], 2) = 6389
  -close(4)                                = 0
  -time(NULL)                              = 873959960
  -write(17, "127.0.0.1 - - [10/Sep/1997:23:39"..., 71) = 71
  -gettimeofday({873959960, 417742}, NULL) = 0
  -times({tms_utime=5, tms_stime=0, tms_cutime=0, tms_cstime=0}) = 446747
  -shutdown(3, 1 /* send */)               = 0
  -oldselect(4, [3], NULL, [3], {2, 0})    = 1 (in [3], left {2, 0})
  -read(3, "", 2048)                       = 0
  -close(3)                                = 0
  -sigaction(SIGUSR1, {0x8059954, [], SA_INTERRUPT}, {SIG_IGN}) = 0
  -munmap(0x400ee000, 6144)                = 0
  -flock(18, LOCK_EX)                      = 0
  -</pre>
  -    </blockquote>
  -
  -    <p>Notice the accept serialization:</p>
  -
  -    <blockquote>
  -<pre>
  -flock(18, LOCK_UN)                      = 0
  -...
  -flock(18, LOCK_EX)                      = 0
  -</pre>
  -    </blockquote>
  -    These two calls can be removed by defining
  -    <code>SINGLE_LISTEN_UNSERIALIZED_ACCEPT</code> as described
  -    earlier. 
  -
  -    <p>Notice the <code>SIGUSR1</code> manipulation:</p>
  -
  -    <blockquote>
  -<pre>
  -sigaction(SIGUSR1, {SIG_IGN}, {0x8059954, [], SA_INTERRUPT}) = 0
  -...
  -sigaction(SIGUSR1, {SIG_IGN}, {SIG_IGN}) = 0
  -...
  -sigaction(SIGUSR1, {0x8059954, [], SA_INTERRUPT}, {SIG_IGN}) = 0
  -</pre>
  -    </blockquote>
  -    This is caused by the implementation of graceful restarts. When
  -    the parent receives a <code>SIGUSR1</code> it sends a
  -    <code>SIGUSR1</code> to all of its children (and it also
  -    increments a "generation counter" in shared memory). Any
  -    children that are idle (between connections) will immediately
  -    die off when they receive the signal. Any children that are in
  -    keep-alive connections, but are in between requests will die
  -    off immediately. But any children that have a connection and
  -    are still waiting for the first request will not die off
  -    immediately. 
  -
  -    <p>To see why this is necessary, consider how a browser reacts
  -    to a closed connection. If the connection was a keep-alive
  -    connection and the request being serviced was not the first
  -    request then the browser will quietly reissue the request on a
  -    new connection. It has to do this because the server is always
  -    free to close a keep-alive connection in between requests
  -    (<em>i.e.</em>, due to a timeout or because of a maximum number
  -    of requests). But, if the connection is closed before the first
  -    response has been received the typical browser will display a
  -    "document contains no data" dialogue (or a broken image icon).
  -    This is done on the assumption that the server is broken in
  -    some way (or maybe too overloaded to respond at all). So Apache
  -    tries to avoid ever deliberately closing the connection before
  -    it has sent a single response. This is the cause of those
  -    <code>SIGUSR1</code> manipulations.</p>
  -
  -    <p>Note that it is theoretically possible to eliminate all
  -    three of these calls. But in rough tests the gain proved to be
  -    almost unnoticeable.</p>
  -
  -    <p>In order to implement virtual hosts, Apache needs to know
  -    the local socket address used to accept the connection:</p>
  -
  -    <blockquote>
  -<pre>
  -getsockname(3, {sin_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("127.0.0.1")},
[16]) = 0
  -</pre>
  -    </blockquote>
  -    It is possible to eliminate this call in many situations (such
  -    as when there are no virtual hosts, or when <code>Listen</code>
  -    directives are used which do not have wildcard addresses). But
  -    no effort has yet been made to do these optimizations. 
  -
  -    <p>Apache turns off the Nagle algorithm:</p>
  -
  -    <blockquote>
  -<pre>
  -setsockopt(3, IPPROTO_TCP1, [1], 4)     = 0
  -</pre>
  -    </blockquote>
  -    because of problems described in <a
  -    href="http://www.isi.edu/~johnh/PAPERS/Heidemann97a.html">a
  -    paper by John Heidemann</a>. 
  -
  -    <p>Notice the two <code>time</code> calls:</p>
  -
  -    <blockquote>
  -<pre>
  -time(NULL)                              = 873959960
  -...
  -time(NULL)                              = 873959960
  -</pre>
  +    <p>Here is a system call trace of Apache 2.0.38 with the worker MPM
  +    on Solaris 8.  This trace was collected using:</p>
  +<blockquote>
  +<code>truss -l -p <i>httpd_child_pid</i></code>.</code>
  +</blockquote>
  +    <p>The <code>-l</code> option tells truss to log the ID of the
  +    LWP (lightweight process--Solaris's form of kernel-level thread)
  +    that invokes each system call.</p>
  +
  +    <p>Other systems may have different system call tracing utilities
  +    such as <code>strace</code>, <code>ktrace</code>, or <code>par</code>.
  +    They all produce similar output.</p>
  +
  +    <p>In this trace, a client has requested a 10KB static file
  +    from the httpd.  Traces of non-static requests or requests
  +    with content negotiation look wildly different (and quite ugly
  +    in some cases).
  +
  +    <blockquote>
  +<pre>
  +/67:    accept(3, 0x00200BEC, 0x00200C0C, 1) (sleeping...)
  +/67:    accept(3, 0x00200BEC, 0x00200C0C, 1)            = 9
  +</pre>
  +<blockquote>
  +<p>In this trace, the listener thread is running within LWP #67.</p>
  +<p>Note the lack of accept(2) serialization.  On this particular
  +platform, the worker MPM uses an unserialized accept by default
  +unless it is listening on multiple ports.</p>
  +</blockquote>
  +<pre>
  +/65:    lwp_park(0x00000000, 0)                         = 0
  +/67:    lwp_unpark(65, 1)                               = 0
  +</pre>
  +<blockquote>
  +<p>Upon accepting the connection, the listener thread wakes up
  +a worker thread to do the request processing.  In this trace,
  +the worker thread that handles the request is mapped to LWP #65.</p>
  +</blockquote>
  +<pre>
  +/65:    getsockname(9, 0x00200BA4, 0x00200BC4, 1)       = 0
  +</pre>
  +<blockquote>
  +<p>In order to implement virtual hosts, Apache needs to know
  +the local socket address used to accept the connection.  It
  +is possible to eliminate this call in many situations (such
  +as when there are no virtual hosts, or when <code>Listen</code>
  +directives are used which do not have wildcard addresses). But
  +no effort has yet been made to do these optimizations. </p>
  +</blockquote>
  +<pre>
  +/65:    brk(0x002170E8)                                 = 0
  +/65:    brk(0x002190E8)                                 = 0
  +</pre>
  +<blockquote>
  +<p>The brk(2) calls allocate memory from the heap.  It is rare
  +to see these in a system call trace, because the httpd uses
  +custom memory allocators (<code>apr_pool</code> and
  +<code>apr_bucket_alloc</code>) for most request processing.
  +In this trace, the httpd has just been started, so it must
  +call malloc(3) to get the blocks of raw memory with which
  +to create the custom memory allocators.
  +</blockquote>
  +<pre>
  +/65:    fcntl(9, F_GETFL, 0x00000000)                   = 2
  +/65:    fstat64(9, 0xFAF7B818)                          = 0
  +/65:    getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B910, 2190656) = 0
  +/65:    fstat64(9, 0xFAF7B818)                          = 0
  +/65:    getsockopt(9, 65535, 8192, 0xFAF7B918, 0xFAF7B914, 2190656) = 0
  +/65:    setsockopt(9, 65535, 8192, 0xFAF7B918, 4, 2190656) = 0
  +/65:    fcntl(9, F_SETFL, 0x00000082)                   = 0
  +</pre>
  +<blockquote>
  +<p>Next, the worker thread puts the connection to the client (file
  +descriptor 9) in non-blocking mode.  The setsockopt(2) and getsockopt(2)
  +calls are a side-effect of how Solaris's libc handles fcntl(2) on sockets.</p>
  +</blockquote>
  +<pre>
  +/65:    read(9, " G E T   / 1 0 k . h t m".., 8000)     = 97
  +</pre>
  +<blockquote>
  +<p>The worker thread reads the request from the client.</p>
  +</blockquote>
  +<pre>
  +/65:    stat("/var/httpd/apache/httpd-8999/htdocs/10k.html", 0xFAF7B978) = 0
  +/65:    open("/var/httpd/apache/httpd-8999/htdocs/10k.html", O_RDONLY) = 10
  +</pre>
  +<blockquote>
  +<p>This httpd has been configured with <code>Options FollowSymLinks</code>
  +and <code>AllowOverride None</code>.  Thus it doesn't need to lstat(2)
  +each directory in the path leading up to the requested file, nor
  +check for <code>.htaccess</code> files.  It simply calls stat(2) to
  +verify that the file: 1) exists, and 2) is a regular file, not a
  +directory.
  +</blockquote>
  +<pre>
  +/65:    sendfilev(0, 9, 0x00200F90, 2, 0xFAF7B53C)      = 10269
  +</pre>
  +<blockquote>
  +<p>In this example, the httpd is able to send the HTTP response
  +header and the requested file with a single sendfilev(2) system call.
  +Sendfile semantics vary among operating systems.  On some other
  +systems, it is necessary to do a write(2) or writev(2) call to
  +send the headers before calling sendfile(2).</p>
  +</blockquote>
  +<pre>
  +/65:    write(4, " 1 2 7 . 0 . 0 . 1   -  ".., 78)      = 78
  +</pre>
  +<blockquote>
  +<p>This write(2) call records the request in the access log.
  +Note that one thing missing from this trace is a time(2) call.
  +Unlike Apache 1.3, Apache 2.0 uses gettimeofday(3) to look up
  +the time.  On some operating systems, like Linux or Solaris,
  +gettimeofday has an optimized implementation that doesn't require
  +as much overhead as a typical system call.</p>
  +</blockquote>
  +<pre>
  +/65:    shutdown(9, 1, 1)                               = 0
  +/65:    poll(0xFAF7B980, 1, 2000)                       = 1
  +/65:    read(9, 0xFAF7BC20, 512)                        = 0
  +/65:    close(9)                                        = 0
  +</pre>
  +<blockquote>
  +<p>The worker thread does a lingering close of the connection.</p>
  +</blockquote>
  +<pre>
  +/65:    close(10)                                       = 0
  +/65:    lwp_park(0x00000000, 0)         (sleeping...)
  +</pre>
  +<blockquote>
  +<p>Finally the worker thread closes the file that it has just delivered
  +and blocks until the listener assigns it another connection.</p>
  +</blockquote>
  +<pre>
  +/67:    accept(3, 0x001FEB74, 0x001FEB94, 1) (sleeping...)</pre>
  +</pre>
  +<blockquote>
  +<p>Meanwhile, the listener thread is able to accept another connection
  +as soon as it has dispatched this connection to a worker thread (subject
  +to some flow-control logic in the worker MPM that throttles the listener
  +if all the available workers are busy).  Though it isn't apparent from
  +this trace, the next accept(2) can (and usually does, under high load
  +conditions) occur in parallel with the worker thread's handling of the
  +just-accepted connection.</p>
  +</blockquote>
       </blockquote>
  -    One of these occurs at the beginning of the request, and the
  -    other occurs as a result of writing the log. At least one of
  -    these is required to properly implement the HTTP protocol. The
  -    second occurs because the Common Log Format dictates that the
  -    log record include a timestamp of the end of the request. A
  -    custom logging module could eliminate one of the calls. Or you
  -    can use a method which moves the time into shared memory, see
  -    the <a href="#patches">patches section below</a>. 
  -
  -    <p>As described earlier, <code>ExtendedStatus On</code> causes
  -    two <code>gettimeofday</code> calls and a call to
  -    <code>times</code>:</p>
   
  -    <blockquote>
  -<pre>
  -gettimeofday({873959960, 404935}, NULL) = 0
  -...
  -gettimeofday({873959960, 417742}, NULL) = 0
  -times({tms_utime=5, tms_stime=0, tms_cutime=0, tms_cstime=0}) = 446747
  -</pre>
  -    </blockquote>
  -    These can be removed by setting <code>ExtendedStatus Off</code>
  -    (which is the default). 
  -
  -    <p>It might seem odd to call <code>stat</code>:</p>
  -
  -    <blockquote>
  -<pre>
  -stat("/home/dgaudet/ap/apachen/htdocs/6k", {st_mode=S_IFREG|0644, st_size=6144, ...}) =
0
  -</pre>
  -    </blockquote>
  -    This is part of the algorithm which calculates the
  -    <code>PATH_INFO</code> for use by CGIs. In fact if the request
  -    had been for the URI <code>/cgi-bin/printenv/foobar</code> then
  -    there would be two calls to <code>stat</code>. The first for
  -    <code>/home/dgaudet/ap/apachen/cgi-bin/printenv/foobar</code>
  -    which does not exist, and the second for
  -    <code>/home/dgaudet/ap/apachen/cgi-bin/printenv</code>, which
  -    does exist. Regardless, at least one <code>stat</code> call is
  -    necessary when serving static files because the file size and
  -    modification times are used to generate HTTP headers (such as
  -    <code>Content-Length</code>, <code>Last-Modified</code>) and
  -    implement protocol features (such as
  -    <code>If-Modified-Since</code>). A somewhat more clever server
  -    could avoid the <code>stat</code> when serving non-static
  -    files, however doing so in Apache is very difficult given the
  -    modular structure. 
  -
  -    <p>All static files are served using <code>mmap</code>:</p>
  -
  -    <blockquote>
  -<pre>
  -mmap(0, 6144, PROT_READ, MAP_PRIVATE, 4, 0) = 0x400ee000
  -...
  -munmap(0x400ee000, 6144)                = 0
  -</pre>
  -    </blockquote>
  -    On some architectures it's slower to <code>mmap</code> small
  -    files than it is to simply <code>read</code> them. The define
  -    <code>MMAP_THRESHOLD</code> can be set to the minimum size
  -    required before using <code>mmap</code>. By default it's set to
  -    0 (except on SunOS4 where experimentation has shown 8192 to be
  -    a better value). Using a tool such as <a
  -    href="http://www.bitmover.com/lmbench/">lmbench</a> you can
  -    determine the optimal setting for your environment. 
  -
  -    <p>You may also wish to experiment with
  -    <code>MMAP_SEGMENT_SIZE</code> (default 32768) which determines
  -    the maximum number of bytes that will be written at a time from
  -    mmap()d files. Apache only resets the client's
  -    <code>Timeout</code> in between write()s. So setting this large
  -    may lock out low bandwidth clients unless you also increase the
  -    <code>Timeout</code>.</p>
  -
  -    <p>It may even be the case that <code>mmap</code> isn't used on
  -    your architecture; if so then defining
  -    <code>USE_MMAP_FILES</code> and <code>HAVE_MMAP</code> might
  -    work (if it works then report back to us).</p>
  -
  -    <p>Apache does its best to avoid copying bytes around in
  -    memory. The first write of any request typically is turned into
  -    a <code>writev</code> which combines both the headers and the
  -    first hunk of data:</p>
  -
  -    <blockquote>
  -<pre>
  -writev(3, [{"HTTP/1.1 200 OK\r\nDate: Thu, 11"..., 245}, {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
6144}], 2) = 6389
  -</pre>
  -    </blockquote>
  -    When doing HTTP/1.1 chunked encoding Apache will generate up to
  -    four element <code>writev</code>s. The goal is to push the byte
  -    copying into the kernel, where it typically has to happen
  -    anyhow (to assemble network packets). On testing, various
  -    Unixes (BSDI 2.x, Solaris 2.5, Linux 2.0.31+) properly combine
  -    the elements into network packets. Pre-2.0.31 Linux will not
  -    combine, and will create a packet for each element, so
  -    upgrading is a good idea. Defining <code>NO_WRITEV</code> will
  -    disable this combining, but result in very poor chunked
  -    encoding performance. 
  -
  -    <p>The log write:</p>
  -
  -    <blockquote>
  -<pre>
  -write(17, "127.0.0.1 - - [10/Sep/1997:23:39"..., 71) = 71
  -</pre>
  -    </blockquote>
  -    can be deferred by defining <code>BUFFERED_LOGS</code>. In this
  -    case up to <code>PIPE_BUF</code> bytes (a POSIX defined
  -    constant) of log entries are buffered before writing. At no
  -    time does it split a log entry across a <code>PIPE_BUF</code>
  -    boundary because those writes may not be atomic.
  -    (<em>i.e.</em>, entries from multiple children could become
  -    mixed together). The code does its best to flush this buffer
  -    when a child dies. 
  -
  -    <p>The lingering close code causes four system calls:</p>
  -
  -    <blockquote>
  -<pre>
  -shutdown(3, 1 /* send */)               = 0
  -oldselect(4, [3], NULL, [3], {2, 0})    = 1 (in [3], left {2, 0})
  -read(3, "", 2048)                       = 0
  -close(3)                                = 0
  -</pre>
  -    </blockquote>
  -    which were described earlier. 
  -
  -    <p>Let's apply some of these optimizations:
  -    <code>-DSINGLE_LISTEN_UNSERIALIZED_ACCEPT
  -    -DBUFFERED_LOGS</code> and <code>ExtendedStatus Off</code>.
  -    Here's the final trace:</p>
  -
  -    <blockquote>
  -<pre>
  -accept(15, {sin_family=AF_INET, sin_port=htons(22286), sin_addr=inet_addr("127.0.0.1")},
[16]) = 3
  -sigaction(SIGUSR1, {SIG_IGN}, {0x8058c98, [], SA_INTERRUPT}) = 0
  -getsockname(3, {sin_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("127.0.0.1")},
[16]) = 0
  -setsockopt(3, IPPROTO_TCP1, [1], 4)     = 0
  -read(3, "GET /6k HTTP/1.0\r\nUser-Agent: "..., 4096) = 60
  -sigaction(SIGUSR1, {SIG_IGN}, {SIG_IGN}) = 0
  -time(NULL)                              = 873961916
  -stat("/home/dgaudet/ap/apachen/htdocs/6k", {st_mode=S_IFREG|0644, st_size=6144, ...}) =
0
  -open("/home/dgaudet/ap/apachen/htdocs/6k", O_RDONLY) = 4
  -mmap(0, 6144, PROT_READ, MAP_PRIVATE, 4, 0) = 0x400e3000
  -writev(3, [{"HTTP/1.1 200 OK\r\nDate: Thu, 11"..., 245}, {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,
6144}], 2) = 6389
  -close(4)                                = 0
  -time(NULL)                              = 873961916
  -shutdown(3, 1 /* send */)               = 0
  -oldselect(4, [3], NULL, [3], {2, 0})    = 1 (in [3], left {2, 0})
  -read(3, "", 2048)                       = 0
  -close(3)                                = 0
  -sigaction(SIGUSR1, {0x8058c98, [], SA_INTERRUPT}, {SIG_IGN}) = 0
  -munmap(0x400e3000, 6144)                = 0
  -</pre>
  -    </blockquote>
  -    That's 19 system calls, of which 4 remain relatively easy to
  -    remove, but don't seem worth the effort. 
  -
  -    <h3><a id="preforking" name="preforking">Appendix: The
  -    Pre-Forking Model</a></h3>
  -
  -    <p>Apache (on Unix) is a <em>pre-forking</em> model server. The
  -    <em>parent</em> process is responsible only for forking
  -    <em>child</em> processes, it does not serve any requests or
  -    service any network sockets. The child processes actually
  -    process connections, they serve multiple connections (one at a
  -    time) before dying. The parent spawns new or kills off old
  -    children in response to changes in the load on the server (it
  -    does so by monitoring a scoreboard which the children keep up
  -    to date).</p>
  -
  -    <p>This model for servers offers a robustness that other models
  -    do not. In particular, the parent code is very simple, and with
  -    a high degree of confidence the parent will continue to do its
  -    job without error. The children are complex, and when you add
  -    in third party code via modules, you risk segmentation faults
  -    and other forms of corruption. Even should such a thing happen,
  -    it only affects one connection and the server continues serving
  -    requests. The parent quickly replaces the dead child.</p>
  -
  -    <p>Pre-forking is also very portable across dialects of Unix.
  -    Historically this has been an important goal for Apache, and it
  -    continues to remain so.</p>
  -
  -    <p>The pre-forking model comes under criticism for various
  -    performance aspects. Of particular concern are the overhead of
  -    forking a process, the overhead of context switches between
  -    processes, and the memory overhead of having multiple
  -    processes. Furthermore it does not offer as many opportunities
  -    for data-caching between requests (such as a pool of
  -    <code>mmapped</code> files). Various other models exist and
  -    extensive analysis can be found in the <a
  -    href="http://www.cs.wustl.edu/~jxh/research/research.html">papers
  -    of the JAWS project</a>. In practice all of these costs vary
  -    drastically depending on the operating system.</p>
  -
  -    <p>Apache's core code is already multithread aware, and Apache
  -    version 1.3 is multithreaded on NT. There have been at least
  -    two other experimental implementations of threaded Apache, one
  -    using the 1.3 code base on DCE, and one using a custom
  -    user-level threads package and the 1.0 code base; neither is
  -    publicly available. There is also an experimental port of
  -    Apache 1.3 to <a
  -    href="http://www.mozilla.org/docs/refList/refNSPR/">Netscape's
  -    Portable Run Time</a>, which <a
  -    href="http://www.arctic.org/~dgaudet/apache/2.0/">is
  -    available</a> (but you're encouraged to join the <a
  -    href="http://dev.apache.org/mailing-lists">new-httpd mailing
  -    list</a> if you intend to use it). Part of our redesign for
  -    version 2.0 of Apache will include abstractions of the server
  -    model so that we can continue to support the pre-forking model,
  -    and also support various threaded models. 
  -    <!--#include virtual="footer.html" -->
  -    </p>
     </body>
   </html>
   
  
  
  

Mime
View raw message