Аналоги функций на более быстрые

inklesspen

Пишу модули под LSD
Меценат
Сообщения
1,687
Реакции
696
Недавно задался вопросом, в сурсе столько функций, а какие быстрые, какие медленные?
Написал небольшой плагин и понял, что StrEqual, который, чисто логически, должен быть быстрее strcmp, который вычисляет, насколько строка больше или меньше, медленней своего аналога с большим функционалом
44956
1 и 3 - StrEqual
2 и 4 - strcmp, проверялось плагином, прикрепленным как "lal.sp"

Хотя в большинстве плагинов как раз таки используется StrEqual
Так вот предлагаю прямо здесь составить список функций и их аналогов на замену, включая операторов
где-то слышал, что != быстрее, что кстати логично, но разница есть, что сравнивать (lal2.sp)
44958

каждый раз разные показатели, то быстрее, то нет, решайте уж сами

PHP:
IntToString(integer, buffer, sizeof buffer)
на
PHP:
FormatEx(buffer, sizeof buffer, "%i", integer)
PHP:
if(StrEqual(...))
{

}
на
PHP:
if(!strcmp(...))
{

}
 

Вложения

  • lal.sp
    835 байт · Просмотры: 15
  • lal2.sp
    755 байт · Просмотры: 10
Последнее редактирование:

Reiko1231

AlexTheRegent
Меценат
Сообщения
501
Реакции
1,241
При декомпиляции плагина функция StrEqual будет объявлена как функция
C-подобный:
bool:StrEqual(String:str1[], String:str2[], bool:caseSensitive)
{
    return strcmp(str1, str2, caseSensitive) == 0;
}
Поэтому в вопросах оптимизации всегда нужно начинать с просмотра декомпила.
 

Саша Шеин

Кому костылей?
Сообщения
1,688
Реакции
539
При декомпиляции плагина функция StrEqual будет объявлена как функция
C-подобный:
bool:StrEqual(String:str1[], String:str2[], bool:caseSensitive)
{
    return strcmp(str1, str2, caseSensitive) == 0;
}
Поэтому в вопросах оптимизации всегда нужно начинать с просмотра декомпила.
Стоит начать с инклюдов соурсмода.
 

R1KO

fuck society
Команда форума
Сообщения
9,016
Реакции
6,897
в данной ситуации интересно что быстрее
strcmp, который в см вызывает затем сишный strcmp или кастомная ф-я сравнения строк?
например такой
C++:
stock bool UTIL_StrCmpEx(const char[] szString1, const char[] szString2)
{
    int iLen1 = strlen(sString1),
        iLen2 = strlen(sString2);

    int iMaxLen = (iLen1 > iLen2) ? iLen2:iLen1;

    for (int i = 0; i < iMaxLen; i++)
    {
        if(sString1[i] != sString2[i])
        {
            return false;
        }
    }

    return true;
}
 

iLoco

А печеньки будут :?
Меценат
Сообщения
2,039
Реакции
1,020
Сравните циклы на скорость.
 

inklesspen

Пишу модули под LSD
Меценат
Сообщения
1,687
Реакции
696
в данной ситуации интересно что быстрее
strcmp, который в см вызывает затем сишный strcmp или кастомная ф-я сравнения строк?
например такой
C++:
stock bool UTIL_StrCmpEx(const char[] szString1, const char[] szString2)
{
    int iLen1 = strlen(sString1),
        iLen2 = strlen(sString2);

    int iMaxLen = (iLen1 > iLen2) ? iLen2:iLen1;

    for (int i = 0; i < iMaxLen; i++)
    {
        if(sString1[i] != sString2[i])
        {
            return false;
        }
    }

    return true;
}
В сишном strcmp какой код?
 

Kruzya

Raspberry Pi 4
Команда форума
Меценат
Сообщения
10,550
Реакции
8,726
Я бы уже при несовпадении длин строк выдал, что они не совпадают.
Да и в реализации выше, выйдет так, что если обе строки начинаются одинаково, но у другой есть продолжение, то прилетит true всё равно.
 

R1KO

fuck society
Команда форума
Сообщения
9,016
Реакции
6,897
Я бы уже при несовпадении длин строк выдал, что они не совпадают.
Да и в реализации выше, выйдет так, что если обе строки начинаются одинаково, но у другой есть продолжение, то прилетит true всё равно.
это очень старый код. я его просто копипастнул.
 

