PDA

Просмотр полной версии : Оптимизация для скорости в общем


heilong
31.05.2006, 14:29
Предлагаю обсудить техники оптимизации actionscript кода (меня конкретно интересует Flash 8) для скорости. Постоянно вижу обсуждения оптимизации размера файла, куча информации на эту тему, а про скорость не нашёл ничего. Если плохо искал, сорри.

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

В качестве примера - я сейчас активно занялся написанием 3d движка на 8м флэше. Всяких разных фич в большом кол-ве я не хочу, но, в отличии от других движков с миллионом мулек, что я видел, обязательно нужно текстурирование и освещение (не flat как во всех движках что я видел, а Gouraud). Собственно, технический вопрос этого дела я вчера разрешил, откуда и возникло желание эту тему поднять. Дело в том, что функцию, которая за 5 секунд текстурировала и закрашивала всего 6800 треугольников, удалось оптимизировать (алгоритм остался неизменным) до скорости 80000 треугольников в секунду, в процессе я открыл для себя, что, казалось бы, несложная операций Matrix.createGradientBox - очень тормозная, также очень медленно прочитать property MovieClip.transform, а из него - colorTransform и matrix. Подробности в моём посте на эту тему:
http://www.flasher.ru/forum/showthread.php?t=79791

Вот такие вот детали я и предлагаю собрать в список. Какие функции и property тормозные и как это обойти.
Ну и конечно просто технологии оптимизации, свойственные именно flash-у. Всякие loop unrolling и другие общие техники тоже интересно, но уже на 2м плане.

orangeline
31.05.2006, 21:31
сам с такой жёсткой оптимизацией по скорости не сталкивался ввиду отсутствия необходимости таковой, но слышал. - генерируемый as байт-код является избыточным и если из него убрать (утилитой flasm) лишнее то + 20-30% скорости

Bkmz
31.05.2006, 22:14
думаю не стоит подходить ограниченно для флеша. проанализировать ту или иную функцию, цикл, как он работает(хотя бы навскидку). думаю некоторые выгодные замены будут бросаться в глаза(не будете же вы парсировать строку в архив по запятым регулярными выражениями+)))...

heilong
01.06.2006, 11:39
просто об оптимизации в общем есть много ресурсов и информации, а конкретно как лучше делать во флэше я нигде не нашёл.
или какие функции и property во флэше медленные и как это обойти.
flasm надо бы попробовать

iNils
01.06.2006, 12:01
первое что в голову пришло
/*
*
* Пример : используемые внешние переменные внутри функции лучше передевать в качестве аргументов
*
*/
v = 5;
////////////////////////////////////
function test1 () {
var u = v;
}
function test2 (v) {
var u = v;
}
////////////////////////////////////
t1 = getTimer ();
for (var i = 0; i < 100000; i++) {
test1 ();
}
t2 = getTimer ();
trace (t2 - t1);
////////////////////////////////////
t1 = getTimer ();
for (var i = 0; i < 100000; i++) {
test2 (v);
}
t2 = getTimer ();
trace (t2 - t1);

KPaul
01.06.2006, 12:25
Также можно пособирать в инете быстрые ф-ции и использовать их вместо дефолтных. Например следующая ф-ция выполняется более чем на 50% быстрее чем встроенная Array.reverse();
function reverse(a:Array){
var l = 0;
var r = a.length-1;
var t;
while(l<r){
t = a[l];
a[l] = a[r];
a[r] = t;
++l;
--r;
}
}
Естественно длинна цепочки разрешения переменных(областей видимости), как сказал iNils может сильно влиять на производительность.
На самом деле очень много нюансов, начинаю от стиля написания кода и заканчивая течническими деталями(best practice).
Попробуй почитать тут, может чем-то поможет:
http://www.adobe.com/devnet/flash/articles/flash8_bestpractices.html
http://www.adobe.com/devnet/flash/articles/as_bestpractices.html

vooparker
01.06.2006, 12:28
Прошу прощения, что не в тему. Но.

