VANIT'S PROFILE
Search
Filter
Performance Scripting in 2k3
author=bulmabriefs1442) Reduce overhead with common eventsHe means overhead. Imagine having the same event on every map. Parallel process a common event, or outright make it switch activated. Not only did this just reduce thousands of hours of code edit if something goes wrong (you just edit the common event), but it actually does speed the execution up. I've got hundreds of common events.
I think what you mean is reduce code redundancy, which is definitely good practice, but it is not always the best solution when it comes to executing calculation-intensive events. Ironically what you have suggested, while reducing the size of the code, has increased the execution overhead of the event thats calling your common event.
Uhhh ... Thats called reducing redundancy. When you have redundant code it means you have code that does the same thing written in multiple places, when you could've put the code in one place and have everywhere reference that one place (in this case a common event), which is what you described but are calling the wrong thing. When you reduce overhead it means things run faster, which using "Call: Common Event" DOES NOT do.
I think you've misunderstood the distinction I was making between a parallel process and CALLING an event. When you have a loop and you put Call: Event, the code that loads the event will lag the loop. If you're doing stuff in a loop it'll run faster if the code is right there rather than off someone else in a different event. It can make things a little bit more difficult when you have to fix code, but if you absolutely want to push rm2k3 to the limit in terms of execution speed its a necessary evil.
I suggest you check out my full tutorial here: http://rpgmaker.net/tutorials/451/.
Proper performance scripting in 2k3
Not at all. I cherish any constructive feedback I get and thank you for continuing to take the time to read and consider my article. :D
author=KazesuiThere's not a lot I can think of that would require upfront computational speed in rm2k3. The only one I've come up with so far is the sorting algorithms I've implemented for the Item and Materia submenus, which can take up to a second to execute in their current implementation. Before I start the computation I just pop a message for the player that just says "Calculating..." or something as the wait time is sadly unavoidable until I get around to putting in an O(nlogn) sorting algorithm.
I thought it was weird for call event to have that adverse effect, considering I was pretty sure I had tested them in some similar manner, and also because of how much I use them in my events which needs to be updated around once every 0.0167 sec. Any extra 0.0167 per event call would have been pretty drastic there.
I don't think I've called too too many big events in label loops though, as the only time it would seem practical is if the screen is static at the time, so I guess I don't know too much about it's potential ill effects and as long as one follow your advice of having at least a 0.0 wait in the loop somewhere, it doesn't seem to have any noticable problems for me at least.
author=KazesuiI was aware of variable operations all seeming to take the same time. I expected modulo and divide to take a bit longer, but apparantly they're all as worse as eachother it seems. I wasn't aware of the comments thing though, that is sad. :( I guess a part of me blindly hoped there was a precompiler that removed them or something.
Using the method I mentioned earlier I get
60 ips for pp loops
200,000 ips for loops, and
300,000 ips for label loops.
I've done quite a bit of testing on these things as well, which has revealed to me interesting and sad things, like comments taking an instruction cycle, and even empty lines as well, which is why "loops" are slower than labels.
Doing variable operation on any variable range seems to be just as fast as any other variable operation though, which is good for optimizing code with lot of similar variable operations. In other words, being thoughtful about the location of your various variables might help as well.
author=KazesuiIt seems you've helped me discover another lapse in my judgement. Up until now I had thought that all code was "read over" even if it wasn't executed because I had observed this behaviour in my ATB algorithm - huge chunks would not be touched when the enemies that used them weren't in play for that battle, yet the ips of the event would not change regardless of how little or much of the code was active. It turns out that this was because I had put a 0.0 wait at the end and that had regulated the execution time. When I take out the 0.0s wait there's a huge disparity in the ips depending on the enemies that are active. This does give rise to the existence of a behaviour that I still don't fully understand - why execution time of instructions seems to give way once you start putting a wait in. I've tried to think of ways that could work, but as of writing it completely escapes me why this behaviour exists.
Another thing I found peculiar was your claim about nesting if statements not being good unless there's a loop in it which you could prevent.
When I add a branch to the label loop with just a counter, it tells me that if the condition is permnantly false, the if statement will only execute 2 instructions for each iteration ( the check, and a jump to the command after "end" I suppose), regardless of any amount of instructions inside of it.
The problem with nesting them comes from all the empty lines and the "end" lines, when you get further into the nests, which still get read.
an "if nest" with 4 if's and only additional code in the final one, will execute 11 lines if all if's were true except the last one. This is regardless of the amount of commands within the top if (which btw. is almost all the lines if all if's are empty). If only the first if was true, it would only execute 5 lines.
You could use labels at the end of each nest top optimize it though. This could cut the 3 of 4 if's true scenario down to 6 lines. You'll just need a lot of labels in case you have many nested statements.
The way I use to determine this, is to take 600,000 / lines to read, and it will return the same value at the end of a counter session using my label loop method. it has held true for all my observations so far.
Proper performance scripting in 2k3
@Kazesui: It seems I made a slight error in that regard, by the time I finished writing the article it was 4am and I think I made it as an assumption based on me guess of how a Parallel Process loops and why it is so slow compared to everything else. In anycase, I plan to rectify that now as I looked further into it!
The Overhead of a Common Event
It seems my previous claim for the overhead of a common event was inaccurate, upon further study I found that it is both worse and better than I thought at the same time, depending on the circumstances!
Before I start showing you numbers, keep in mind that this is relative. Any code I put into the loops will slow them down significantly as before I was only comparing the delay between the end of an iteration and the beginning of the next iteration. If you conduct versions of my experiments and feel like posting the results go ahead, but also remember to post the control values of the loops running empty (that is, with only a counter in them) or the data is useless.
To save you scrolling up and down, here was the results of my loops with only counters in them (ips is iterations per second):
-Parallel Processes 60ips
-Loops inside an event, 200055ips
-Label Loops inside an event, 300083ips
For the sake of this having some real world application I used a moderate but linear event (no loops in it) as the Common Event I'd be testing with. Its one I have in my game that resets all the characters health to full and a few variations in if statements depending on the mode the event is running in. Its a very simple, but useful event and appropriate for this test I think. I got some really strange results.
When I pasted the code for the event into the Loop itself, it executed at 13337ips and didn't lag the game. You'll notice this number is significantly slower than when the event is empty - remember I said everything affects the latency of a loop, the point is it doesn't lag the game. But when I had that same code in a Common Event and the Loop was calling it every iteration I didn't need to worry about what the ips was because the game became jittery as shit, the lag made it unplayable. The moral of the story: calling Common Events over and over in a Loop is a no go!
I didn't bother testing the Parallel Process with the code itself inside as I knew it'd run properly, but what I didn't expect was how stable the Parallel Process would be with Common Event calls in it. The Parallel Process still executed at a steady 60ips with FORTY Common Event calls in it. Slow, but steady eh? However when I pushed it further it'd lag the actual game making it unplayable. You can safely use a a lot of Common Events in this fella with no additional latency at all!
Label Loops weren't much better off than Loops. With the code of the Common Event inside the Label Loop it happily executed at 13636ips with no ingame lag. Similar to the Loop, replacing that code with a call to a Common Event made the game so laggy it was unplayable. Code only inside Label Loops please!
So there you have it. I can't give you the exact overhead of a Common Event as I previously tried to. In the best of cases, Parallel Processes, there is no overhead. In the worst of cases, Loops and Label Loops, the game becomes so laggy its unplayable, but this can be avoided by using the other techniques I suggested in the original article.
The Overhead of a Common Event
It seems my previous claim for the overhead of a common event was inaccurate, upon further study I found that it is both worse and better than I thought at the same time, depending on the circumstances!
Before I start showing you numbers, keep in mind that this is relative. Any code I put into the loops will slow them down significantly as before I was only comparing the delay between the end of an iteration and the beginning of the next iteration. If you conduct versions of my experiments and feel like posting the results go ahead, but also remember to post the control values of the loops running empty (that is, with only a counter in them) or the data is useless.
To save you scrolling up and down, here was the results of my loops with only counters in them (ips is iterations per second):
-Parallel Processes 60ips
-Loops inside an event, 200055ips
-Label Loops inside an event, 300083ips
For the sake of this having some real world application I used a moderate but linear event (no loops in it) as the Common Event I'd be testing with. Its one I have in my game that resets all the characters health to full and a few variations in if statements depending on the mode the event is running in. Its a very simple, but useful event and appropriate for this test I think. I got some really strange results.
When I pasted the code for the event into the Loop itself, it executed at 13337ips and didn't lag the game. You'll notice this number is significantly slower than when the event is empty - remember I said everything affects the latency of a loop, the point is it doesn't lag the game. But when I had that same code in a Common Event and the Loop was calling it every iteration I didn't need to worry about what the ips was because the game became jittery as shit, the lag made it unplayable. The moral of the story: calling Common Events over and over in a Loop is a no go!
I didn't bother testing the Parallel Process with the code itself inside as I knew it'd run properly, but what I didn't expect was how stable the Parallel Process would be with Common Event calls in it. The Parallel Process still executed at a steady 60ips with FORTY Common Event calls in it. Slow, but steady eh? However when I pushed it further it'd lag the actual game making it unplayable. You can safely use a a lot of Common Events in this fella with no additional latency at all!
Label Loops weren't much better off than Loops. With the code of the Common Event inside the Label Loop it happily executed at 13636ips with no ingame lag. Similar to the Loop, replacing that code with a call to a Common Event made the game so laggy it was unplayable. Code only inside Label Loops please!
So there you have it. I can't give you the exact overhead of a Common Event as I previously tried to. In the best of cases, Parallel Processes, there is no overhead. In the worst of cases, Loops and Label Loops, the game becomes so laggy its unplayable, but this can be avoided by using the other techniques I suggested in the original article.
Performance Scripting in 2k3
As well intended as this article was, I hate to say that most, if not all, of it is incorrect. This inaccuracy mostly has resulted from a failure to understand the overhead of events and how they execute. I will elaborate.
1) Reducing parallel processes
All these events are not calculation intensive, and what I mean by that is there is no need for them to execute *quickly*. The main reason for lag from events is the overhead of when an evident is actually called (more on this later). You can happily run about 40 linear parallel events by sticking a 0.0 wait on the end of them.
2) Reduce overhead with common events
I think what you mean is reduce code redundancy, which is definitely good practice, but it is not always the best solution when it comes to executing calculation-intensive events. Ironically what you have suggested, while reducing the size of the code, has increased the execution overhead of the event thats calling your common event.
When you call another event it has an overhead of 0.0165 seconds (the execution time of the 0.0s wait). It takes A HUUUUUUUUUGE event to cause that kind of overhead. By separating your code into a common event and calling it over and over you've made a huge overhead for your code. If you're aiming for speed, if your code is less than 100 instructions, you're better off copying and pasting rather than using common events like that because they have a huge overhead. Everytime you call a common event, even the same one, it increases the execution time of the parent event by however many times you called it. A parallel process that makes 6 common event calls takes 0.1155s to get through a single loop, thats hella slow (6*0.0165 + 1*0.0165 for the overhead of looping the parallel event on itself).
3) Don't branch forks too often in one go
Now this one is completely incorrect. I'm not sure why you think this works, but the truth is that rm2k3 runs every line, whether the logic dictates that line is executed or not. I know that in real programming languages this isn't the case, but in rm2k3 it is. You can test this by taking any giant linear event you have with a lot of if statements, and at the end of the event put a counter that increments a variable by 1. Test the variable after 1 second and you'll find whether parts of the code were deactivated with if statements or not, that the entire thing still took the same amount of time to execute.
4) How to fragment big loops
A loop script that loops 100 times, are you kidding me? Rm2k3 can execute a linear loop THOUSANDS of times in a blink of an eye. The issue is that unbeknownst to most the Loop command is FARRRR more quicker than how fast a parallel process loops. I ran a test, in 60 seconds an empty Loop executed 12003333 times, a parallel process only looped 3601. Thats how fricking insane Loop is. You get lag from loops because they execute at lightning speed, which is good sometimes, but if you have a continuous process running in the background rather than a once off calculation, then you'll want to slow it down, because chances are you don't need it executed that fast. Inside the loop you just need a 0.0s wait to bring the loop back down to the speed of a parallel process which is far more tame.
Ironically you solved this by accident, because as I said earlier, calling a common event has an overhead of 0.0165s (the same as a 0.0 wait), so thats why your solution works.
I'm writing up an article now that explains this information in greater detail and how I worked it out.
1) Reducing parallel processes
All these events are not calculation intensive, and what I mean by that is there is no need for them to execute *quickly*. The main reason for lag from events is the overhead of when an evident is actually called (more on this later). You can happily run about 40 linear parallel events by sticking a 0.0 wait on the end of them.
2) Reduce overhead with common events
I think what you mean is reduce code redundancy, which is definitely good practice, but it is not always the best solution when it comes to executing calculation-intensive events. Ironically what you have suggested, while reducing the size of the code, has increased the execution overhead of the event thats calling your common event.
When you call another event it has an overhead of 0.0165 seconds (the execution time of the 0.0s wait). It takes A HUUUUUUUUUGE event to cause that kind of overhead. By separating your code into a common event and calling it over and over you've made a huge overhead for your code. If you're aiming for speed, if your code is less than 100 instructions, you're better off copying and pasting rather than using common events like that because they have a huge overhead. Everytime you call a common event, even the same one, it increases the execution time of the parent event by however many times you called it. A parallel process that makes 6 common event calls takes 0.1155s to get through a single loop, thats hella slow (6*0.0165 + 1*0.0165 for the overhead of looping the parallel event on itself).
3) Don't branch forks too often in one go
Now this one is completely incorrect. I'm not sure why you think this works, but the truth is that rm2k3 runs every line, whether the logic dictates that line is executed or not. I know that in real programming languages this isn't the case, but in rm2k3 it is. You can test this by taking any giant linear event you have with a lot of if statements, and at the end of the event put a counter that increments a variable by 1. Test the variable after 1 second and you'll find whether parts of the code were deactivated with if statements or not, that the entire thing still took the same amount of time to execute.
4) How to fragment big loops
A loop script that loops 100 times, are you kidding me? Rm2k3 can execute a linear loop THOUSANDS of times in a blink of an eye. The issue is that unbeknownst to most the Loop command is FARRRR more quicker than how fast a parallel process loops. I ran a test, in 60 seconds an empty Loop executed 12003333 times, a parallel process only looped 3601. Thats how fricking insane Loop is. You get lag from loops because they execute at lightning speed, which is good sometimes, but if you have a continuous process running in the background rather than a once off calculation, then you'll want to slow it down, because chances are you don't need it executed that fast. Inside the loop you just need a 0.0s wait to bring the loop back down to the speed of a parallel process which is far more tame.
Ironically you solved this by accident, because as I said earlier, calling a common event has an overhead of 0.0165s (the same as a 0.0 wait), so thats why your solution works.
I'm writing up an article now that explains this information in greater detail and how I worked it out.
Pages:
1













