Understanding Android Tight loops / Spin-On-Suspend error - java

I am developing a game on android, 'Space RPG' - currently only seeing this error pop up on most Galaxy S4s, and HTC Ones. This is all Java.
The game will stall, when I try to debug the process and suspend the thread in question, it won't suspend, and a spin-on-suspend error happens.
The thread dump lets me see that it was inside a certain while loop that is taking a desired 'end position' and iterating backwards at an ever increasing distance step to find a 'start position'.
This is where things get annoying. I can verify that the loop can not run indefinitely, even though the condition is while(true), it is not possible for it to run more than maybe 200 iterations before my break gets called (this assertion being backed up by the code working on every other phone I have tried).
To help ease my mind on this matter, I added a simple incremented variable inside the loop, and if it ever goes above 1000 it will log something out so I can see that it DID run too many times, just in case some variable was set badly or something.
When this counter code is present, NO crash/hang occurs. Nor do I see any logs indicating it ran over 1000 times.
If I remove this counter, the hang occurs every time after 5-10 seconds of playing [in which the while loop will have run maybe 10 times, though that varies].
My question is therefore, what the hell is going on? :P
Why would these newer phones (but seemingly none of the older phones) have a problem with a loop that is doing valid work and doesn't last long, when there is no incremented variable in there. How could the thread possibly stall in that loop, and how does having an extra counter variable fix the issue?
This work is being done on the opengl render thread, in case that is important.
I have reports of this happening on most S4s, but there is at least one S4 out there where it didn't happen. The one I am using today it IS happening. This makes me wonder if it could possibly be to do with the specific android, java, dalvik or something else on the phone but I unfortunately dont have any details from the S4 where it worked.
Any help, guidance, thoughts or further reading on stuff like this would be appreciated, thanks a lot.
float vel = 1.0f; // final velocity is 1. We are working backwards to find out what the starting velocity will need to be.
int i = 0;
double xmath = Math.sin(rot* (Math.PI/180.0f)); // component of velocity for x,y direction based on rotation
double ymath = Math.cos(rot* (Math.PI/180.0f));
while (true) {
/* with this section uncommented, the stall never happens...
++i;
if (i>1000) {
// Something went rather wrong
vel = 91.0f; // LOG WAS HERE, now has a fallback value justincase
break;
}
*/
vel *= 1.2f;
dx -= vel* xmath;
dy += vel* ymath;
if (distance < (float)Math.sqrt(dx*dx+dy*dy)) {
break;
}
}
// Give the ship a velocity that is appropriate for the distance remaining
_AI.Ship.Velocity = vel;

This is probably http://b.android.com/58726.
The bug has full details; in short: some vendors appear to use a modified version of the Dalvik VM. Changes made to the JIT compiler prevent thread suspension from occurring in certain situations.
The litmus test for this issue is to compare the standard retail device against the "pure Android" Google Play Edition of the GS4 and HTC1. If the former shows the broken behavior, but the latter works correctly, you are likely seeing a vendor-specific problem.
The workaround is to do what you've done: make the code less efficient so it doesn't fall into the "optimized" case. Ideally the app would runtime-select a different code path for devices without the issue, but I don't know of a good way to detect the problem at run time.

Related

If compareAndSet fails, is the code below still executed?

I have a very dumb question.
If I use AtomicReferences compareAndSet
this way
original.set(atomic.get());
long next = some new value
atomic.compareAndSet(original.get(), next);
....more code....
is more code still updated if the comparison fails (i.e. atomic has been updated by another thread).
I'm trying to find an error in an assignment and this is the only thing I can think about and I've been trying for few hours.
P.S.
Weirdly enough, if I use synchronize on this code
it gives me the correct answer on my laptop, but not on my desktop
MangatRaiModi and SotiriosDelimanolis put me on the right path.
A simple fix:
original.set(atomic.get());
long next = some new value
while(!atomic.compareAndSet(original.get(), next))
{
do above again
}
....more code....
did it.
Still not sure how synchronized fixed this on my laptop but not on my desktop.
I'm guessing that it's slowing the threads down on the mobile Chip enough so that they can operate sequentially (Like a Print statement).
I'm probably wrong though.

