Шукати в цьому блозі

Профілювання ефективності коду (Profiling)

Gideros поставляється з вбудованим lua. Профілювальником

Для тих, хто не знає, що є Профілювальник коду, він є інструментом, який вимірює ефективність коду та виводить статистику про використання ЦП: кількість викликів кожної функції, скільки часу потрібно для виконання, і звідки вона була викликана. 

Gideros надає два засоби, що дозволяють профілювати:

  • Запустивши сеанс профілювання безпосередньо через пункт меню Player\Profile або піктограму панелі інструментів з Gideros Studio
  • За допомогою виклику Core.profiler * API від lua
У першому випадку Gideros Studio покаже результати профілювання, коли кнопка Player\Stop натиснута на панелі інструментів Gideros Studio. В останньому випадку вам належить самостійно обробляти збір та відображення даних профілювання.

     Зверніть увагу, що навіть якщо ви почали профілювати через Gideros Studio, ви все ще можете використовувати Core.profilier * API у вашому коді. API профілювання Gideros доступний з lua:

Core.profilerStart() --інструктує gideros розпочати збір даних профілювання Core.profilerStop() -- призупиняють збір Core.profilerReset() --очищає зібрані дані Core.profilerReport() --повертає таблицю, що містить зібрані дані профілювання

Як нам може допомогти профілювання?

 припустимо, що ви використовуєте наступний код:

local function myFunction(a)
 local function c(a) return math.cos(a*math.pi/180) end
 return c(a)+c(a+1)
end
Це  не оптимізовано(навмисно) і є повільним, але як ми можемо виміряти це?


Виконати цей  код 100000 разів:

for i=1,100000 do myFunction(i) end
І запустити профілювання:
ми отримаємо таку таблицю:
Блок\Час  обробки\ % \ кількість повторів Функція \ Розташування

# Time Ratio Count Function                   Location
[1] 423         0%         1         callFile                   =[C] 00421900(callFile)
        423         100% 1         Unknown                   @main.lua:0:033FAC64

        423          100% 1         callFile                    =[C] 00421900(callFile)
[2] 423          4%         1         Unknown                    @main.lua:0:033FAC64
        405          96% 100000 myFunction            @main.lua:26:033FD87C

        405          100% 100000 Unknown                     @main.lua:0:033FAC64
[3] 405          35% 100000 myFunction             @main.lua:26:033FD87C
        265          65% 200000 c                             @main.lua:27:033FC328

        265         100% 200000 myFunction              @main.lua:26:033FD87C
[4] 265          60% 200000 c                              @main.lua:27:033FC328
        107          40% 200000 cos                               =[C] 6E416FE0(cos)

        107          100% 200000 c                               @main.lua:27:033FC328
[5] 107          100% 200000 cos                                =[C] 6E416FE0(cos)

[6] 2          100% 313         gideros_enterFrame =[C] 00423050(gideros_enterFrame)


[7] 0          100% 1         broadcastEvent         =[C] 00423340(broadcastEvent)



     Це список всіх функцій, керованих кодом, сортованим за завантаженням процесора (найвищий спочатку). Перший фрагмент - це функція callFile. Це внутрішня функція Gideros, яка завантажує кожен файл lua. У нашому випадку його використовували для запуску main.lua, що відповідає блоку [2]. Але звернемо увагу на нашу функцію myFunction, ми бачимо, що вона показанав блоці [3]:

# Time Ratio Count Function        Location
        405        100% 100000 Unknown         @main.lua:0:033FAC64
[3] 405         35%         100000 myFunction @main.lua:26:033FD87C

        265         65%         200000 c                 @main.lua:27:033FC328

 Таким чином, функція myFunction займала, як і очікувалося, більшу частину часу обробки. Цифри вказують, що її визивали 100000 разів і споживали 405мс на ЦП. Ми також дізнаємося, що його викликали з неназваної функції "Unknown", розташованої за адресою main.lua: 0, яка є кодом верхнього луа файлу main.lua, і що весь час (100%), що витрачається в myFunction, було викликано тим, що його викликали main .lua. Більш цікавим є те, що 65% часу (265 мс) було витрачено на виклики функції c, розташованої на main.lua: 27, і що c було викликано 200000 разів, двічі на виклик.


     Наступний блок [4]- це функція c: 40% часу c було витрачено на math.cos (), а 60% на функцію . 
Тепер, ми знаємо виклик функції є задорогим, і що c функція потрібно оптимізувати. Змінимо код:

 local function myFunction(a)
 return math.cos(a*math.pi/180)+math.cos((a+1)*math.pi/180)
end
Тепер звіт  профілювання виглядає так: (скорочено)

# Time Ratio Count Function         Location
        65         100% 100000 Unknown  @main.lua:0:033FC4FC
[3] 65          73% 100000 myFunction @main.lua:26:033FB670
        17          27% 200000 cos                 =[C] 6E416FE0(cos)

        17         100% 200000 myFunction @main.lua:26:033FB670

[4] 17         100% 200000 cos                 =[C] 6E416FE0(cos)


myfunction вже швидша: 65ms зараз де ми мали 405ms раніше. але ми ще двічі визиваємо і math.cos. Зробимо його (і math.pi) локальними.


 local function myFunction(a)
 local cos=math.cos
 local pi=math.pi
 return cos(a*pi/180)+cos((a+1)*pi/180)
end
 та звіт профілера:
# Time Ratio Count Function         Location
        60         100% 100000 Unknown         @main.lua:0:033FAC64
[3] 60         71%         100000 myFunction @main.lua:26:033FD1E8

        17         29%         200000 cos                 =[C] 6E416FE0(cos)

Ми врятували час у myFunction, тоді як cos () має той же час. 

Що робити?, ми використаємо новий gideros deg  to rad оператор  замість math.pi/180 константи.

local function myFunction(a)
 local cos=math.cos
 return cos(^<a></a>
end
та звіт профілера:
# Time Ratio Count Function        Location
         57        100% 100000 Unknown         @main.lua:0:033FC4FC
[3]  57         69%         100000 myFunction @main.lua:26:033FB9DC

         17         31%         200000 cos                 =[C] 6E416FE0(cos)

Ми врятували ще кілька дорогоцінних мілісекунд!


Як ви можете бачити, профілер є корисним інструментом для виявлення вузьких місць для процесора у вашому додатку, а  кілька незначних змін у коді : 

  • уникнути доступу до таблиці, 
  • уникати викликів функцій,
  •  уникати дублювання обчислень.

можуть зробити великі відмінності




2 коментарі: