Всякие разные штуки сомнительной полезности сделанные в свободное от работы время.
Manitu Group сделали интересную програмку - Azoth
Запись от wvxvw размещена 28.05.2010 в 01:14
Alchemy очень интересная штука, но для многих флешеров - скорее что-то из области научной фантастики. Кроме того, в обычной жизни ее так особо никто и не использует, кроме как всем извесный jpeg_encoder.
Что такое Azoth - это возможность использовать некоторые фишки Алхимии в обычных проектах.
Что он делает - заменяет вызовы к специальному классу специальными опкодами (командами виртуальной машины) для быстрого доступа к памяти.
Ниже приводится тест применения его на практике. Тестировались Адобовский Base64Encoder и мой на скорую руку написаный кодировщик Base64. Результат внушающий. Вариант обработанный Азотом оказался примерно в 6.5 раз быстрее фрейморковского. Хотя, я думаю, что если задаться целью соптимизировать еще больше, то можно еще улучшить показатели (можно было писать результат тоже в память вместо другуго ByteArray, но для теста / демонстрации и этого достаточно).
Итак, исходники и бенчмарки:
package org.wvxvws.encoding.base64 { import flash.utils.ByteArray; import flash.utils.Endian; import com.buraks.utils.fastmem; public class Base64 { private static const PAD:String = "="; /** * ... * @author wvxvw */ public function Base64() { super(); } public static function encode(bytes:ByteArray):String { var chunk:int; var readPosition:int = 64; var witePosition:int; var bytesLength:int = ((bytes.length * 0.3333333333333333) >>> 0) * 3 + 64; var tail:int = bytes.length + 64 - bytesLength; var ret:ByteArray = new ByteArray(); ret.length = ((bytes.length * 0.3333333333333333) >>> 0) * 4; bytes.endian = Endian.LITTLE_ENDIAN; bytes.length += 64; bytes.position = 0; bytes.readBytes(bytes, 64); bytes.position = 0; bytes.writeMultiByte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "us-ascii"); if (bytes.length < 1024) bytes.length = 1024; fastmem.fastSelectMem(bytes); while (readPosition < bytesLength) { chunk = fastmem.fastGetByte(readPosition++) << 16; chunk |= (fastmem.fastGetByte(readPosition++) << 8); chunk |= fastmem.fastGetByte(readPosition++); ret[witePosition++] = fastmem.fastGetByte(chunk >>> 18); ret[witePosition++] = fastmem.fastGetByte((chunk >>> 12) & 0x3F); ret[witePosition++] = fastmem.fastGetByte((chunk >>> 6) & 0x3F); ret[witePosition++] = fastmem.fastGetByte(chunk & 0x3F); } switch (tail) { case 1: chunk = fastmem.fastGetByte(readPosition++); ret[witePosition++] = fastmem.fastGetByte(chunk >>> 2); ret[witePosition++] = fastmem.fastGetByte((chunk & 3) << 4); ret[witePosition++] = 61; ret[witePosition++] = 61; break; case 2: chunk = fastmem.fastGetByte(readPosition++) << 8; chunk |= fastmem.fastGetByte(readPosition++); ret[witePosition++] = fastmem.fastGetByte(chunk >>> 10); ret[witePosition++] = fastmem.fastGetByte((chunk >>> 4) & 0x3F); ret[witePosition++] = fastmem.fastGetByte((chunk & 15) << 2); ret[witePosition++] = 61; break; } return ret.toString(); } } }
package tests { import flash.display.Sprite; import flash.text.TextField; import flash.utils.ByteArray; import flash.utils.Endian; import flash.utils.getTimer; import org.wvxvws.encoding.base64.Base64; import mx.utils.Base64Encoder; /** * ... * @author wvxvw */ public class TestBase64 extends Sprite { [Embed(source='../../rsx/gray-lines.jpg', mimeType='application/octet-stream')] private var _binData:Class; // 444 Kb private var _field:TextField = new TextField(); public function TestBase64() { super(); this._field.width = super.stage.stageWidth; this._field.height = super.stage.stageHeight; super.addChild(this._field); this.testFlex(); this.testAzot(); } /** * Results for release player 10.0.45.2 standalone Windows XP SP3 * Run 0: Bytes encoded: 615197 time spent: 268 * Run 1: Bytes encoded: 615197 time spent: 258 * Run 2: Bytes encoded: 615197 time spent: 263 * Run 3: Bytes encoded: 615197 time spent: 285 * Run 4: Bytes encoded: 615197 time spent: 269 * Run 5: Bytes encoded: 615197 time spent: 261 * Run 6: Bytes encoded: 615197 time spent: 275 * Run 7: Bytes encoded: 615197 time spent: 256 * Run 8: Bytes encoded: 615197 time spent: 256 * Run 9: Bytes encoded: 615197 time spent: 276 * Run 10: Bytes encoded: 615197 time spent: 264 */ private function testFlex():void { var encoder:Base64Encoder = new Base64Encoder(); var ba:ByteArray = new _binData() as ByteArray; ba.endian = Endian.LITTLE_ENDIAN; var t:int = getTimer(); encoder.encodeBytes(ba); var s:String = encoder.flush(); t = getTimer() - t; this._field.appendText("\rFlex\rBytes encoded: " + s.length + "\rtime spent: " + t + "\r "); } /** * Results for release player 10.0.45.2 standalone Windows XP SP3 * Run 0: Bytes encoded: 607208 time spent: 40 * Run 1: Bytes encoded: 607208 time spent: 44 * Run 2: Bytes encoded: 607208 time spent: 39 * Run 3: Bytes encoded: 607208 time spent: 40 * Run 4: Bytes encoded: 607208 time spent: 39 * Run 5: Bytes encoded: 607208 time spent: 39 * Run 6: Bytes encoded: 607208 time spent: 41 * Run 7: Bytes encoded: 607208 time spent: 40 * Run 8: Bytes encoded: 607208 time spent: 40 * Run 9: Bytes encoded: 607208 time spent: 40 * Run 10: Bytes encoded: 607208 time spent: 40 */ private function testAzot():void { var ba:ByteArray = new _binData() as ByteArray; ba.endian = Endian.LITTLE_ENDIAN; var t:int = getTimer(); var s:String = Base64.encode(ba); t = getTimer() - t; this._field.appendText("\rAzot\rBytes encoded: " + s.length + "\rtime spent: " + t + "\r "); } } }
Теперь, небольшое объяснение, как оно работает: По сути все очень просто, обращения к fastmem заменяются после обработки на соответствующие им опкоды, в чем можно легко убедится используя SWFDump утилиту из SDK. Ниже приводится участок кода который соответствует while циклу из Base64.encode(). Первый листинг - до обработки, второй - после. Обратите внимание на строчки с :fastGetByte (1), которые трансформируются в OP_0x35.
Код:
L2: label getlex com.buraks.utils:fastmem getlocal3 dup increment_i setlocal3 callproperty :fastGetByte (1) pushbyte 16 lshift setlocal2 getlocal2 getlex com.buraks.utils:fastmem getlocal3 dup increment_i setlocal3 callproperty :fastGetByte (1) pushbyte 8 lshift bitor setlocal2 getlocal2 getlex com.buraks.utils:fastmem getlocal3 dup increment_i setlocal3 callproperty :fastGetByte (1) bitor setlocal2 getlocal 7 getlocal 4 dup increment_i setlocal 4 dup setlocal 8 getlex com.buraks.utils:fastmem getlocal2 pushbyte 18 urshift callproperty :fastGetByte (1) setproperty private,,private,org.wvxvws.encoding.base64,org.wvxvws.encoding.base64,http://adobe.com/AS3/2006/builtin,org.wvxvws.encoding.base64:Base64,org.wvxvws.encoding.base64:Base64,Object:null getlocal 7 getlocal 4 dup increment_i setlocal 4 dup setlocal 9 getlex com.buraks.utils:fastmem getlocal2 pushbyte 12 urshift pushbyte 63 bitand callproperty :fastGetByte (1) setproperty private,,private,org.wvxvws.encoding.base64,org.wvxvws.encoding.base64,http://adobe.com/AS3/2006/builtin,org.wvxvws.encoding.base64:Base64,org.wvxvws.encoding.base64:Base64,Object:null getlocal 7 getlocal 4 dup increment_i setlocal 4 dup setlocal 10 getlex com.buraks.utils:fastmem getlocal2 pushbyte 6 urshift pushbyte 63 bitand callproperty :fastGetByte (1) setproperty private,,private,org.wvxvws.encoding.base64,org.wvxvws.encoding.base64,http://adobe.com/AS3/2006/builtin,org.wvxvws.encoding.base64:Base64,org.wvxvws.encoding.base64:Base64,Object:null getlocal 7 getlocal 4 dup increment_i setlocal 4 dup setlocal 11 getlex com.buraks.utils:fastmem getlocal2 pushbyte 63 bitand callproperty :fastGetByte (1) setproperty private,,private,org.wvxvws.encoding.base64,org.wvxvws.encoding.base64,http://adobe.com/AS3/2006/builtin,org.wvxvws.encoding.base64:Base64,org.wvxvws.encoding.base64:Base64,Object:null kill 11 kill 10 kill 9 kill 8
Код:
L2: label nop getlocal3 dup increment_i setlocal3 OP_0x35 pushbyte 16 lshift setlocal2 getlocal2 nop getlocal3 dup increment_i setlocal3 OP_0x35 pushbyte 8 lshift bitor setlocal2 getlocal2 nop getlocal3 dup increment_i setlocal3 OP_0x35 bitor setlocal2 getlocal 7 getlocal 4 dup increment_i setlocal 4 dup setlocal 8 nop getlocal2 pushbyte 18 urshift OP_0x35 setproperty private,,private,org.wvxvws.encoding.base64,org.wvxvws.encoding.base64,http://adobe.com/AS3/2006/builtin,org.wvxvws.encoding.base64:Base64,org.wvxvws.encoding.base64:Base64,Object:null getlocal 7 getlocal 4 dup increment_i setlocal 4 dup setlocal 9 nop getlocal2 pushbyte 12 urshift pushbyte 63 bitand OP_0x35 setproperty private,,private,org.wvxvws.encoding.base64,org.wvxvws.encoding.base64,http://adobe.com/AS3/2006/builtin,org.wvxvws.encoding.base64:Base64,org.wvxvws.encoding.base64:Base64,Object:null getlocal 7 getlocal 4 dup increment_i setlocal 4 dup setlocal 10 nop getlocal2 pushbyte 6 urshift pushbyte 63 bitand OP_0x35 setproperty private,,private,org.wvxvws.encoding.base64,org.wvxvws.encoding.base64,http://adobe.com/AS3/2006/builtin,org.wvxvws.encoding.base64:Base64,org.wvxvws.encoding.base64:Base64,Object:null getlocal 7 getlocal 4 dup increment_i setlocal 4 dup setlocal 11 nop getlocal2 pushbyte 63 bitand OP_0x35 setproperty private,,private,org.wvxvws.encoding.base64,org.wvxvws.encoding.base64,http://adobe.com/AS3/2006/builtin,org.wvxvws.encoding.base64:Base64,org.wvxvws.encoding.base64:Base64,Object:null kill 11 kill 10 kill 9 kill 8
Всего комментариев 4
Комментарии
28.05.2010 03:10 | |
Интересный момент. Попробовал "соптимизировать" вот так:
package org.wvxvws.encoding.base64 { import flash.utils.ByteArray; import flash.utils.Endian; import com.buraks.utils.fastmem; public class Base64 { /** * ... * @author wvxvw */ public function Base64() { super(); } public static function encode(bytes:ByteArray):String { var chunk:int; var readPosition:int = 64; var witePosition:int; var bytesLength:int = ((bytes.length * 0.3333333333333333) >>> 0) * 3 + 64; var tail:int = bytes.length + 64 - bytesLength; var ret:ByteArray = new ByteArray(); ret.length = ((bytes.length * 0.3333333333333333) >>> 0) * 4; bytes.endian = Endian.LITTLE_ENDIAN; bytes.length += 64; bytes.position = 0; bytes.readBytes(bytes, 64); bytes.position = 0; bytes.writeMultiByte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "us-ascii"); if (bytes.length < 1024) bytes.length = 1024; fastmem.fastSelectMem(bytes); while (readPosition < bytesLength) { chunk = fastmem.fastGetByte(readPosition++) << 16; chunk |= (fastmem.fastGetByte(readPosition++) << 8); chunk |= fastmem.fastGetByte(readPosition++); ret.writeUnsignedInt( (fastmem.fastGetByte(chunk >>> 18) << 24) | (fastmem.fastGetByte((chunk >>> 12) & 0x3F) << 16) | (fastmem.fastGetByte((chunk >>> 6) & 0x3F) << 8) | fastmem.fastGetByte(chunk & 0x3F) ); } switch (tail) { case 1: chunk = fastmem.fastGetByte(readPosition++); ret.writeUnsignedInt( (fastmem.fastGetByte(chunk >>> 2) << 24) | (fastmem.fastGetByte((chunk & 3) << 4) << 16) | 15677 ); break; case 2: chunk = fastmem.fastGetByte(readPosition++) << 8; chunk |= fastmem.fastGetByte(readPosition++); ret.writeUnsignedInt( (fastmem.fastGetByte(chunk >>> 10) << 24) | (fastmem.fastGetByte((chunk >>> 4) & 0x3F) << 16) | (fastmem.fastGetByte((chunk & 15) << 2) << 8) | 61 ); break; } ret.position = 0; return ret.readUTFBytes(ret.length); } } } Ну и раз уж пошло такое дело, решил попробовать в HaXe: /** * ... * @author wvxvw */ package org.wvxvws.encoding; import haxe.io.Bytes; import haxe.Timer; class Base64 { public function new() { } public static function encode(input:Bytes):String { var chunk:Int; var readPosition:Int = 64; var witePosition:Int = 0; var bytes:Bytes = Bytes.alloc(input.length + 64); var bytesLength:Int = Std.int(bytes.length * 0.3333333333333333) * 3 + 64; var tail:Int = bytes.length + 64 - bytesLength; var ret:Bytes = Bytes.alloc(Std.int(bytes.length * 0.3333333333333333) * 4); bytes.blit(0, Bytes.ofString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), 0, 64); bytes.blit(64, input, 0, input.length); while (readPosition < bytesLength) { chunk = bytes.get(readPosition++) << 16; chunk |= (bytes.get(readPosition++) << 8); chunk |= bytes.get(readPosition++); ret.set(witePosition++, bytes.get(chunk >>> 18)); ret.set(witePosition++, bytes.get((chunk >>> 12) & 0x3F)); ret.set(witePosition++, bytes.get((chunk >>> 6) & 0x3F)); ret.set(witePosition++, bytes.get(chunk & 0x3F)); } switch (tail) { case 1: chunk = bytes.get(readPosition++); ret.set(witePosition++, bytes.get(chunk >>> 2)); ret.set(witePosition++, bytes.get((chunk & 3) << 4)); ret.set(witePosition++, 61); ret.set(witePosition++, 61); case 2: chunk = bytes.get(readPosition++) << 8; chunk |= bytes.get(readPosition++); ret.set(witePosition++, bytes.get(chunk >>> 10)); ret.set(witePosition++, bytes.get((chunk >>> 4) & 0x3F)); ret.set(witePosition++, bytes.get((chunk & 15) << 2)); ret.set(witePosition++, 61); } return ret.readString(0, ret.length); } } /** * ... * @author wvxvw */ package tests; import flash.Lib; import flash.text.TextField; import haxe.io.Bytes; import haxe.io.BytesData; import org.wvxvws.encoding.Base64; class TestBase64 { public function new() { } public static function main() { var tf:TextField = new TextField(); tf.width = Lib.current.stage.stageWidth; tf.height = Lib.current.stage.stageHeight; Lib.current.addChild(tf); var bd:BytesData = new BytesData(); bd.writeBytes(new GraylinesImage()); var ba:Bytes = Bytes.ofData(bd); var t:Int = Lib.getTimer(); var s:String = Base64.encode(ba); t = Lib.getTimer() - t; tf.text = "HaXe Bytes encoded: " + s.length + "\ttime spent: " + t; } } import flash.utils.ByteArray; class GraylinesImage extends ByteArray { public function new() { super(); } } Код:
<shx:resources version="9" compress="false" package="tests" xmlns:shx="http://mindless-labs.com/samhaxe" xmlns:bin="http://mindless-labs.com/samhaxe/modules/Binary" xmlns:comp="http://mindless-labs.com/samhaxe/modules/Compose" xmlns:font="http://mindless-labs.com/samhaxe/modules/Font" xmlns:img="http://mindless-labs.com/samhaxe/modules/Image" xmlns:snd="http://mindless-labs.com/samhaxe/modules/Sound" xmlns:swf="http://mindless-labs.com/samhaxe/modules/Swf" > <shx:frame> <bin:binary import="gray-lines.jpg" class="GraylinesImage"/> </shx:frame> </shx:resources> |
|
Обновил(-а) wvxvw 28.05.2010 в 04:37
|
03.06.2010 20:37 | |
03.06.2010 21:19 | |
Пробовал, примерно в 2 раза медленнее.
|
04.06.2010 14:30 | |
аке =) спасибо
|
Последние записи от wvxvw
- Dired - текстовый проводник по файловой системе (29.06.2013)
- Навигация по HTML с WASD (09.06.2012)
- JavaScript, все не так плохо (07.06.2012)
- Что такое tarball и чем его пакуют (11.04.2012)
- Критика Presentation Model (18.02.2012)