Need help with efficiency NXC code

Discussion specific to NXT-G, NXC, NBC, RobotC, Lejos, and more.
spillerrec
Posts: 358
Joined: 01 Oct 2010, 06:37
Location: Denmark
Contact:

Re: Need help with efficiency NXC code

Post by spillerrec »

muntoo, ahh I see, that makes it easier. Any idea for why this limitation was made btw?

About the profiling results,
It definitively needs another run. Almost half of the spend time is used outside the profiled sections, we could be overlooking something important. I usually time large sections first covering the whole program and then dig down into the interesting parts, timing those in more detail.
Anyway, from these results the first part outside the ******************s is of interest in my opinion. Tile() is of cause the biggest player, but Jump(), MoveRight(), Down() and CheckVargs() ends up being 15% combined never the less. Most of them are related to player movement, perhaps you can improve performance by combining them?

John,
My proposal is to ignore the boolean value during the evaluation and calculate it afterwards. I argue that

Code: Select all

__D0main = b1 && b2; //Or any other boolean expression
will work exactly like

Code: Select all

if( b1 && b2 )
   __D0main = true;
else
   __D0main = false;
I also argue that this approach is more efficient than calculating the boolean value during the evaluation when it needs to be short-circuited.
Feel free to prove me wrong.

It also might be worth to do something like this instead:

Code: Select all

__D0main = false;
if( expression )
   __D0main = true:
Some speed-tests might cast light upon that.


I cannot see why it should be that hard to implement. There should be two functions, one that generates the corresponding code when a boolean expression is needed for a conditional jump and another one which generates the code for when the boolean value is needed from a boolean expression. (The second function can be easily implemented by using the first in a if-like structure shown above.)
If the boolean expression belongs to a if, for, while or do-while structure, use the first function. Otherwise use the second. Is there anything which makes this hard to do with the current compiler?
My blog: http://spillerrec.dk/category/lego/
RICcreator, an alternative to nxtRICeditV2: http://riccreator.sourceforge.net/
muntoo
Posts: 834
Joined: 01 Oct 2010, 02:54
Location: Your Worst Nightmare
Contact:

Re: Need help with efficiency NXC code

Post by muntoo »

[Nevermind, I was delirious from lack of sleep when I posted this. ;)]
Last edited by muntoo on 20 Aug 2011, 18:40, edited 1 time in total.
Image

Commit to LEGO Mindstorms Robotics Stack Exchange:
bit.ly/MindstormsSE


Commit to LEGO Stack Exchange: bit.ly/Area51LEGOcommit
muntoo
Posts: 834
Joined: 01 Oct 2010, 02:54
Location: Your Worst Nightmare
Contact:

Re: Need help with efficiency NXC code

Post by muntoo »

afanofosc wrote:What is the purpose of this post? I hope it is not to tell me how I should be writing my compiler.
Yup... Er wait... No? I can't remember.
Image

Commit to LEGO Mindstorms Robotics Stack Exchange:
bit.ly/MindstormsSE


Commit to LEGO Stack Exchange: bit.ly/Area51LEGOcommit
nxtboyiii
Posts: 366
Joined: 02 Oct 2010, 07:08
Location: Everywhere

Re: Need help with efficiency NXC code

Post by nxtboyiii »

Well, I still need the ****** part to run faster. The faster, the better because then when I add more enemies it won't make much of a difference.

I temporarily commented out the Tile(). It made the code run a lot faster. If I made Tile() faster it would help a lot.

So how would I make Tile() run faster?

Here's a new version of the code(It should be easier to understand):
Attachments
Updated files-Mario.zip
(22.21 KiB) Downloaded 250 times
Thanks, and have a nice day,
nxtboy III

programnxt.com
spillerrec
Posts: 358
Joined: 01 Oct 2010, 06:37
Location: Denmark
Contact:

Re: Need help with efficiency NXC code

Post by spillerrec »

Try changing

Code: Select all

bool OnETile(int pt, int pox, int poy)
{
    return(map[pox][poy].p == pt);
}
to a macro function.

Code: Select all

#define OnETile( pt, pox, poy ) (map[pox][poy].p == pt)
Functions call have a overhead (which increases depending on the parameters amount and complexity and returns), so avoid them for simple one-liners like this.

Can't help you with much more as that part is not commented at all and is not indented properly.
My blog: http://spillerrec.dk/category/lego/
RICcreator, an alternative to nxtRICeditV2: http://riccreator.sourceforge.net/
muntoo
Posts: 834
Joined: 01 Oct 2010, 02:54
Location: Your Worst Nightmare
Contact:

Re: Need help with efficiency NXC code

Post by muntoo »

You can use UniversalGUIIndent. (I use the UniversalGUIIndent plugin for Notepad++. Code Indenting/Formatting is as simple as Ctrl+Shift+Alt+J.)

Indented code:

Code: Select all