java.awt.Robot.waitForIdle() is unrealiable

We are seeing frequent timing issues in our nightly UI tests. The tests often fail because events performed by the java.awt.Robot have not completed before the test code tries to verifying the results.
We are code like using:
Point p = cb.getLocationOnScreen();
int m = 5;
if (cb.getWidth()<5||cb.getHeight()<5)
m=3;
System.out.println("Click at " + (p.x+m) + "," + (p.y+m));
robot.mouseMove(p.x + m, p.y + m);
robot.mousePress(MouseEvent.BUTTON1_MASK);
robot.mouseRelease(MouseEvent.BUTTON1_MASK);
robot.waitForIdle();
Thread.sleep(100);
// Verify results...
We keep having the bump up the Thread.sleep to ensure things complete on the event thread (things like clicking on a button or typing text) despite the java.awt.Robot.waitForIdle() call.
I found this question (Does java.awt.Robot.waitForIdle() wait for events to be dispatched?) which says to use java.awt.Toolkit.realSync(), but this is not an accessible method and with Java 9 coming, I'd rather not add any unnecessary reflection to our tests.
Are there better solutions? Or do people use realSync() or just increase the wait time until tests pass reliably?
UPDATE
I tried using sun.awt.SunToolkit.realSync(), but it is hanging in some tests and never returning. It looks like the EventThread is painting borders and such.
Looks like my only solution is to bump the sleep time up until the test can actually pass reliably. Yuck.
UPDATE 2
I figured out the first hang I had with realSync(). It was a problem in our code, where some paint code called a get method that called a set method which queued up another paint. Repeat forever.
Fixed our code and realSync() worked for a while, sort of. It still seems to return before it should. No idea why and I have no work around.
Also, I've seen realSync() hang and time out on my Linux box running under Java 1.7, but it works under Java 1.8. Very reliable tool here. /s
So, back the to original question. What is a decent way to tell when UI updates are done?
I came to the conclusion that I did need to use SunToolkit.realSync() and it seems to work correctly for Java 9 as well.
It seems, although I couldn't find any hard evidence, that realSync() waits for all graphics related threads while Robot.waitForIdle() and SwingUntilities.invokeLater() only wait for the Java EventThread to finish it's work.
If someone comes up with a better answer, I'd being will to accept that instead of my answer.

Repeating a method multiple times per thread loop

To give some background information, I'm currently working on a Java coded pinball game. I'm keeping it in an MVC design model. It has a fairly realistic physics system that allows it to work collisions, gravity, friction etc. The system runs on a 20 FPS system right now.
The problem I'm having is that the physics loop that checks for collisions in the system works by running a method that using the current velocity of the ball calculates the time until the next collision. The most effective way for this to work would obviously be to keep running the check to account for the movement of the ball between checks to get it as accurate as possible, and if the time until collision is less than the time until the next check, then carry out the collision.
However, right now the system I am working with can only run the loop 20 times per second, which does not provide as accurate results as I would like, particularly during times of high acceleration, such as at ball launch.
The timer loop that I use is in the controller section of the MVC, and places a call to the physics section, located within the model. I can pass in the time remaining at the time the method is called in the controller, which the physics system can use, however I don't know how to run the loop multiple times while still tracking the remaining time before the next screen refresh?
Ideally I would like to run this at least 10 times per screen refresh. If anybody needs any more information please just ask.
Thanks for any help.
So the actual problem is that you do not know when the the collision will happen and when the next frame update is?
Shouldnt these be seperate running tasks? One thread that manages the collision detection and one that does the updating? each thread can run on its own interval (Timer.addTask(...)) and they should propebly be synchronized so colission/location updates are not performed when the render thread is executed.
Hope this answers your question.
Regards, Rob.

Java Metronome with High Speeds