Саша Шеин

Кому костылей?
Сообщения
1,688
Реакции
539
Сделал небольшой плагин ради прикола, вот результаты на lan сервере, OS win 10 x64 (Ну если это играет роль конечно), камешек ~3.5Ghz
log:
StartProfiling: 0/31
[0] 0.024224
StartProfiling: 1/31
[1] 0.047079
StartProfiling: 2/31
[2] 0.028050
StartProfiling: 3/31
[3] 0.075852
StartProfiling: 4/31
[4] 0.034310
StartProfiling: 5/31
[5] 0.118067
StartProfiling: 6/31
[6] 0.012878
StartProfiling: 7/31
[7] 0.015782
StartProfiling: 8/31
[8] 0.012774
StartProfiling: 9/31
[9] 0.019183
StartProfiling: 10/31
[10] 0.013039
StartProfiling: 11/31
[11] 0.022244
StartProfiling: 12/31
[12] 0.024485
StartProfiling: 13/31
[13] 0.047271
StartProfiling: 14/31
[14] 0.028012
StartProfiling: 15/31
[15] 0.075901
StartProfiling: 16/31
[16] 0.027374
StartProfiling: 17/31
[17] 0.119294
StartProfiling: 18/31
[18] 0.017334
StartProfiling: 19/31
[19] 0.020515
StartProfiling: 20/31
[20] 0.017049
StartProfiling: 21/31
[21] 0.024081
StartProfiling: 22/31
[22] 0.017782
StartProfiling: 23/31
[23] 0.026984
StartProfiling: 24/31
[24] 0.038707
StartProfiling: 25/31
[25] 0.034716
StartProfiling: 26/31
[26] 0.034163
StartProfiling: 27/31
[27] 0.028542
StartProfiling: 28/31
[28] 0.429823
StartProfiling: 29/31
[29] 0.389454
StartProfiling: 30/31
[30] 0.593417
StartProfiling: 31/31
[31] 0.538270
StartProfiling: 32/31
>>> END <<<

Код будет только в файле, а то много лишнего текста. Возможно с UTIL_StrCmpEx2 что-то сделал не так как надо, т.к. результаты странные.
 

Вложения

  • benchmark.sp
    25.5 КБ · Просмотры: 9

Grey83

Ленивая и невнимательная жопа
Сообщения
4,827
Реакции
2,837
C-подобный:
sm plugins load benchmark
[SM] Loaded plugin benchmark.smx successfully.
StartProfiling: 0/31
        [0] 0.040090
StartProfiling: 1/31
        [1] 0.086170
StartProfiling: 2/31
        [2] 0.058728
StartProfiling: 3/31
        [3] 0.153880
StartProfiling: 4/31
        [4] 0.054068
StartProfiling: 5/31
        [5] 0.211072
StartProfiling: 6/31
        [6] 0.016071
StartProfiling: 7/31
        [7] 0.023134
StartProfiling: 8/31
        [8] 0.031175
StartProfiling: 9/31
        [9] 0.027414
StartProfiling: 10/31
        [10] 0.016611
StartProfiling: 11/31
        [11] 0.034528
StartProfiling: 12/31
        [12] 0.039353
StartProfiling: 13/31
        [13] 0.084925
StartProfiling: 14/31
        [14] 0.049856
StartProfiling: 15/31
        [15] 0.139185
StartProfiling: 16/31
        [16] 0.045430
StartProfiling: 17/31
        [17] 0.202945
StartProfiling: 18/31
        [18] 0.023241
StartProfiling: 19/31
        [19] 0.028025
StartProfiling: 20/31
        [20] 0.022776
StartProfiling: 21/31
        [21] 0.033725
StartProfiling: 22/31
        [22] 0.037383
StartProfiling: 23/31
        [23] 0.039790
StartProfiling: 24/31
        [24] 0.057302
StartProfiling: 25/31
        [25] 0.052543
StartProfiling: 26/31
        [26] 0.052957
StartProfiling: 27/31
        [27] 0.047902
StartProfiling: 28/31
        [28] 1.408524
StartProfiling: 29/31
        [29] 1.135886
StartProfiling: 30/31
        [30] 1.705608
