Fix for DEV-39442: Increased the performance of LLDate::toHTTPDateString

by over 50 times.

Looking at the usage, toHTTPDateStream is not called anywhere (except
internally by toHTTPDateString), and toHTTPDateString is called only
once outside of lldate.cpp, by LLStringUtil::formatDatetime. Also, the
method is most commonly called with a single two-character token, such
as "%Y" or "%A".

I therefore removed toHTTPDateStream and optimized toHTTPDateString.
Setting the locale was the most expensive operation, so I looked into
caching that, both in terms of std::ostream and strftime. The timings
for those implementations (averaged over 10 calls) is:

toHTTPDateString timings:
 - with ostream (current)                -> 0.314156 ms
 - with ostream and std::locale caching  -> 0.033999 ms
 - with strftime and setlocale() caching -> 0.005985 ms

I therefore went with the standard C library strftime solution.

I also wrote a few unit tests to make sure that I didn't break any
existing functionality, and tested this under Windows and Linux.

Reviewed by steve.
master
Martin Reddy 2009-09-09 10:21:58 +00:00
parent bc106b1b4b
commit f7231263d4
2 changed files with 14 additions and 20 deletions

View File

@ -38,7 +38,7 @@
#include "apr_time.h"
#include <time.h>
#include <locale>
#include <locale.h>
#include <string>
#include <iomanip>
#include <sstream>
@ -100,33 +100,28 @@ std::string LLDate::toHTTPDateString (std::string fmt) const
{
LLFastTimer ft1(FT_DATE_FORMAT);
std::ostringstream stream;
time_t locSeconds = (time_t) mSecondsSinceEpoch;
struct tm * gmt = gmtime (&locSeconds);
stream.imbue (std::locale(LLStringUtil::getLocale().c_str()));
toHTTPDateStream (stream, gmt, fmt);
return stream.str();
return toHTTPDateString(gmt, fmt);
}
std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
{
LLFastTimer ft1(FT_DATE_FORMAT);
std::ostringstream stream;
stream.imbue (std::locale(LLStringUtil::getLocale().c_str()));
toHTTPDateStream (stream, gmt, fmt);
return stream.str();
}
void LLDate::toHTTPDateStream(std::ostream& s, tm * gmt, std::string fmt)
{
LLFastTimer ft1(FT_DATE_FORMAT);
// avoid calling setlocale() unnecessarily - it's expensive.
static std::string prev_locale = "";
std::string this_locale = LLStringUtil::getLocale();
if (this_locale != prev_locale)
{
setlocale(LC_TIME, this_locale.c_str());
prev_locale = this_locale;
}
const char * pBeg = fmt.c_str();
const char * pEnd = pBeg + fmt.length();
const std::time_put<char>& tp = std::use_facet<std::time_put<char> >(s.getloc());
tp.put (s, s, s.fill(), gmt, pBeg, pEnd);
// use strftime() as it appears to be faster than std::time_put
char buffer[128];
strftime(buffer, 128, fmt.c_str(), gmt);
return std::string(buffer);
}
void LLDate::toStream(std::ostream& s) const

View File

@ -86,7 +86,6 @@ public:
void toStream(std::ostream&) const;
std::string toHTTPDateString (std::string fmt) const;
static std::string toHTTPDateString (tm * gmt, std::string fmt);
static void toHTTPDateStream(std::ostream&, tm *, std::string);
/**
* @brief Set the date from an ISO-8601 string.
*