Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.
Показано с 1 по 8 из 8
  1. #1
    Аватар для Daniel_Cortez
    "Это не хак, это фича"

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    2,192
    Репутация:
    2589 ±

    Сравнение производительности кода на Pawn (профилирование)

    Привет всем участникам Pro-Pawn.
    В данном уроке я объясню вам, как сравнивать производительность разных вариантов кода. Сделано это будет с помощью написанного мной профайлера.

    Примеры вопросов, на которые можно найти ответ с помощью профилирования:
    • Работает ли функция strcat быстрее, чем format, и если да, то в каких случаях?
    • Как лучше проверять подключение игрока: с помощью IsPlayerConnected или добавлением в итератор (foreach.inc) и использованием функции Itter_Contains ?



    Код профайлера:
    PHP код:
    // Profiler v1.3 (copyright (c) 2014-2017 Daniel_Cortez)  \\ Pro-Pawn.ru
    // Условия использования данного кода: http://pro-pawn.ru/showthread.php?12585


    /*======== Настройки =========================================================*/
    // Кол-во итераций в циклах.
    const PROFILER_ITERATIONS_MAJOR 10_000;
    const 
    PROFILER_ITERATIONS_MINOR 1_000;

    // Названия отрывков кода.
    new const code_snippets_names[2][] =
    {
        {
    "отрывок 1"},
        {
    "отрывок 2"}
    };

    // Здесь вы можете объявить переменные, используемые в профилируемых отрывках кода
    // и выполнить некоторые действия непосредственно перед профилированием.
    #define Prerequisites();\
        // <ваш код>

    /*
        Собственно, сами отрывки кода, которые нужно тестировать.
        Если код состоит из нескольких строк, переносите их обратным слэшем.
        Пример:
        #define CodeSnippet1();\
            DoSomething();\
            DoSomethingElse();
    */
    #define CodeSnippet0();\
        // <ваш код>

    #define CodeSnippet1();\
        // <ваш код>
    /*======== Конец настроек ===================================================*/



    // Не рекомендую изменять следующий код, если вы в нём не разбираетесь.
    #tryinclude <a_samp>
    #if defined _samp_included
        #define LINE_BREAK ""
    #else
        #define LINE_BREAK "\n"
        #include <core>
        #include <time>
        #define GetTickCount() tickcount()
    #endif

    #define _PROFILE_START(%0)\
        
    __t[%0] = GetTickCount();\
        for (
    __j 0__j PROFILER_ITERATIONS_MINOR; ++__j)\
        {
    #define _PROFILE_END(%0)        __t[%0] = GetTickCount()-__t[%0]

    #if defined _samp_included
        #define PROFILE_START(%0);    _PROFILE_START(%0)
        #define PROFILE_END(%0);\
            
    }\
            
    _PROFILE_END(%0);
    #else
        #define PROFILE_START(%0);    _PROFILE_START(%0)
        #define PROFILE_END(%0);\
            
    }\
            if ((
    _PROFILE_END(%0)) < 0) {--__i; continue;}
    #endif

    #define CODE_SNIPPET_EXISTS(%0)\
        
    (sizeof(code_snippets_names) >= ((%0) + 1)) && (defined CodeSnippet%0)


    new 
    code_snippets_time[sizeof(code_snippets_names)] = {0, ...};

    main()
    {
        new 
    __i__j__t[sizeof(code_snippets_names)];
        
    #emit    zero.pri
        #emit    lctrl        7
        #emit    stor.s.pri    __i
    #if CODE_SNIPPET_EXISTS(2)
        
    static const ending[] =
        
    #if (sizeof(code_snippets_names) <= 4)
            
    "ка";
        
    #else
            
    "ков";
        
    #endif
        
    printf(
            
    "Тестирование: %d отрыв%s кода." LINE_BREAK,
            
    sizeof(code_snippets_names), ending
        
    );
    #else
        
    printf(
            
    "Тестирование: <%s> vs <%s>" LINE_BREAK,
            
    code_snippets_names[0], code_snippets_names[1]
        );
    #endif
        
    static const JIT_status_strings[2][] =
            {
    "интерпретируемый""с JIT-компиляцией"};
        
    printf(
            
    "Режим: %s, %dx%d итераций.\a" LINE_BREAK,
            
    JIT_status_strings[__i],
            
    PROFILER_ITERATIONS_MAJORPROFILER_ITERATIONS_MINOR
        
    );
        
    Prerequisites();
        for (
    __i 0__i PROFILER_ITERATIONS_MAJOR; ++__i)
        {
            
    PROFILE_START(0);
            
    CodeSnippet0();
            
    PROFILE_END(0);
            
    PROFILE_START(1);
            
    CodeSnippet1();
            
    PROFILE_END(1);
    #if CODE_SNIPPET_EXISTS(2)
            
    PROFILE_START(2);
            
    CodeSnippet2();
            
    PROFILE_END(2);
    #endif
    #if CODE_SNIPPET_EXISTS(3)
            
    PROFILE_START(3);
            
    CodeSnippet3();
            
    PROFILE_END(3);
    #endif
    #if CODE_SNIPPET_EXISTS(4)
            
    PROFILE_START(4);
            
    CodeSnippet4();
            
    PROFILE_END(4);
    #endif
    #if CODE_SNIPPET_EXISTS(5)
            
    PROFILE_START(5);
            
    CodeSnippet5();
            
    PROFILE_END(5);
    #endif
    #if CODE_SNIPPET_EXISTS(6)
            
    PROFILE_START(6);
            
    CodeSnippet6();
            
    PROFILE_END(6);
    #endif
    #if CODE_SNIPPET_EXISTS(7)
            
    PROFILE_START(7);
            
    CodeSnippet7();
            
    PROFILE_END(7);
    #endif
    #if CODE_SNIPPET_EXISTS(8)
            
    PROFILE_START(8);
            
    CodeSnippet8();
            
    PROFILE_END(8);
    #endif
    #if CODE_SNIPPET_EXISTS(9)
            
    PROFILE_START(9);
            
    CodeSnippet9();
            
    PROFILE_END(9);
    #endif
    #if CODE_SNIPPET_EXISTS(10)
            
    PROFILE_START(10);
            
    CodeSnippet10();
            
    PROFILE_END(10);
    #endif
    #if CODE_SNIPPET_EXISTS(11)
            
    PROFILE_START(11);
            
    CodeSnippet11();
            
    PROFILE_END(11);
    #endif
    #if CODE_SNIPPET_EXISTS(12)
            
    PROFILE_START(12);
            
    CodeSnippet12();
            
    PROFILE_END(12);
    #endif
    #if CODE_SNIPPET_EXISTS(13)
            
    PROFILE_START(13);
            
    CodeSnippet13();
            
    PROFILE_END(13);
    #endif
    #if CODE_SNIPPET_EXISTS(14)
            
    PROFILE_START(14);
            
    CodeSnippet14();
            
    PROFILE_END(14);
    #endif
    #if CODE_SNIPPET_EXISTS(15)
            
    PROFILE_START(15);
            
    CodeSnippet15();
            
    PROFILE_END(15);
    #endif
            
    for (__j 0__j sizeof(code_snippets_names); ++__j)
                
    code_snippets_time[__j] += __t[__j];
        }
        for (
    __i 0__i sizeof(code_snippets_names); ++__i)
            
    printf(
                
    "%s: %d" LINE_BREAK,
                
    code_snippets_names[__i], code_snippets_time[__i]
            );
        
    printf("\a\a" LINE_BREAK);


    Условия использования:

      Открыть/закрыть
    1. Вам предоставляется право на копирование данного ПО, изменение и распространение и другие виды использования при соблюдении условий данной лицензии.
    2. Данное ПО предоставляется "как есть", без каких-либо гарантий (как явно выраженных, так и подразумеваемых).
      Автор ПО не несёт никакой ответственности за ущерб, причинённый в результате использования данного ПО и/или каких-либо других действий с ним.
    3. В данном ПО и во всех производных от него работах заявление об авторстве и ссылка на страницу с данной лицензией должны оставаться в неизменном виде (т.е. как в оригинале). Также, если это производная работа, она должна быть явным образом помечена как изменённая версия и не выдаваться за оригинал.
    4. Вы можете копировать, распространять и публиковать настройки профайлера отдельно - в этом случае указание авторства и ссылки на данную страницу не требуется.


    А теперь более простым языком*:
    1. Не выдавайте данный код за свой.
    2. Строки с упоминанием об авторстве и ссылкой на эту страницу должны оставаться в коде, в неизменном виде.
    3. Вы можете изменять код, если соблюдаются остальные условия использования (например, можете удалить все комментарии, кроме копирайта и ссылки на эту страницу).
    4. Если вы публикуете изменённую версию профайлера, обязательно указывайте, что это изменённая версия, а не оригинал.
    5. Настройки профайлера не попадают под эти условия, можете делать с ними всё, что захотите.

    *Приведённое выше упрощённое содержание не является полной лицензией.


    Настройка и использование:

    Для начала разберём назначение каждой настраиваемой константы:
    • Количество итераций цикла профилирования.
      PROFILER_ITERATIONS_MINOR - кол-во итераций перед измерением времени выполнения.
      PROFILER_ITERATIONS_MAJOR - кол-во измерений времени.
      Весь процесс профилирования сделан с помощью вложенных циклов. Таким образом уменьшаются погрешности от многократных вызовов GetTickCount.
      Также сглаживаются погрешности из-за разной нагрузки на ЦП в разные моменты времени. Например, во время профилирования может включиться запланированная по расписанию проверка антивирусом - это намного меньше повлияет на результаты профилирования в случае с вложенными циклами.
    • Названия отрывков кода.
      Для этой цели предназначен массив строк code_snippets_names.
    • Отрывки кода.
      Для указания сравниваемых отрывков кода предназначены макросы "CodeSnippet0();", "CodeSnippet1();", ... "CodeSnippet15();".
      Также для подготовительных действий (объявление и инициализация переменных, etc.) есть макрос Prerequisites.

    Рассмотрим использование профайлера на примере измерения производительности функций format и strcat для конкатенации строк:
    PHP код:
    /*======== Настройки =========================================================*/
    const PROFILER_ITERATIONS_MAJOR 10_000;
    const 
    PROFILER_ITERATIONS_MINOR 1_000;

    new const 
    code_snippets_names[2][] =
    {
        {
    "format"},
        {
    "strcat"}
    };

    #define Prerequisites();\
        
    static const str1[] = "1234567890123456789012345678901234567890";\
        static const 
    str2[] = "1234567890123456789012345678901234567890";\
        new 
    buffer[128];

    #define CodeSnippet0();\
        
    format(buffersizeof(buffer), "%s%s"str1str2);

    #define CodeSnippet1();\
        
    buffer str1strcat(bufferstr2);
    /*======== Конец настроек ====================================================*/ 


    Автор статьи: Daniel_Cortez
    Специально для Pro-Pawn.ru
    Копирование данной статьи на других ресурсах без разрешения автора запрещено!
    Последний раз редактировалось Daniel_Cortez; 03.05.2017 в 18:32. Причина: v1.3
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  2. 13 пользователя(ей) сказали cпасибо:
    $continue$ (16.08.2015) Alanchick (17.01.2016) Camelot (18.08.2015) DCPSHER (01.06.2018) Desulaid (16.08.2015) franked (19.02.2016) Hidden (17.08.2015) Osetin (16.08.2015) Redsan (09.10.2016) Sp1ke (18.08.2015) wAx (16.08.2015) [ForD] (09.10.2015) ^_^ (16.08.2015)
  3. #2
    Аватар для Desulaid
    лесоруб продакшен

    Статус
    Оффлайн
    Регистрация
    15.03.2015
    Адрес
    Slobodskoy
    Сообщений
    667
    Репутация:
    236 ±
    Все равно скопипастят

  4. Пользователь сказал cпасибо:
    $continue$ (16.08.2015)
  5. #3
    Аватар для Daniel_Cortez
    "Это не хак, это фича"

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    2,192
    Репутация:
    2589 ±
    Обновил код профайлера, теперь он должен работать не только на сервере SA:MP, но и под управлением оригинального интерпретатора Pawn.
    В алгоритм измерения скорости пришлось добавить обход проблемы, при которой функция tickcount почему-то возвращает неправильные значения.
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  6. #4
    Аватар для Daniel_Cortez
    "Это не хак, это фича"

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    2,192
    Репутация:
    2589 ±
    Ещё одно обновление. Теперь можно профилировать от 2 до 16 отрывков кода, не внося изменений в код самого профайлера.
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  7. #5
    Аватар для Daniel_Cortez
    "Это не хак, это фича"

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    2,192
    Репутация:
    2589 ±
    Добавил к переменным в коде профилирования префикс "__". Теперь в макросах Prerequisites и CodeSnippet* можно объявлять и использовать переменные с именами "i", "j" и "t" без конфликта имён.
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  8. #6
    Аватар для DCPSHER
    Пользователь

    Статус
    Оффлайн
    Регистрация
    14.05.2018
    Сообщений
    16
    Репутация:
    2 ±
    Есть пара вопросов:
    Правильно ли я понимаю, что профайлер нужно использовать как отдельный filterscript или gamemode? Т.к. в нем есть main() и его нельзя использовать как простой include, если в моде уже есть main()
    Как можно запустить профилирование отложенно? Например как указано в статье "Как лучше проверять подключение игрока: с помощью IsPlayerConnected или добавлением в итератор (foreach.inc) и использованием функции Itter_Contains ?". Конкретно я хочу потестировать функции вычисления расстояний между игроками и т.п., но мне нужно их включать, когда игроки уже на сервере, а не при его старте.
    Последний раз редактировалось DCPSHER; 03.06.2018 в 19:04.

  9. #7
    Аватар для Daniel_Cortez
    "Это не хак, это фича"

    Статус
    Оффлайн
    Регистрация
    06.04.2013
    Адрес
    Novokuznetsk, Russia
    Сообщений
    2,192
    Репутация:
    2589 ±
    Цитата Сообщение от DCPSHER Посмотреть сообщение
    Есть пара вопросов:
    Правильно ли я понимаю, что профайлер нужно использовать как отдельный filterscript или gamemode? Т.к. в нем есть main() и его нельзя использовать как простой include, если в моде уже есть main()
    Как можно запустить профилирование отложенно? Например как указано в статье "Как лучше проверять подключение игрока: с помощью IsPlayerConnected или добавлением в итератор (foreach.inc) и использованием функции Itter_Contains ?". Конкретно я хочу потестировать функции вычисления расстояний между игроками и т.п., но мне нужно их включать, когда игроки уже на сервере, а не при его старте.
    Вы так каждый день будете пытаться "поднять" тему новыми одинаковыми постами? (удалил пост за сегодняшний день) Сообщение ваше видел ещё вчера, просто не было времени ответить.

    Отложенное профилирование в моём коде не предусмотрено. Я могу реализовать его и переоформить всю эту работу в инклуд, но сейчас всё свободное время уходит на подготовку статей для Pro-Pawn Wiki. Пока что внёс это в список задач на будущее.
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  10. #8
    Аватар для DCPSHER
    Пользователь

    Статус
    Оффлайн
    Регистрация
    14.05.2018
    Сообщений
    16
    Репутация:
    2 ±
    Цитата Сообщение от Daniel_Cortez Посмотреть сообщение
    Вы так каждый день будете пытаться "поднять" тему новыми одинаковыми постами? (удалил пост за сегодняшний день) Сообщение ваше видел ещё вчера, просто не было времени ответить.

    Отложенное профилирование в моём коде не предусмотрено. Я могу реализовать его и переоформить всю эту работу в инклуд, но сейчас всё свободное время уходит на подготовку статей для Pro-Pawn Wiki. Пока что внёс это в список задач на будущее.
    Прошу прощения за поднятие, вчера отвечал без реплая, поэтому подумал, что уведомление могло до вас не дойти, а так как тема уже немолодая, вы ее не проверяете.
    Буду очень ждать данный инклуд!
    Большое спасибо за ответ!

 

 

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •