I am developing a trading app with a GUI and charting modules using JavaFX that has to be run on a server to be close to trading centers. While my app runs very smoothly on my home PC it is unresponsive on any dedicated server or VPS I have tried so far.
The trading app is too big to share the code here, so I made a small test app that allows to quantify the difference. It is showing the frame rate (thanks to What is the preferred way of getting the frame rate of a JavaFX application?) and if you click the button it simulates some GUI work.
The dedicated server specs are:
AMD Ryzen 5 3600X 6-Core Processor 3.80 GHz 16.0 GB RAM 64-bit Operating System, x64-based processor Windows Server 2016 Standard
My home PC specs are:
AMD Ryzen 7 5700U with Radeon Graphics 1.80 GHz 16.0 GB RAM 64-bit Operating System, x64-based processor Windows 10 Home
Running the test on my home PC:
Frame rate after starting: 60 per second. Frame rate when simulation GUI work: 60 per second.
Running the test on the dedicated server:
Frame rate after starting: 52 per second. Frame rate when simulation GUI work: 40 per second.
When doing the test with the app started simultaneously five times it pushes the frame rate down towards 30 frames per second on the server, while on the PC it stays at 60 per second.
Running the app with -Dprism.verbose=true shows that on the server the Microsoft Basic Render Driver is used what might cause the difference in performance:
What can I do to improve the performance of JavaFX on the server or if possible to make it run as smoothly as it is running on the home PC?
Edit: I figured out that running the app with -Dprism.order=sw as VM option enhances the performance on the server significantly. The test app is there now running at same FPS as on local PC.
Here is the code of the test app:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class SimpleFrameRateMeter extends Application {
private final long[] frameTimes = new long[100];
private int frameTimeIndex = 0;
private boolean arrayFilled = false;
@Override
public void start(Stage primaryStage) {
borderPane = new BorderPane();
runFrameRateMeter();
//add a button to start some GUI action
button = new Button("Start");
button.setOnAction(e -> {
if (button.getText().equals("Start")) {
button.setText("Running...");
doSomething();
}
});
borderPane.setLeft(button);
primaryStage.setScene(new Scene(borderPane, 250, 150));
primaryStage.show();
}
private BorderPane borderPane;
private Button button;
private Label label = new Label();
//some GUI work
private void doSomething() {
new Thread(() -> {
for (int i = 0; i < 5; i++) {
final int cnt = i;
Platform.runLater(() -> {
//Label label = new Label(String.valueOf(cnt));
label.setText(String.valueOf(cnt));
borderPane.setCenter(label);
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Platform.runLater(() -> {
button.setText("Start");
});
}).start();
}
//Measure frame rates from https://stackoverflow.com/questions/28287398/what-is-the-preferred-way-of-getting-the-frame-rate-of-a-javafx-application
private void runFrameRateMeter() {
Label label = new Label();
borderPane.setTop(label);
AnimationTimer frameRateMeter = new AnimationTimer() {
@Override
public void handle(long now) {
long oldFrameTime = frameTimes[frameTimeIndex];
frameTimes[frameTimeIndex] = now;
frameTimeIndex = (frameTimeIndex + 1) % frameTimes.length;
if (frameTimeIndex == 0) {
arrayFilled = true;
}
if (arrayFilled) {
long elapsedNanos = now - oldFrameTime;
long elapsedNanosPerFrame = elapsedNanos / frameTimes.length;
double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame;
label.setText(String.format("Current frame rate: %.3f", frameRate));
}
}
};
frameRateMeter.start();
}
public static void main(String[] args) {
launch(args);
}
}