Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Заблуждения в оптимизации (http://www.flasher.ru/forum/showthread.php?t=212488)

caseyryan 24.02.2016 11:14

Заблуждения в оптимизации
 
Создал эту тему просто, чтобы поделиться опытом своих заблуждений)

Несколько раз читал разные блоги и сайты по оптимизации приложений, и последний раз читал статью Дэниэла по оптимизации кода в старлинге.
Сам код для потимизации stage3d оставлю, меня заинтересовало то, что он рекомендовал избегать использования for each циклов, и заменять их на for var i:int ...
Но мои замеры показали, что разница в скорости между этими циклами составляет почти 3 раза! Причем совсем не в пользу вторых.

Тест содержит ошибку, ответ здесь
Вот мой тест на 10 миллионах объектов
Код AS3:

// создаем 10 миллионов объектов с одним свойством
var array:Array = []
for (var i:int = 0; i < 10000000; i++) {
        array.push( { t: 1 } );
}
 
var length:int = array.length;
var obj:Object = null;
var time:int = getTimer();
for (i = 0; i < length; i++) {
        obj = array[i];
        obj.t = 0;
}
trace("FOR i", getTimer() - time); // 1554
time = getTimer();
for each (obj in array) {
        obj.t = 0;
}
trace("FOR EACH", getTimer() - time); // 671

Но если тут я сам и ожидал примерно такого результата, то вот хорошей скорости работы от Math методов точно не ожидал. А оказалось, что они лишь немного проигрывают в скорости инлайнам. И ощутимо это только на огромном количестве итераций.
Вот еще пример
Код AS3:

public function MathCrap() {
 
 
        var number:Number = -14;
        var i:int = 0;
        var result:Number = 0;
        var time:int = 0;
 
        time = getTimer();
        for (i = 0; i < 10000000; i++) {
                result = Math.abs(number);
        }
        trace("Math.abs()", getTimer() - time);
        time = getTimer();
        for (i = 0; i < 10000000; i++) {
                result = abs(number);
        }
        trace("Inline abs", getTimer() - time);
        trace("CEIL >>>");
        number = 1.5;
        time = getTimer();
        for (i = 0; i < 10000000; i++) {
                result = Math.ceil(number);
        }
        trace("Math.ceil()", getTimer() - time);
        time = getTimer();
        for (i = 0; i < 10000000; i++) {
                result = ceil(number);
        }
        trace("Inline ceil", getTimer() - time);
 
}
[Inline]
public static function abs(value:Number):Number {
        return value > 0 ? value : -value;
}
[Inline]
public static function ceil(value:Number):int {
        return int(value) + 1;
}

Результат такой:
Код AS3:

Math.abs() 1328
Inline abs 1139
CEIL >>>
Math.ceil() 1348
Inline ceil 1139

То есть совсем незначительная разница, хотя я расчитывал увидеть цифры раза в 2, а то и в 3 различающиеся. Видимо Адоби хорошо поработали над оптимизацией кода в ASC 2.0

Korchy 24.02.2016 11:27

Цитата:

Сообщение от caseyryan (Сообщение 1192112)
он рекомендовал избегать использования for each циклов, и заменять их на for var i:int ...

Обычно each-циклы не рекомендуют использовать из-за того, что не гарантируется порядок обхода. А по скорости ни разу не встречал таких рекомендаций.

i.o. 24.02.2016 11:30

Результаты в DEBUG и RELEASE версиях плеера могут сильно отличаться. Судя по трейсам использовался именно дебажный вариант

Tails 24.02.2016 11:39

Да, и ещё версию тестов с старым компилятором бы.

caseyryan 24.02.2016 11:41

Цитата:

Обычно each-циклы не рекомендуют использовать из-за того, что не гарантируется порядок обхода. А по скорости ни разу не встречал таких рекомендаций.
Да. Но он там говорил именно о скорости работы, поэтому меня это и заинтересовало. Так как я всегда был уверен что for in и for each in гораздо быстрее упорядоченных циклов
Вот цитата Дэниэла
Цитата:

Loops