StartProfiling: 31/31
        [31] 1.406740
>>> END <<<
Правда я чуть-чуть переписал код (убрал создание переменных при каждом запуске таймера)

SM: 1.9.0.6276
CPU: Win7 SP1 x64
CPU: Intel Core i5-2500
MB: Gigabyte GA-Z68A-D3-B3
RAM: 24GB
VC: Gigabyte Radeon HD 7870 OC Windforce 3x 2GB
Disc: Intel 545s 256GB 2.5"
 

Вложения

  • benchmark.sp
    25.6 КБ · Просмотры: 4

R1KO

fuck society
Команда форума
Сообщения
9,016
Реакции
6,897
C-подобный:
sm plugins load benchmark
[SM] Loaded plugin benchmark.smx successfully.
StartProfiling: 0/31
        [0] 0.040090
StartProfiling: 1/31
        [1] 0.086170
StartProfiling: 2/31
        [2] 0.058728
StartProfiling: 3/31
        [3] 0.153880
StartProfiling: 4/31
        [4] 0.054068
StartProfiling: 5/31
        [5] 0.211072
StartProfiling: 6/31
        [6] 0.016071
StartProfiling: 7/31
        [7] 0.023134
StartProfiling: 8/31
        [8] 0.031175
StartProfiling: 9/31
        [9] 0.027414
StartProfiling: 10/31
        [10] 0.016611
StartProfiling: 11/31
        [11] 0.034528
StartProfiling: 12/31
        [12] 0.039353
StartProfiling: 13/31
        [13] 0.084925
StartProfiling: 14/31
        [14] 0.049856
StartProfiling: 15/31
        [15] 0.139185
StartProfiling: 16/31
        [16] 0.045430
StartProfiling: 17/31
        [17] 0.202945
StartProfiling: 18/31
        [18] 0.023241
StartProfiling: 19/31
        [19] 0.028025
StartProfiling: 20/31
        [20] 0.022776
StartProfiling: 21/31
        [21] 0.033725
StartProfiling: 22/31
        [22] 0.037383
StartProfiling: 23/31
        [23] 0.039790
StartProfiling: 24/31
        [24] 0.057302
StartProfiling: 25/31
        [25] 0.052543
StartProfiling: 26/31
        [26] 0.052957
StartProfiling: 27/31
        [27] 0.047902
StartProfiling: 28/31
        [28] 1.408524
StartProfiling: 29/31
        [29] 1.135886
StartProfiling: 30/31
        [30] 1.705608
StartProfiling: 31/31
        [31] 1.406740
>>> END <<<
Правда я чуть-чуть переписал код (убрал создание переменных при каждом запуске таймера)

SM: 1.9.0.6276
CPU: Win7 SP1 x64
CPU: Intel Core i5-2500
MB: Gigabyte GA-Z68A-D3-B3
RAM: 24GB
VC: Gigabyte Radeon HD 7870 OC Windforce 3x 2GB
Disc: Intel 545s 256GB 2.5"
лучше бы еще ф-ю выводили а не просто StartProfiling. так нагляднее будет
 

Grey83

Ленивая и невнимательная жопа
Сообщения
4,827
Реакции
2,837
R1KO, в смысле работу с профайлером вывести в отдельную функцию?
 

Grey83

Ленивая и невнимательная жопа
Сообщения
4,827
Реакции
2,837
R1KO, вот так?
C-подобный:
>>> START <<<
0) StrCmpEx:   0.040049
1) StrCmpEx:   0.082765
2) StrCmpEx:   0.048805
3) StrCmpEx:   0.138852
4) StrCmpEx:   0.052025
5) StrCmpEx:   0.204811
6) strcmp:     0.016060
7) strcmp:     0.022665
8) strcmp:     0.016292
9) strcmp:     0.028133
10) strcmp:     0.016356
11) strcmp:     0.034003
12) StrCmpEx2:  0.040666
13) StrCmpEx2:  0.082089
14) StrCmpEx2:  0.049187
15) StrCmpEx2:  0.137953
16) StrCmpEx2:  0.044232
17) StrCmpEx2:  0.206152
18) StrEqual:   0.021870
19) StrEqual:   0.027628
20) StrEqual:   0.021127
21) StrEqual:   0.032964
22) StrEqual:   0.021909
23) StrEqual:   0.039912
24) StrEqual:   0.057008
25) StrEqual:   0.052833
26) strcmp:     0.052650
27) strcmp:     0.047448
28) StrCmpEx2:  1.405882
29) StrCmpEx2:  1.138547
30) StrCmpEx:   1.679404
31) StrCmpEx:   1.387086
>>> END <<<
Сообщения автоматически склеены:

Вообще, нуно было сделать последовательное сравнение строк всем способами, потом менять строки и снова их сравнивать
Так были бы понятнее результаты.
Пожалуй сделаю так сейчас
Сообщения автоматически склеены:

Вот, переписал. Теперь всё гораздо нагляднее выглядит:
C-подобный:
>>> START <<<

Compare #1:
  StrCmpEx:     0.055925
  StrCmpEx2:    0.040946
  strcmp:       0.017737
  StrEqual:     0.022320

Compare #2:
  StrCmpEx:     0.082015
  StrCmpEx2:    0.094290
  strcmp:       0.040454
  StrEqual:     0.044560

Compare #3:
  StrCmpEx:     0.050946
  StrCmpEx2:    0.065946
  strcmp:       0.032702
  StrEqual:     0.038497

Compare #4:
  StrCmpEx:     0.148396
  StrCmpEx2:    0.134688
  strcmp:       0.030026
  StrEqual:     0.034050

Compare #5:
  StrCmpEx:     0.053020
  StrCmpEx2:    0.048554
  strcmp:       0.017705
  StrEqual:     0.025442

Compare #6:
  StrCmpEx:     0.197345
  StrCmpEx2:    0.201285
  strcmp:       0.036372
  StrEqual:     0.040478

Compare #7:
  StrCmpEx:     1.649590
  StrCmpEx2:    1.402318
  strcmp:       0.053740
  StrEqual:     0.057978

Compare #8:
  StrCmpEx:     1.367011
  StrCmpEx2:    1.127665
  strcmp:       0.059084
  StrEqual:     0.053850

>>> END <<<
 

Вложения

  • benchmark.sp
    28.1 КБ · Просмотры: 3
  • benchmark 1.0.2.sp
    12.5 КБ · Просмотры: 5
Последнее редактирование:

Саша Шеин

Кому костылей?
Сообщения
1,688
Реакции
539
Увлекся я немного данным вопросом и мне стало интересно, так ли хорош вариант посимвольного сравнения, ведь для его работы SP делает немного больше действий чем, вызов сишной функции.
Для тестов использую SM 1.10:
SourceMod Version Information:
SourceMod Version: 1.10.0.6434
SourcePawn Engine: 1.10.0.6434, jit-x86 (build 1.10.0.6434)
SourcePawn API: v1 = 5, v2 = 12
Compiled on: Aug 13 2019 20:27:12
Built from: Create menu if multiple nom matches found (#983) · alliedmodders/sourcemod@b8fd7db
Build ID: 6434:b8fd7db5
SourceMod: Half-Life 2 Scripting

И немного доработанный вариант от Grey83
Вот, переписал. Теперь всё гораздо нагляднее выглядит:

Какие изменения я внес?
1) Ранее я использовал случайный набор строк, мне казалось что это хороший вариант, но зачастую сравнение строк используется для проверки classname у entity или название оружия с которого было совершено убийство.
→ Выбрал несколько вариантов оружия с префиксом weapon_ и без него:
Первая пара: (строки одинаковой длины, но разные по содержанию)
weapon_mp9
weapon_mp7

Вторая пара: (полностью одинаковые строки)
weapon_mp9
weapon_mp9

Третья пара: (полностью разные строки)
weapon_hegrenade
weapon_awp

Четвертая пара: (строки одинаковой длины, но разные по содержанию)
mp9
mp7

Пятая пара: (полностью одинаковые строки)
mp9
mp9

Шестая пара: (полностью разные строки)
hegrenade
awp