bool OnTile(int pointx, int pointy, int paddx2, int paddy2, char ptile)
{
	return((map[pointx][pointy].p == ptile) || (map[pointx+paddx2][pointy+paddy2].p == ptile) || (map[pointx][pointy+paddy2].p == ptile) || (map[pointx+paddx2][pointy].p == ptile));
}
bool OnTTile(char ptile)
{
	return(xy == ptile || xpy == ptile || xyp == ptile || xpyp == ptile);
}
bool OnSLDTile(byte pox, byte poy, byte pdx, byte pdy, char ptile)
{
	return((map[pox][poy].sld == ptile) || (map[pox+pdx][poy].sld == ptile) || (map[pox][poy+pdy].sld == ptile) || (map[pox+pdx][poy+pdy].sld == ptile));
}
bool OnETile(int pt, int pox, int poy)
{
	return(map[pox][poy].p == pt);
}


MapType RTile(int pointx, int pointy, int paddx2, int paddy2, char ptile)
{
	MapType ont;
	if (map[pointx][pointy].p == ptile)
	{
		ont.x=pointx;
		ont.y=pointy;
		return(ont);
	}
	if (map[pointx+paddx2][pointy].p == ptile)
	{
		ont.x=pointx+paddx2;
		ont.y=pointy;
		return(ont);
	}
	if (map[pointx][pointy+paddy2].p == ptile)
	{
		ont.x=pointx;
		ont.y=pointy+paddy2;
		return(ont);
	}
	if (map[pointx+paddx2][pointy+paddy2].p == ptile)
	{
		ont.x=pointx+paddx2;
		ont.y=pointy+paddy2;
		return(ont);
	}

}

void Tile()
{
	unsigned long t0;


	xy=map[mapx][mapy].p;
	xpy=map[mapx+paddx][mapy].p;
	xyp=map[mapx][mapy+paddy].p;
	xpyp=map[mapx+paddx][mapy+paddy].p;


	MapType tilem;


	if (fmapy == floor(fmapy))
	{
		if ((OnETile(UNS,mapx,mapy-1) || OnETile(UNS,mapx+paddx,mapy-1)) && bu == 0)
		{
			t0=CurrentTick()/1000;
			bu=1;
		}
		if (CurrentTick()/1000-t0 >= 1)
		{
			if (OnETile(UNS,mapx,mapy-1) && bu == 1)
			{
				map[mapx][mapy-1].sld=0;
				map[mapx][mapy-1].p=3;
				bu=0;
			}
			if (OnETile(UNS,mapx+paddx,mapy-1) && bu == 1)
			{
				map[mapx+paddx][mapy-1].sld=0;
				map[mapx+paddx][mapy-1].p=3;
				bu=0;
			}
		}
		if (jumping == 1 || bUp)
		{
			if (OnETile(CBR,mapx,mapy+1))
			{
				jc=2;
				ong=0;
				map[mapx][mapy+1].sld=0;
				map[mapx][mapy+1].p=AIR;
				repeat(10)
				{
					RectOut(x+Random(16),y+16+Random(16),Random(3),Random(3));
				}
			}
			if (OnETile(CBR,mapx+paddx,mapy+1))
			{
				jc=2;
				ong=0;
				map[mapx+paddx][mapy+1].sld=0;
				map[mapx+paddx][mapy+1].p=AIR;
				repeat(10)
				{
					RectOut(x+Random(16),y+16+Random(16),Random(3),Random(3));
				}
			}
			if (OnETile(CB2,mapx,mapy+1))
			{
				jc=2;
				ong=0;
				map[mapx][mapy+1].p=BLO;
				map[mapx][mapy+2].p=CON;
				repeat(10)
				{
					RectOut(x+Random(16),y+16+Random(16),Random(3),Random(3));
				}
			}
			if (OnETile(CB2,mapx+paddx,mapy+1))
			{
				jc=2;
				ong=0;
				map[mapx+paddx][mapy+1].p=BLO;
				map[mapx+paddx][mapy+2].p=CON;
				repeat(10)
				{
					RectOut(x+Random(16),y+16+Random(16),Random(3),Random(3));
				}
			}
			if (OnETile(QES,mapx,mapy+1))
			{
				jc=2;
				ong=0;
				map[mapx][mapy+1].p=BLO;
				map[mapx][mapy+2].p=MUS;
			}
			if (OnETile(QES,mapx+paddx,mapy+1))
			{
				jc=2;
				ong=0;
				map[mapx+paddx][mapy+1].p=BLO;
				map[mapx+paddx][mapy+2].p=MUS;
			}
		}
	}
	/*            if(OnETile(MUS,mapx,mapy))
	    {
	     map[mapx][mapy].p=AIR;
	          if(msize == 22)
	          {
	     msa=192;
	     csf=1;
	     }
	     else
	     {
	     msa=96;
	     }
	     msize=22;
	    }*/
	if (OnETile(MUS,mapx+paddx,mapy))
	{
		map[mapx+paddx][mapy].p=AIR;
		if (msize == 22)
		{
			msa=192;
			csf=1;
		}
		else
		{
			msa=96;
			csf=0;
		}
		msize=22;
	}
	if (OnSLDTile(mapx,mapy,paddx,paddy,-2) || OnTTile(LAV) || OnTTile(LAB) || OnSLDTile(mapx,mapy,paddx,paddy,4) || OnSLDTile(mapx,mapy,paddx,paddy,-1) || OnSLDTile(mapx,mapy,paddx,paddy,8) || OnTTile(FIR))
	{
		if (msa == 192)
		{
			msa=96;
			csf=0;
		}
		else if (msa == 96)
		{
			msa=0;
			msize=20;
		}
		else
		{
			dead=1;
		}
	}
	if (mapy == 0)
	{
		dead=1;
	}
	if (OnTTile(CON))
	{
		tilem=RTile(mapx,mapy,paddx,paddy,CON);
		map[tilem.x][tilem.y].p=AIR;
		if (m == 0)
			PlayFileEx("buding.rso",Volume(),0);
	}
	if (OnTTile(END))
	{
		//Display winning screen or go to next level
		SetDisplayFlags(DISPLAY_ON | DISPLAY_REFRESH);
		s=0;
		TextOut(0,0,"loading...");
		Wait(1000);
		lvl++;
		GraphicOut(0,0,"title.ric");
		RectOut(10,5,80,5,DRAW_OPT_CLEAR | DRAW_OPT_FILL_SHAPE);
		if (lvl <= levels)
		{
			PlayToneEx(700,30,1,0);
			unlockedlevels++;
		}
		LoadMap(lvl);
		xadd=0;
		yadd=0;
		mapx=2;
		mapy=1;
		xx=16;
		yy=8;
		fmapx=2;
		fmapy=1;
		x=32;
		y=16;
		xpp=0;
		ypp=0;
		bFire=0;
		paddx=0;
		paddy=0;
		yj=0;
		ffd=0;
		jumping=0;
		dgArgs.Variables[1]=dovar;
		int cnt=2;
		int cnt2=2;
		lvlc=NumToStr(lvl);
		ul=NumToStr(unlockedlevels);
		OpenFileAppend("mariosave.txt",mfsize,mhandle);
		WriteLnString(mhandle,lvlc,cnt);
		WriteLnString(mhandle,ul,cnt2);
		CloseFile(mhandle);
		s=1;
	}
}
Of course, it's still quite messy. Try splitting it into at least 5 functions - the file saving, for example, could be in a separate function.
Image

