JDK-4656562 : performance problem with lots of rotated text
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2002-03-22
  • Updated: 2005-08-25
  • Resolved: 2005-08-25
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.
Other
1.4.2 1.4.2Fixed
Related Reports
Relates :  
Description
This is the second half of bug 4650997, dealing with the performance issue.

Here's the test from the original submitter:

A slight modification to the example shows that 1.4 also suffers a huge 
performance degradation over 1.3, even though a feature of 1.4 is supposed to be 
improved graphics 2D performance. On the Windows2000 platform the attached 
example runs in about 3.3 seconds under 1.3.1, but it takes about 20 seconds 
under 1.4 (it does not matter whether or not the bounding box is drawn). 

Here is the example that shows the performance problem:

<<TL.java>>
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.awt.font.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.util.*;

import javax.swing.*;

public class TL extends JComponent{
  int number = 360;
  boolean print = false;
  boolean box = true;
  int counter = 0;
  // Text we render
  String text = ".This is a STRINg.";

  // The following transform performs a flip along the x axis
  AffineTransform flip;

  // Rendering context parameters
  Font font = new Font("Default", Font.PLAIN, 24);
  Font flippedFont;

  public TL(){
    setPreferredSize(new Dimension(700,700));
  }

  public void paint(Graphics _g){
    long start = System.currentTimeMillis();
    Graphics2D g = (Graphics2D)_g;
    Dimension d = getSize();
    counter++;
    int x = d.width/2;
    int y = d.height/2;
    FontRenderContext frc = g.getFontRenderContext();

    for (int i = 0; i < number; i++) {
	double angle = -Math.PI*2.0/number*i;
	flip = AffineTransform.getRotateInstance(angle);
	flippedFont = font.deriveFont(flip);
	TextLayout tl = new TextLayout(text, flippedFont, frc);
	Rectangle2D bb = tl.getBounds();
	g.setPaint(Color.black);
	tl.draw(g, x, y);
	g.setPaint(Color.red);
	if (box) {
	  g.drawRect(x + (int) bb.getX(), y + (int) bb.getY(),
	      (int) bb.getWidth(), (int) bb.getHeight());
	}

	if (print && counter == 1) {
	    System.out.println("Angle: "+angle);
	    System.out.println("getAscent: "+tl.getAscent());
	    System.out.println("getAdvance: "+tl.getAdvance());
	    System.out.println("getBaseline: "+tl.getBaseline());
	    System.out.println("getBounds: "+tl.getBounds());
	    System.out.println("getDescent: "+tl.getDescent());
	    System.out.println("getLeading: "+tl.getLeading());
	    System.out.println("getVisibleAdvance: "+tl.getVisibleAdvance());
	    System.out.println(".");
	} else if (print && i == 0) {
	    System.out.println("Paint, counter="+counter);
	}
    }
    System.out.println("Time="+(System.currentTimeMillis()-start));
  }

  public static void main(String args[]){
    new SnippetFrame(new TL());
  }
}

class SnippetFrame extends JFrame{
  /**
   * @param cmp component to add to the frame's content pane
   */
  public SnippetFrame(JComponent cmp){
    super();

    getContentPane().add(cmp);

    // Set white background as a default
    getContentPane().setBackground(Color.white);

    // Pack to fit cmp's preferred size
    pack();

    // Add a listener to close the application when
    // user closes the frame.
    addWindowListener(new WindowAdapter(){
      public void windowClosing(WindowEvent evt){
	System.exit(0);
      }
    });

    setVisible(true);
  }
}

Comments
EVALUATION And on a SPARC system I got 1.4.1 : 27.5 secs 1.4.2 : 5.2 secs 1.5.0 : 5.1 secs 1.6.0 : 5.0 secs (b48) So I think we'll close this out as fixed in 1.4.2
25-08-2005

EVALUATION (perf related comments from previous bug) The performance degradation is due to tweaking of the glyph and strike cache sizes to reduce memory footprint. The large number of different strikes (360) is overflowing the strike cache. If you run with 45 different rotations you'll see that JDK 1.4 is actually faster. We're looking into improving the strike cache behavior, we optimized for the more common case of regular text. ###@###.### 2002-05-06 ============================== I find that this was still slow in 1.4.1 but in 1.4.2 it returned to 1.3.1 performance levels. Since i don't remember the cache being updated in 1.4.2 this is somewhat puzzling. 1.5 is slightly slower than 1.4.2 on the first paint, eg 1.4.1: 20 seconds 1.4.2: 1.6 seconds 1.5.0: 2.1 seconds but much 1.5 is faster on subsequent paints down to as little as 0.25 seconds (probably because of the different caching scheme) whereas 1.4.2 never gets much faster than its original time. So I think we can close this out but it is a historical puzzle what got better in 1.4.2 ###@###.### 10/22/04 22:10 GMT
22-10-0004