JDK-7050528 : Improve performance of java.text.DecimalFormat.format() call stack
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.text
  • Affected Version: 7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-06-01
  • Updated: 2015-07-20
  • Resolved: 2012-10-02
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
7u45Fixed 8 b61Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
SpecJEntreprise 2010 uses a lot NumberFormat default usage path (NumberFormat.getInstance() + format(double) method) to report 
data to end-user. This kind of usage is relevant is most business
JEE server applications as well.

This in turn translate to using DecimalFormat.format(...) methods
either for currency or decimal usage. DecimalFormat.format() call 
stack has shown to consume a lot of CPU time in JEnt profiles (from
16% in 2010 to 6.5% recently (02-2011)). Improving format() call
stack may bring a lot to SpecJEntreprise or Business server apps.

SUGGESTED FIX After trying several possible optimization solutions, one has shown to provide best performances. Here is a limited description of this optimized algorithm, a fast-path for double values in the Integer range used when the DecimalFormat instance used follows a set of constraints mostly valid when the defaut instanciation path is used (NumberFormat.get[Currency]Instance() : - Verify first that the optimized fast-path can be applied, depending on both DecimalFormat instance and passed double value. - If optimization cannot be applied, fallback to existing algorithm, otherwise : - Decompose double value into its integral and fractional part. - Decide if rounding must be applied on the passed double value. - Collect digit from integral and fractional parts converted into integer, taking into accoount rounding and special cases (like all nines, i.e. "99...99,99...", using char arrays only and char assignment (no use of either String or StringBuilder). Pattern rule and punctuation chars is applied directly while collecting digits. - Localize the collected digits (if needed) in the given Locale. - Add required prefix and suffix. - Build and return a String from the char array used. The algorithm can be applied both in currency or non-currency instantiation case. The footprint cost of the fast-path algorithm is ~6kbytes of static data containinig char array constant to collect digits from integer values, plus for each instance a set of utility fields (8) and state fields (12), most of which with a basic type, to support the new algorithm. This rewriting of DecimalFormat.format() call stack has shown a speedup of ~x9 (X86) to ~x11 (SPARC-USIV+) depending on the architecturre, and x10 on T4. The micro-benchmark used for testing the perf improvement is single-threaded and consists in calling NumberFormat.format(double) on a large set (1000000) of double values "fairly" distributed in the integer range. Fairly means that the used values do not put the fast-path algorithm in a priviledged situation where less work has to done.

EVALUATION To provide best performance improvements, one can take advantage of the properties of the instances of DecimalFormat that are used by most business application, that is properties of instances returned by NumberFormat.getInstance() or getCurrencyInstance(). In addition most of these applications will use double values that are most of the time in the Integer range. The profiling of the call stack of NumberFormat.format(double, ...) shows that there are three main time consumers : - sun.misc.FloatingDecimal.dtoa(), - java.text.DigitList.set(), - java.text.DecimalFormat.subformat() private method. Thus these time consumers must be avoided A rewriting of DecimalFormat().subformat that is specifically designed for DecimalFormat instances returned by NumberFormat.get[Currency]Instance() and double values in the Integer range should be exercized. *** (#1 of 1): [ UNSAVED ] ###@###.###