JDK-4930801 : Excessive CPU time when Unicode character list displayed under Japanese environm
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 1.4.2
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2003-10-01
  • Updated: 2003-10-16
  • Resolved: 2003-10-16
Related Reports
Duplicate :  
Description

Name: dk106046			Date: 10/01/2003

When Unicode character list is displayed using a sample Java program under Japanese environment, too much CPU time is used.

The CharacterList program accepts two option parameter. The first one is the interval of screen updates in millseconds and the second one is number of Unicode characters to be displayed in order. 

If the program was invoked with:
java CharacterList 500 1000 
it will display only first 1000 characters of CJK Unified Ideographs and the CPU usage is very low. 

If the program was invoked with:
java CharacterList 500 2000 
it will display first 2000 characters and CPU usage is almost 100%.  

/*
 * CharacterList.java
 */

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class CharacterList extends JPanel {

    public CharacterList() {        
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        font = new Font("Monospaced", Font.PLAIN, 16);
        codePoint = codePointLow;
        timer = new Timer(interval, 
            new ActionListener() {
                public void actionPerformed(ActionEvent e){
                    repaint();
                }
            });
        timer.start();
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        this.g = g;

        int panelWidth = getWidth();
        int panelHeight = getHeight();

        g.setFont(font);
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, panelWidth, panelHeight);
        g.setColor(Color.BLACK);

        if (stringLength == 0) {
            FontMetrics fm = g.getFontMetrics();
            width = fm.charWidth(FULL_WIDTH_ZERO);
            height = fm.getHeight();
        }
        
        stringLength = panelWidth / width;
        
        for (int y = height; y < panelHeight; y += height)
            g.drawString(getString(), 0, y);
    }
    
    public String getString() {
        char[] ca = new char[stringLength];
        
        for (int i =0; i < stringLength; ++i) {
            ca[i] = (char)codePoint++;
            if (codePoint > codePointHigh)
                codePoint = codePointLow;
        }
        
        return new String(ca);
    }
    
    public static void main(String[] args) {
        interval = DEFAULT_INTERVAL;
        try {
            interval = Integer.parseInt(args[0]);
            if (args.length > 1) {
                numberOfCharacters = Integer.parseInt(args[1]);
                codePointHigh = codePointLow + numberOfCharacters;
            }
        } catch (Exception e) {
        }
        
        System.out.println("redraw interval (msec) = " + interval);
        if (numberOfCharacters > 0)
            System.out.println("number of characters to be displayed in the list = " 
                + numberOfCharacters);
            
        JFrame frame = new JFrame(TITLE);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        
        frame.setContentPane(new CharacterList());
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
    }
    
    private Font font;
    private int codePoint;
    private int width, height, stringLength;
    
    private Timer timer;
    private Graphics g;

    private static final String TITLE = "CharacterList";
    private static final int WIDTH = 400;
    private static final int HEIGHT = 400;
    
    private static final char FULL_WIDTH_ZERO = '\uff10';

    private static final int CODE_POINT_LOW = 0x4e00;
    private static final int CODE_POINT_HIGH = 0x9fff;

    private static final int DEFAULT_INTERVAL = 500;

    private static int interval;
    private static int numberOfCharacters;
    private static int codePointLow = CODE_POINT_LOW;
    private static int codePointHigh = CODE_POINT_HIGH;
}

======================================================================

Comments
EVALUATION I was able to reproduce this on a 1.7 P4 under XP The larger number of glyphs (2000) for the JA font is I think exceeding the glyph cache in 1.4.2, so the expensive rasterisation of these glyphs is happening for every display, which pretty much throttles the CPU. The good news is that 1.5 fixed this and the same test case ticks along at about 1% CPU usage in 1.5. In fact I can increase the number of glyphs and reduce the time interval and the window really flies in 1.5 This kind of (usability) improvement was one of the goals of the 1.5 fix. I am closing this as a duplicate of the work reponsible for this fix: 4641861: Improve performance of Java 2D font implementation ###@###.### 2003-10-16 ============================
16-10-2003