You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Tim Kientzle <ki...@acm.org> on 2000/10/17 21:07:11 UTC

Re: SimpleDateFormat considered harmful

Alex,

As you may recall, logging is not the only place where formatted dates
are required.  The bottleneck I ran into was caused by my servlet
setting
several date headers (such as "Expires" and "Last-Modified") using
setDateHeader, which results in Tomcat making many calls to the date
formatter to format random dates.  Caching a converted form of the
current
time will not remove this bottleneck.

Following your idea of "the best of both worlds", I've repackaged
my date formatter into a complete date formatting class (right now,
it only supports RFC-1123 dates, but adding others is pretty trivial).
It provides the following optimizations:

* Unsynchronized.  The code is completely unsynchronized.
  This reduces time spent setting/clearing monitors and reduces thread
conflicts.
* Minimal object creation.  The formatter accepts a long timestamp
  value and returns a character or byte array.  There are at most
  two heap objects created per call.  (In particular, it doesn't
  create any String or StringBuffer objects, which require two heap
  allocations each.)
* "now" versions: the "now" versions return a reference to a cached
  version of the current time.  This is re-formatted at most once
  per second.  (Again, the cache is managed without synchronization.)
  In the usual case, no objects are created at all.
* both "char" and "byte" versions:  In my experience, char-to-byte
  conversions are troublesome overhead.  I've provided versions that
  return byte arrays already encoded in ISO8859_1, suitable for
  emitting log entries or HTTP response headers without requiring
  a separate char-to-byte conversion step.  (In my experience,
  writing bytes to an OutputStream is a tremendous speedup over
  writing strings to a PrintWriter.)

The full date formatter is approximately 10 times faster than
java.util.SimpleDateFormat.  The cached now() versions provide
another factor of 20 performance gain.  On my system, 
SimpleDateFormatter.format can handle about 700 calls/second,
my date formatter can do about 6700 calls/second, and
the cached version can handle upwards of 130,000 calls/second.
As I suggested earlier, the biggest win is probably from being
unsynchronized, which is critical to very high-performance servlets.

I think the cached "now" functions should remove any concerns people
have about including timestamps in log files; the char-to-byte
conversion
required for each log write is several orders of magnitude
more expensive than retrieving a cached date.  For comparison with
the above, I timed the following line of code
   byte[] b = (new String(s)).getbytes();
On my system, this line can only be executed 10,000 times/second.
(My full date formatter is only a tiny bit slower than this.)
Moral: char-to-byte conversion is a MUCH bigger headache for log
performance than retrieving cached dates.

				- Tim Kientzle

Code attached. Enjoy.

Alex Chaffee wrote:
> 
> I haven't looked at your code, but can you try replacing
> SimpleDateFormat with org.apache.tomcat.util.FastDateFormat in the
> offending class and rerun the performance test?  It calls a
> SimpleDateFormat, but caches its response, so it's only called once
> per second.
> 
> Perhaps rewriting FastDateFormat to use your code would give us the
> best of both worlds.  The reason to do this is that FastDateFormat is
> used in other code, specifically logging, that is invoked very
> frequently.
> 
> Cheers -
> 
>  - Alex
> 
> On Fri, Oct 13, 2000 at 12:43:43PM -0700, Tim Kientzle wrote:
> > While stress-testing a Tomcat-based servlet system,
> > I'm running into performance problems caused
> > by thread contention.  Most of them have been
> > in my code, but I just found a big one within Tomcat:
> >
> > org.apache.tomcat.util.MimeHeaderField.dateFormat()
> >
> > invokes a java.text.SimpleDateFormat object to format
> > the dates on outgoing headers.  SimpleDateFormat relies
> > on DecimalFormat, which is synchronized.  (With 50
> > simultaneous requests against my servlet, I'm seeing over 20
> > of them waiting on a single shared DecimalFormat object.)
> >
> > The attached sample program contains a drop-in replacement
> > for MimeHeaderField.dateFormat() that produces exactly the
> > same results, but is approximately six times faster and is
> > not synchronized.  Please include this (or something similar)
> > in Tomcat to improve performance.
> >
> > Just for the record: the attached program is my own work,
> > I release it into the public domain.  Do with it as you will.
> >
> >                       - Tim Kientzle
> 
> --
> Alex Chaffee                       mailto:alex@jguru.com
> jGuru - Java News and FAQs         http://www.jguru.com/alex/
> Creator of Gamelan                 http://www.gamelan.com/
> Founder of Purple Technology       http://www.purpletech.com/
> Curator of Stinky Art Collective   http://www.stinky.com/