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

Non functional tests #31

Merged
merged 3 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions doc/Non_functional_tests.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
= Non-Functional Testing Report

== Decision to Use JProfiler

After careful consideration of the application's type — an offline, Java Swing-based, single-player game — we decided to use JProfiler instead of JMeter. While JMeter is excellent for load testing and performance testing of web applications, JProfiler offers more comprehensive capabilities for profiling Java applications. JProfiler's robust feature set makes it an ideal choice for analyzing CPU and memory usage, detecting memory leaks, and optimizing performance.
n0F4x-player marked this conversation as resolved.
Show resolved Hide resolved

== Profiling the Application

In this project, we used JProfiler to profile the entire application, focusing on both the menu screen and the in-game state. The primary areas of focus were:

- **Memory Usage**: Monitoring the application's memory consumption and identifying any memory leaks.
- **CPU Usage**: Analyzing CPU utilization to detect performance bottlenecks.

=== Menu Screen Profiling

While profiling the application in the menu screen, we observed a significant amount of continuous object creation. The top objects by instance count and memory consumption were:

- `java.awt.geom.AffineTransform`: 7000 instances/sec
- `sun.java2d.SunGraphics2D`: 4500 instances/sec
- `java.awt.Rectangle`: 3500 instances/sec

These objects were being created at a high rate, leading to increased memory usage and CPU consumption.

=== In-Game Profiling

During in-game profiling, similar patterns of excessive object creation were noted. By analyzing the memory and CPU usage, we were able to identify areas where performance could be optimized.

== Identifying and Optimizing the Window Refresher Method

One of the key findings from the profiling sessions was a small issue with the window refresher method. The `repaint` method was being called more often than needed, leading to unnecessary object creation and higher CPU usage. We implemented a small optimization by reducing the frequency of the `repaint` calls, resulting in a noticeable improvement in performance.
20 changes: 14 additions & 6 deletions src/macaroni/app/App.java
n0F4x-player marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,37 @@
import java.util.logging.Level;

public final class App {

private static final Logger logger = Logger.getLogger(App.class.getName());

private final long FPS = 60;
boolean running = false;

private final Window window = new Window();

public void run() {
logger.info("Application started.");
running = true;
window.open();

long fps = 60;
n0F4x-player marked this conversation as resolved.
Show resolved Hide resolved
long lastLoopTime = System.currentTimeMillis();
final long OPTIMAL_TIME = 1000 / fps;

while (running) {
long currentLoopTime = System.currentTimeMillis();
long elapsedTime = currentLoopTime - lastLoopTime;

if (window.shouldClose()) {
logger.info("Window should close. Stopping application.");
running = false;
}

if (elapsedTime >= OPTIMAL_TIME) {
window.repaint();
lastLoopTime = currentLoopTime;
}

window.repaint();

long currentLoopTime = System.currentTimeMillis();
long sleepTime = 1000 / FPS - (currentLoopTime - lastLoopTime);
long sleepTime = lastLoopTime - System.currentTimeMillis() + OPTIMAL_TIME;
if (sleepTime >= 0) {
try {
logger.fine("Sleeping for " + sleepTime + " ms.");
Expand All @@ -35,7 +44,6 @@ public void run() {
running = false;
}
}
lastLoopTime = currentLoopTime;
}

window.close();
Expand Down
Loading