PDA

Просмотр полной версии : [Урок] Мифы о Pawn-скриптинге - #7



Daniel_Cortez
20.02.2016, 13:41
Внимание: данная тема закрыта для защиты от копирования.
Если есть какие-то вопросы, замечания или просто пожелания по поводу данного урока - оставляйте их здесь (http://pro-pawn.ru/showthread.php?12774-%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5).




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

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

Описание:

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


Доказательство:
Многие нативные функции предназначены для того, чего нельзя или очень сложно сделать другими средствами.
Лишь некоторые нативные функции можно заменить эквивалентным кодом на Pawn - обычно это функции для работы с целыми числами и строковые функции.
Рассмотрим это на примере двух алгоритмов преобразования всех символов верхнего регистра в строке на символы нижнего регистра.
В одном алгоритме для преобразования будет использоваться функция tolower, а в другом - аналогичный код на Pawn.
Для сравнения скорости выполнения каждого из алгоритмов воспользуемся профайлером.

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

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


#include <core>

LowerCase0(string[])
{
static pos;
for (pos = -1; string[++pos] != '\0';)
string[pos] = tolower(string[pos]);
}

LowerCase1(string[])
{
static pos, c;
for (pos = 0; ; ++pos)
{
if (0 != (c = string[pos]))
{
if (c < 'A')
continue;
if ('Z' < c)
continue;
string[pos] = c + ('a' - 'A');
continue;
}
break;
}
}


#define Prerequisites();\
static string[] = "ABCabcAABBCCaabbccXYZxyzXXYYZZxxyyzz";

#define CodeSnippet0();\
LowerCase0(string);

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

Результаты:


Тестирование: <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, но можно сделать и свой код.

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

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


#include <core>

new max_value;
#pragma unused max_value

#define Prerequisites();\
new a = random(100), b = random(100);

#define CodeSnippet0();\
max_value = max(a, b);

#define CodeSnippet1();\
max_value = (b > a) ? b : a;
/*======== Конец настроек ====================================================*/

Результаты:


Тестирование: <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-компиляции.
Рассмотрим ещё один пример: удалить из строки все пробелы.

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

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


#include <string>

RemoveSpaces0(string[])
{
static pos;
pos = 0;
while (strfind(string, " ", false, pos) != -1)
strdel(string, pos, ++pos);
}

RemoveSpaces1(string[])
{
static pos, pos2, c;
for (pos = 0, pos2 = 0;; ++pos)
{
switch (c = string[pos])
{
case ' ': continue;
case '\0':
{
string[pos2] = '\0';
return;
}
}
string[pos2++] = c;
}
}


#define Prerequisites();\
static string[] =\
" AaBbCcDdEeFfGgHh IiJjKkLlMmNnOoPp QqRrSsTtUuVvWwXx YyZz ";

#define CodeSnippet0();\
RemoveSpaces0(string);

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

Результаты:


Тестирование: <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, лучше использовать такой аналог.
Но всё же, если вы не уверены в факте прироста производительности, используйте профайлер (http://pro-pawn.ru/showthread.php?12585).



Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Не разрешается копирование данной статьи на других ресурсах без разрешения автора.