Copy portions of a Vector Speed test

7 posts

Flag Post

So I’m trying to optimize a function that is eating up 10% of my runtime shown here:

private var mRawData:Vector.<Number>;
//other private variables

/** Copies the vertex data (or a range of it, defined by 'vertexID' and 'numVertices') 
 *  of this instance to another vertex data object, starting at a certain index. 
 */
public function copyTo(targetData:VertexData, targetVertexID:int=0, vertexID:int=0, numVertices:int=-1):void
{
            if (numVertices < 0 || vertexID + numVertices > mNumVertices)
                numVertices = mNumVertices - vertexID;
            
            // todo: check/convert pma
            
            var targetRawData:Vector.<Number> = targetData.mRawData;
            var targetIndex:int = targetVertexID * ELEMENTS_PER_VERTEX;
            var sourceIndex:int = vertexID * ELEMENTS_PER_VERTEX;
            var dataLength:int = numVertices * ELEMENTS_PER_VERTEX;
            
            for (var i:int=sourceIndex; i<dataLength; ++i)
                targetRawData[targetIndex++] = mRawData[i];
}

I figured that the largest impact must be the vector copying, from a start to end index. So I did some performance testing:

private function init(): void
{
	var beforeTime:int;
	var afterTime:int;
	var i:int;
	var j:int;
	var REPS:int = 10;
	var LENGTH:int = 100000;
	
	var v:Vector.<Number> = new Vector.<Number>();
	var v2:Vector.<Number> = new Vector.<Number>();
	for (i = 0; i < LENGTH; ++i)
	{
		v[i] = i;
		v2[i] = i;
	}
			row("Method", "Time");
	
	
	beforeTime = getTimer();
	for (i = 0; i < REPS; ++i)
	{
		v2 = v.slice(1000, LENGTH-1000);
	}
	afterTime = getTimer();
	row("slice", (afterTime-beforeTime));
	
	
	beforeTime = getTimer();
	for (i = 0; i < REPS; ++i)
	{
		for (j = 1000; j < LENGTH-1000; ++j)
		{
			v2[j] = v[j];
		}
		
	}
	afterTime = getTimer();
	row("manual", (afterTime-beforeTime));
			
}

Does that performance test look correct? I’m getting really really weird results, saying that slice() is 10x faster than manual copying.

EDIT Hrm. I realize now that v2 will be different than V1 because slice will overwrite it.
That said, is there anyway to speed up the original function, specifically the loop at the end.

 
Flag Post

Looks fine to me. I seem to recall reading somewhere that while loops are faster than for loops, but dunno if by enough to make a significant difference.
EDIT: Google says while faster than for was true for the old virtual machine, but choice of loop is irrelevant for AS3, so ignore me :)

 
Flag Post

I’d rather see if there is a faster copy (maybe flash player internals code) than working on loops right now. If none exists, sure, loop optimizations are fine. I’m fairly positive the loop is happening 1,000 times per frame at the minimum. (Function takes up 997ms out of 8,292ms sample time)

 
Flag Post
arr.splice.apply([start, end].concat(arr2.slice(start, end)))

there’s no nice way to do that, though; and most certainly won’t be faster. also only works on Array

you can speed up the inner loop substantially with: for (j = 1000; j !== k; ++j) where k = LENGTH-1000; only use !== instead of < when you know the starting value is less than the end value (the strict-typing of !== is marginally faster) and by using more than one operation per loop; non-multiples can be handled prior to the start of the loop with an if/else tree and bitwise operations

 
Flag Post

OK, loop optimization it is then. :/

 
Flag Post

UG, is there someway you can skip this step altogether? Like writing directly to the vector that is uploaded instead of copying over after generating one?

 
Flag Post

Originally posted by UnknownGuardian:

OK, loop optimization it is then. :/

here’s something, though i make no promises at 5 AM

public function copyTo(targetData:VertexData, targetVertexID:int=0, vertexID:int=0, numVertices:int=-1):void { // bug: vertexID > mNumVerticies
	if (vertexID + Number(numVertices) > mNumVertices) // faster than ||
		numVertices = mNumVertices - vertexID;

	// todo: check/convert pma

	var targetRawData:Vector.<Number> = targetData.mRawData;
	targetVertexID *= ELEMENTS_PER_VERTEX;
	vertexID *= ELEMENTS_PER_VERTEX;
	numVertices *= ELEMENTS_PER_VERTEX;
	numVertices += vertexID; // best not to merge this and the above. also, bugfix for non-zero starting index

	while (vertexID & 3 & -int(vertexID < numVerticies)) {
		targetRawData[targetVertexID] = mRawData[vertexID]; ++vertexID, ++targetVertexID; // handle non-multiples of 4
	}

	while (vertexID !== numVerticies) {
		targetRawData[targetVertexID] = mRawData[vertexID]; ++vertexID, ++targetVertexID;
		targetRawData[targetVertexID] = mRawData[vertexID]; ++vertexID, ++targetVertexID;
		targetRawData[targetVertexID] = mRawData[vertexID]; ++vertexID, ++targetVertexID;
		targetRawData[targetVertexID] = mRawData[vertexID]; ++vertexID, ++targetVertexID;
	}
}