Commit to LEGO Mindstorms Robotics Stack Exchange:
bit.ly/MindstormsSE


Commit to LEGO Stack Exchange: bit.ly/Area51LEGOcommit
schodet
Posts: 139
Joined: 29 Sep 2010, 11:21
Contact:

Re: Need help with efficiency NXC code

Post by schodet »

I think that multi dimension array operation could be costly. If I am not wrong, when you write:

Code: Select all

a = an_array[i][j]
the compiler translates to:

Code: Select all

tmp_array = an_array[i]
a = tmp_array[j]
If this is the case, you can emulate a fixed size two dimensions array by computing yourself an offset:

Code: Select all

a = an_array[i * SIZE_OF_LINE + j]
LEGO things http://ni.fr.eu.org/lego/ - NXT Improved Firmware (GCC) http://nxt-firmware.ni.fr.eu.org/ - Other robots http://apbteam.org
nxtboyiii
Posts: 366
Joined: 02 Oct 2010, 07:08
Location: Everywhere

Re: Need help with efficiency NXC code

Post by nxtboyiii »

Yes, but that will not work with what I am doing. I have fmapx and fmapy. They are floats for the x and y on the map. They are floats because they need to be inbetween each map element. ie: fmapx=10.5; fmapy=9.5; I cannot do that if it is 1-d
Thanks, and have a nice day,
nxtboy III

programnxt.com
spillerrec
Posts: 358
Joined: 01 Oct 2010, 06:37
Location: Denmark
Contact:

Re: Need help with efficiency NXC code

Post by spillerrec »

If you can do it with a 2D array, you can do it with a 1D array. You would need to round fmapx and fmapy anyway to correctly access the array. (How do the firmware act if given a float as an index pointer btw?)

And schodet, yes, you are correct, you need two array lookups. But what is faster, doing two array lookups, or doing some math + one array lookup? Some testing is required imo. I guess 1D arrays will in many cases allow for more manual optimizing though.
Anyway, the array in question is an array of a struct which causes overhead when writing back to the array as it needs to both read and write. I mentioned both of these issues a few pages earlier in this thread btw.
My blog: http://spillerrec.dk/category/lego/
RICcreator, an alternative to nxtRICeditV2: http://riccreator.sourceforge.net/
nxtboyiii
Posts: 366
Joined: 02 Oct 2010, 07:08
Location: Everywhere

Re: Need help with efficiency NXC code

Post by nxtboyiii »

But how exactly could I make it not an array of structures?
Thanks, and have a nice day,
nxtboy III

programnxt.com
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest