AS3: Inefficient to make too many references across classes? - performance

I was told once that I should avoid referencing properties and such of my main game class from other classes as much as possible because it's an inefficient thing to do. Is this actually true? For a trivial example, in my Character class would
MainGame.property = something;
MainGame.property2 = something2;
MainGame.property3 = something3;
//etc.
take more time to execute than putting the same in a function
MainGame.function1();
and calling that (thereby needing to "open" that class only once rather than multiple times)? By the same logic, would
something = MainGame.property;
something2 = MainGame.property;
be slightly less efficient than
variable = MainGame.property;
something = variable;
something2 = variable;?

Think of referencing things as of operations. Every "." is an operation, every function call "()" is an operation (and a heavy one), every "+", "-" and so on.
So, indeed, certain approaches will generate more efficient code than other ones.
But. The thing is, to feel the result of inefficient approach you need to create a program performing millions of operations (or heavy tasks of the appropriate difficulty) each frame. If you are not parsing megabytes of binary data, or converting bitmaps, or such, you can not worry about performance. Although worrying about performance and efficiency is generally a good thing to do.
If you are willing to measure the efficiency of your code, you are free to measure its performance:
var aTime:int;
var a:int = 10;
var b:int = 20;
var c:int;
var i:int;
var O:Object;
aTime = getTimer();
O = new Object;
for (i = 0; i < 1000000; i++)
{
O.ab = a + b;
O.ba = a + b;
}
trace("Test 1. Elapsed", getTimer() - aTime, "ms.");
aTime = getTimer();
O = new Object;
c = a + b;
for (i = 0; i < 1000000; i++)
{
O.ab = c;
O.ba = c;
}
trace("Test 2. Elapsed", getTimer() - aTime, "ms.");
aTime = getTimer();
O = new Object;
for (i = 0; i < 1000000; i++)
{
O['ab'] = a + b;
O['ba'] = a + b;
}
trace("Test 3. Elapsed", getTimer() - aTime, "ms.");
Be prepared to run million-iteration loops so that total execution time exceeds 1 second, otherwise the precision will be too low.

Related

Do I count Math.max in a Big O Runtime?

I have trouble in understanding weather or not using Math.max should be counted as a loop, therefore should be included in calculating Big O runtime.
I assume for the Math.max to find the max value it has to loop and compare through all the values it was provided. Therefore it is actually looping.
My code in JS:
function getWaterCapacityPerSurface(surface){
let waterAmount = 0;
// full loop
for(let i = 1; i < surface.length - 1; i++){
const current = surface[i];
// I assume each slice is counted as a half of the full loop
const leftSlice = surface.slice(0, (i - 1 < 0 ? 0 : i));
const rightSlice = surface.slice(i + 1, surface.length);
// I assume each Math.max is counted as a half of the full loop
const leftBound = Math.max(...leftSlice);
const rightBound = Math.max(...rightSlice);
const canWaterStay = leftBound > current && rightBound > current;
const currentBound = Math.min(leftBound, rightBound);
const waterLevel = currentBound - current;
if(canWaterStay) waterAmount += waterLevel;
}
return waterAmount;
}
console.log(getWaterCapacityPerSurface([4,2,1,3,0,1,2]));
// returns 6
Is Big O runtime O(N(N+N)) or O(N(N))?
I assume in this case it doesn't really matter because we drop constants and at the end it is going to be O(N(N+N)) = O(N(2N)) = O(N(N)) = O(N²)
But I just would like to know weather I should count Math.max/Math.min as a loop for future reference.
Yes, if you pass a list of arguments of length n to Math.max(), then it is an O(n) operation. Math.max() iterates through every argument. See more info in the specification.

X-Path Query performance

