Performance test for reading variable ints of a bytearray

by leichtgewicht
♥0 | Line 377 | Modified 2011-09-15 01:49:01 | MIT License
play

ActionScript3 source code

/**
 * Copyright leichtgewicht ( http://wonderfl.net/user/leichtgewicht )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/ozwn
 */

package {
    import flash.utils.getTimer;
    import flash.text.TextFormat;
    import flash.utils.Endian;
    import flash.utils.ByteArray;
    import flash.display.Sprite;
    public class FlashTest extends Sprite {
        
        public function FlashTest() {
            
            addChild(field);
            field.defaultTextFormat = new TextFormat("Courier", 10);
            field.width = stage.stageWidth;
            field.height = stage.stageHeight;
            basicAssumptions();
            flagTests();
            testFunctionality();
            testPerformance();
        }
        
        public function basicAssumptions():void {
            text("\nBasic Data storage assumption");
            var byteArray:ByteArray = new ByteArray();
            byteArray.endian = Endian.LITTLE_ENDIAN;
            
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            
            byteArray.position = 0;
            
            t( "11111111111111111111111111111111", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(128); // 00000001
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            
            byteArray.position = 0;
            
            t( "00000001000000000000000000000000", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(127); // 11111110
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            
            byteArray.position = 0;
            
            t( "11111110000000000000000000000000", byteArray.readInt() );   
            
            byteArray.position = 0;
            
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(128); // 00000001
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            
            byteArray.position = 0;
            
            t( "00000000000000010000000000000000", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(127); // 11111110
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            
            byteArray.position = 0;
            
            t( "00000000111111100000000000000000", byteArray.readInt() );   
            
            byteArray.position = 0;
            
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(127); // 11111110
            byteArray.writeByte(0); // 00000000
            
            byteArray.position = 0;
            
            t( "00000000000000001111111000000000", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(128); // 00000001
            byteArray.writeByte(0); // 00000000
            
            byteArray.position = 0;
            
            t( "00000000000000000000000100000000", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(127); // 11111110
            
            byteArray.position = 0;
            
            t( "00000000000000000000000011111110", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(0); // 00000000
            byteArray.writeByte(128); // 00000001
            
            byteArray.position = 0;
            
            t( "00000000000000000000000000000001", byteArray.readInt() );
            
            text("\nTest Numbers");
            
            byteArray.position = 0;
            
            byteArray.writeByte(127); // 11111110
            byteArray.writeByte(0);   // 00000000
            byteArray.writeByte(0);   // 00000000
            byteArray.writeByte(0);   // 00000000
            
            byteArray.position = 0;
            
            t( "11111111000000000000000000000000", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(63);  // 11111100
            byteArray.writeByte(0);   // 00000000
            byteArray.writeByte(0);   // 00000000
            
            byteArray.position = 0;
            
            t( "11111111111111000000000000000000", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(31);  // 11111000
            byteArray.writeByte(0);   // 00000000
            
            byteArray.position = 0;
            
            t( "11111111111111111111100000000000", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(15);  // 11110000
            
            byteArray.position = 0;
            
            t( "11111111111111111111111111110000", byteArray.readInt() );
            
            byteArray.position = 0;
            
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255);  // 11111111
            
            byteArray.position = 0;
            
            t( "11111111111111111111111111111111", byteArray.readInt() );
            
            text("\nreadByte/writeByte important for the last part of the reader");
                     
            byteArray.position = 0;
            
            byteArray.writeByte(128); // 00000001
            
            byteArray.position = 0;
            
            t( "00000001", byteArray.readByte() );
                     
            byteArray.position = 0;
            
            byteArray.writeByte(127); // 11111110
            
            byteArray.position = 0;
            
            t( "11111110", byteArray.readByte() );
                     
            byteArray.position = 0;
            
            byteArray.writeByte(15); // 11110000
            
            byteArray.position = 0;
            
            t( "11110000", byteArray.readByte() );
        }
        
        public function flagTests():void {
            text("\nByte checks for each level");
            binChk(-1,128); // first byte check
            binChk(-1,32768); // second byte check
            binChk(-1,8388608); // third byte check
            binChk(-1,-2147483648); // fourth byte check
        }
        
        public function prepareTestNumbers(byteArray:ByteArray): int {
            var amountNumbers: int = 0;
            
            // Number 11111110000000000000000000000000 = 127
            byteArray.writeByte(127); // 11111110
            
            ++amountNumbers;
            
            // Number 00000000000000000000000000000000 = 0
            byteArray.writeByte(0); // 00000000
            
            ++amountNumbers;
            
            // Number 11111111111111000000000000000000 = 16383
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(127); // 11111110
            
            ++amountNumbers;
            
            // Number 11111111111111111111100000000000 = 2097151
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(127); // 11111110
            
            ++amountNumbers;
            
            // Number 11111111111111111111111111110000 = 268435455
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(127); // 11111110
            
            ++amountNumbers;
            
            // Number 11111111111111111111111111111111 = -1
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(255); // 11111111
            byteArray.writeByte(15);  // 11110000
            
            ++amountNumbers;
           
            return amountNumbers;
        }
        
        public function testFunctionality():void {
            
            text( "\nFunctionality test");
            
            var valuesA: Vector.<int>= new Vector.<int>;
            var valuesB: Vector.<int> = new Vector.<int>;
            var bytes: ByteArray  = new ByteArray();
            bytes.endian = Endian.LITTLE_ENDIAN;
            var nums: int = prepareTestNumbers(bytes);
            var i: int;
            
            bytes.position = 0;
            for( i= 0; i < nums; ++i ) {
                valuesA.push(readVariableLengthOld(bytes));
            }
            bytes.position = 0;
            for( i= 0; i < nums; ++i ) {
                valuesB.push(readVariableLengthIntDiscussion(bytes));
            }
            
            for( i= 0; i < nums; ++i ) {
                var same: Boolean = valuesA[i] == valuesB[i];
                if( same ) {
                    text( "ok:    "+valuesA[i]+" == "+valuesB[i]+ " = "+same );
                } else {
                    text( "error: "+valuesA[i]+" == "+valuesB[i]+ " = "+same );
                }

            }
        }
        
        public function testPerformance():void {
            
            text( "\nPerformance test");
           
            var bytes: ByteArray  = new ByteArray();
            bytes.endian = Endian.LITTLE_ENDIAN;
            var nums: int = prepareTestNumbers(bytes);
            var i: int;
            var j: int;
            const count: int = 100000;
            
            var t:Number;
            
            t = getTimer();
            for( j=0; j<count;++j) {
                bytes.position = 0;
                for( i= 0; i < nums; ++i ) {
                    readVariableLengthOld(bytes);
                }
            }
            text( (getTimer()-t)+"ms for the old implementation");
            
            t = getTimer();
            for( j=0; j<count;++j) {
                bytes.position = 0;
                for( i= 0; i < nums; ++i ) {
                    readVariableLengthOldTest(bytes);
                }
            }
            text( (getTimer()-t)+"ms for the old test implementation");
            
            t = getTimer();
            for( j=0; j<count;++j) {
                bytes.position = 0;
                for( i= 0; i < nums; ++i ) {
                    readVariableLengthIntDiscussion(bytes);
                }
            }
            text( (getTimer()-t)+"ms for the new implementation");
            const l: int = bytes.length-3;
            t = getTimer();
            for( j=0; j<count;++j) {
                bytes.position = 0;
                for( i= 0; i < nums; ++i ) {
                    readVariableLengthInt(bytes,l);
                }
            }
            text( (getTimer()-t)+"ms for the newer implementation");
            t = getTimer();
            for( j=0; j<count;++j) {
                bytes.position = 0;
                for( i= 0; i < nums; ++i ) {
                    readVariableLengthUnsignedShort(bytes);
                }
            }
            text( (getTimer()-t)+"ms for the short implementation");
        }
        
        public function readVariableLengthOld( byteArray:ByteArray ):int {
            var result: int = byteArray.readUnsignedByte();
            if ((result & 0x00000080)) {
                result = result & 0x0000007f | byteArray.readUnsignedByte() << 7;
                if ((result & 0x00004000)) {
                    result = result & 0x00003fff | byteArray.readUnsignedByte() << 14;
                    if ((result & 0x00200000)) {
                        result = result & 0x001fffff | byteArray.readUnsignedByte() << 21;
                        if ((result & 0x10000000)) {
                            result = result & 0x0fffffff | byteArray.readUnsignedByte() << 28;
                        }
                    }
                }
            }
            return result;
        }
        
        public function readVariableLengthOldTest( byteArray:ByteArray ):int {
            var result: int = byteArray.readUnsignedByte();
            if ((result & 0x00000080)) {
                result = result & 0x0000007f | byteArray.readUnsignedByte() << 7;
                if ((result & 0x00004000)) {
                    result = result & 0x00003fff | byteArray.readUnsignedByte() << 14;
                    if ((result & 0x00200000)) {
                        result = result & 0x001fffff | byteArray.readUnsignedByte() << 21;
                        if ((result & 0x10000000)) {
                            result = result & 0x0fffffff | byteArray.readByte() << 28;
                        }
                    }
                }
            }
            return result;
        }
        
        public function readVariableLengthInt( byteArray:ByteArray, bytesTotalMinus3:int ):int {
            var temp: int;
            var result: int = byteArray.readUnsignedByte();
            // result contains             11111110000000000000000000000000
            if( result & 0x80 ) {
                if( byteArray.position < bytesTotalMinus3 ) {
                    // reading                 11111110000000000000000000000000
                    // putting it seven aside 
                    temp = byteArray.readInt();
                    result = result & 0x7f | ((temp & 0x7f) << 7);
                    // contains                11111111111111000000000000000000
                    if( temp & 0x80 ) {
                        // reading             00000000111111100000000000000000
                        // putting it six aside 
                        result += (temp & 0x7f00) << 6;
                        // contains            11111111111111111111100000000000
                        if( temp & 0x8000 ) {
                            // reading         00000000000000001111111000000000
                            // putting it three aside 
                            result += (temp & 0x7f0000) << 5;
                            // contains        11111111111111111111111111110000
                            if( temp & -0x800000 ) {
                                // reading     00000000000000000000000011110000
                                result += (temp & 0x7f000000) << 4;
                                // contains    11111111111111111111111111111111 (*yeah!*)
                            } else {
                                --byteArray.position;
                            }
                        } else {
                            byteArray.position -= 2;
                        }
                    } else {
                        byteArray.position -= 3;
                    }
                } else {
                    result = result & 0x0000007f | byteArray.readUnsignedByte() << 7;
                    if ((result & 0x00004000)) {
                        result = result & 0x00003fff | byteArray.readUnsignedByte() << 14;
                        if ((result & 0x00200000)) {
                            result = result & 0x001fffff | byteArray.readUnsignedByte() << 21;
                            if ((result & 0x10000000)) {
                                result = result & 0x0fffffff | byteArray.readUnsignedByte() << 28;
                            }
                        }
                    }
                }
            }
            return result;
        }

        
        public function readVariableLengthIntDiscussion( byteArray:ByteArray ):int {
            var temp: int = byteArray.readInt();
            var result: int = temp & 0x7f;
            // result contains             11111110000000000000000000000000
            if( temp & 0x80 ) {
                // reading                 00000000111111100000000000000000
                //                                > ... this bit has been used by the marker bit before
                // putting it one aside 
                result += (temp & 0x7f00) >> 1;
                // contains                11111111111111000000000000000000
                if( temp & 0x8000 ) {
                    // reading             00000000000000001111111000000000
                    //                                   >> ... now we've had 2 marker bits
                    // putting it two aside 
                    result += (temp & 0x7f0000) >> 2;
                    // contains            11111111111111111111100000000000
                    if( temp & 0x800000 ) {
                        // reading         00000000000000000000000011111110
                        //                                      >>> ... and now 3 marker bit
                        // putting it three aside 
                        result += (temp & 0x7f000000) >> 3;
                        // contains        11111111111111111111111111110000
                        if( temp & -0x80000000 ) {
                            // reading     11110000000000000000000000000000
                            //                 <<<<<<<<<<<<<<<<<<<<<<<<<<<< // (28 = 7 value bits in 4 bytes);
                            result += byteArray.readUnsignedByte() << 28;
                            // contains    11111111111111111111111111111111 (*yeah!*)
                        }
                    } else {
                        --byteArray.position;
                    }
                } else {
                    byteArray.position -= 2;
                }
            } else {
                byteArray.position -= 3;
            }
            return result;
        }
        
        public function readVariableLengthUnsignedShort( byteArray:ByteArray ):int {
            var temp: int = byteArray.readUnsignedShort();
            var result: int = temp & 0x7f;
            if( temp & 0x80 ) {
                result = result | (temp & 0x7f00) >> 1;
                if( temp & 0x8000 ) {
                    temp = byteArray.readUnsignedShort();
                    result = result | (temp & 0x7f) << 6;
                    if( temp & 0x80 ) {
                        result = result | (temp & 0x7f00) << 5;
                        if( temp & 0x8000 ) {
                            result = result | byteArray.readUnsignedByte() << 28;// (28 = 7*3);
                        }
                    } else {
                        byteArray.position -= 1;
                    }
                }
            } else {
               byteArray.position -= 1;
            }
            return result;
        }
    }
}
import flash.text.TextField;

const field: TextField = new TextField();

function binChk(value:int,mask:int):void {
    field.appendText( value.toString(10) + " & " + mask.toString(10)+" = "+((value&mask)!=0)+"\n");
}


function t(bin:String, no:int ):void {
    
    var str: String = no.toString(10);
    while( str.length < 11 ) {
        str = " "+str;
    }
    var str2: String = no.toString(16);
    while( str2.length < 11 ) {
        str2 = " "+str2;
    }
    field.appendText(bin+"..."+str+"..."+str2+"\n");
}

function text(txt:String):void {
    field.appendText(txt+"\n");
}