2) Какие еще строки обычно сравниваются плагинами? Верно, команды игрока. Уже давно перестал использовать RegConsoleCmd для создания команды, что позволяет менять список команд "налету", а также поддерживать команды на кириллице.
→ Для сравнения команд обычно используется StrCompare, особенно если команда имеет аргументы. Еще кстати StrCompare во многих Weapon Skins плагинах используется для определения ножей. Все понимают, что адекватная длина команды в приделах 20 символов, более длинные строки использовать просто неудобно.
В данном примере StrContains используется, чтобы отсеять все команды с префиксом sm_ т.к. использовать их в чате нельзя.
C-подобный:
    strcopy(cmd, sizeof(cmd), sArgs);
    TrimString(cmd);
  
    if (StrContains(cmd, "sm_") == -1)
    {
        if (g_aCommands.FindString(cmd) != -1)
        {
            //
        }
      
        if (cmd[0] == '/')
            return Plugin_Handled;
    }

Строки которые я добавил:
Первая пара: (строки одинаковой длины, но разные по содержанию)
1лтшау
!knife

Вторая пара: (полностью одинаковые строки)
!ножи
!ножи

Третья пара: (полностью разные строки)
Вася, привет. Почему давно не заходил на сервер. У нас тут много нового, тебе показать что такое RP в CS:GO?
!ножи

Со строками определились, остается определиться с функциями. Вообще, использовать самописные ф-и не эффективно, т.к. SP это виртуальный язык и любая инструкция плагина передается сначала в VM, обрабатывается и возвращает результат. (Если я ошибаюсь, то поправьте) Но в качестве эксперимента воспользуемся функцией написанной R1KO и мой вариант. Теперь остается выбрать встроенные варианты: StrContains, strcmp. А также стоковую функцию: StrEqual. Функцию strncmp тоже задействуем, будем сравнивать строки, дабы найти weapon_ , такое тоже частенько используется в плагинах для отслеживания урона например. А также вариант его замены: str[0] == 'w' , но такое подойдет только если мы точно знаем, что в строке на w может начинаться только weapon_ , для чистоты эксперимента посимвольное сравнение с weapon_ вынесем в стоковую функцию.

Код тестового плагина с вариантом кастомной функции проверки строк:
UTIL_StrCmpEx2.sp:
public void OnPluginStart()
{
    PrintToServer("%i", UTIL_StrCmpEx2("test", "test"));
    PrintToServer("%i", UTIL_StrCmpEx2("t", "test"));
    PrintToServer("%i", UTIL_StrCmpEx2("test", "t"));
    PrintToServer("%i", UTIL_StrCmpEx2("test", "sers"));
}stock bool UTIL_StrCmpEx2(const char[] szString1, const char[] szString2) // Это бред, изначально было лучше, но вылетало
{
    static int x; static bool b; x = 0; b = szString1[0] == szString2[0];
    while (b && !(szString1[x] == '\0' || szString2[x] == '\0')) { ++x; b = szString1[x] == szString2[x]; } return b;
}

Вообщем вот что получилось:
вывод.sp:
>>> START <<<
== Function StrContains ==
                #0(len+dif): 0.000172
                #1(equal): 0.000202
                #2(dif): 0.000178
                #3(len+dif): 0.000241
                #4(equal): 0.000197
                #5(dif): 0.000172
                #6(len+dif): 0.000172
                #7(equal): 0.000197
                #8(dif): 0.000254
                #9(len+dif): 0.000881
                #10(equal): 0.000995
                #11(dif): 0.000810
== min: 0.000172 , avg: 0.000373 , max: 0.000995 ==
== Function strcmp ==
                #0(len+dif): 0.000228
                #1(equal): 0.000173
                #2(dif): 0.000161
                #3(len+dif): 0.000143
                #4(equal): 0.000192
                #5(dif): 0.000140
                #6(len+dif): 0.000140
                #7(equal): 0.000170
                #8(dif): 0.000140
                #9(len+dif): 0.000140
                #10(equal): 0.003227
                #11(dif): 0.000140
== min: 0.000140 , avg: 0.0004165 , max: 0.003227 ==
== Function StrEqual ==
                #0(len+dif): 0.000265
                #1(equal): 0.000218
                #2(dif): 0.000205
                #3(len+dif): 0.000189
                #4(equal): 0.000192
                #5(dif): 0.000185
                #6(len+dif): 0.000185
                #7(equal): 0.000214
                #8(dif): 0.000194
                #9(len+dif): 0.000190
                #10(equal): 0.003299
                #11(dif): 0.000185