as an excercise I'm trying to create a metronome with Java using Thread.sleep as a timer and JMF for sounds. It's working out quite well but for some reason JMF seems to be only playing sounds at a maximum of 207 beats per minute.
From my Metronome-class:
public void play() {
soundPlayer.play();
waitPulse();
play();
}
From my SoundPlayer-class:
public void play() {
new Thread(new ThreadPlayer()).start();
}
private class ThreadPlayer implements Runnable {
public void run() {
System.out.println("Click");
player.setMediaTime(new Time(0));
player.start();
}
}
I've made SoundPlayer.play() work as a thread to test if it would make a difference, but it's not. I can easily change tempos up to about 207bpm but even if I set my timer to 1000bpm the sounds aren't played any faster than about 207bpm.
I've put the System.out.println("Click"); inside my ThreadPlayer.run() to check if my loop is working correctly – it is.
The issue seems to be with my implementation of JMF. I'm pretty sure there is a simple solution, can anybody help me out?
Thank you so much for your help! :)
The answer about Thread.sleep() being unreliable is correct: you can't count on it to return in exactly the amount of time you specify. In fact, I'm rather surprised your metronome is usable at all, especially when your system is under load. Read the docs for Thread.sleep() for more details. Max Beikirch's answer about MIDI is a good suggestion: MIDI handles timing very well.
But you ask how to do this with audio. The trick is to open an audio stream and fill it with silence between the metronome clicks and insert the metronome clicks where you want. When you do that, your soundcard plays back the samples (whether they contain a click or silence) at a constant rate. The key here is to keep the audio stream open and never close it. The clock, then, is the audio hardware, not your system clock -- a subtle but important distinction.
So, let's say you are generating 16 bit mono samples at 44100 Hz. Here is a function that will create a click sound at the requested rate. Keep in mind that this click sound is bad for speakers (and your ears) so if you actually use it, play it at a low volume. (Also, this code is untested -- it's just to demonstrate the concept)
int interval = 44100; // 1 beat per second, by default
int count = 0;
void setBPM( float bpm ) {
interval = ( bpm / 60 ) * 44100 ;
}
void generateMetronomeSamples( short[] s ) {
for( int i=0; i<s.length; ++i ) {
s = 0;
++count;
if( count == 0 ) {
s = Short.MAX_VALUE;
}
if( count == interval ) {
count = 0;
}
}
}
Once you set the tempo with setBPM, you can play back the samples generated by calling the the generateMetronomeSamples() function repeatedly, and streaming that output to your speakers using JavaSound. (see JSResources.org for a good tutorial)
Once you have that working, you could replace the harsh click with a sound you get from a WAV or AIFF or a short tone or whatever.
Take your time and take a look at MIDI! - http://www.ibm.com/developerworks/library/it/it-0801art38/ or http://docs.oracle.com/javase/tutorial/sound/TOC.html . It's the best solution for everything related to computer made sound.
My assumption would be, and maybe someone else can jump in here, is that thread running times are up to the whims of the thread scheduler. You can't guaranty how long it will take for the JVM to get back to that thread. Also, seeing as the JVM is running as a process on the machine, and is subject to the OS's process scheduler, you are looking at at least two levels of unpredictability.
Just like Jamie Duby said, just because you tell the Thread to sleep 1 millisecond, doesn't mean that it will get called back at exactly one millisecond. The ONLY guarantee is that AT LEAST one millisecond has passed since you called Thread.sleep();. In reality, the processor cannot process the code fast enough to play a beep sound every millisecond, which is why you see the delay. If you want a dramatic example, make a home-made timer class and try making it count one millisecond for a full minute, you will see that the timer is off by quite a bit.
The person who really deserves the answer credit here is Max Beikrich, Midi is the only way you are going to be able to produce the output you are looking for.
I have far more experience as a musician than a programmer but I just finished a metronome application I started a while back, I had put the project on hold for a while because I couldn't figure out why I was having the same problem you are. Yes Thread.sleep() can be unreliable but I'm managed to make a good metronome using that method.
I saw you mentioned trying an ExecutorService I don't think using concurrent classes will solve your problem. My guess is its a system resource issue, I'm pretty certain MIDIs are the way to go with a metronome. I force my students to practice with a metronome and I've used many, I haven't ever been too concerned with the audio quality of the ticks, timing is far more important and MIDIs are going to be much faster than any other audio file. I used the javax.sound.midi library from the Sound API. I suspect that will solve your problem.
You may notice your ticks are uneven when it works properly, this is due to the Thread.sleep() method not being very reliable. How I solved that problem was by doing all my calculations in nanoseconds using the System.nanoTime() method instead of the System.currentTimeMillis() method, just don't forget to convert back to milliseconds before passing the sleep time into the Thread.sleep() method.
I don't want to post the code for my metronome here in case you want to figure it out on your own but if you'd like to see it just send me an e-mail kevin.bigler3#gmail.com and I'd be happy to send it to you. Good luck.