iNils можешь объяснить одну вещь, исходя из примера test1 работает медленнее поскольку начинает искать по цепочке областей видимости значение v (если я правильно понимаю). Так вот после первого TestMovie в OutPut у меня вывалилось 1064 и 868 соответственно (что вполне логично). НО! Второй TestMovie мне выдал примерно одинаковый результат - 856 и 860, а третий - 823 и 852.

Собственно вопрос почему?
Сразу прошу прощения, если ответ на вопрос очевиден, но все же хотелось бы его увидеть.

Скрипун
01.06.2006, 12:28
Мы тут как-то обсуждалди что С++ в десятки (сам посчитал) считает sin в цикле... вот... Я сделал так:
Вставил флэш во С++ и там считал это синус, а результат только передавал флэшу... и все довольные... (флэш, С, я ....)

heilong
01.06.2006, 12:49
iNils, у меня твой тест выдаёт
1553
1534
разница, пожалуй, несущественна

KPaul, в этом reverse видимо алгорит лучше, выбор лучшего алгоритма естественно нужно проводить сначала, до всяких оптимизаций, и в данную тему я думаю не входит. А ссылки интересные, читаю...

Скрипун, как это вставил флэш в C++?

iNils
01.06.2006, 12:50
Мой первый пример оказался очень не удачным :)
Этот лучше
/*
*
* Пример : используемые внешние переменные внутри функции лучше передевать в качестве аргументов
*
*/
v = 5;
////////////////////////////////////
test1 = function () {
var t1 = getTimer ();
for (var i = 0; i < 100000; i++) {
var u = v;
}
var t2 = getTimer ();
trace ((t2 - t1) + " " + u);
};
test2 = function (v) {
var t1 = getTimer ();
for (var i = 0; i < 100000; i++) {
var u = v;
}
var t2 = getTimer ();
trace ((t2 - t1) + " " + u);
};
////////////////////////////////////
test1 ();
test2 (v);

orangeline
01.06.2006, 13:09
если говорить о технике программирования на as слышал что конструкция
with object {
...
}
(особенно если много обращений к св-вам и методам object'а) сильно замедляет алгоритм.
for-in так же работает медленнее чем for
вообще мне кажется что много-мало сложные функции лучще не полениться, написать самому, нежели исп. встроенные - они медленнее
пример был выше про Array.reverse()

JhAZZ
05.06.2006, 08:14
Вот что я вынес из своей работы со флэшем
1. Функции надо вызывать как можно реже. Вобщем, как в ассемблере. Лучше 50 строчек кода накопировать, чем сделать цикл от 1 до 50

2. Обращение к хэшу локальных переменных быстрее чем к глобальным и уж тем более выше, если используется поиск в подхэшах. Потому при передаче данных через аргумент функции (как в примере вверху) все быстрее происходит. Хэш-то получается из одной переменной состоит. Вобщем локальные переменные адресуются быстрее.

3. Лучше создавать промежуточные переменные для хранения адресов на хэш. То есть обращение типа
xxx.tr.mx.v+=xxx.tr.mx.dv

лучше привести к следующему:
var mx:Object=xxx.tr.mx;
mx.v+=mx.dv;

тем самым мы избавляемся от двух хэш-поисков. Конечно во флэше все супермегаоптимизировано, но когда речь идет о перелопачивании огромных массивов каждое бегание по индексам хэшей вызывает тормоза.

4. От длины имен переменных или функций скорость почти не зависит. Это просто best practice. Все равно все "имена" индексируются и к ним обращаются не по имени, а по цифрам индексов хэшей.

5. for in работает тормозно
6. Array.length тормозной, так что лучше сначала узнать его длину в переменную перед началом цикла
7. Жалеть память броузера зрителя и делать delete неиспользуемых объектов не нужно - все равно никто не оценит. Поэтому например если надо очистить Array - проще взять и переприсвоить ему new Array();
8. with притормаживает, потому что бегает по with-хэшу, затем по localvar-хэшу, затем по this-хэшу . Одним беганием больше. А ведь в this и with сидят ключи не только переменных, но и функций.

Мои выводы зиждятся на собственных наблюдениях и курсах программирования, где мы делали элементарные бинарные индексы

heilong
05.06.2006, 10:51
1. про фунцкии верно, а unroll-нуть цикл в 50 строчек это уж совсем last resort для самого inner loop-а

4. мне казалось, best practice это разумный компромисс между длиной имён и их осмысленностью. в институте нас учили "переменные должны иметь мнемонические названия"

7. мне кажется, это неважно, т.к. в любом случае или сам их удалишь, или рано или поздно garbage collector их удалит

for in и with почти не использую. с with-ом вообще стрёмно, его разве что для Drawing API можно использовать, хотя мне сделать var p = my_movie_clip; p.beginFill(... не влом.

JhAZZ: вообще, дельные советы!

Скрипун
05.06.2006, 13:50
Кто то тут говорил что своя реверсия массива быстрее работает... [censored]ЧистоЙ ВОДЫ!!! Я целый час извращался... в раза медленее!

А вот недавно узнал что Math.random тоже в 2-3 раза медленее работает чем random. Вот как...

Nirth
05.06.2006, 14:07
Удалил лишние знаки препинания и плохие слова, Скрипун
1) Веди себя культурно,мы в обществе
2) Нервные клетки не востанавливаются

