Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.

Реклама


**Как получить V.I.P** (Перейти)
Чтобы заказать рекламу на Pro-Pawn.Ru, обращайтесь в Skype.
Баннерная реклама 200руб/мес, Текстовая 100руб/мес.
Показано с 1 по 1 из 1
  1. #1
    Аватар для Daniel_Cortez
    new fuck_logic[0] = EOS;

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

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

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


    Миф 5: "Функция sizeof медленная, а ещё с ней код медленно компилируется, не надо пользоваться ей."

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

    Описание:
    Описание #не_нужно, всё уже есть в названии мифа. Равно, как и не нужно говорить, с какого форума была взята та цитата.
    Впрочем, популярен этот миф не только на г-и: http://ihost.pro-pawn.ru/image.php?di=HU2W
    И я бы не стал опровергать столь очевидный миф, если бы не "профессионалы", которые время от времени ещё и набегают сюда.

    Доказательство:
      Открыть/закрыть
    На самом деле в названии мифа сразу две ошибки.
    Во-первых, sizeof - это не функция, а оператор, с помощью которого можно заставить компилятор автоматически подсчитать размер массива в ячейках.
    Во-вторых, размер массива постоянен и результат работы оператора sizeof вычисляется компилятором. Код не может выполняться медленнее из-за константы.

    Рассмотрим это на следующем примере:
    PHP код:
    #define fpub%0(%1) forward%0(%1);public%0(%1)

    fpub Snippet1() // Отрывок кода #1, без использования sizeof.
    {
        new 
    a[10];
        
    #pragma unused a
        
    return 10;
    }

    fpub Snippet2() // Отрывок кода #2, с использованием sizeof.
    {
        new 
    a[10];
        
    #pragma unused a
        
    return sizeof(a);

    Скомпилируем скрипт с ключом "-a" для получения ассемблерного листинга:
    Код:
    CODE 0	; 0
    ;program exit point
    	halt 0
    
    	proc	; Snippet1
    	; line 4
    	; line 5
    	break	; c
    	;$lcl a ffffffd8
    	stack ffffffd8
    	zero.pri
    	addr.alt ffffffd8
    	fill 28
    	; line 7
    	break	; 2c
    	const.pri a
    	stack 28
    	retn
    
    	proc	; Snippet2
    	; line b
    	; line c
    	break	; 48
    	;$lcl a ffffffd8
    	stack ffffffd8
    	zero.pri
    	addr.alt ffffffd8
    	fill 28
    	; line e
    	break	; 68
    	const.pri a
    	stack 28
    	retn
    
    
    STKSIZE 1000
    Обратите внимание на Snippet1 и Snippet2: опкоды в этих функциях абсолютно одинаковые.
    Как и было сказано ранее, результат работы оператора sizeof был вычислен компилятором и подставлен на место его применения в виде числовой константы.
    Поскольку сгенерированный код в обоих отрывках совпадает, тесты скорости не нужны, т.к. производительность у них тоже будет одинаковой (разница будет равняться погрешности метода тестирования).

    Теперь проверим утверждение про замедление работы компилятора. Для этого сгенерируем два скрипта, в одном из которых будет 1000 функций, которые возвращают результат, вычисляемый с помощью sizeof, а в другом 1000 функций, которые возвращают обычные числа.
    Первый скрипт будет выглядеть примерно так:
    PHP код:
    new a[128];
    #pragma unused a

    forward Function0();public Function0()
        return 
    128;

    forward Function1();public Function1()
        return 
    128;

    forward Function2();public Function2()
        return 
    128;

    //... 
    Примерно так же будет выглядеть второй скрипт, только вместо "128" будет возвращаться "sizeof(a)".
    Можно было использовать макрос fpub для сокращения объявления функции, как в первом примере, но это увеличит время препроцессинга скрипта, а вместе с ним и общее время компиляции.

    Ещё для ускорения компиляции можно использовать ключ "-a", чтобы компилятор не генерировал файл .amx, а выдавал ассемблерный листинг (.asm).
    Всё равно при обычной компиляции этот листинг тоже генерируется, а на его основе уже создаётся файл .amx.
    Указав ключ "-a" мы избавим компилятор от бремени составления файла .amx, тем самым ещё больше увеличив время компиляции.

    Также можно указать ключи "-(+" и "-;+", чтобы сделать обязательными скобки для параметров функций и точку с запятой в конце каждого предложения (по умолчанию они не обязательны, но разработчики SA:MP зачем-то решили форсировать их обязательное использование, сделав так, чтобы редактор pawno сам запускал компилятор с этими ключами). Кроме того, не лишним будет компилятор "-v0", чтобы компилятор не выводил никаких сообщений.

    Принцип работы теста:
    • Генерируются скрипты test1.pwn и test2.pwn с 10 000 функций в каждом.
      В одном из них функции возвращают значение в виде целочисленной константы, в другом значение определяется с помощью оператора sizeof.
    • Сервер с помощью плагина pawnCompiler запускает компилятор Pawn.
      Запуск происходит асинхронно, поэтому чтобы определить момент завершения компиляции, нужно проверять существование файла с расширением *.asm - как только этот файл будет готов, компилятор завершит свою работу.
    • Чтобы во время постоянных проверок на существование файла .asm сервер не создавал большую нагрузку на процессор (~50%) и не мешал компилятору, следует перед каждой проверкой использовать оператор sleep.
      Т.к. при частом использовании этого оператора можно добиться ошибки "stack/heap collision", лучше использовать функцию dc_SleepFix.
    • Как только замеры компиляции времени будут готовы, вывести их вместе с разницей во времени, как общей, так и на одно использование sizeof.


    PHP код:
    #include <a_samp>
    #include "../include/pawnCompiler.inc"

    #define    TEST_SCRIPT_1            "test1"
    #define    TEST_SCRIPT_2            "test2"
    #define    TEST_SCRIPT_PWN_1        TEST_SCRIPT_1 ".pwn"
    #define    TEST_SCRIPT_PWN_2        TEST_SCRIPT_2 ".pwn"
    #define    TEST_SCRIPT_ASM_1        TEST_SCRIPT_1 ".asm"
    #define    TEST_SCRIPT_ASM_2        TEST_SCRIPT_2 ".asm"
    #define    TEST_ARRAY_SIZE            128
    #define    TEST_FUNCTIONS_COUNT    10_000


    GenerateScript(name[], bool:use_sizeof)
    {
        static const 
    header[] =
            
    "/* !! This file has been generated automatically. !! */" "\n"\
            
    "\n"\
            
    "new a[" #TEST_ARRAY_SIZE "];" "\n"\
            
    "#pragma unused a" "\n"\
            
    "\n";
        static const 
    function_str0[] = "forward Function";
        static const 
    function_str1[] = "();public Function";
        static const 
    function_str2[] = "()return ";
        static const 
    function_str3[2][] =
        {
            {
    "" #TEST_ARRAY_SIZE ";\n"},
            
    {"sizeof(a);\n"}
        };
        new 
    File:handle fopen(nameio_write);
        
    fwrite(
            
    handle,
            
    header
        
    );
        new 
    num_buffer[11];
        for (new 
    0TEST_FUNCTIONS_COUNT; ++i)
        {
            
    fwrite(handlefunction_str0);
            
    valstr(num_bufferi);
            
    fwrite(handlenum_buffer);
            
    fwrite(handlefunction_str1);
            
    fwrite(handlenum_buffer);
            
    fwrite(handlefunction_str2);
            
    fwrite(handlefunction_str3[!!use_sizeof]);
        }
        
    fclose(handle);
    }

    dc_SleepFix(time)    // by Daniel_Cortez \\ pro-pawn.ru
    {    // WARNING: This function is still only usable in main().
        // It just fixes the stack/heap collision error in default sleep().
        
    static heap_ptrstack_ptr;
        
    #emit    lctrl        2
        #emit    stor.pri    heap_ptr
        #emit    lctrl        4
        #emit    stor.pri    stack_ptr
        
    sleep(time);
        
    #emit    load.pri    stack_ptr
        #emit    sctrl        4
        #emit    load.pri    heap_ptr
        #emit    sctrl        2
    }
    #if defined _ALS_sleep
        #undef sleep
    #else
        #define _ALS_sleep
    #endif
    #define sleep(%0) dc_SleepFix(%0)

    main()
    {
        
    GenerateScript(!TEST_SCRIPT_PWN_1false);
        
    GenerateScript(!TEST_SCRIPT_PWN_2true);
        
    fremove(TEST_SCRIPT_ASM_1);
        
    fremove(TEST_SCRIPT_ASM_2);
        new 
    t1t2t;
        
    GetTickCount();
        
    WinExec("pawno/pawncc.exe -(+ -;+ -v0 -a scriptfiles/" TEST_SCRIPT_PWN_1);
        do { 
    sleep(0); } while (== fexist(TEST_SCRIPT_ASM_1));
        
    t1 GetTickCount() - t;
        
    GetTickCount();
        
    WinExec("pawno/pawncc.exe -(+ -;+ -v0 -a scriptfiles/" TEST_SCRIPT_PWN_2);
        do { 
    sleep(0); } while (== fexist(TEST_SCRIPT_ASM_2));
        
    t2 GetTickCount() - t;
        new 
    Float:dt float(t2 t1) / float(TEST_FUNCTIONS_COUNT);
        
    printf("Компиляция без sizeof: %d"t1);
        
    printf("Компиляция с использованием sizeof: %d"t2);
        
    printf(
            
    "dt = %d / %d = %.4f тиков = %.8f мс",
            
    t2 t1TEST_FUNCTIONS_COUNTdtdt 1000
        
    );

    Результат:
    PHP код:
    Компиляция без sizeof8484
    Компиляция с использованием sizeof
    9741
    dt 
    1257 10000 0.1476 тиков 0.00014769 мс 
    Получается, при каждом использовании sizeof время компиляции увеличивается примерно на ~0.00015 миллисекунды или на ~147 микросекунд - крайне малый отрезок времени.
    Измерения были получены на ПК с процессором Intel Pentium E6600, 3.06 ГГц. Сейчас всё чаще можно встретить ПК и помощнее, поэтому у вас разница может оказаться ещё меньше.
    Можно больше времени потерять на подсчёт размера массива вручную, чем на компиляцию с sizeof.
    Как результат, миф о вреде использования sizeof опровергнут.


    Вывод: sizeof не влияет на производительность кода, а на время компиляции воздействие ничтожно мало и им можно принебречь.


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

  2. 16 пользователя(ей) сказали cпасибо:
    $continue$ (13.01.2016)Alanchick (13.07.2016)ALIT13 (13.01.2016)DeimoS (13.01.2016)franked (17.02.2016)LLIapuk (14.01.2016)Londlem (13.01.2016)MaKcuM (12.01.2017)Nurick (13.01.2016)Salik_Davince (13.01.2016)seriu (13.01.2016)Unreal (15.01.2016)untonyst (13.01.2016)VVWVV (13.01.2016)[ForD] (18.01.2016)Роуди. (14.01.2016)
 

 

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

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

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

Ваши права

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