Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
Developer
rcmaniac25
Posts: 1,804
Registered: ‎04-28-2009
My Device: Z10 (STL100-4)-10.2.1.2174, Z10 (STL100-3)-10.3.0.700 Dev OS, Z30 (STA100-5)-10.3.0.700 Dev OS, PlayBook (16GB)-2.1.0.1917
My Carrier: Verizon

Any optimization tips

Header: Any ideas on how to speed this up?

 

Recently I became interested in "Falling Sand" games. I didn't want a long project so I made a simple port of "MicroSand" (http://siebn.de/burningsand/microsand). i didn't care to much about making it as small as possible, just enough so it works.

 

This is what I got:

//#preprocessor

/* 
 * Code.java
 * 
 */
package msm;

//#ifndef NO_SIGN
import net.rim.device.api.system.Display;
//#endif
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.TouchGesture;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.container.MainScreen;
//import net.rim.device.api.util.Arrays;

public final class Code extends UiApplication
{
	public static void main(String[] args)
	{
		new Code().enterEventDispatcher();
	}
	
	public Code()
	{
//#ifdef NO_SIGN
		int ori = 0x20; //ORIENTATION_PORTRAIT
//#else
		int ori = Display.getOrientation();
//#endif
		UiApplication.getUiApplication().getUiEngineInstance().setAcceptableDirections(ori); //Just so I don't need to do any modifications right now
		this.pushScreen(new SandScreen());
	}
	
	public final class SandScreen extends MainScreen implements Runnable
	{
		private volatile boolean running,pause;
		private volatile int[] p/*,scanRow*/;
		private int o=0,r,/*u,*/x,y,a=-1,b,h,z,q[]={0,r=91,/*u=*/140,200},c[]={0x000000,0x49DBFF,0x926D00,0xDB4900};
		private int w,op;
		private int keyIndex = 2;
		
//#ifndef NO_MIN
		private static final long MIN = 150;
//#endif
		private static final int DRAW_SIZE = 18;
		private static final int EMPTY = 0x000055;
		
		public SandScreen()
		{
//#ifdef NO_SIGN
			w = z = 360;
			h = 480;
//#else
			w = z = Display.getWidth();
			h = Display.getHeight();
//#endif
			p = new int[h*h];
			//scanRow = new int[z];
			op = z;
			
			//Arrays.fill(scanRow, EMPTY);
		}
		
		public void Process()
		{
			//System.arraycopy(scanRow, 0, p, op+1-z, w-1);
			//System.arraycopy(scanRow, 0, p, op+(h-2)*z+1, w-1);
			for (x=0; ++x<w; p[op+x-z]=p[op+(h-2)*z+x]=EMPTY);
			
			for (o=(h-2)*z; --o>0;)
			{
				int pOpo = (p[op+o]);
				if ((pOpo-0xDB4900)!=0)
				{
					if((pOpo>(b=(p[op+o+z])))&&((r*=5)%(getValue(pOpo-b)/5+2)>5))
					{
						p[op+o+z]=p[op+o];
						p[op+o]=((b-EMPTY)!=0?b:0);
					}
					else if ((b=pOpo)>(p[op+o+(y=1)])&&((r*=7)%97)>1||b>(p[op+o+(y=a)]))
					{
						p[op+o]=p[op+o+y];
						p[op+o+y]=((b-EMPTY)!=0?b:0);
					}
				}
			}
		}
		
		private int getValue(int value)
		{
			for(int i = 0; i < 4; i++)
			{
				if(c[i] == value)
				{
					return q[i];
				}
			}
			return 0;
		}
		
		protected void paint(Graphics graphics)
		{
			super.paint(graphics);
			graphics.drawRGB(p, 0, z, 0, 0, w, h);
		}
		
		public void run()
		{
			while(running)
			{
				if (pause)
	            {
	                synchronized (this)
	                {
	                    try
	                    {
	                        wait();
	                    }
	                    catch (InterruptedException x)
	                    {
	                    }
	                }
	            }
//#ifndef NO_MIN
				long time = System.currentTimeMillis();
//#endif
				Process();
//#ifndef NO_MIN
				time = System.currentTimeMillis() - time;
//#endif
				invalidate();
//#ifndef NO_MIN
				try
				{
					if(time < MIN)
					{
						Thread.sleep(MIN - time);
					}
				}
				catch (InterruptedException e)
				{
				}
			}
//#endif
		}
		
		protected boolean touchEvent(TouchEvent message)
		{
			switch(message.getEvent())
			{
				case TouchEvent.GESTURE:
					if(message.getGesture().getEvent() == TouchGesture.DOUBLE_TAP)
					{
						keyIndex++;
						if(keyIndex > 3)
						{
							keyIndex = 0;
						}
						/*u=q[keyIndex];*/
						return true;
					}
					break;
				case TouchEvent.DOWN:
				case TouchEvent.MOVE:
					//TODO: Optimize as much as possible
					int tX = message.getX(1);
					int tY = message.getY(1);
					int t = c[keyIndex];
					for (y = tY-(DRAW_SIZE/2); y++ < tY + (DRAW_SIZE/2); )
					{
						if(y<h&&y>a)
						{
							for (x = tX-(DRAW_SIZE/2); x++ < tX + (DRAW_SIZE/2); )
							{
								if((x<w)&&(y>a))
								{
									p[op+y*z+x]=t;
								}
							}
						}
					}
					return true;
			}
			return super.touchEvent(message);
		}
		
		protected void onVisibilityChange(boolean visible)
	    {
	        if (visible)
	        {
	        	//Resume
	        	if (running)
	            {
	                // Pause the render loop
	                pause = false;
	                synchronized (this)
	                {
	                	notifyAll();
	                }
	            }
	            else
	            {
	                // Start the render thread.
	            	running = true;
	                new Thread(this).start();
	            }
	        }
	        else
	        {
	        	//Pause
	        	pause = true;
	        }
	    }
		
		public boolean onClose()
		{
			running = false;
			try
			{
				Thread.sleep(100); //Just to allow cleanup
			}
			catch (InterruptedException e)
			{
			}
			super.close();
			return true;
		}
		
		protected void makeMenu(Menu menu, int instance)
		{
		}
		
		public boolean onMenu(int instance)
		{
			return false;
		}
	}
}

 

It currently runs about 4 frames a second, If I could get it to about 15 it would make life much easier to get it working correctly (compile the actual one and you'll see the difference... and the speed). The speed of actual touch interaction I don't really care about right now but I want it to update faster. Any ideas for this (very inefficent) code?

 

Ported for the Storm2.

---Spends time in #blackberrydev on freenode (IRC)----
Three simple rules:
1. Please use the search bar before making new posts.
2. "Like" posts that you find helpful.
3. If a solution has been found for your post, mark it as solved.
--I code too much. Well, too bad.
Please use plain text.
Developer
dnepr
Posts: 723
Registered: ‎03-12-2009
My Device: Playbook

Re: Any optimization tips

[ Edited ]

Without understanding the actual algorithm...

 

I see that you basically process/repaint/process/repaint.

 

So you're constantly repainting and reprocessing the whole screen.

 

Is the whole screen changing with every frame? 

 

Have you profiled the code?  What is taking the most time, the process or the paint operation?

Please use plain text.
Developer
rcmaniac25
Posts: 1,804
Registered: ‎04-28-2009
My Device: Z10 (STL100-4)-10.2.1.2174, Z10 (STL100-3)-10.3.0.700 Dev OS, Z30 (STA100-5)-10.3.0.700 Dev OS, PlayBook (16GB)-2.1.0.1917
My Carrier: Verizon

Re: Any optimization tips

The way the original C/SDL code works is the window is setup and a pointer to the screen buffer is returned, the buffer is updated every time (Process()) and the whole screen basically does get updated so a full screen refresh is required.

 

So to answer the questions:

Yes

No (I could never really get the profiler to work) but I did implement a couple lines so for testing to artificially slow it down, when I ran that I got between 189 and 300 milliseconds to run Process().

 

If I ran that on invalidate it says 0, I don't know if it just simply adds an item to the event stack or actually runs it. I think its the process operation (which is why I asked if anyone can think of any way to optimize it) because the paint operation basically draws raw pixels so it should be quick.

 

The process operation on the other hand does a loop through each pixel on screen which I know is inefficient but I'm not sure how to get around it because the code was written specifically for that single-buffer model and not for a organized "only draw what changed" system.

 

I am finishing one thing up and will see if I can profile the code and get back to you on where it says it is slowing down.

---Spends time in #blackberrydev on freenode (IRC)----
Three simple rules:
1. Please use the search bar before making new posts.
2. "Like" posts that you find helpful.
3. If a solution has been found for your post, mark it as solved.
--I code too much. Well, too bad.
Please use plain text.
Developer
dnepr
Posts: 723
Registered: ‎03-12-2009
My Device: Playbook

Re: Any optimization tips

[ Edited ]

invalidate() is a non-blocking call.

 

I'm guessing a singlular paint is not taking all that long, but repainting the whole screen is expensive if you are looking for high FPS.

 

A simple example is a signature capture app one can write.  If you repaint the whole screen after every pointer move, the whole process is very slow and un-responsive.  Repainting only the little part that changed makes FPS (so to speak) go through the roof and the capture becomes extremely smooth.

 

In your case 300 ms to create a single frame is definitely not good and is probably causing majority of the slowdown (I'm just speaking theoretically here, can't really test on device/simulator at the moment).

 

If the whole screens composure changes (no static parts) than that kinda makes it pointless to only repaint parts :smileywink:

 

Time to look through the process().  I like optimization problems :smileyvery-happy:

Please use plain text.
Developer
dnepr
Posts: 723
Registered: ‎03-12-2009
My Device: Playbook

Re: Any optimization tips

[ Edited ]

Inside your TouchEvent don't divide by 2.   Use (var>> 1) instead of(var/2)

 

I would just take a look at that whole loop as well, I think you're doing more calculations than you need.  If you can, if using value only once, calculate it once and re-use.

 

 

Please use plain text.
Developer
rcmaniac25
Posts: 1,804
Registered: ‎04-28-2009
My Device: Z10 (STL100-4)-10.2.1.2174, Z10 (STL100-3)-10.3.0.700 Dev OS, Z30 (STA100-5)-10.3.0.700 Dev OS, PlayBook (16GB)-2.1.0.1917
My Carrier: Verizon

Re: Any optimization tips

Lol, me too.

 

The divide by 2 isn't a problem because it is to a static final int, in other words: division is done at compile time, not run time.

---Spends time in #blackberrydev on freenode (IRC)----
Three simple rules:
1. Please use the search bar before making new posts.
2. "Like" posts that you find helpful.
3. If a solution has been found for your post, mark it as solved.
--I code too much. Well, too bad.
Please use plain text.
Developer
dnepr
Posts: 723
Registered: ‎03-12-2009
My Device: Playbook

Re: Any optimization tips

[ Edited ]

Didn't notice :smileyvery-happy:

 

 

Is this ever called?

				try
				{
					if(time < MIN)
					{
						Thread.sleep(MIN - time);
					}
				}
				catch (InterruptedException e)
				{
				}
Please use plain text.
Developer
dnepr
Posts: 723
Registered: ‎03-12-2009
My Device: Playbook

Re: Any optimization tips

I notice you do stuff like this:

 

if ((pOpo-0xDB4900)!=0)

I would think that just comparing p0po != 0xDB4900 would be faster than doing a subtraction and than comparing vs. 0.   (Again kinda wishcasting performance, would need to check it i.e. do it 10000 times and compare which is faster).

 

 

Micro optimizations =\

Please use plain text.
Developer
rcmaniac25
Posts: 1,804
Registered: ‎04-28-2009
My Device: Z10 (STL100-4)-10.2.1.2174, Z10 (STL100-3)-10.3.0.700 Dev OS, Z30 (STA100-5)-10.3.0.700 Dev OS, PlayBook (16GB)-2.1.0.1917
My Carrier: Verizon

Re: Any optimization tips

[ Edited ]

The release version doesn't have it, it's solely for debugging. I know try/catch is slow but sleep does get called (as I optimize it). I already made great strides before I got to asking for help... there was a time it took 22 seconds in Process().

 

True on the second post, changing.

---Spends time in #blackberrydev on freenode (IRC)----
Three simple rules:
1. Please use the search bar before making new posts.
2. "Like" posts that you find helpful.
3. If a solution has been found for your post, mark it as solved.
--I code too much. Well, too bad.
Please use plain text.
Developer
dnepr
Posts: 723
Registered: ‎03-12-2009
My Device: Playbook

Re: Any optimization tips

Inside getValue() function.

 

Do a reverse for loop.  i.e. start at i=4 and compare vs. 0.   It keeps a variable off the stack and comparison vs. 0 is faster.

Please use plain text.