Which of the following queries are considered heavier performance wise:
//*/*/*/*/*
or
//ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*
or
/descendant-or-self::*/*/*/*
To my understanding the second would be more complex to compute?
Thanks.
About time of execution: it does not have a noticeable difference due to the fact that exist a lot of affecting factors, but anyway with almost identical tiny execution time of each requests.
On the current page each of requests performed on average in 0.07–0.09µs; 1µs = 1second * 10^-6.
let arrExecutionTime = [];
function getAverageExecutionTime(locator) {
let maxIteration = 1000;
let timeTotal = 0;
for (let i = 0; i < maxIteration; i++) {
let executionTimeStart = performance.now();
let arrNode = document.evaluate(locator, document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
arrExecutionTime.push(performance.now() - executionTimeStart);
}
for (let k = 0; k < arrExecutionTime.length; k++) {
timeTotal += arrExecutionTime[k];
}
let avgExecutionTime = timeTotal / arrExecutionTime.length;
console.log(`avgExecutionTime: ${avgExecutionTime}µs \nafter ${maxIteration} iterations \nfor locator:\"${locator}\"`);
}
getAverageExecutionTime("//*/*/*/*/*");
getAverageExecutionTime("//ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*/ancestor-or-self::*");
getAverageExecutionTime("/descendant-or-self::*/*/*/*");

Is this PLINQ bug?

Why PLINQ output is different than sequential processing and Parallel.For loop
I want to add sum of square root of 10,000,000 numbers.. Here is the code for 3 cases:
sequential for loop:
double sum = 0.0;
for(int i = 1;i<10000001;i++)
sum += Math.Sqrt(i);
Output of this is: 21081852648.717
Now Using Parallel.For loop:
object locker = new object();
double total ;
Parallel.For(1,10000001,
()=>0.0,
(i,state,local)=> local+Math.Sqrt(i),
(local)=>
{
lock(locker){ total += local; }
}
);
Output of this is: 21081852648.7199
Now using PLINQ
double tot = ParallelEnumerable.Range(1, 10000000)
.Sum(i => Math.Sqrt(i));
Output of this is: 21081852648.72
Why there is difference between PLINQ output and Parallel.For and Sequential for loop?
I strongly suspect it's because arithmetic with doubles isn't truly associative. Information is potentially lost while summing values, and exactly what information is lost will depend on the order of the operations.
Here's an example showing that effect:
using System;
class Test
{
static void Main()
{
double d1 = 0d;
for (int i = 0; i < 10000; i++)
{
d1 += 0.00000000000000001;
}
d1 += 1;
Console.WriteLine(d1);
double d2 = 1d;
for (int i = 0; i < 10000; i++)
{
d2 += 0.00000000000000001;
}
Console.WriteLine(d2);
}
}
In the first case, we can add very small numbers lots of times until they become big enough to still be relevant when added to 1.
In the second case, adding 0.00000000000000001 to 1 always just results in 1 as there isn't enough information in a double to represent 1.00000000000000001 - so the final result is still just 1.
EDIT: I've thought of another aspect which could be confusing things. For local variables, the JIT compiler is able to (and allowed to) use the 80-bit FP registers, which means arithmetic can be performed with less information loss. That's not the case for instance variables which definitely have to be 64-bit. In your Parallel.For case, the total variable will actually be an instance variable in a generated class because it's captured by a lambda expression. This could change the results - but it may well depend on computer architecture, CLR version etc.

For VS Foreach on Array performance (in AS3/Flex)

Which one is faster? Why?
var messages:Array = [.....]
// 1 - for
var len:int = messages.length;
for (var i:int = 0; i < len; i++) {
var o:Object = messages[i];
// ...
}
// 2 - foreach
for each (var o:Object in messages) {
// ...
}
From where I'm sitting, regular for loops are moderately faster than for each loops in the minimal case. Also, as with AS2 days, decrementing your way through a for loop generally provides a very minor improvement.
But really, any slight difference here will be dwarfed by the requirements of what you actually do inside the loop. You can find operations that will work faster or slower in either case. The real answer is that neither kind of loop can be meaningfully said to be faster than the other - you must profile your code as it appears in your application.
Sample code:
var size:Number = 10000000;
var arr:Array = [];
for (var i:int=0; i<size; i++) { arr[i] = i; }
var time:Number, o:Object;
// for()
time = getTimer();
for (i=0; i<size; i++) { arr[i]; }
trace("for test: "+(getTimer()-time)+"ms");
// for() reversed
time = getTimer();
for (i=size-1; i>=0; i--) { arr[i]; }
trace("for reversed test: "+(getTimer()-time)+"ms");
// for..in
time = getTimer();
for each(o in arr) { o; }
trace("for each test: "+(getTimer()-time)+"ms");
Results:
for test: 124ms
for reversed test: 110ms
for each test: 261ms
Edit: To improve the comparison, I changed the inner loops so they do nothing but access the collection value.
Edit 2: Answers to oshyshko's comment:
The compiler could skip the accesses in my internal loops, but it doesn't. The loops would exit two or three times faster if it was.
The results change in the sample code you posted because in that version, the for loop now has an implicit type conversion. I left assignments out of my loops to avoid that.
Of course one could argue that it's okay to have an extra cast in the for loop because "real code" would need it anyway, but to me that's just another way of saying "there's no general answer; which loop is faster depends on what you do inside your loop". Which is the answer I'm giving you. ;)
When iterating over an array, for each loops are way faster in my tests.
var len:int = 1000000;
var i:int = 0;
var arr:Array = [];
while(i < len) {
arr[i] = i;
i++;
}
function forEachLoop():void {
var t:Number = getTimer();
var sum:Number = 0;
for each(var num:Number in arr) {
sum += num;
}
trace("forEachLoop :", (getTimer() - t));
}
function whileLoop():void {
var t:Number = getTimer();
var sum:Number = 0;
var i:int = 0;
while(i < len) {
sum += arr[i] as Number;
i++;
}
trace("whileLoop :", (getTimer() - t));
}
forEachLoop();
whileLoop();
This gives:
forEachLoop : 87
whileLoop : 967
Here, probably most of while loop time is spent casting the array item to a Number. However, I consider it a fair comparison, since that's what you get in the for each loop.
My guess is that this difference has to do with the fact that, as mentioned, the as operator is relatively expensive and array access is also relatively slow. With a for each loop, both operations are handled natively, I think, as opossed to performed in Actionscript.
Note, however, that if type conversion actually takes place, the for each version is much slower and the while version if noticeably faster (though, still, for each beats while):
To test, change array initialization to this:
while(i < len) {
arr[i] = i + "";
i++;
}
And now the results are:
forEachLoop : 328
whileLoop : 366
forEachLoop : 324
whileLoop : 369
I've had this discussion with a few collegues before, and we have all found different results for different scenarios. However, there was one test that I found quite eloquent for comparison's sake:
var array:Array=new Array();
for (var k:uint=0; k<1000000; k++) {
array.push(Math.random());
}
stage.addEventListener("mouseDown",foreachloop);
stage.addEventListener("mouseUp",forloop);
/////// Array /////
/* 49ms */
function foreachloop(e) {
var t1:uint=getTimer();
var tmp:Number=0;
var i:uint=0;
for each (var n:Number in array) {
i++;
tmp+=n;
}
trace("foreach", i, tmp, getTimer() - t1);
}
/***** 81ms ****/
function forloop(e) {
var t1:uint=getTimer();
var tmp:Number=0;
var l:uint=array.length;
for(var i:uint = 0; i < l; i++)
tmp += Number(array[i]);
trace("for", i, tmp, getTimer() - t1);
}
What I like about this tests is that you have a reference for both the key and value in each iteration of both loops (removing the key counter in the "for-each" loop is not that relevant). Also, it operates with Number, which is probably the most common loop that you will want to optimize that much. And most importantly, the winner is the "for-each", which is my favorite loop :P
Notes:
-Referencing the array in a local variable within the function of the "for-each" loop is irrelevant, but in the "for" loop you do get a speed bump (75ms instead of 105ms):
function forloop(e) {
var t1:uint=getTimer();
var tmp:Number=0;
var a:Array=array;
var l:uint=a.length;
for(var i:uint = 0; i < l; i++)
tmp += Number(a[i]);
trace("for", i, tmp, getTimer() - t1);
}
-If you run the same tests with the Vector class, the results are a bit confusing :S
for would be faster for arrays...but depending on the situation it can be foreach that is best...see this .net benchmark test.
Personally, I'd use either until I got to the point where it became necessary for me to optimize the code. Premature optimization is wasteful :-)
Maybe in a array where all element are there and start at zero (0 to X) it would be faster to use a for loop. In all other case (sparse array) it can be a LOT faster to use for each.
The reason is the usage of two data structure in the array: Hast table an Debse Array.
Please read my Array analysis using Tamarin source:
http://jpauclair.wordpress.com/2009/12/02/tamarin-part-i-as3-array/
The for loop will check at undefined index where the for each will skip those one jumping to next element in the HastTable
guys!
Especially Juan Pablo Califano.
I've checked your test. The main difference in obtain array item.
If you will put var len : int = 40000;, you will see that 'while' cycle is faster.
But it loses with big counts of array, instead for..each.
Just an add-on:
a for each...in loop doesn't assure You, that the elements in the array/vector gets enumerated in the ORDER THEY ARE STORED in them. (except XMLs)
This IS a vital difference, IMO.
"...Therefore, you should not write code that depends on a for-
each-in or for-in loop’s enumeration order unless you are processing
XML data..." C.Moock
(i hope not to break law stating this one phrase...)
Happy benchmarking.
sorry to prove you guys wrong, but for each is faster. even a lot. except, if you don't want to access the array values, but a) this does not make sense and b) this is not the case here.
as a result of this, i made a detailed post on my super new blog ... :D
greetz
back2dos

Most efficient way to sort parallel arrays in a restricted-feature language

The environment: I am working in a proprietary scripting language where there is no such thing as a user-defined function. I have various loops and local variables of primitive types that I can create and use.
I have two related arrays, "times" and "values". They both contain floating point values. I want to numerically sort the "times" array but have to be sure that the same operations are applied on the "values" array. What's the most efficient way I can do this without the benefit of things like recursion?
You could maintain an index table and sort the index table instead.
This way you will not have to worry about times and values being consistent.
And whenever you need a sorted value, you can lookup on the sorted index.
And if in the future you decided there was going to be a third value, the sorting code will not need any changes.
Here's a sample in C#, but it shouldn't be hard to adapt to your scripting language:
static void Main() {
var r = new Random();
// initialize random data
var index = new int[10]; // the index table
var times = new double[10]; // times
var values = new double[10]; // values
for (int i = 0; i < 10; i++) {
index[i] = i;
times[i] = r.NextDouble();
values[i] = r.NextDouble();
}
// a naive bubble sort
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
// compare time value at current index
if (times[index[i]] < times[index[j]]) {
// swap index value (times and values remain unchanged)
var temp = index[i];
index[i] = index[j];
index[j] = temp;
}
// check if the result is correct
for (int i = 0; i < 10; i++)
Console.WriteLine(times[index[i]]);
Console.ReadKey();
}
Note: I used a naive bubble sort there, watchout. In your case, an insertion sort is probably a good candidate. Since you don't want complex recursions.
Just take your favourite sorting algorithm (e.g. Quicksort or Mergesort) and use it to sort the "values" array. Whenever two values are swapped in "values", also swap the values with the same indices in the "times" array.
So basically you can take any fast sorting algorithm and modify the swap() operation so that elements in both arrays are swapped.
Take a look at the Bottom-Up mergesort at Algorithmist. It's a non-recursive way of performing a mergesort. The version presented there uses function calls, but that can be inlined easily enough.
Like martinus said, every time you change a value in one array, do the exact same thing in the parallel array.
Here's a C-like version of a stable-non-recursive mergesort that makes no function calls, and uses no recursion.
const int arrayLength = 40;
float times_array[arrayLength];
float values_array[arrayLength];
// Fill the two arrays....
// Allocate two buffers
float times_buffer[arrayLength];
float values_buffer[arrayLength];
int blockSize = 1;
while (blockSize <= arrayLength)
{
int i = 0;
while (i < arrayLength-blockSize)
{
int begin1 = i;
int end1 = begin1 + blockSize;
int begin2 = end1;
int end2 = begin2 + blockSize;
int bufferIndex = begin1;
while (begin1 < end1 && begin2 < end2)
{
if ( values_array[begin1] > times_array[begin2] )
{
times_buffer[bufferIndex] = times_array[begin2];
values_buffer[bufferIndex++] = values_array[begin2++];
}
else
{
times_buffer[bufferIndex] = times_array[begin1];
values_buffer[bufferIndex++] = values_array[begin1++];
}
}
while ( begin1 < end1 )
{
times_buffer[bufferIndex] = times_array[begin1];
values_buffer[bufferIndex++] = values_array[begin1++];
}
while ( begin2 < end2 )
{
times_buffer[bufferIndex] = times_array[begin2];
values_buffer[bufferIndex++] = values_array[begin2++];
}
for (int k = i; k < i + 2 * blockSize; ++k)
{
times_array[k] = times_buffer[k];
values_array[k] = values_buffer[k];
}
i += 2 * blockSize;
}
blockSize *= 2;
}
I wouldn't suggest writing your own sorting routine, as the sorting routines provided as part of the Java language are well optimized.
The way I'd solve this is to copy the code in the java.util.Arrays class into your own class i.e. org.mydomain.util.Arrays. And add some comments telling yourself not to use the class except when you must have the additional functionality that you're going to add. The Arrays class is quite stable so this is less, less ideal than it would seem, but it's still less than ideal. However, the methods you need to change are private, so you've no real choice.
You then want to create an interface along the lines of:
public static interface SwapHook {
void swap(int a, int b);
}
You then need to add this to the sort method you're going to use, and to every subordinate method called in the sorting procedure, which swaps elements in your primary array. You arrange for the hook to get called by your modified sorting routine, and you can then implement the SortHook interface to achieve the behaviour you want in any secondary (e.g. parallel) arrays.
HTH.

Resources