Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance Difference with SteelSeries/AWT and Medusa when changing needle position #172

Open
elklaaso opened this issue Jun 25, 2019 · 5 comments

Comments

@elklaaso
Copy link

Hi,

I compared the performance of this JavaFx medusa example:

https://www.coolithelp.com/2018/11/how-to-create-gauge-in-javafx-medusa.html

with this Steelseries AWT example:

https://stackoverflow.com/questions/24274134/java-steelseries-library-step-by-step-guide

If i make the needle go from 0 to 100 with both (smal adaptation necessary in first example) then then Medusa/JavaFx uses +- 30% or more cpu and the SteelSeries/AWT 2,5%.

Ive tried a few things but nothing helps. For example if i update the needle every 30ms using concurrent task in JavaFx i even get 40% cpu usage. Also removing any gauge options from the first example doenst help.

It even does not seem to matter wether hardware acceleration is enabled or not. The above JavaFX percentage is with this driver:

D3D Driver Information:
Microsoft Basic Render Driver
\.\DISPLAY1
Driver d3d10warp.dll, version 6.3.9600.16384
Pixel Shader version 3.0
Device : ven_1414, dev_008C, subsys_00000000
Max Multisamples supported: 4

So hardware accelerated.

I really like the medusa gauges but they are totally unusable for me like this.
What am i missing?

@HanSolo
Copy link
Owner

HanSolo commented Jun 26, 2019

First of all you should provide some code to get a better understanding of what you do. It is absolutely possible that you end up using more cpu using JavaFX so what? Nobody ever said that JavaFX uses less CPU than AWT and nobody ever said that JavaFX is faster than AWT, that's just the way it is. If Medusa is unusable for you than I guess you should create your own gauges or stay with AWT...

@elklaaso
Copy link
Author

I get the feeling i have offended you, this was not my intention. I guess i was a bit dissapointed as i really like the medusa library.

Also hurried writing the issue a bit, i will provide examples.

First i would like to try your newest version 11, ive missed that one.

Also i assume i am doing something wrong as you have for example this tilesfx example on youtube:
https://www.youtube.com/watch?v=ybDlnt7lxnw

Will get back to this

@HanSolo
Copy link
Owner

HanSolo commented Jun 28, 2019

No problem, like I wrote, provide some code and I can take a look at it and let you know if it is the right way to use it.

@elklaaso
Copy link
Author

elklaaso commented Jul 2, 2019

Ok, i wrote two test cases:

JavaFX/Medusa:

package javafx_vs_awt;

import eu.hansolo.medusa.Gauge;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.CacheHint;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class TestJavaFX extends Application {
private static final Random RND = new Random();
AnimationTimer timer;

public static void main(String[] args) {
	launch(args);
}

@Override
public void start(Stage primaryStage) {
    Gauge gauge = new Gauge();

    gauge.setValue(40.00); //deafult position of needle on gauage
    gauge.setValueVisible(false);
   
    
    StackPane root = new StackPane();
    root.getChildren().addAll(gauge);

    Scene scene = new Scene(root, 300, 300);       
    primaryStage.setTitle("Test JavaFX");
    primaryStage.setScene(scene);
    
    
    
    timer = new AnimationTimer() {
    	//called in each frame while it is active
        @Override public void handle(final long now) {
        	gauge.setValue(RND.nextDouble() * 20+40);
        }
    };        
    
    primaryStage.show();


    timer.start();
}

}

SWT/SteelSeries:

package javafx_vs_awt;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import eu.hansolo.steelseries.gauges.Radial;

public class TestSwing {
private static final Random RND = new Random();

private static void createAndShowUI() {
    final JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationByPlatform(true);

    JPanel panel = new JPanel() {
        
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }
    };

    final Radial gauge = new Radial();
    gauge.setTitle("Test Swing");
    gauge.setFrameVisible(false);
    gauge.setLcdVisible(false);
    gauge.setLedVisible(false);
    
    
    panel.setLayout(new BorderLayout());
    panel.add(gauge, BorderLayout.CENTER);
    frame.add(panel);

    final JTextField valueField = new JTextField(7);
    valueField.setText("40");
    
    int delay=1000/60;
    System.out.println("delay " + delay);
    ActionListener task = new ActionListener() {
    	public void actionPerformed(ActionEvent evt) {
    		//test
    		gauge.setValue(RND.nextDouble() * 20+40);
    	}
    };
    
    new Timer(delay,task).start();

    frame.pack();
    frame.setVisible(true);
}	

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowUI();
        }
    });
}

}

Only, it turns out that the SWT/SteelSeries uses double the CPU.
I decided not to use animation in both examples to rule that out. When i made the first post i animated both from 0 to 100 and then it happens.

I dont have that much time for this and i dont need animation. But decided to post this anyway.

I have tried a few things though to get it faster, these dont help much compared to (software) rendering but show up in the profiler. If you're interested ill post them.

The main thing that made my application use less (50% less) CPU is reducing the pulse:

-Djavafx.animation.pulse=30

What was really confusing me is that this did not actually change the pulse rate. Then i realized that it might be vsync stopping the pulse to be set:

-Dprism.vsync=false

Now at least i can reduce cpu on quite slow CPU this application has to be installed on.

Also i found out that the rotation of the needle shape causes almost all cpu. Ive tried a lot to get the needle to rotate with less cpu. Only needle.setSmooth(false); seemed to help a bit but im not sure.

@HanSolo
Copy link
Owner

HanSolo commented Jul 2, 2019

If you make a test like this (where you set the value really quick) you should set animated to false. This will prevent the animation of the needle which is only needed if the values will be updated within seconds to get a smooth movement of the needle. As soon as you update the needle really fast the animation is not needed and might lead to performance loss.

I also recommend using the GaugeBuilder like follows:

Gauge gauge = GaugeBuilder.create()
                          .skinType(SkinType.GAUGE)
                          .value(40.0)
                          .valueVisible(false)
                          .animated(false)  // switch off animation of needle
                          .build();`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants