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

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

    Мифы о Pawn-скриптинге - #7

    Внимание: данная тема закрыта для защиты от копирования.
    Если есть какие-то вопросы, замечания или просто пожелания по поводу данного урока - оставляйте их здесь.


    Миф 7: "В Pawn лучше всегда использовать нативные функции."

    Статус: Опровергнут.

    Описание:
    Есть такие уникумы, которые думают, якобы нативные функции всегда работают быстрее, чем аналогичный код на Pawn и поэтому лучше всегда использовать нативные функции.
    На самом деле это предположние верно не во всех случаях. Сам по себе вызов нативной функции - сравнительно затратная операция, т.к. нужно лишний раз копировать параметры функции (из стека виртуальной машины в массив параметров для вызываемой функции - вспомните, как выглядят заголовки функций в плагинах для SA:MP), передать управление из виртуальной машины на нативный код, выполнить код функции и перейти обратно в виртуальную машину.
    Собственно, выигрыш в использовании нативной функции зависит от сложности самой функции. У некоторых простых функций быстродействия может не хватить на компенсацию временных затрат на парсинг параметров и переход на нативный код и обратно.
    Примеры таких функций: clamp, min, max, tolower, toupper, strfind.

    Доказательство:
      Открыть/закрыть
    Многие нативные функции предназначены для того, чего нельзя или очень сложно сделать другими средствами.
    Лишь некоторые нативные функции можно заменить эквивалентным кодом на Pawn - обычно это функции для работы с целыми числами и строковые функции.
    Рассмотрим это на примере двух алгоритмов преобразования всех символов верхнего регистра в строке на символы нижнего регистра.
    В одном алгоритме для преобразования будет использоваться функция tolower, а в другом - аналогичный код на Pawn.
    Для сравнения скорости выполнения каждого из алгоритмов воспользуемся профайлером.
    1. /*======== Настройки =========================================================*/
    2. // Кол-во итераций в циклах.
    3. const PROFILER_ITERATIONS_MAJOR = 10_000;
    4. const PROFILER_ITERATIONS_MINOR = 100;
    5.  
    6. // Названия отрывков кода.
    7. new const code_snippets_names[2][] =
    8. {
    9. {"native function"},
    10. {"Pawn function"}
    11. };
    12.  
    13.  
    14. #include <core>
    15.  
    16. LowerCase0(string[])
    17. {
    18. static pos;
    19. for (pos = -1; string[++pos] != '\0';)
    20. string[pos] = tolower(string[pos]);
    21. }
    22.  
    23. LowerCase1(string[])
    24. {
    25. static pos, c;
    26. for (pos = 0; ; ++pos)
    27. {
    28. if (0 != (c = string[pos]))
    29. {
    30. if (c < 'A')
    31. continue;
    32. if ('Z' < c)
    33. continue;
    34. string[pos] = c + ('a' - 'A');
    35. continue;
    36. }
    37. break;
    38. }
    39. }
    40.  
    41.  
    42. #define Prerequisites();\
    43.   static string[] = "ABCabcAABBCCaabbccXYZxyzXXYYZZxxyyzz";
    44.  
    45. #define CodeSnippet0();\
    46.   LowerCase0(string);
    47.  
    48. #define CodeSnippet1();\
    49.   LowerCase1(string);
    50. /*======== Конец настроек ====================================================*/

    Результаты:
    Код:
    Тестирование: <native function> vs <Pawn function>
    Режим: интерпретируемый, 10000x100 итераций.
    native function: 8001
    Pawn function: 2263
    Код:
    Тестирование: <native function> vs <Pawn function>
    Режим: с JIT-компиляцией, 10000x100 итераций.
    native function: 5072
    Pawn function: 213

    Ещё пример: определить из двух чисел то, которое больше.
    Для таких целей в Pawn есть нативная функция max, но можно сделать и свой код.
    1. /*======== Настройки =========================================================*/
    2. // Кол-во итераций в циклах.
    3. const PROFILER_ITERATIONS_MAJOR = 100_000;
    4. const PROFILER_ITERATIONS_MINOR = 1000;
    5.  
    6. // Названия отрывков кода.
    7. new const code_snippets_names[2][] =
    8. {
    9. {"native function"},
    10. {"Pawn function"}
    11. };
    12.  
    13.  
    14. #include <core>
    15.  
    16. new max_value;
    17. #pragma unused max_value
    18.  
    19. #define Prerequisites();\
    20.   new a = random(100), b = random(100);
    21.  
    22. #define CodeSnippet0();\
    23.   max_value = max(a, b);
    24.  
    25. #define CodeSnippet1();\
    26.   max_value = (b > a) ? b : a;
    27. /*======== Конец настроек ====================================================*/

    Результаты:
    Код:
    Тестирование: <native function> vs <Pawn function>
    Режим: интерпретируемый, 100000x1000 итераций.
    native function: 4564
    Pawn function: 3794
    Код:
    Тестирование: <native function> vs <Pawn function>
    Режим: с JIT-компиляцией, 100000x1000 итераций.
    native function: 3010
    Pawn function: 353
    В обоих приведённых выше примерах реализация на Pawn обходит по производительности нативные функции, причём с JIT преимущество кода на Pawn только увеличивается.
    Но бывают и случаи, когда код на Pawn работает быстрее нативной функции только при использовании JIT-компиляции.
    Рассмотрим ещё один пример: удалить из строки все пробелы.
    1. /*======== Настройки =========================================================*/
    2. // Кол-во итераций в циклах.
    3. const PROFILER_ITERATIONS_MAJOR = 10_000;
    4. const PROFILER_ITERATIONS_MINOR = 100;
    5.  
    6. // Названия отрывков кода.
    7. new const code_snippets_names[2][] =
    8. {
    9. {"native function"},
    10. {"Pawn function"}
    11. };
    12.  
    13.  
    14. #include <string>
    15.  
    16. RemoveSpaces0(string[])
    17. {
    18. static pos;
    19. pos = 0;
    20. while (strfind(string, " ", false, pos) != -1)
    21. strdel(string, pos, ++pos);
    22. }
    23.  
    24. RemoveSpaces1(string[])
    25. {
    26. static pos, pos2, c;
    27. for (pos = 0, pos2 = 0;; ++pos)
    28. {
    29. switch (c = string[pos])
    30. {
    31. case ' ': continue;
    32. case '\0':
    33. {
    34. string[pos2] = '\0';
    35. return;
    36. }
    37. }
    38. string[pos2++] = c;
    39. }
    40. }
    41.  
    42.  
    43. #define Prerequisites();\
    44.   static string[] =\
    45.   " AaBbCcDdEeFfGgHh IiJjKkLlMmNnOoPp QqRrSsTtUuVvWwXx YyZz ";
    46.  
    47. #define CodeSnippet0();\
    48.   RemoveSpaces0(string);
    49.  
    50. #define CodeSnippet1();\
    51.   RemoveSpaces1(string);
    52. /*======== Конец настроек ====================================================*/

    Результаты:
    Код:
    Тестирование: <native function> vs <Pawn function>
    Режим: интерпретируемый, 10000x100 итераций.
    native function: 1237
    Pawn function: 4601
    Код:
    Тестирование: <native function> vs <Pawn function>
    Режим: с JIT-компиляцией, 10000x100 итераций.
    native function: 1464
    Pawn function: 472
    Как видно по результатам, нативная функция работает в 3.7 раза быстрее кода на Pawn, но при включении JIT результаты меняются вплоть до наоборот: код на Pawn опережает нативную функцию в 3.1 раза.

    Вывод: во многих случаях, когда нативной функции можно найти аналогичный код на Pawn, лучше использовать такой аналог.
    Но всё же, если вы не уверены в факте прироста производительности, используйте профайлер.


    Специально для Pro-Pawn.ru
    Не разрешается копирование данной статьи на других ресурсах без разрешения автора.
    Индивидуально в ЛС по скриптингу не помогаю. Задавайте все свои вопросы здесь (click).

  2. 8 пользователя(ей) сказали cпасибо:
    DeimoS (21.02.2016) Desulaid (20.02.2016) L0ndl3m (20.02.2016) Nurick (22.02.2016) Processing (24.02.2016) Profyan (20.02.2016) StevenH (06.03.2016) VVWVV (20.02.2016)
 

 

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

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

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

Ваши права

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