GL_OUT_OF_MEMORY after a call to glDrawArrays. Why?

I have a situation that seems rather strange. I will try to provide enough details, so that someone smarter than me can explain this. Basically here is the setup:
OS: Android 2.2 Froyo
Device: SGS Vibrant
Application: OpenGL-ES 1.1
And here is the problem: I can successfully render a fairly complex scene, and it can run endlessly for hours without leaking any memory. Dalvikvm shows up in the logcat once every 3-5 minutes and there would have been no problem unless I try to exit my application and run it again. In fact I can restart my application 2 times, but on the third time, I get GL_OUT_OF_MEMORY.
I have tracked the error down to the gl.glDrawArrays() call. I can confirm that the gl.glGetError() returns 0 prior to the DrawArrays call in question, and it will return 1285 (GL_OUT_OF_MEMORY) after the DrawArrays call.
Naturally, I have thought that I am not cleaning up the resources and releasing OpenGL context. Here is what I do when the application is being shut down.
for(int x=0; x<buffers.length; x++){
if(gl.glIsBuffer(buffers[x])){
gl.glDeleteBuffers(1, buffers, x);
buffers[x]=0;
}
}
for(int y=0; y<textures.length; y++){
if(gl.glIsTexture(textures[y])){
gl.glDeleteTextures(1, textures, y);
textures[y]=0;
}
}
System.out.println("ERROR: "+gl.glGetError());
finish();
When I run my application the first two times, I do not get any error returned at shutdown. However on the 3rd try, I get the aforementioned error, which I tracked down to the gl.glDrawArrays() call.
Here is a brief summary of what happens during the 3rd run:
Objects 1-56 go through their respective gl.glDrawArrays() calls like hot knives through butter. No errors generated.
Objects 57-64 generate a GL_OUT_OF_MEMORY error. The objects get rendered, but the texture is black.
I am more than sure that I am deleting all of the Buffers and Textures at app shutdown. I am also confident that this error is not specific to one 3D model, as I have tried skipping model #57, but then #58 will still get this error.
Please help, as I am running out of ideas!
I just found out GL_OUT_OF_MEMORY can be set if you first pass the NULL pointer to glVertexAttribPointer.
No error before drawArrays, GL_OUT_OF_MEMORY after. (tested on Galaxy S2 4.1.2, GLES2) Maybe that's what's going on for some reason after a while in your program?
this took me forever to find... TODO: more unit tests :)
GL_OUT_OF_MEMORY after a call to glDrawArrays. Why?
It is really hard to say but from what I have learned, this error occurs when you are having too many polygons in memory, or at least, same vertices are being defined n times. Since you said you're having a complex scene; this problem is probably a memory problem.
One solution could be to use glDrawElements() and let your scene reduce the amount of vertices by letting your polygons share same vertices when necessary. In this way your memory is lowered and it is possible that this fixes the problem.
I found that glDrawArrays() was setting GL_OUT_OF_MEMORY when glVertexAttribPointer() was being called with a non-null pointer. This turned out to be because a different bit of code had called glBindBuffer() to use a vertex array object but then hadn't unbound the buffer afterwards. A call to glBindBuffer(GL_ARRAY_BUFFER, 0) fixed the problem.
Can also happen if you have incorrect glVertexAttribPointer calls on Android. I got this error , when I incorrectly passed ST attributes to a previously prepared normal attribute (duplicate glVertexAttribPointer calls to prepare the normal attribute, the second should have bound to the ST attribute).

Categories