Skip to main content

JRE7's java.awt performance degradation caused by java.util.logging on Linux

3 replies [Last post]
nicarran
Offline
Joined: 2004-10-25

I opened a bug report about this issue on bugs.sun.com. It seems that there is no way to know if the bug report is being considered... so I prefer to post it here. This bug affects desktop (mouse) applications running over the JRE7 on Linux (and probably on Solaris). JRE6 works as expected.

Problem Description

Moving the mouse pointer over a java.awt.Window using JRE7 consumes aprox. twice the CPU time as when running the (almost) same application with a call to java.util.logging.getLogger(String)---without even using the returned Logger.

Steps to Reproduce

-1- Run "java PerformanceRegressionTest useLogging" and move the mouse over the window and observe CPU usage using top.
-2- Run "java PerformanceRefressionTest" and move the mouse over the window and observe CPU usage using top.
-3- Compare the CPU usage obtained from -1- and -2-. -2- consumes 2x CPU time. Cry.

import java.util.logging.*;
import java.awt.*;
import javax.swing.*;

class PerformanceRegressionTest{

public static void main(String... args) throws Throwable{
if(args.length>0 && args[0].toLowerCase().equals("uselogging")){
Logger.getLogger("");
System.out.println("Logger.getLogger(...) called");
}
JFrame f=new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel l=new JLabel("move the mouse over this window and see CPU utilization");
f.getContentPane().add(l);
f.setSize(600,400);
f.setVisible(true);
}
}

Alternatively:
-1- Run "time -p java PerformanceRegressionTest2 useLogging" . On my system I get ~ real 3.43, user 0.93, sys 0.05 .
-2- Run "time -p java PerformanceRegressionTest2". On my system I get ~ real 3.43, user 0.42, sys 0.03 .
-3- Compare the results of -1- and -2-. On my system I get: (0.93+0.05)/(0.42+0.03)=2.17 -> the application consumes ~2.2 more cpu time when logging is used.

(You can also use gnu time with the '-f "%P"' option for a clearer comparison.)

import java.util.logging.*;
import java.awt.*;
import javax.swing.*;

class PerformanceRegressionTest2{

public static void main(String... args) throws Throwable{
if(args.length>0 && args[0].toLowerCase().equals("uselogging")){
Logger.getLogger("");
System.out.println("Logger.getLogger(...) called");
}
JFrame f=new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel l=new JLabel("move the mouse over this window and see CPU utilization");
f.getContentPane().add(l);
f.setSize(600,400);
f.setVisible(true);

moveMouseOverComponent(l);
System.exit(0);
}

static void moveMouseOverComponent(Component component) throws Throwable{
Robot robot=new Robot();
Point p=new Point();
for(int i=100; --i>=0; ){
Thread.sleep(30);
evalRandomScreenPointOverComponent(component, p);
robot.mouseMove(p.x, p.y);
}
}

static void evalRandomScreenPointOverComponent(Component component, Point p){
p.x=p.y=0;
SwingUtilities.convertPointToScreen(p, component);
p.x+=Math.random()*component.getWidth();
p.y+=Math.random()*component.getHeight();
}
}

Workaround

Please let me know if you find a workaround.

The performance degradation occurs after the call sun.util.logging.PlatformLogger.redirectPlatformLoggers() done by Logger.getLogger()->LogManager.getLogManager()->
LogManager.readPrimorialConfiguration()->sun.util.logging.PlatformLogger.redirectPlatformLoggers(). This call wasn't made on JDK6.

Cheers!
Nicolas

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
nicarran
Offline
Joined: 2004-10-25

This problem is fixed on jdk7 update 4. See: http://mail.openjdk.java.net/pipermail/jdk7u-dev/2012-April/002704.html .

nicarran
Offline
Joined: 2004-10-25

PerformanceRegressionTest3 is jvisualvm friendly: it uses a button to start moving the mouse cursor.

import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.logging.*;
import javax.swing.*;

class PerformanceRegressionTest3{

public static void main(String... args) throws Throwable{
if(args.length>0 && args[0].toLowerCase().equals("uselogging")){
//Logger.getLogger("");
sun.util.logging.PlatformLogger.redirectPlatformLoggers();
System.out.println("Logger.getLogger(...) called");
}
JFrame f=new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final JButton b=new JButton();
b.setAction(new AbstractAction(){
@Override
public void actionPerformed(ActionEvent ev){
try{
moveMouseOverComponent(b);
}catch(Throwable t){
  t.printStackTrace();
}
}
});
b.setText("push me when ready to profile");
f.getContentPane().add(b);
f.setSize(600,400);
f.setVisible(true);
}

static void moveMouseOverComponent(Component component) throws Throwable{
Robot robot=new Robot();
Point p=new Point();
for(int i=100; --i>=0; ){
Thread.sleep(30);
evalRandomScreenPointOverComponent(component, p);
robot.mouseMove(p.x, p.y);
}

}

static void evalRandomScreenPointOverComponent(Component component, Point p){
p.x=p.y=0;
SwingUtilities.convertPointToScreen(p, component);
p.x+=Math.random()*component.getWidth();
p.y+=Math.random()*component.getHeight();
}
}

PerformanceRegresionTest3-jvisualvm-memprof.nps_.zip contains a jvisualvm memory profiling snapshot.

nicarran
Offline
Joined: 2004-10-25

This bug affects key event processing as well. Try keeping the spacebar pressed instead of moving the mouse while the window is active: the cpu consumption nearly doubles. Specially noticeable if the auto repeat rate is high.