Operator Speed: Part 2
Today’s article is a followup to a flawed article I wrote last October. Skyboy’s comment brought this to my attention, so today I’m (hopefully) correcting the problems with an important test: AS3 operators. Read on for the updated test code and results.
The first problem pointed out is that the anonymous log
function caused an activation object to be generated by the compiler, which in turn caused a slowdown. Coincidentally, the original article was written one week before I wrote Activation Objects, detailing the slowdown. From then on, I stopped using local log
functions. The updated test removes the local log
function.
Secondly, the test for <=
had a typo causing it to actually test for the <
operator. The updated test fixes this typo. Also, the original test had no declared test for <
. These test was added.
Thirdly, the original test only tested post-increment (e.g. val++
) and vaguely labeled the tests. The new test explicitly checks the performance of pre- and post-increment.
Fourthly, with such cheap operators, the loop’s time itself was distorting the results. The updated test does two things to address this. First, the loop time is subtracted from the total time. Since this frequently yields negative values, the test is run every frame until all results are non-negative.
Lastly, when comparing results, even with loop times removed, there was much statistical variance between them. To correct for this, the test is run every frame until five successful (i.e. all values are non-negative) tests are generated. The results are then averaged.
Now for the test. Just as a warning, it is extremely long as it tests a lot of operators. The results table follows the source code, so feel free to scroll on past the test. Also, if you decide to compile and run the test, keep in mind that it will take quite a while to complete due to a combination of a high repetition count for each operator, the requirement of all non-negative values, and the requirement of multiple successful tests.
package { import flash.display.*; import flash.events.*; import flash.utils.*; import flash.text.*; /** * An app to test operator performance * @author Jackson Dunstan */ [SWF(frameRate="1000")] public class OperatorPerformance extends Sprite { private static const SUCCESSES:int = 5; private var __logger:TextField = new TextField(); private var __results:Array; private var __resultsCol:int; private var __resultsRow:int; private var __totalResults:Array; private var __successes:int; private var __numResultRows:int; private var __numResultCols:int; public function OperatorPerformance() { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; __logger.autoSize = TextFieldAutoSize.LEFT; __logger.defaultTextFormat = new TextFormat("_typewriter", 13); __logger.text = "Progress: " + __successes + "/" + SUCCESSES; addChild(__logger); addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function initResultsTable(): void { __results = [ ["Operator","int","uint","int/uint","Number","int/Number","uint/Number"], ["&","","","","","",""], ["|","","","","","",""], ["^","","","","","",""], ["~","","","","","",""], [">>","","","","","",""], [">>>","","","","","",""], ["<<","","","","","",""], ["+","","","","","",""], ["-","","","","","",""], ["*","","","","","",""], ["/","","","","","",""], ["%","","","","","",""], ["v++","","","","","",""], ["v--","","","","","",""], ["++v","","","","","",""], ["--v","","","","","",""], ["==","","","","","",""], ["===","","","","","",""], ["!=","","","","","",""], ["!==","","","","","",""], [">","","","","","",""], ["<","","","","","",""], [">=","","","","","",""], ["<=","","","","","",""], ["&&","","","","","",""], ["||","","","","","",""], ["!","","","","","",""], ["=","","","","","",""] ]; __numResultRows = __results.length; __numResultCols = __results[0].length; if (__totalResults == null) { __totalResults = __results.slice(); for (var i:int = 0; i < __totalResults.length; ++i) { __totalResults[i] = __totalResults[i].slice(); } } __resultsCol = 1; __resultsRow = 1; } private function reportResult(result:String): Boolean { __results[__resultsRow++][__resultsCol] = result; return result == "n/a" || int(result) >= 0; } public function onEnterFrame(ev:Event): void { var i:int; const REPS:int = 10000000; var beforeTime:int; var afterTime:int; var loopTime:int; var val1int:int; var val2int:int; var val1uint:uint; var val2uint:uint; var val1number:Number; var val2number:Number; initResultsTable(); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { } afterTime = getTimer(); loopTime = afterTime - beforeTime; val1int = 1; val2int = 2; val1uint = 1; val2uint = 2; val1number = 1; val2number = 2; beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int & val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int | val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int ^ val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { ~val1int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >> val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >>> val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int << val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int + val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int - val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int * val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int / val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int % val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int++; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int--; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { ++val1int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { --val1int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int == val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int === val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int != val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int !== val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int > val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int < val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >= val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int <= val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int && val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int || val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { !val1int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int = val2int; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } __resultsCol++; __resultsRow = 1; val1int = 1; val2int = 2; val1uint = 1; val2uint = 2; val1number = 1; val2number = 2; beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint & val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint | val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint ^ val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { ~val1uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint >> val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint >>> val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint << val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint + val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint - val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint * val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint / val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint % val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint++; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint--; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { ++val1uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { --val1uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint == val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint === val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint != val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint !== val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint > val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint < val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint >= val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint <= val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint && val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint || val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { !val1uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint = val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } __resultsCol++; __resultsRow = 1; val1int = 1; val2int = 2; val1uint = 1; val2uint = 2; val1number = 1; val2number = 2; beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int & val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int | val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int ^ val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >> val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >>> val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int << val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int + val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int - val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int * val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int / val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int % val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int == val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int === val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int != val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int !== val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int > val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int < val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >= val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int <= val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int && val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int || val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int = val2uint; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } __resultsCol++; __resultsRow = 1; val1int = 1; val2int = 2; val1uint = 1; val2uint = 2; val1number = 1; val2number = 2; beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number & val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number | val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number ^ val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { ~val1number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number >> val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number >>> val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number << val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number + val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number - val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number * val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number / val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number % val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number++; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number--; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { ++val1number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { --val1number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number == val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number === val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number != val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number !== val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number > val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number < val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number >= val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number <= val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number && val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number || val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { !val1number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1number = val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } __resultsCol++; __resultsRow = 1; val1int = 1; val2int = 2; val1uint = 1; val2uint = 2; val1number = 1; val2number = 2; beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int & val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int | val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int ^ val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >> val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >>> val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int << val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int + val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int - val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int * val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int / val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int % val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int == val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int === val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int != val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int !== val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int > val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int < val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int >= val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int <= val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int && val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int || val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1int = val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } __resultsCol++; __resultsRow = 1; val1int = 1; val2int = 2; val1uint = 1; val2uint = 2; val1number = 1; val2number = 2; beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint & val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint | val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint ^ val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint >> val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint >>> val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint << val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint + val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint - val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint * val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint / val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint % val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint == val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint === val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint != val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint !== val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint > val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint < val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint >= val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint <= val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint && val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint || val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } if (!reportResult("n/a")) { return; } beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { val1uint = val2number; } afterTime = getTimer(); if (!reportResult(String(afterTime-beforeTime-loopTime))) { return; } for (var row:int = 1; row < __numResultRows; ++row) { for (var col:int = 1; col < __numResultCols; ++col) { var cell:String = __results[row][col]; if (cell != "n/a") { var totalCell:String = __totalResults[row][col]; __totalResults[row][col] = int(cell) + int(totalCell); } } } __successes++; if (__successes == SUCCESSES) { for (row = 1; row < __numResultRows; ++row) { for (col = 1; col < __numResultCols; ++col) { cell = __totalResults[row][col]; if (cell != "n/a") { __totalResults[row][col] = Number(cell) / SUCCESSES; } } } __logger.text = __totalResults.join("\n"); removeEventListener(Event.ENTER_FRAME, onEnterFrame); } else { __logger.text = "Progress: " + __successes + "/" + SUCCESSES; } } } }
Here is the test environment I ran the above app on:
- Flex SDK (MXMLC) 4.1.0.16076, compiling in release mode (no debugging or verbose stack traces)
- Release version of Flash Player 10.2.152.26
- 2.4 Ghz Intel Core i5
- Mac OS X 10.6.6
Operator | int | uint | int/uint | Number | int/Number | uint/Number |
---|---|---|---|---|---|---|
& | 2.2 | 2 | 3 | 2.2 | 3.4 | 2.6 |
| | 3.6 | 4 | 2.4 | 2.2 | 2.8 | 4.2 |
^ | 2.4 | 3 | 2.6 | 2.2 | 3.4 | 2.6 |
~ | 3.6 | 3 | 0 | 2 | 0 | 0 |
>> | 4.6 | 2.2 | 4.4 | 2 | 5 | 2.4 |
>>> | 4 | 4.8 | 2.6 | 1.6 | 4 | 3.8 |
<< | 3 | 2.8 | 4 | 2.6 | 1.8 | 2.6 |
+ | 3.6 | 3.8 | 2.6 | 1.6 | 4.6 | 4 |
– | 3.4 | 2.2 | 4.2 | 3.2 | 2.6 | 3 |
* | 4 | 4.2 | 2.8 | 1.4 | 4.6 | 4.4 |
/ | 3 | 2.8 | 3.6 | 2.6 | 2.6 | 2.2 |
% | 4 | 3.8 | 3.8 | 4.4 | 4.6 | 4 |
v++ | 1.4 | 1.2 | 0 | 16.2 | 0 | 0 |
v-- | 1.4 | 1.6 | 0 | 16.2 | 0 | 0 |
++v | 1.2 | 2 | 0 | 16.2 | 0 | 0 |
--v | 1.6 | 1.4 | 0 | 15.8 | 0 | 0 |
== | 4.6 | 3.8 | 4.6 | 4 | 3 | 3 |
=== | 2.8 | 1.4 | 2.2 | 2.6 | 3.6 | 2 |
!= | 3.2 | 4.2 | 3.2 | 3.8 | 2.4 | 3.2 |
!== | 2.4 | 4.2 | 2.4 | 1.8 | 4 | 1.6 |
> | 4.2 | 3.6 | 3 | 4.4 | 2.8 | 2.6 |
< | 3.2 | 2 | 2.6 | 2.2 | 3.8 | 2.4 |
>= | 4 | 4.6 | 2.6 | 4 | 3.8 | 2.2 |
<= | 2.6 | 3 | 4.8 | 3.6 | 4.6 | 2.8 |
&& | 1.4 | 2 | 73.6 | 25.2 | 71.2 | 70 |
|| | 2.4 | 1.6 | 71.2 | 25.6 | 73.8 | 73.4 |
! | 2.4 | 2.4 | 0 | 2.6 | 0 | 0 |
= | 4 | 3.6 | 4.4 | 4 | 1.8 | 2.4 |
At this point I should mention that it is very tempting to look at these numbers and leap to conclusions. It looks like the >>
operator is more than twice as fast with Number
than with int
. This is not true due to the margin of error, even with the added averaging in this version of the test.
So, the way I recommend reading the above numbers is to group similar values together. I’ve binned them in groups of five below:
Operator | int | uint | int/uint | Number | int/Number | uint/Number |
---|---|---|---|---|---|---|
& | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
| | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
^ | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
~ | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
>> | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
>>> | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
<< | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
+ | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
– | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
* | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
/ | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
% | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
v++ | 0-5 | 0-5 | 0-5 | 15-20 | 0-5 | 0-5 |
v-- | 0-5 | 0-5 | 0-5 | 15-20 | 0-5 | 0-5 |
++v | 0-5 | 0-5 | 0-5 | 15-20 | 0-5 | 0-5 |
--v | 0-5 | 0-5 | 0-5 | 15-20 | 0-5 | 0-5 |
== | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
=== | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
!= | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
!== | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
> | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
< | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
>= | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
<= | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
&& | 0-5 | 0-5 | 70-75 | 25-30 | 70-75 | 70-75 |
|| | 0-5 | 0-5 | 70-75 | 25-30 | 70-75 | 70-75 |
! | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
= | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 | 0-5 |
Notice that almost all of the operators—those in the 0-5 range—are extremely fast. What I recommend concerning yourself with are those that aren’t in the 0-5 range. Namely, these:
Number
-- (3-4x slower)Number
++ (3-4x slower)- -
Number
(3-4x slower) - ++
Number
(3-4x slower) int
&&uint
(14-15x slower)int
||uint
(14-15x slower)Number
&&Number
(5-6x slower)Number
||Number
(5-6x slower)int
&&uint
(14-15x slower)int
&&Number
(14-15x slower)int
||Number
(14-15x slower)uint
&&Number
(14-15x slower)uint
||Number
(14-15x slower)
The above list should serve as a good reference when you’re questioning the contents of a very hot loop.
Thanks again to Skyboy for pointing out some of the flaws in the original test. Please, as always, feel free to comment if you too find anything wrong with any of tests or just to chime in with your thoughts.
#1 by skyboy on March 7th, 2011 ·
I still think the tests are skewed, because branching is significantly more expensive than int addition, while the way I did the test isn’t fun — regex find+replace to duplicate tests until 100 tests are performed each loop combined with reducing the number of repetitions by 10x; end result is 10x more tests in 1/10th the time on most. it can be made more readable with apparat’s macro expansions, though. (a macro with 10x operations, then another with 10x of calls to that macros. for each operator) — it yields more correct results, from what I can tell.
The end result of that is 500 million tests per operator, and from what I’ve seen across various machines, the VM flash runs in brings most of the operators to be the same speed, and logical operators are much slower due to the branching.
http://pastebin.com/7yzw09uZ
The results at that link (10.1) are from an AMD Phenomâ„¢ II X6 Black 1090T using the above method of 100 tests per loop with 5 million loops per operator.
By far the beefiest computer I’ve seen run flash yet.
As a side note of the test ran, the || operator between int and uint was mistakenly made an XOR operator, it’s assumed similar results to the number/int and number/uint tests would be seen; And the test was not run with minimal other applications running, this was closer to a “real world” test than “optimal.” On other tests ran that were on the “optimal” side of things, the operators performed largely the same, ie: http://pastebin.com/R48ybgb1
#2 by jackson on March 7th, 2011 ·
I think that the “slow list” I put at the end of the article is really what counts, as there is definitely going to be a lot of wiggle room in this kind of broad test regardless of how it’s built. In this sense, it seems that our results mostly match. The only difference would seem to be that your test shows
int
/int
anduint
/uint
&&
and||
operators as slow where mine doesn’t. I wonder what explains this. Perhaps a more targeted test would elucidate…#3 by skyboy on March 7th, 2011 ·
Another relatively large jump is uint pre/post de/increment operators between versions.
The difference in the logical operators is likely the differences in the number of tests: 500 million vs 50 million, in combination with removing the some of the overhead for the loop’s logical branching making differences more prominent, but stepping it up to 5 billion tests at 5 million iterations is virtual insanity (1,000 tests per iteration); The logical operators take so long, that these would have to be tested one at a time, independent of each other with the timeout limit set to 60 seconds. Even at that, some of them may crash.
I haven’t looked at (or seen) any source code for the operators in the VM, but that would likely shed more light on the logical operators inconsistency.
#4 by Sandro Manke on March 11th, 2011 ·
did you try out instead of
Number++
Number+=1.0
as internal this might be a f****up and they actually have a cast when incrementing, +=1 might be faster especially considering how much faster the + operator is.
at least to me that makes a lot of sense
concerning the other results they are basically what i would expect. type casting is very expensive, as is
uint && Number (14-15x slower)
etc.
no suprise there at all.
but really concerning those test results one should wonder – as i need Number more than often in an application – does the extensive use of int outside of loops, or cases when i need the accuracy (rounding problem of floats, to mention it, e.g.) really make any sense at all? I’d say no, but sometimes i wonder if i am alone in this in the flash world.
Optimizing something down to this level is quite some core internal stuff and after lots of years i havent encountered one time when i actually needed to do it like that, cause optimizing this way has one result:
it breaks your code maintainability.
unmaintainable code though is much harder to optimize on a logical level
which then itself leads to unoptimized code
and when i learned one thing: logical optimizations always beat code optimization (which this tiny difference here shown in the article displays dramatically – i grant some exceptions – but its some)
#5 by jackson on March 11th, 2011 ·
Theoretically, the
int
operations are faster and over the course of your whole application should add up. They also consume half the memory (4 bytes vs. 8 bytes), so that should be nice. Also, they can’t beNaN
and can be clamped to non-negative viauint
. So there are many good reason to use them, including more than just this short list.As for your points about optimization, I’m not sure exactly which optimization you’re talking about. However, I agree that targeted optimizations at the algorithm level are almost always more effective than syntax-ish operations at the low level.
PS: Please do not include curse words on my site. I’ve edited your comment to remove the one.
#6 by Sandro Manke on March 12th, 2011 ·
i agree with you, that there are cases in which you have an easier life with int/uint.
one problem i have with them: why 32bit?
when it werent for 32bit, i would not need int that often anymore. the only way right now for storing fixed integer is 2 ints, which unfortunately also has its own problems (think of 1.0001 to store as a 2-int-fixed-integer) and calculations related to that.
i sure hope, adobe will fix this soon – but it will not be as memory efficient anymore as you describe.
nevertheless i am not so sure about memory efficiency. as my background from c++/asm suggests, also flash will have a memory alignment (eventually of its own as it is a vm) and i would have to investigate if it is really a 4 byte word. its more likely to be bigger. in swf size this is a different story, indeed.
i am pretty sure though, that the flash guys did not reinvent the wheel here
#7 by Sandro Manke on March 12th, 2011 ·
replace to ” would not need Number that often anymore”
#8 by jackson on March 12th, 2011 ·
That’s a good point- the VM may end up storing the
int
as more than 4 bytes. It may end up storing it as 1 KB. The choice is up to the VM. However, the VM must store it with at least 4 bytes as we are guaranteed that precision. WithNumber
, the VM is forced to use at least 8 bytes. So, assuming the VM is making efficient use of structure padding, we can hope it only uses 4 bytes most of the time.As for fixed-point integers, I often use them with a single
int
oruint
. For example, if your 3D coordinate system is on a foot scale (i.e. 1 foot = 1 unit), there are probably lots of cases where you don’t need much fractional precision. In these cases, I’ve used a singleint
in 1.29.2 (1 sign bit, 29 integer bits, 2 fractional bits) to get precision down to 1/100 inch, maintain sign to support negatives, and still have numbers up to 536,870,912. As with all fixed-point integers, they are extremely domain specific. A “two-int” approach would definitely have advantages when lots of precision or very high numbers are required.I would love to see
long
andulong
types added to the language for 64-bit support. This would be very nice for encyption/decryption, random number generators, and just storing huge values. Likewise, aFloat
type would be very nice for 32-bit floating point values. I’m actually a little surprised that they don’t seem to have introduced this with Molehill as 32-bit floats are very common in 3D programming.#9 by skyboy on April 30th, 2011 ·
In a recent post over on bytearray (http://www.bytearray.org/?p=3007) floats (and float4…? PxB color format migration?) are slated for a later version of flash. No mention of long/ulong though.
#10 by skyboy on March 15th, 2012 ·
Errors with this test keep cropping up. This time, the error is introduced by the JIT removing operations. Every result is wrong because it was all removed.
http://megaswf.com/serve/2238161
% on in/uint is 2x slower than % on Number.
% on Number is 2x slower than / on Number.
/ on Number is 4x slower than * on Number
* on Number is 0.25x slower than – on Number.
* on int/uint is 2x slower than * on Number.
– on int/uint is 65% faster than – on Number.
leftshift, rightshift, unsginedrightshift are 10x slower than &^| on int/uint.
leftshift, rightshift, unsginedrightshift show equal speed between Number/int/uint.
The huge difference is made by making the loops non-trivial: that is, the result of one loop depends on the result of the previous loop.
val1Int ^= val0Int
for instance.#11 by skyboy on March 15th, 2012 ·
The source: http://pastebin.com/4sx2A3W4
Compiled with latest flex + TDSI from apparat. (To insure I got the bytecode I wanted)