I'm working on optimizing a little java program I made for Christmas. I was testing the amount of time it takes to run the methods and one of them, Snow_AI, is taking 1234567 nano seconds to run.
The issues is with the counter method:
public boolean Count() {
if (CreateCnt > CreateTime) {
CreateCnt = 0;
return true;
} else {
CreateCnt = CreateCnt + 1;
}
return false;
}
This is how I'm making the calls:
MethTmr1 = System.nanoTime();
if (Snw.Count()) {
MethTmr = System.nanoTime();
Snw.Snow_AI();
MethTPS = 1000000000 / (System.nanoTime() - MethTmr);
}
try{
MethTPS1 = 1000000000 / (System.nanoTime() - MethTmr1);
}catch(Exception e){}
when I move the timing calls inside the If statement it changed the time to run to less than 5000. Anyone know why the counter method is causing this to happen?
Your measurement is flawed.
Check this: Why is System.nanoTime() way slower (in performance) than System.currentTimeMillis()?
And then look at your code:
MethTmr1 = System.nanoTime();
if (Snw.Count()) {
//expensive! Added to outer time
MethTmr = System.nanoTime();
Snw.Snow_AI();
//expensive! Added to outer time
MethTPS = 1000000000 / (System.nanoTime() - MethTmr);
}
try{
MethTPS1 = 1000000000 / (System.nanoTime() - MethTmr1);
}catch(Exception e){}
Baseline. Your MethTPS1 includes your (fast) getCount(), your Snow_AI() and two tcalls to System.nanoTime()
Try it this way once:
MethTmr1 = System.nanoTime();
if (Snw.Count()) {
//expensive! Added to outer time
//MethTmr = System.nanoTime();
Snw.Snow_AI();
//expensive! Added to outer time
//MethTPS = 1000000000 / (System.nanoTime() - MethTmr);
}
try{
MethTPS1 = 1000000000 / (System.nanoTime() - MethTmr1);
}catch(Exception e){}
Related
I have 2 integer values, let's say int a = 5 and int b = 4.
public static void run() {
long lastTime = System.nanoTime();
final double ns = 1000000000.0 / 60.0;//60 times per second
double delta = 0;
while(running) {
long now = System.nanoTime();
delta = delta + ((now-lastTime) / ns);
lastTime = now;
while (delta >= 1)//Make sure update is only happening 60 times a second
{
delta--;
}
}
What I want to achieve is to be able to change values of the integers within the while (delta >= 1){} every second to a number between 100 and 400. I want to create a paint method that takes the values of the integers and updates the component sizes within my JFrame. I just need an idea to go with, so I can move on.
I'm not sure if I fully understood your question. However, if your intention is to run a bit of code 60 times per second, there is definitely an easier way to accomplish this - via Java's Thread.sleep() mechanism. You can use Java's Random class to actually generate random values for a and b:
public static void run() {
Random random = new Random();
while (running) {
try {
Thread.sleep(16); // 16 millisecond sleep; will run 60 times per second
// Generate random number between 100 and 400
a = (random.nextInt() % 300) + 100;
b = (random.nextInt() % 300) + 100;
} catch (Exception e) {
System.out.println("Exception encountered when trying to sleep! " + e.toString());
}
}
}
Alternatively, you can also use Java's Timer and TimerTask classes to the same effect.
I want to create a start menue for a Pong clone where the ball in the background bounces off the edges. However the game loop updates to fast so the Coordinates of the ball are already out of the JFrame before you can see it and it moves to fast. I found that through sysouts.
I guess it has something to do with threads but I am not sure.
The main class calls this Class as a thread but the important part is in the class BackgroundBallMovement
package main;
public class BackgroundBallMovement implements Runnable{
private boolean running = true;
#Override
public void run() {
long lastTime = System.nanoTime();
final double ns = 1000000000.0 / 60;
double delta = 0;
while(running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
while(delta >= 1) {
update();
delta = 0;
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
}
render();
}
}
//Spiellogik updaten
private synchronized void update() {
Var.ballX += 1;
Var.ballY += 1;
}
//Objekte zeichnen
private synchronized void render() {
Var.drawStartMenue.repaint();
}
}
You're not using Thread.sleep(). Instead you are waiting until System.nanoTime() changed. This means that the CPU is running all the time (not good).
Also this loop:
while(delta >= 1) {
...
delta = 0;
...
}
doesn't make sense because it could be replaced by an if.
Then you are never updating the lastTime variable. So this line:
delta += (now - lastTime) / ns;
will result in a quadratic function because it will result in something like this (each loop execution):
delta += 0.1;
delta += 0.2;
delta += 0.3;
...
Then because you are never updating the lastTime variable after 1s the condition
while(delta >= 1)
will always be met and your ball will move incredibly fast.
Your first approach could be something like this:
#Override
public void run()
{
while(running)
{
update();
render()
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
Thread.sleep(1000L/60L);
}
}
That's because your math sucks ;-)
Yes, (now - lastTime) / ns is the amount of frames that should have been rendered since the engine started. Therefore your code simplifies to:
while (true) {
delta = framesSinceStart();
while (delta >= 1) {
renderFrame();
delta = 0;
}
}
which is equivalent to
while (true) {
if (framesSinceStart() >= 1) {
renderFrame();
}
}
That is, your code correctly waits to render the first frame, but doesn't record that it has rendered that frame, and therefore always thinks it is late, and never waits anymore.
Instead, you might try something like:
while (true) {
if (framesSinceStart() - framesRendered >= 1) {
renderFrame();
framesRendered++;
}
}
Btw, simply staying in an endless loop to spend time is not very power efficient. It would be better to use something like Thread.sleep() to wait - but calculating the time it should be waiting by hand is a little hairy. Fortunately, the Java API comes with nice helper classes to use:
ThreadPoolExecutor executor = Executors.newSingleThreadExecutor();
executor.scheduleAtFixedRate(() -> renderFrame(), 0, 1000 / 60, TimeUnit.ms);
Try Thread.sleep(long millis)
while(running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
while(delta >= 1) {
update();
delta = 0;
try{
Thread.sleep(1000);
} catch(Exception e) { }
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
}
render();
}
another thing you can try is reducing the ball speed.
private synchronized void update() {
Var.ballX += 0.01;
Var.ballY += 0.01;
}
can anyone help with my problem? In my game loop for game refreshing and redrawing, sometimes variable "wait" returned negative value. How its possible?
while(running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - (elapsed / 1000000);
try {
System.out.println(wait);
Thread.sleep(wait);
} catch (Exception e) {
e.printStackTrace();
}
}
elapsed = System.nanoTime() - start;
wait = targetTime - (elapsed / 1000000);
wait is not the value of System.nanotime(); wait being negative just means targetTime - (elapsed / 1000000) is negative
nano = 1 billionth = 1/1000000000 so if targetTime is in seconds you probably don't want 1000000
It is possible that the elapsed time is greater than the refresh interval (targetTime). In this case, check if the elapsed is +ve, and sleep only then.
I'm following a tutorial and below is the run method to generate logic and frame updates. I understand how the ticks are updated 60 ticks/second but I don't understand how we adjust frame per second here.
Right now with Thread.sleep(2), frame per second is around 460. Without it the numbers go way up, around 10 million updates per second. The code Thread.sleep(2) suspends the thread for only 2 milliseconds right? Why/how does Thread.sleep exactly work here to drop it so low?
Isn't it simpler to create a nsPerFrame = 1000000000D/ (FPS)D to set whatever FPS I want the way he did with ticks?
public void run(){
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 60D;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
while(delta >= 1){
ticks++;
tick();
delta-= 1;
}
try{
Thread.sleep(2);
} catch(InterruptedException e){
e.printStackTrace();
}
frames++;
render();
if(System.currentTimeMillis() - lastTimer >= 1000){
lastTimer += 1000;
System.out.println(ticks + "," + frames);
frames = 0;
ticks = 0;
}
}
}
Well sleep(2) is called repeatedly in your running-loop so the hard upper limit in this case is 500 cycles per second (1000 ms divided by 2 ms), and your measured 460 fps is pretty close to that.
Sure enough you can adjust the sleep duration according to your needs and if needed stuff it into the somewhat higher-precision method Thread#sleep(long, int) where the second parameter is "nanos" (take a look at the docu for caveats!).
The formula for your case is FPS = 1000 ms / sleep duration in ms. From which follows: sleep duration in ms = 1000 ms / FPS.
I'm trying to keep my game at 60fps, but I'm getting strange results from my code like "2-8000 fps" Why isn't this staying at 60?
public static void main(String[] args) {
joglplat m = new joglplat();
while(true){
long startTime = System.nanoTime() / 1000000;
try
{
// 123456: 6 zeros => 16ms
long nsToSleep = 16000000 - (System.nanoTime() - lastFrame);
System.out.println("ns: " + nsToSleep);
lastFrame = System.nanoTime();
if(nsToSleep > 0)
{
System.out.println("ns2: " + (nsToSleep/1000));
System.out.println("ns3: " + (nsToSleep%1000));
Thread.sleep(nsToSleep/16000000, (int)(nsToSleep % 1000));
}
else
{
Thread.yield(); // Only necessary if you want to guarantee that
// the thread yields the CPU between every frame
}
}
catch(Exception e){
e.printStackTrace();
}
m.controls();
m.update();
m.repaint();
System.out.println("framerate: " + (System.nanoTime() / 1000000 - startTime));
}
}
Your output is the number of seconds your program has run for, not framerate. You should be dividing your frame count (which you aren't collecting) by the total time run.
To get the frame count, simply add a new variable outside of your game loop, and increment it each time through...
public static void main(String[] args) {
long frames = 0;
joglplat m = new joglplat();
while(true){
frames++;
// other code here
System.out.println("framerate: " + ((System.nanoTime() / 1000000 - startTime) / frames ) );
}
}
Note, however, that this will give you the average framerate throughout the entire execution of your program. Two other options you have are to get the instantaneous framerate, and the average framerate over the past N frames.
All styles in one (untested/uncompiled, so might have some errors, but should get you started in the right direction):
public static void main(String[] args) {
long startTime = System.nanoTime();
long lastFrameTime = startTime;
long frames = 0;
int framesToAverage = 10;
long[] frameTimes = new long[framesToAverage];
joglplat m = new joglplat();
while(true){
// logic here
long currentFrameDuration = System.nanoTime() - lastFrame;
lastFrameTime = System.nanoTime();
long instantFramerate = currentFrameDuration / 1000000;
int currentFrameIndex = frames % frameTimes.length;
frameTimes[currentFrameIndex] = currentFrameDuration;
frames++;
long averageFramerate = ( ( lastFrameTime - startTime) / frames ) / 1000000;
long instantFramerate = currentFrameDuration / 1000000;
if( frames > frameTimes.length ) { // if it isn't, we don't have enough data yet
int firstFrameIndex = currentFrameIndex + 1;
if( firstFrameIndex > frameTimes.length ) {
firstFrameIndex = 0;
}
long averageFrameratePerN = ( ( frameTimes[currentFrameIndex] - frameTimes[firstFrameindex] ) / frameTimes.length ) / 1000000;
}
// yield/sleep here
}
}
My suspicion is that this is caused by the inaccuracy of Thread.sleep():
Causes the currently executing thread
to sleep (cease execution) for the
specified number of milliseconds plus
the specified number of nanoseconds,
subject to the precision and accuracy
of system timers and schedulers. The
thread does not lose ownership of any
monitors.
Is there any reason why you have to hold the framerate down like this? Perhaps you can explain more fully what you are trying to accomplish?