When working with loops that are repeated very often or are deeply nested, it's better to avoid “for each”; the classic “for i” yields a better performance. Furthermore, beware that the loop condition is executed once per loop, so it's faster to save it into an extra variable.
Цитата:

Сообщение от i.o. (Сообщение 1192115)
Результаты в DEBUG и RELEASE версиях плеера могут сильно отличаться. Судя по трейсам использовался именно дебажный вариант

Блин, а ведь верно. Я даже не подумал) Туплю.
Сделал релизный тест, и мои изначальные ожидания оправдались с лихвой.
Вот для релиза:

Код AS3:

public function MathCrap() {
 
        var tf:TextField = new TextField();
        tf.width = 800;
        tf.height = 600;
        addChild(tf);
 
        var number:Number = -14;
        var i:int = 0;
        var result:Number = 0;
        var time:int = 0;
 
        time = getTimer();
        for (i = 0; i < 10000000; i++) {
                result = Math.abs(number);
        }
        tf.appendText("Math.abs() " + (getTimer() - time) + "\n");
        time = getTimer();
        for (i = 0; i < 10000000; i++) {
                result = abs(number);
        }
        tf.appendText("Inline abs " + (getTimer() - time) + "\n");
        tf.appendText("CEIL >>>");
        number = 1.5;
        time = getTimer();
        for (i = 0; i < 10000000; i++) {
                result = Math.ceil(number);
        }
        tf.appendText("Math.ceil() " + (getTimer() - time) + "\n");
        time = getTimer();
        for (i = 0; i < 10000000; i++) {
                result = ceil(number);
        }
        tf.appendText("Inline ceil " + (getTimer() - time) + "\n");
 
}
[Inline]
public static function abs(value:Number):Number {
        return value > 0 ? value : -value;
}
[Inline]
public static function ceil(value:Number):int {
        return int(value) + 1;
}

Код AS3:

Math.abs() 528
Inline abs 85
CEIL >>>Math.ceil() 549
Inline ceil 55

То то же :D

Никогда не думал, что придется настолько заморачиваться с оптимизацией приложений)

Tails 24.02.2016 11:49

Цитата:

Math.abs() 528
Inline abs 85
Да ну нафиг, в 6 раз что ли разница? :)
А вот с ceil при приведений Number к int мы можем потерять информацию, если число будет за диапазоном int. Мы так-же потеряем Infinity и NaN в обоих случаях.

И ещё, неужели весь остальной код в игре уже так идеально оптимизирован, что пришлось взяться за нативные реализаций?

caseyryan 24.02.2016 11:56

Цитата:

А вот с ceil при приведений Number к int мы можем потерять информацию, если число будет за диапазоном int. Мы так-же потеряем Infinity и NaN в обоих случаях.
Да, ты прав, надо как-то bitwise видимо задействовать.

Цитата:

И ещё, неужели весь остальной код в игре уже так идеально оптимизирован, что пришлось взяться за нативные реализаций?
Видимо да. Оптимизирую те места, где скаут показывает наибольшие потери в производительности. Уже давно оптимизирую все что только можно. И больше всего погряз в Dragon Bones. Там огромные просторы для оптимизации :D Made in China говорит само за себя)

Tails 24.02.2016 12:00

Если получиться ускорить ceil, round с поддержкой Number, ты обязательно напиши.

Цитата:

Made in China
Да там ребята вообще огонь! :)

Ещё вот о чём я думал, так как класс Math. нативный, он может быть по разному реализован на разных архитектурах процессоров. Где-то быстрее, где то медленнее. В то время как собственная, кастомная реализация везде будет одинаковой по скорости. Я к тому, что было бы здорово, после написания теста, прогнать его на разных устройствах, в том числе web player конечно! )

undefined 24.02.2016 12:19

Цитата:

Сделал релизный тест, и мои изначальные ожидания оправдались с лихвой.
Так а что для циклов в релизе?

i.o. 24.02.2016 14:43

Вычисление целой и дробной части не на интах будет примерно таким
Код AS3:

var n:Number = 100000 * (0.5 - Math.random());
 
var frac:Number = n % 1;
var full:Number = n - frac;

Для round() floor() и ceil() можно допереть)


Часовой пояс GMT +4, время: 17:34.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.