Бармалей
05.06.2006, 18:01
Стандартный прием - если порядок обращения к элементам массива не важен, то лучше воспользоваться циклом while с обратной итерацией в условии:
var i = my_array.lendth;
for(i--){
// здесь действия над элементом массива my_array[i]
}

KPaul
05.06.2006, 19:01
to Скрипун
Если этот "кто-то" - я, то многое может зависеть от машины и версии плеера. (Возможно если машина довольно быстрая, то разница будет минимальная). У меня целик 1800, плеер 8,0,22,0.
Следующий код (в руте) давал довольно разные по значениям листинги:
var arr = [];
for(var i=0; i<200000; i++){
arr[i] = 1;
}
var c=0;
this.onEnterFrame = function(){
if(c>=9){
delete this.onEnterFrame;
}
c++;
var time1 = new Date().getTime();
arr.reverse();
//reverse(arr);
var time2 = new Date().getTime();
var result = time2-time1;
trace(result);

}

function reverse(a:Array){
var l = 0;
var r = a.length-1;
var t;
while(l<r){
t = a[l];
a[l] = a[r];
a[r] = t;
++l;
--r;
}
}
2634 3008 2977 3008 2992 3008 2961 2945 3024 3008
и соответственно 359 374 359 374 374 358 358 375 374 374
PS Ругаться действительно не хорошо... :)

iNils
05.06.2006, 19:20
P4 3000 (HT)

родной: 1107, 1217, 1170, 1186, 1372, 1310, 1201, 1217, 1201, 1201

кустарный: 265, 249, 265, 266, 249, 265, 250, 249, 250, 265

__i
05.06.2006, 21:05
Вот что я вынес из своей работы со флэшем
1. Функции надо вызывать как можно реже. Вобщем, как в ассемблере. Лучше 50 строчек кода накопировать, чем сделать цикл от 1 до 50

это логично само по себе, во время цикла у тебя выполняеться "лишние" операции (увеличили счетчик, произвели сравнение, переместили "указатель" выполнямого кода)

5. for in работает тормозно

Естественно, также если задать в качестве индекса у массива не целые числа....


6. Array.length тормозной, так что лучше сначала узнать его длину в переменную перед началом цикла

Array.length не тормозной, он нормальный, каким и должен быть, тормозит это потом что на каждом шаге цикла ты вызываешь эту пропертю(функцию), естественно время тратиться больше.


8. with притормаживает, потому что бегает по with-хэшу, затем по localvar-хэшу, затем по this-хэшу . Одним беганием больше. А ведь в this и with сидят ключи не только переменных, но и функций.



with - это вообще ужасная практика программирования!!!.

MrKIT
23.08.2006, 08:31
Народ коли тут все за убыстренее посмотрите этот код скажите что тут заменить чтоб меньше тормозило...

MrKIT
23.08.2006, 08:31
заранее спасибо