Ah, I see, it might have been due to my misuse of wait() and notify(). In any case, I remember that even sleeping the thread caused decreased fps rate, (which I took as increased cpu usage.)
I mentioned the pool thread, not because I implemented one, but because I avoided implementing one and avoided dealing with polling (and timestep calculations) by using the TimerTask class. Which uses a more efficient thread pool/looping that I could implement with wait() and notify(). And in this case, yes it was the thing that worked the best first, but thanks for the useful information/code. I will try to apply it when I revisit the code. On Sun, Apr 11, 2010 at 12:25 PM, Bob Kerns <r...@acm.org> wrote: > You say: "So, say I have the game loop logic in a thread like that, > using the > render fps average as a counter, I've noticed that the fps drops when > using more than one thread, even if it's just running in an empty > loop. " > > Um, ESPECIALLY if it's running in an empty loop. The point is, you > don't want it to run AT ALL unless it has something to do. > > Handler is one way to do this. Sleep never helps you do this, UNLESS > "something to do" is purely based on time. > > What your code below is doing is called "polling". Polling is the > technique of last resort, because your thread has to wake up > periodically even if there's nothing to do. > > That may not be serious -- and sometimes it's your only choice. But > the ideal is to block, waiting to be told there's actual work to do. > > "I remember timing this was I would constantly send network data to > the > network thread with a timestamp, then I would check how long it took > for that message to make it to the game loop by determining the time > difference. " > > This doesn't sound like a good way to measure, as there are too many > variables. > > If you created the timestamp at the point of sending it to the > handler, and how long it took before the handler began executing, > you'd have a valid measurement of the latency. However, even latency > is not telling you efficiency. > > Using a Handler does not involve creating a thread, so I'm not sure > why you mention that you use a thread pool. Indeed, if you're using > multiple threads to do intermittent work, a thread pool is a good > idea. However, since you have only one main processor, if you're doing > work that doesn't block, you may find no advantage, and even a small > performance DECREASE, by having more than one thread in your pool! > (There can be other reasons to have more than one thread, however; I'm > just discussing performance). > > Handler is presumably doing something like this to queue: > synchronized (m_actions) { > m_actions.add(r); > m_actions.notify(); > } > And something like this to pull from the queue and execute: > while (true) { > Runnable action = null; > synchronized (m_actions) { > while (m_actions.isEmpty()) { > try { > m_actions.wait(); > } catch (InterruptedException e) { > } > } > action = m_actions.remove(); > } > action.run(); > } > > When there's nothing to do, the thread is waiting in the wait() call, > not running, not consuming any CPU. (It does consume some significant > memory; idle threads are not free!) > > (Don't worry about that inner loop and catch of InterruptedException > -- nobody will be interrupting, that's a holdover from the early days > of Java). > > When something is placed in m_actions, the thread running the loop > *immediately* becomes runnable. Whether it runs immediately depends on > whether it has to compete with other threads which are also runnable. > And more importantly, if it was NOT in the wait() call -- that is, it > is still running an earlier request, then it will not run the new > runnable until the old one completes, and it goes around the loop > again to check. > > This loop NEVER runs unless there is work to do -- yet it's > immediately runnable when there is. (The exception is that it checks > if something is already queued on first entry). This is the ideal. > With polling, you have to check if there's work to do. The check here > IS run before waiting after just completing work, but the thread was > already awake in this case. It never wakes up just to see if there's > work. > > "The game loop I'm using is SUPPOSED to be 60fps but will undoubtedly > vary, I use the Timer class's scheduleAtFixedRate to automatically > take care of the timestep adjustments/wait time. > Since the timer class uses a thread pool, it doesn't have an overhead > of thread creation. I don't have to handle calculating how long to > sleep to maintain a constant rate, and is quite efficient. > I've achieved a smooth display, and the physics progresses a step at > each game loop iteration. > This has worked well for me. " > > If that's all worked well for you, I'm NOT telling you that you need > to change it. However, there's a number of ways this can break down > when you really push the limits. > > But a guiding principle is -- Do The Simplest Thing That Could > Possibly Work. It sounds like you've achieved that, for now. Or maybe > "The First Thing That Worked", and sometimes that's a good choice, > too! :=) > > If someday you find it no longer meeting your needs, you can take > these other things into consideration. Or others reading this thread > may find them useful. > > On Apr 10, 6:34 pm, Miguel Morales <therevolti...@gmail.com> wrote: >> Ok, like I said I may have missed something, but say I have something like >> this: >> >> class MyThread extends Thread >> { >> run() >> { >> while (something) >> { >> if (something_else) //perhaps input has changed, or we have >> data in a socket >> { >> //do some work, not idle >> } >> else >> { >> //no work to do >> } >> Thread.sleep(x); //maybe needed, based on implementation >> } >> } >> >> } >> >> So, say I have the game loop logic in a thread like that, using the >> render fps average as a counter, I've noticed that the fps drops when >> using more than one thread, even if it's just running in an empty >> loop. >> >> Using a looper object forces me to communicate with the thread by >> posting messages to its handler. Say I have a network thread that >> just got a message and wants to let the game loop of a new data >> available, or the UI thread wants to let the game loop know that the >> input state has changed. It can be done using a handler, or using a >> lock to protect a data buffer. >> >> So say in the game logic loop we constantly check the state of some >> variable and doing work accordingly, I have found it's much faster to >> use a lock around an object than it is to post to a handler. The way >> I remember timing this was I would constantly send network data to the >> network thread with a timestamp, then I would check how long it took >> for that message to make it to the game loop by determining the time >> difference. >> >> I was working directly with bytes, as to avoid any sort of >> serialization overhead. >> >> The game loop I'm using is SUPPOSED to be 60fps but will undoubtedly >> vary, I use the Timer class's scheduleAtFixedRate to automatically >> take care of the timestep adjustments/wait time. >> >> Since the timer class uses a thread pool, it doesn't have an overhead >> of thread creation. I don't have to handle calculating how long to >> sleep to maintain a constant rate, and is quite efficient. >> >> I've achieved a smooth display, and the physics progresses a step at >> each game loop iteration. >> This has worked well for me. >> >> >> >> On Sat, Apr 10, 2010 at 12:57 PM, Bob Kerns <r...@acm.org> wrote: >> > If a thread is hogging the CPU, it is *BY DEFINITION* not idle. And >> > vice versa. >> >> > An idle thread will be waiting on something. Either a synchronization >> > lock, or an object using wait(), or some blocking IO call. This may be >> > buried inside some other code, of course. >> >> > I would suggest wondering why you thought this. How are you >> > determining what threads are consuming what CPU? Either you have some >> > sort of methodology error, or interpretation error. >> >> > I would wonder about your statement about a Looper and Handler being >> > slow. I haven't read the code, but the implementation I would expect >> > would be very simple, and using wait/notify. In other words, they >> > SHOULD be fast. If you find them slow, I'd again check your >> > methodology -- and if you can confirm, I'd suggest filing a bug >> > report, since that's something that could be improved and would >> > improve things for the entire platform. >> >> > Re 60 fps game logic -- some alternatives to consider that may be >> > better choices in some circumstances. I'm only considering physics >> > here; I'm not sure what the time constraints on other game logic might >> > be: >> >> > If you're doing your physics calculations correctly, you won't be >> > constrained to a constant game logic rate. You may be able to vary >> > your simulation time step to maintain a more steady render rate (at >> > the cost of some accuracy), and even vary it between different parts >> > of the model, e.g. critical portions (e.g. collisions) run a higher >> > rate, while running a longer timestep for portions not subject to time- >> > varying forces. >> >> > If smooth display is more important than physical accuracy, running >> > physics after each frame, driven by actual elapsed time, may be the >> > way to go. You can trigger that as you're about to flip the scene, so >> > it overlaps the GPU. You may prioritize your fast-moving stuff, and >> > only update a portion of your model on each frame. >> >> > Also, you may be able to apply Level of Detail (LOD) control to your >> > scene -- including fewer polygons when the overall frame rate drops >> > (due to either graphics or physics). >> >> > All that is a lot more complex, of course, but may let you push the >> > envelope a bit further. >> >> > On Apr 9, 7:42 pm, Miguel Morales <therevolti...@gmail.com> wrote: >> >> I may be completely wrong on this, but I've found that threads hog the >> >> CPU even when idle. >> >> >> The way that has worked well for me is to have the render thread, and >> >> the logic timer. >> >> >> (using a looper and communicating via a handler can be slow, from my >> >> experience locks are faster) >> >> >> To keep things simply I use a TimerTask to simulate a 60fps game logic >> >> rate (game_loop_timer.schedule(game_loop_task, 0, 17);). The game >> >> logic rate can vary based on what needs to be done. (i.e pathfinding, >> >> network syncing, etc.) and sets a scene to the buffer. >> >> >> The render thread stays constant by simply drawing what's on the scene >> >> buffer at every onDraw. >> >> >> I use a single lock to keep the scene buffer safe between the two threads. >> >> >> It's actually pretty simple, and I only really need two classes. >> >> >> I highly recommend reading articles about this, here are some of my >> >> bookmarks:http://gafferongames.com/game-physics/fix-your-timestep/http://stacko...... >> >> >> For input, I use a lock for the state of the hardware. (i.e. when the >> >> screen is being touched, I set a boolean isTouched to true and use a >> >> lock to safely read/write from the threads. However, a queue/handler >> >> is really the way to go when it comes to that since it's not as >> >> time/latency sensitive. >> >> >> On Fri, Apr 9, 2010 at 6:29 PM, Lance Nanek <lna...@gmail.com> wrote: >> >> > There are a lot of built in classes in Android and Java that you can >> >> > use to avoid having to write any synchronization or lock code >> >> > yourself. In my case GLSurfaceView sets up my render thread. I use >> >> > HandlerThread for my game thread. The game thread sends an update >> >> > object detailing all the draw commands needed for a frame to the >> >> > render thread via a BlockingQueue. The render thread returns it via >> >> > the game thread's Handler. The UI thread tells the game thread about >> >> > input via the game thread's Handler as well. These classes are in the >> >> > android.os and java.util.concurrent packages. >> >> >> > On Apr 9, 6:36 pm, Eddie Ringle <ed...@eringle.net> wrote: >> >> >> Okay, I figured I could just pass the Activity through parameters, but >> >> >> wanted to know if a better way was possible. >> >> >> Thanks for all the help everyone. >> >> >> >> On Apr 9, 5:56 pm, Mario Zechner <badlogicga...@gmail.com> wrote: >> >> >> >> > That depends on what kind of input you need. If your game is happy >> >> >> > with just checking the current state of the accelerometer/touch >> >> >> > screen/ >> >> >> > keyboard/trackball simply polling will do the trick. This means that >> >> >> > in the UI thread, where you have your event listeners installed, you >> >> >> > simply save the last state reported to you. In your logic thread you >> >> >> > can savely access this state even without synchronization as it will >> >> >> > only be composed of plain old data types like booleans or ints (of >> >> >> > course there are cases where you catch the x coordinate of the >> >> >> > previous event and the y coordinate of the current event but i dare >> >> >> > say that the differences are so tiny, it doesn't make a difference). >> >> >> >> > Other things might need event based input handling, like a GUI you >> >> >> > implement yourself with say OpenGL. In that case you will need a >> >> >> > queue >> >> >> > that gets filled in the Android GUI thread by the listeners you have >> >> >> > installed for the input devices. The logic thread acts as a consumer >> >> >> > and takes the events from the queue. As you are working with a >> >> >> > complex >> >> >> > data structure you need to synchronize the adding and removing of >> >> >> > events to and from the queue in both the Android GUI thread and your >> >> >> > logic thread. This is a classical consumer/producer pattern which can >> >> >> > be found frequently in multithreaded applications. Check out Robert's >> >> >> > site athttp://www.rbgrn.net, i think he wrote an article on that sort >> >> >> > of thing once. >> >> >> >> > it basicaly boils down to this (pseudo code, written from the top of >> >> >> > my head, will not compile) >> >> >> >> > public class GameActivity extends Activity implements >> >> >> > MotionEventListener >> >> >> > { >> >> >> > Queue<Event> events = new Queue<Event>(); >> >> >> >> > public void onTouch( MotionEvent event ) >> >> >> > { >> >> >> > synchronized( events ) >> >> >> > { >> >> >> > events.add( new Event( event.getX(), event.getY() ); >> >> >> > } >> >> >> > } >> >> >> >> > } >> >> >> >> > public class GameLogic >> >> >> > { >> >> >> > GameActivity activity; >> >> >> >> > public GameLogic( GameActivity activity ) >> >> >> > { >> >> >> > this.activity = activity; >> >> >> > } >> >> >> >> > public void handleInput( ) >> >> >> > { >> >> >> > synchronized( gameActivity.events ) >> >> >> > { >> >> >> > // proces events here >> >> >> > } >> >> >> > } >> >> >> >> > } >> >> >> >> > Now, a couple of comments: You don't want to instantiate a new Event >> >> >> > everytime a listener method in the GameActivity is called. You will >> >> >> > need to implement a simple object pool and reuse events. That way the >> >> >> > garbage collector will stay calm. Also note that the design above is >> >> >> > a >> >> >> > bit nasty, i would directly pass the GameActivity to the GameLogic >> >> >> > among other things. But that's up to you. >> >> >> >> > Polling input handling would work like above but without a queue and >> >> >> > without the need for the synchronized blocks. All you do is set some >> >> >> > members of GameActivity, say touchX and touchY in the >> >> ... >> >> read more » > > -- > You received this message because you are subscribed to the Google > Groups "Android Developers" group. > To post to this group, send email to android-developers@googlegroups.com > To unsubscribe from this group, send email to > android-developers+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/android-developers?hl=en > > To unsubscribe, reply using "remove me" as the subject. > -- http://diastrofunk.com, http://developingthedream.blogspot.com/, http://www.youtube.com/user/revoltingx, ~Isaiah 55:8-9 -- You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en