== min: 0.000185 , avg: 0.0004605 , max: 0.003299 ==
== Function strncmp ==
                #0(len+dif): 0.000168
                #1(equal): 0.000168
                #2(dif): 0.000164
                #3(len+dif): 0.000146
                #4(equal): 0.000142
                #5(dif): 0.000146
                #6(len+dif): 0.000146
                #7(equal): 0.000146
                #8(dif): 0.000146
                #9(len+dif): 0.000142
                #10(equal): 0.000142
                #11(dif): 0.000157
== min: 0.000142 , avg: 0.0001515  , max: 0.000168 ==
== Function StrCmpEx ==
                #0(len+dif): 0.000584
                #1(equal): 0.000488
                #2(dif): 0.000442
                #3(len+dif): 0.000296
                #4(equal): 0.000318
                #5(dif): 0.000250
                #6(len+dif): 0.000256
                #7(equal): 0.000460
                #8(dif): 0.000525
                #9(len+dif): 0.003116
                #10(equal): 0.029757
                #11(dif): 0.003390
== min: 0.000250 , avg: 0.003324  , max: 0.029757 ==
== Function StrCmpEx2 ==
                #0(len+dif): 0.000725
                #1(equal): 0.000727
                #2(dif): 0.000500
                #3(len+dif): 0.000223
                #4(equal): 0.000292
                #5(dif): 0.000080
                #6(len+dif): 0.000078
                #7(equal): 0.000606
                #8(dif): 0.000080
                #9(len+dif): 0.000080
                #10(equal): 0.060797
                #11(dif): 0.000080
== min: 0.000078 , avg: 0.005356  , max: 0.060797 ==
== Function char[0] ==
                #0(len+dif): 0.000082
                #1(equal): 0.000044
                #2(dif): 0.000044
                #3(len+dif): 0.000062
                #4(equal): 0.000044
                #5(dif): 0.000044
                #6(len+dif): 0.000047
                #7(equal): 0.000044
                #8(dif): 0.000044
                #9(len+dif): 0.000045
                #10(equal): 0.000044
                #11(dif): 0.000044
== min: 0.000044 , avg: 0.00004925  , max: 0.000082 ==
== Function chars&& ==
                #0(len+dif): 0.000188
                #1(equal): 0.000101
                #2(dif): 0.000102
                #3(len+dif): 0.000046
                #4(equal): 0.000046
                #5(dif): 0.000046
                #6(len+dif): 0.000048
                #7(equal): 0.000046
                #8(dif): 0.000045
                #9(len+dif): 0.000046
                #10(equal): 0.000046
                #11(dif): 0.000044
== min: 0.000044 , avg: 0.00006725  , max: 0.000188 ==
== Function chars|| ==
                #0(len+dif): 0.000170
                #1(equal): 0.000091
                #2(dif): 0.000091
                #3(len+dif): 0.000048
                #4(equal): 0.000046
                #5(dif): 0.000046
                #6(len+dif): 0.000048
                #7(equal): 0.000046
                #8(dif): 0.000046
                #9(len+dif): 0.000046
                #10(equal): 0.000046
                #11(dif): 0.000046
== min: 0.000046 , avg: 0.00006425  , max: 0.000170 ==

>>> END <<<
 

Вложения

  • benchmark 1.0.3.sp
    11.8 КБ · Просмотры: 4
Последнее редактирование:

Kruzya

Raspberry Pi 4
Команда форума
Меценат
Сообщения
10,550
Реакции
8,726
В данном примере StrContains используется, чтобы отсеять все команды с префиксом sm_ т.к. использовать их в чате нельзя.
Да ты что?
45020

И вообще, StrContains() странное решение. Если в команде хоть где-нибудь есть sm_, то оно зафэйлит её исполнение.
 

Саша Шеин

Кому костылей?
Сообщения
1,688
Реакции
539
как среднее значение может оказаться больше максимального? О_о
я немного не на то поделил ;) Поправил в посте.

Речь не про это, а про конкретный плагин. Но кстати, никогда не пробовал даже писать так)

И вообще, StrContains() странное решение. Если в команде хоть где-нибудь есть sm_, то оно зафэйлит её исполнение.
Данный код не будет фэйлить комманды, т.к. рассчитан на определенный список команд. А вообще соглашусь, хз почему так сделал
 
Последнее редактирование:
Сверху