#167043 - Ruben - Fri Feb 27, 2009 4:42 pm
Hey.
Before you start flaming me and telling me to use the search thingo.. I did. :P But I couldn't find what I wanted..
So I decided to code an FFIV-like demo.. with no sound, that's all fine and dandy.. but when adding sound.. Houston, we have a problem!
So basically.. you're supposed to call your sound 'main' routines once per frame, right? If so, one would place this in the v-blank interrupt, after graphics processing... but what if you're actually modifying graphics in a child process? Eg..
Code: |
void VBlankISR(void) {
SoundVBlank();
//Graphics handling, blah
SoundMain();
}
void SomeChildProcess(void) {
int i = 655;
do {
Halt();
//Here modify graphic-related stuff, like palette, OAM, tiles, etc
} while(--i);
}
|
I mean.. I know I can place the SoundMain routine inside the while loop.. but what if I'm doing huge transfers.. say..
Code: |
void SomeChildProcess(u32 *Dest, u32 *Src, Map_t *Map) {
int TileCount = 1024;
//Copy tiles
do {
*Dest++ = *Src++; *Dest++ = *Src++;
*Dest++ = *Src++; *Dest++ = *Src++;
*Dest++ = *Src++; *Dest++ = *Src++;
*Dest++ = *Src++; *Dest++ = *Src++;
} while(--TileCount);
//Copy collision stuff (8->2 bit packing)
//I know this can be done outside the game, but
//just to make my point ;)
int Size = Map->sX * Map->sY; //Size X * Size Y
u8 *cDst = collisionTable;
u8 *cSrc = Map->Collision;
do {
*cDst = (*cSrc++ & 3) << 0;
*cDst |= (*cSrc++ & 3) << 2;
*cDst |= (*cSrc++ & 3) << 4;
*cDst |= (*cSrc++ & 3) << 6;
cDst++;
} while((Size-=4) > 0);
} |
.. What would be the 'correct' method of doing this?
#167047 - samel - Fri Feb 27, 2009 7:21 pm
May be a thread [ http://donotjava.netsons.org/?page_id=67 ]
May be a timer
May be you can [or you already] use a sound library that's not arm9 related
But may also be that i misunderstud your post 8)))))) .
#167071 - Ruben - Sat Feb 28, 2009 5:37 am
Heh, yeah, I think you misunderstood my post, but that was my bad, cos I didn't specify much more than code..
I'm still coding for the GBA cos it's, IMO, a lot easier than DS.
#167081 - Ruben - Sat Feb 28, 2009 12:30 pm
Hm..
Well, I was reading articles on Wikipedia and stuff... and I think threads are what I need... but do I really need to use a timer? It'd be much better if it didn't need a timer, but I suppose I can afford one if it's actually necessary...
#167082 - eKid - Sat Feb 28, 2009 12:37 pm
But DS is so easy to pick up if you know GBA. :)
#167083 - Kyoufu Kawa - Sat Feb 28, 2009 1:12 pm
eKid wrote: |
But DS is so easy to pick up if you know GBA. :) |
Ob-frikken-jection! XD
#167086 - Ruben - Sat Feb 28, 2009 2:32 pm
eKid wrote: |
But DS is so easy to pick up if you know GBA. :) |
Well, I mean..
Yeah, the DS itself is easy to pic up.. but what makes it the most difficult thing in the world for me (even more difficult than Windows apps :P) is the whole "everything's in RAM"
#167088 - sgeos - Sat Feb 28, 2009 2:50 pm
Ruben wrote: |
Yeah, the DS itself is easy to pic up.. but what makes it the most difficult thing in the world for me (even more difficult than Windows apps :P) is the whole "everything's in RAM" |
On windows you generally need to load something into RAM to do anything useful with it...
#167093 - samel - Sat Feb 28, 2009 7:49 pm
[quote="Ruben"]Hm..
Well, I was reading articles on Wikipedia and stuff... and I think threads are what I need... but do I really need to use a timer? It'd be much better if it didn't need a timer, but I suppose I can afford one if it's actually necessary...[/quote]
The thread library it's a port. The original one it's for the gba and doesn't use timer.
www.gbadev.org -> search -> thread
#167098 - Ruben - Sun Mar 01, 2009 6:19 am
sgeos wrote: |
On windows you generally need to load something into RAM to do anything useful with it... |
Well, yeah, but RAM in Windows tends to be > 4MB, which makes me feel.. Hm.. Idk.. secure, maybe.. I think what most throws me off is the fact that my sound bank atm (unfinished) already uses 8MB, 16-bit @ 32768Hz.. cos I have noooooooooo idea how to do that. :P
#167099 - Ruben - Sun Mar 01, 2009 6:26 am
samel wrote: |
The thread library it's a port. The original one it's for the gba and doesn't use timer.
www.gbadev.org -> search -> thread |
I had a look at the source, and it seems to use a timer, as well. :-/
#167100 - Ruben - Sun Mar 01, 2009 6:29 am
Hmmmmmm
I was taking another look at this.. and came up with another thought:
Is the correct way of doing it just placing the "main" routine in v-blank, and when you go to do hugeeeee things, you disable the screen?
#167101 - sgeos - Sun Mar 01, 2009 6:49 am
Ruben wrote: |
Is the correct way of doing it just placing the "main" routine in v-blank, and when you go to do hugeeeee things, you disable the screen? |
Turn the screen off? You probably want to fade out over a few frames if you are going to turn the screen off. Also, it displays white IIRC, so you would need to fade to white. I don't think this is going to help you except when loading new maps.
Code: |
while (!is_done())
{
wait_for_vblank();
update_sound();
do_everything_else_you_need_to_do_before_drawing_starts();
} |
Sound needs to be syncronized exactly, so it is often the first thing called in the v-blank. I think you could also use a v-count interrupt to make sure it gets called with consistent timing every frame. I don't recommend timers.
#167102 - Ruben - Sun Mar 01, 2009 7:03 am
Well, I was thinking something more like fading out to black or use windowing to "blind" out and then REG_BGPAL[0] = 0, REG_DISPCNT = 0..
Hm.. I'm not sure how sound is done on the DS.. so I probably have no idea how it's done... ... ...
#167104 - sgeos - Sun Mar 01, 2009 7:15 am
You could do this if you don't have things you need to display...
#167105 - Ruben - Sun Mar 01, 2009 7:50 am
Hm.. so sound must be synchronized in v-blank for the DS? Hm..
I suppose in that case it'd be useful to do what I wrote there..
Have you got any tutorials explaining the whole no-memory-mapped-ROM situation? I think that could really help me right now.
#167116 - sgeos - Mon Mar 02, 2009 1:23 am
No, sound must be synchronized with consistent timing.
In general, you want to synchronize things with the display refresh rate instead of timers.
Syncing first thing in V-blank is the easiest, but not the only way, to do this.
I don't know of any tutorials offhand.
Try any of the tutorials out there or just read the API documentation for whatever library you happen to be using.
#167146 - elyk1212 - Tue Mar 03, 2009 6:34 pm
I am confused about your discussion/suggestions on threads for GBA.
Am I wrong in considering this to be an operating system concept? Should not thread abstractions and things happen at a higher level, and likely using a scheduler system for prioritization (or in the least round robin, etc, to avoid starvation)?
This doesn't sound practical in GBA context. What about just using timers (which is similar behavior, sorta, but without preemption or scheduling features.... unless you built this in to the ISRs etc)?
To write your own "Threads" in GBA is to write part of an OS... i would think (yes I did see someone did something like this for NDS, interesting).
BTW, my understanding was to keep any code in the Vblank ISR fairly lean, leaving large transfers elsewhere (perhaps optimized with DMA ,etc). Designing around this idea should keep your music buffer properly fed, no?
#167148 - samel - Tue Mar 03, 2009 6:50 pm
DarkPhantom write the thread library for the gba [as he say "This is more of a computer science demo ...."] and i've ported it to the ds [and let me say "This is more of a computer science demo ...." too 8)))) ]
Threads are not operating system concept, you can applay them on gba and ds programs if you need them.
Using timer it's an alternative, but remember that you have only 4 timer.
Another trick is to use interrupts, just as someone say some post ago.
It's your coice! 8)
[quote]
To write your own "Threads" in GBA is to write part of an OS... i would think (yes I did see someone did something like this for NDS, interesting).
[/quote]
Yes, but threads are a little part of an OS. And be aware that the library just use functions as thread, so no external [loadable from fat] code.
#167153 - elyk1212 - Tue Mar 03, 2009 9:09 pm
Quote: |
Threads are not operating system concept |
Really? Do you have any supporting documentation? All my past engineering classes attribute timeslicing operations to a higher level layer of abstraction, implemented in the OS. This is not to say it cannot be done on a limited resource embedded system(NDS, GBA), just that it has to be implemented (some type of thread scheduler and context switch mechanism etc) in some minimal subset to be considered a true "Thread", and is typically considered an OS concept.
But.. it's all just labeling.. so I guess it could not really matter (and embedded is a grey area it seems for OS).
Quote: |
Using timer it's an alternative, but remember that you have only 4 timer.
Another trick is to use interrupts, |
Well, so how is it implemented in hardware? As far as I can tell, GBA timers are implemented with comparator registers that, when reaching a certain configurable value, trigger a hardware interrupt. So, essentially we're talking about the same thing here.
Also, any time a context switch happens that "interrupts" the standard execution flow (e.g. a thread switching to another for a scheduled timeslice) this would have to be implemented in GBA as a hardware interrupt, no?
I guess my question is more or less, isn't it all just the same idea.. (just using HW interrupts for "threads" etc) but perhaps coding a little more abstraction on top?
If so is the extra fluff really needed for this guys music buffer scheduling? Or is it negligible when it is implemented in this case? Maybe it doesn't use a complex scheduler.
#167154 - samel - Tue Mar 03, 2009 9:43 pm
[quote]
If so is the extra fluff really needed for this guys music buffer scheduling? Or is it negligible when it is implemented in this case? Maybe it doesn't use a complex scheduler.
[/quote]
I misunderstand your post, many sorry!!! In that case you're completly right.
[quote]
Threads are not operating system concept
[/quote]
I meant: Threads are not ONLY an operating system concept 8ppppp
You can use Thread without an OS [in which case they are something like a process] the only thing you need it's a scheduler.
#167158 - sgeos - Wed Mar 04, 2009 1:00 am
Square implemented multithreading in their games on the SNES, and the SNES certainly didn't have an OS.
#167159 - Dwedit - Wed Mar 04, 2009 1:08 am
It's possible to implement threads using setjmp and longjmp.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."
#167160 - elyk1212 - Wed Mar 04, 2009 1:12 am
OS concept, not needing full on OS... maybe by modern comparisons. But what do you consider a bare bones OS? It doesn't need to be a kitchen sink Vista or linux Kernel.
Input handling
Memory management (maybe, not virtual though, many games have a resource manager)
Thread/process scheduler.
Interrupt handler.
Sounds pretty close to a few games (if you add in the thread process scheduler).
Eh... just a categorization, but yeah "OS" is a bit grey in embedded. Yeah you're right though, you don't need a full out GUI monolithic OS to have threads.
Just stating they usually have an overhead associated with threading that can be very complex (or not) all depending on the requirements, I guess.
And the main point I was making (or actually asking, since I am by no means very experienced in GBA) was that a thread abstraction is probably over kill for just keeping a buffer fed.
#167162 - sgeos - Wed Mar 04, 2009 1:39 am
elyk1212 wrote: |
OS concept, not needing full on OS... |
Just because modern operating systems use threads does not make them an OS concept. Ruby supports threads and it is not an OS. Unless your definition of an OS is a thread manager, but I don't think most people think of them as equivalent.
elyk1212 wrote: |
And the main point I was making (or actually asking, since I am by no means very experienced in GBA) was that a thread abstraction is probably over kill for just keeping a buffer fed. |
Threads are not usually the best way to do multiple things at once on the GBA or DS. In general, you can get away with manually iterating over a list of objects that need to be updated and tasks that need to be done.
#167163 - elyk1212 - Wed Mar 04, 2009 2:33 am
I suppose you're right. Process manager would be more of a OS concept, not necessarily the internals of the process implementation (threads). Hmm.
#167166 - Ruben - Wed Mar 04, 2009 2:27 pm
Gah, I don't watch this for 2 days and everything goes bizarre >.>"
Anyway.
So having a whole threading thing just to keep the sound playing nicely is overkill? Hm..
How about this..
V-Blank routine calls the V-Blank routine for sound (GBA only), calls a special routine that copies a shadow buffer of REG_BGxx to the actual registers to avoid "those glitches", using a H-Blank interrupt if needed, and calls child processes from a table, calling sound first.. or is sound handled differently on most DS music players? *blah, those DS specs look evil xD Must keep reading to use GNUARM*
So kinda like...
Code: |
void VBlankISR(void) {
//SoundVBlank(); //Only called by GBA
CopyVideo(); //Only copies video if the right flags are set in another variable
SoundMain(); //Is this used in DS, or is it handled in a timer interrupt?
//Now iterate through the table of child processes
} |
#167170 - sgeos - Wed Mar 04, 2009 5:09 pm
You probably want to used interrupts to do sound. I'd have the interrupt routine lag a frame. Ie, it does what it needs to do to update the sound this frame, and then prepares for the next frame.
In theory, you could split the update and the prep into two routines. The update has critical timing. The prep just needs to finish before the update routine starts running.
The update timing is critical, so you need to make sure nothing is stepping on your sound routine. At the same time, you need to make sure the sound routine doesn't step on anything else that is timing critical. This is why implementing sound and GBA to GBA communications at the same time is so hard. They are both really fussy about timing.
#167196 - Ruben - Thu Mar 05, 2009 5:40 am
Hm..
OK.. so if I wanted to code for DS..
I heard that the DS timers don't time out with v-blank, so you have to have another timer cascading off the sampling timer.. So instead of having a v-blank interrupt.. you'd have a timer interrupt? (Sorry, newbie to DS)
Hm.. and circular buffers..
DekuTree's explained this to me.. twice, actually.. but I never got it and I lost my MSN chat logs so.. how does one use them for the DS again? (Are they even needed if I were to use the hardware channels only?)
#167211 - sgeos - Thu Mar 05, 2009 8:19 pm
Are you using a library for your sound?
Depending on what you want to do, I'd either update first thing in vblank, use a v-count interrupt or use DMA1 and DMA2 to feed the sound buffers. Does anyone know how well a timer interrupt driven sound system would work if you need to do things that way?
#167227 - Ruben - Fri Mar 06, 2009 5:32 am
ATM, I'm using my own custom libraries for the GBA, but since I'll have to move to DS (and maybe even another console, soon >.>"), I'll probably have to use MaxMod or something similar..
#167239 - sgeos - Fri Mar 06, 2009 7:51 pm
Why not just use a library and read the docs that come with it? There are vaild reasons not to do so, but it seems like it would save you a lot of trouble.
#167269 - Ruben - Sat Mar 07, 2009 4:17 pm
Cos I'm stubborn and my brain refuses to let me work with something I haven't coded myself >.>"
(Which is why you don't see me making computer games; hate high-level functions. :P)
#167277 - elyk1212 - Sat Mar 07, 2009 6:14 pm
Yeah, but you haven't worked on the EBNF grammer parser that constructs the obj code from C/C++.... Even if using ASM you work on an abstraction layer, since the instruction set's op codes are abstracted into names, etc.
Point being, abstraction occurs at some level unless you'd like to manually invert the bits on hardware with a magnetic needle :P. Black boxes aren't aways bad.
But, yeah IMO, it's good to learn by doing also.
BTW, if you're really 15 I am quite impressed with what you're interests are and what you are doing. You should consider a career in Soft Engineering/Comp Scie/Comp Engineering etc. You'd likely fly through the course load. Bet you could apply early to the University.
#167289 - Ruben - Sun Mar 08, 2009 8:30 am
Yeah, I really am 15 and plan to take a game programming course for Certificate IV and the diploma, but anyway..
Heh, well, yeah, abstraction will occur either way, but I tend to like things that I wrote, cos.. .. Hm.. Idk.. I guess I'm just stubborn. :P
Probably another reason why is cos the startup code included with libnds takes an ETERNITY to finish copying LMA->VMA (just a stmia, sub, bne), whereas I like to optimize code as much as I can (unless I'm using C, but even then I tend to optimize it a lot).
#167300 - sgeos - Sun Mar 08, 2009 3:31 pm
Keep in mind that you will need to work with other people and their code if you intend to be employed as a programmer in the future. It is probably a good idea to get used to it sooner than later.
#167305 - Ruben - Sun Mar 08, 2009 5:08 pm
Well, yeah, but hm.. I suppose another reason why I like my own code is cos I know that functions are 1) Fairly optimized, and 2) Not "dumb"
By "dumb" I mean like a call to a function in a time-critical loop (on the console, not the computer).. eg..
Code: |
void resetMyStruct(myStruct* Thingo) {
memset(0, &Thingo, sizeof(myStruct));
}
void myFunc(void) {
u16 myVal;
myStruct *Pointer = somePointer;
for(int i=0;i<512;i++) {
//Random, I have no idea what it does >.>"
myVal = sin(345/i + 93 * pi + 0.35672) * cos(85/i + 0.5) * tan(849 * i / pi);
resetMyStruct(Pointer++);
}
} |
Personally, I think that code downright sucks.. First, it uses u16.. on some compilers, it may be OK but on a lot.. big no-no.. Then, it uses memset 512 times to clear continuous data.. why not just call memset(0, somePointer, sizeof(myStruct)*512)? Also the trig functions, division, floating point arithmetic.. why calculate all that during the code instead of using a LUT? I'm pretty sure (though not positive) that one can find a pattern in that data and build a small LUT and reflecting as needed. And even if you must have that.. sine tables can be calculated as small as 128 16-bit entries (or even 8-bit if you need to), co-sine is just sin(90+x), so one should be able to re-scale that logically, as for tangent.. one could use a 256-point LUT and reflect if needed. Divisions... multiplication by reciprocal. And if you "can't", use the software interrupt.. the __udiv and __divsi functions provided by GCC are *slow*. And better yet, if you know the division values are going to be in a certain (small) range, why not use a LUT?
Blah, I'm ranting again..
But my point was.. what if the programmers I have to work with have coding ethics like those?
#167306 - silent_code - Sun Mar 08, 2009 5:09 pm
sgeos wrote: |
Keep in mind that you will need to work with other people and their code if you intend to be employed as a programmer in the future. It is probably a good idea to get used to it sooner than later. |
These are truly words of wisdom, man. :^D
_________________
July 5th 08: "Volumetric Shadow Demo" 1.6.0 (final) source released
June 5th 08: "Zombie NDS" WIP released!
It's all on my page, just click WWW below.
#167307 - kusma - Sun Mar 08, 2009 5:14 pm
Ruben wrote: |
Then, it uses memset 512 times to clear continuous data.. why not just call memset(0, somePointer, sizeof(myStruct)*512)? |
To be honest, I find it way more worrying that it's trying to memset a null-pointer than that it might be slow.
#167308 - Ruben - Sun Mar 08, 2009 6:58 pm
... Did I get the memset order wrong again? Damn. >.>"
#167316 - sgeos - Sun Mar 08, 2009 11:03 pm
Ruben wrote: |
But my point was.. what if the programmers I have to work with have coding ethics like those? |
Things only need to be good enough to get the job done. Programmer time is just as important as execution time. The best program that never got finished is not very useful.
If you are on the job, bring it up in a review if your company does code reviews. Otherwise, don't worry about it until it becomes a problem. If you inherit the code and have extra time, then feel free to rewrite the function.
For homebrew, don't worry about it unless it actually breaks your program. Top priority is getting your program to feature complete status. After that, feel free to go back and rewrite modules.
#167319 - elyk1212 - Mon Mar 09, 2009 12:48 am
Mileage may very in AU, but here in the states I had a friend that applied and started taking College classes by her Junior year in HS.. plus was taking regular classes at HS that counted for Univ credit (you know, the usual Calc, english, etc).
You may want to consider this. Although, I think she did it through our community college (the off HS classes) since it had less restrictions on age/Diploma completion etc.
Just letting you know the way I wish I did things to save more time, and accumulate less debt (since in HS usually = at home saving money!) :)
Oh yeah, BTW, you'll have to swallow your pride when you work on a team (as they mentioned). Just has to be that way, as everyone cannot be unwilling to compromise as the project would probably go no where. Also, you'll run into corp imposed coding standards etc, and even customer imposed coding standards (like DOD seems to, for their contracts in the USA).
Quote: |
Top priority is getting your program to feature complete status. After that, feel free to go back and rewrite modules.
|
Sounds like the advice I need to start following with nearly all my projects.
#167323 - Ruben - Mon Mar 09, 2009 5:49 am
Quote: |
Oh yeah, BTW, you'll have to swallow your pride when you work on a team |
Oh, fooey >.>"
Yeah, I guess I kinda knew that.. but never really took it into account when writing programs..
Hm.. I suppose that what I wanted was probably something like having uber optimized code that I wrote the whole time for my personal projects, only.. but I suppose it really isn't necessary.. cos, as sgeos said, "Things only need to be good enough to get the job done."
#167342 - sgeos - Mon Mar 09, 2009 3:34 pm
The exact definition of "good enough to get the job done" changes depending on what you are doing. Some things *need* to be uber optimized. Most things do not. Some things can be really inefficient.
Optimizing things that don't need to be optimized is often a waste of time. Evidently some team profiled their code and foud that 80% of the time was spent in one loop. They optimized the loop but the program didn't run any faster. They optimized it some more. Not faster. They were perplexed until they realized they had optimized the idle loop.
Code that is easy for humans to understand is often more valuable than "uber optimized" code. (It actually tend to run pretty well too.) In general, you want to write the easy to understand version first, even if it is wasteful, and then go back and optimize if it needs to be optimized. If the optimized version is hard to understand, write comments that explain what is going on.
#167343 - Ruben - Mon Mar 09, 2009 3:51 pm
While were on the topic of 'good' and 'bad' code...
I remember someone once mentioning "Premature optimization is the root of all evil.."
But what about simple optimizations like using a do{} while(--foo) loop instead of for(i=0;i<foo;i++)? Are for loops regarded bad in most cases, or is the do{}while() equivalent better, in a "good enough for the job" (generic) case?
Cos if that's so.. I'm seriously gonna start using more stuff that I haven't used for the fear of speed >.>"
#167344 - elhobbs - Mon Mar 09, 2009 4:39 pm
Ruben wrote: |
While were on the topic of 'good' and 'bad' code...
I remember someone once mentioning "Premature optimization is the root of all evil.."
But what about simple optimizations like using a do{} while(--foo) loop instead of for(i=0;i<foo;i++)? Are for loops regarded bad in most cases, or is the do{}while() equivalent better, in a "good enough for the job" (generic) case?
Cos if that's so.. I'm seriously gonna start using more stuff that I haven't used for the fear of speed >.>" |
ahh this quote is so frequently used... I despise it. even though the premise is sound.
essentially, do not optimise unless you know you need to. optimized code can be difficult to read and is easily misunderstood and it is more prone to have errors/unintended side effects. more often then not it is not necessary as most code is not time critical. keep in mind this is different than picking efficient algorithms in the first place. get something working, then profile, and optimize if needed.
also, do loops and for loops have different purposes. do loops have no pre-condition so they also run at least one iteration.
#167346 - Ruben - Mon Mar 09, 2009 4:45 pm
Well, yeah, but the compiler output is different. :P
Like this..
Code: |
@ for(int i=0;i<8;i++) {foo();}
mov r0, #0
1:
cmp r0, #8
beq 1f
push {r0}
bl foo
pop {r0}
b 1b
2:
@ i = 8; do {foo();}while(--i)
mov r0, #8
1:
push {r0}
bl foo
pop {r0}
sub r0, #1
bne 1b |
And yeah, that difference that do executes once unconditionally aside is what I mean, heh.
EDIT:
BLAH, here goes my optimization mind again >.>"
Code: |
@ for(int i=0;i<8;i++) {foo();}
push {r4}
mov r4, #0
1:
cmp r4, #8
beq 1f
bl foo
b 1b
2:
pop {r4}
@ i = 8; do {foo();}while(--i)
push {r4}
mov r4, #8
1:
bl foo
sub r4, #1
bne 1b
pop {r4} |
EDIT 2: Forgot to add the final label. :P
#167349 - elhobbs - Mon Mar 09, 2009 5:26 pm
I am not sure what the point is you are trying to make. yes, they are different so it makes sense that they generate different code. so?
#167355 - albinofrenchy - Mon Mar 09, 2009 6:19 pm
I mean, I understand the thrill of the challenge of getting something to run as fast as is computationally possible; but consider letting go of that a little so you can focus your attention on bottlenecks. There is nothing like taking a 30 second task in turning it into a 30 ms task.
Also, Prepare yourself for this kind of crap. Especially if you have to ever see someone elses SQL statements.
#167368 - Ruben - Tue Mar 10, 2009 5:57 am
elhobbs:
My point was that if the compiler came up with that, then would it be "premature optimization" to use a do{}while(--foo) loop instead of a for(int i=0;i<foo;i++){} loop?
albinofrenchy:
Oo, SQL.. I haven't worked with *that* in a while.. so I probably wouldn't really find any 'crap' in it, myself. :P
#167369 - sgeos - Tue Mar 10, 2009 6:44 am
Ruben wrote: |
My point was that if the compiler came up with that, then would it be "premature optimization" to use a do{}while(--foo) loop instead of a for(int i=0;i<foo;i++){} loop? |
Yes. Different compilers produce different output. What is faster using your current compiler may be slower when you port your code. By default your code should be portable and easy for people to read.
albinofrenchy's point is, how often is your code being called? Once during setup? Once ever few frames? Once a frame? Multiple times a frame? Every scanline? The answer to that question determines how how optimized your code should be.
H-blank routines? Need to optimized if you need to get a lot done. Hit detection called 100 times a frame? Definitely optimize this. Code that sets in game flags when events are triggered? This can probably be super un-optimized.
If something doesn't need to be optimized and you are spending time optimizing it, there is a good chance you are wasting time. If something doesn't need to be optimized and your code becomes less readable due to your "optimization" you are harming the maintainability of your code. If you optimize code that gets thrown away due to shifting requirements, you wasted effort. If you rewrite the same modules every time instead of porting them, you may be wasting effort.
It's not as simple as "always write modules in as little time as possible" or "always optimize routines". If you want to do a really good job, you need to know when, where, and why to optimize or do a quick and dirty job. You need to know your requirement and the life cycle of your code. It's not easy.
#167371 - keldon - Tue Mar 10, 2009 9:07 am
That 'do' forces the scope to be outside of the loop!
When learning it is good to be able to figure things out for yourself, but equally important to be able to use libraries. Using them will help you to create your own libraries in the future since your mind would be experienced in using good design.
Both premature optimisation and premature pessimism are bad; so for(ITERATOR i = 0; i < XXX; ++i) is fine, the pre-increment does not reduce readability or negatively affect the code in any way, so the post-increment would be a needless waste.
But most 'rules of thumb' are there because doing otherwise [generally] leads to bad code that is harder to maintain. Experience is a good tool, I know there are things I did when I started work but now I know where it leads me so my designs are tighter.
And I know people who use STL in their HBlank routines (not to say that STL is slow). Talking about STL, it's totally awesome - it helps to be aware of the design patterns behind them, but once you are used to the patterns you will find STL even more useful! Even simple things like following STL's iterator and predicate template-designs can boost productivity and result in (or moreof be a part of) good code ... that being said, used blindly it will be like leaps of burning coal on your forehead ^_^
#167380 - Ruben - Tue Mar 10, 2009 4:21 pm
sgeos:
Ahhh... So just to jot this down..
Startup code: Can be super un-optimzed (unless it's that horrible calculate-the-sine-table thing)?
Code that is called once every few frames: Un-optimized but not super un-optimized to the point where it will collide with other V-Blank routines?
Code that is called every frame: Optimized but not supper optimized? (Unless the time taken is huge, like a software 3D engine or high-quality sound mixer)
Code that is called every H-Blank: Super optimized, and possibly in ASM?
Anything that doesn't need to be tightly optimized can be simply written as 'easy-to-read' code to maintain portability and avoid excess effort, whilst everything that must be optimized should contain plenty of comments and/or the previous, 'un-optimized' code?
keldon:
.. But I thought using a pre-increment in a for(;;) loop didn't have any difference to using post-incrementing..?
Oh yeah.. STL can be a blessing or the Devil, depending on what it is.
#167383 - keldon - Tue Mar 10, 2009 5:46 pm
Note the datatype was ITERATOR, so the post increment would result in a redundant copy being made (that isn't even processed).
Nothing needs to be super-optimized or optimized until it becomes a problem (best rule of thumb). Experience will assist in making that decision earlier; you will most likely learn where to optimize by not writing all your code as optimized (just think about it).
#167393 - Ruben - Tue Mar 10, 2009 7:43 pm
... string::iterator?
.. OK, how does that work? :P
#167405 - sgeos - Tue Mar 10, 2009 11:55 pm
Well, so long as things work and move at an acceptable speed, your system is optimized enough. To the extent the code works, it should be portable and readable.
The "hard and fast rules" are really closer to guidelines. Do you need extra cycles? It will be obvious if you do. If you needs extra cycles, you need to "optimize" something to free up cycles or change your spec to reduce the required cycles. If you decide to optimize, first you need to know where the problem is. After you know where the problem is, you can either replace the algorithm with a faster one written in an easy to read portable manner, or rewrite the existing one to use less cycles. To the extent you are rewriting, there is a good chance you want to break out ASM (and leave the high level version around for reference).
H-blank routines need to be tight, but only to the extent you don't have enough cycles. I've been consistently surprised with the amount of high level code I can push through H-blank routines. When I should it to an old school ASM coder, he was horrified. (H-blank was a lot shorter in the past.)
In summary, write portable and readable code. You may even drop some of it into your PC side tools. When and if you run out of cycles, profile your code and fix the problem area. Only fix the problem area. (To the extent your interface stays the same, this should be a matter of rewriting the guts of a function.)
#167407 - albinofrenchy - Wed Mar 11, 2009 1:29 am
I can't overstate how good it is to know how to use a profiler (I would say equally as good as knowing how to use a debugger or a memory profiler). There is a port of cygprofile that works phenomenally for the the ds (hat tip to simonjhall for that).
I've thought about throwing up tutorials on using cygprofile and also on using the gdb tool thats floating around; would people be interested in that?
#167408 - sgeos - Wed Mar 11, 2009 1:54 am
albinofrenchy wrote: |
I've thought about throwing up tutorials on using cygprofile and also on using the gdb tool thats floating around; would people be interested in that? |
How could it hurt? It seems like good information to have around.
#167409 - Ruben - Wed Mar 11, 2009 2:07 am
OK.. so long as it's good enough to run at a reasonable speed. Got it.
But anyway.. I might snap out of GBA/DS code for a bit.. GBA is kinda out-of-business (aside from the homebrew scene) and the DS is waaaay too hard for me, so I'll probably go back to coding in the Sphere environment.. uses JavaScript to run so it'll be fun getting back into that. ^_^"
But when that's over, I'll need the advice you guys gave me. So thanks guys~
#167423 - gauauu - Wed Mar 11, 2009 2:58 pm
Ruben wrote: |
GBA is kinda out-of-business (aside from the homebrew scene) and the DS is waaaay too hard for me, |
If you treat the DS like a GBA with two screens, it's really only the tiniest bit harder than the GBA. Sure, you have to set up your vram banks at the beginning. And music runs on the ARM7 (just use someone else's music library). Other than that, it's pretty much the same thing.
#167424 - Ruben - Wed Mar 11, 2009 3:03 pm
:-|
You even have to set up the VRAM banks at the beginning?!?! Ayayayayay...
Yeah, I know that if I did anything to do with music on the DS, I would use someone else's library.. the thing that makes me go "GAH!!!!!!!" is the whole thing where everything lives in RAM, each processor has its own entry point, each processor can only do certain things, etc.
#167473 - albinofrenchy - Fri Mar 13, 2009 5:50 am
Honestly Ruben, from what I've seen on these boards you are more than competent enough to attack the DS successfully. libnds handles most of the annoying parts of the VRAM(You can set vram in four lines, and a generic video setup in like ten), and you can effectively ignore the second processor until you are ready to deal with it. I haven't actually used the arm7 on my project yet.
#167485 - keldon - Fri Mar 13, 2009 6:49 pm
Don't be put off by these little things, as said above, it's only a few lines of code. If it helps, use a checklist each time you are setting up a screen, so long as you complete the steps.
The agitation you get the first time coding it is good, that's your brain gaining experience. Earn yourself a few scars and you'll be a vet in no time ^_^
#167490 - sgeos - Fri Mar 13, 2009 11:34 pm
keldon wrote: |
If it helps, use a checklist each time you are setting up a screen, so long as you complete the steps. |
Or just use a setup function.