HLFX.Ru Forum
профиль •  правила •  регистрация •  календарь •  народ •  FAQ •  поиск •  новое •  сутки •  главная •  выход  
HLFX.Ru Forum HLFX.Ru Forum > Теория и практика > Half-Life SDK > Замеряем скорость выполнения кода
Типа профайлер =)
  Предыдущая тема   Следующая тема
Автор
Тема Новая тема    Ответить
 XaeroX
Crystice Softworks

Дата регистрации: Oct 2005
Проживает: Торонто
Сообщений: 34498
Нанёс повреждений: 514 ед.
Возраст: 37

Рейтинг



Награды
 
[1 награда]


Замеряем скорость выполнения кода

Не совсем про ХЛ, но все же может быть полезно и моддерам.
В общем, понадобилось мне точно замерять, насколько та или иная реализация алгоритма быстрее. Есть конечно много вариантов, можно GetTickCount использовать или QueryPerformanceCounter, но тут есть две проблемы:
- Невысокая точность
- Сами эти функции содержат код
Это не так принципиально для профилирования больших функций, а если вам надо профилировать небольшие ассемблерные вставки?
Для этого я выбрал TSC - timestamp counter. Это модельно-зависимый регистр процессора, содержимое которого увеличивается с каждым тактом ядра и сбрасывается при остановке (сигналом RESET). Регистр этот 64-битный, так что и работать придется с 64-битными переменными (в MS Visual Studio это тип __int64). Есть тут две тонкости. Во-первых, нужно проверить, так как регистр модельно-зависимый, то по определению он присутствует не на всех моделях процессоров, так что нам нужно будет проверить его наличие. И второе - чтение из него выполняется командой RDTSC, которая может быть сделана защищенной (доступной только в т.н. "нулевом кольце" привилегий). Под WinXP вы такие привилегии не получите... Но обычно она все же не защищена, так что эту проверку я опускаю. Ну и на всякий случай проверим, что в регистре ненулевое значение (иначе - что-то пошло не так).
Я написал три функции - первые две служат для сравнения производительности двух участков кода, а вторая просто выводит число тактов за профилирование.

C++ Source Code:
1
unsigned __int64 __g_ProfilerStart;
2
unsigned __int64 __g_ProfilerEnd;
3
unsigned __int64 __g_ProfilerEnd2;
4
unsigned __int64 __g_ProfilerSpare;
5
unsigned __int8  __g_ProfilerSupported;
6
 
7
void Prof_Init( void )
8
{
9
  __g_ProfilerStart = 0;
10
  __g_ProfilerEnd = 0;
11
  __g_ProfilerEnd2 = 0;
12
  __g_ProfilerSpare = 0;
13
 
14
  __asm {
15
    //Check TSC support (bit 4 in edx, with eax=1)
16
    mov eax, 1
17
    cpuid
18
    test edx, 10h
19
    jz unsupported
20
 
21
    //Check TSC value, it must be non-zero
22
    rdtsc
23
    test eax, eax
24
    jnz supported
25
    test edx, edx
26
    jz unsupported
27
  }
28
supported:
29
  __g_ProfilerSupported = 1;
30
  return;
31
 
32
unsupported:
33
  __g_ProfilerSupported = 0;
34
  return;
35
}

Сами функции профилирования - это макросы, т.к. они должны вставляться строго в код (тратить такты на вызов функций недопустимо). Обратите внимание - во втором макросе RDTSC вызывается дважды. Это делается, чтобы скорректировать полученное значение на такты, затраченные на сами команды профилирования.
C++ Source Code:
1
#define Prof_Start()	\
2
{	\
3
if (__g_ProfilerSupported) \
4
{ \
5
__asm pushad \
6
__asm rdtsc \
7
__asm mov DWORD PTR[__g_ProfilerStart+4], edx \
8
__asm mov DWORD PTR[__g_ProfilerStart], eax \
9
__asm popad \
10
} \
11
}
12
 
13
#define Prof_End()	\
14
{	\
15
if (__g_ProfilerSupported) \
16
{ \
17
__asm pushad \
18
__asm rdtsc \
19
__asm mov DWORD PTR[__g_ProfilerEnd+4], edx \
20
__asm mov DWORD PTR[__g_ProfilerEnd], eax \
21
__asm popad \
22
__asm pushad \
23
__asm rdtsc \
24
__asm mov DWORD PTR[__g_ProfilerEnd2+4], edx \
25
__asm mov DWORD PTR[__g_ProfilerEnd2], eax \
26
__asm popad \
27
} \
28
}

Далее собственно обработка результатов. Первая функция вычисляет запоминает значение первого профилирования, вторая - вычисляет второе значение и выводит, какой код быстрее и на сколько процентов.
C++ Source Code:
1
void Prof_Store( void )
2
{
3
  if (__g_ProfilerSupported) {
4
    __g_ProfilerSpare = __g_ProfilerEnd-__g_ProfilerStart-(__g_ProfilerEnd2-__g_ProfilerEnd);
5
  }
6
}
7
 
8
void Prof_RatioResults( void )
9
{
10
  if (__g_ProfilerSupported) {
11
    unsigned __int64 total = __g_ProfilerEnd-__g_ProfilerStart-(__g_ProfilerEnd2-__g_ProfilerEnd);
12
    double ratio;
13
 
14
    if (total >= __g_ProfilerSpare) {
15
      ratio = (double)(total-__g_ProfilerSpare)/total;
16
      printf("First code is %.2f%% faster\n", ratio*100);
17
    } else {
18
      ratio = (double)(__g_ProfilerSpare-total)/__g_ProfilerSpare;
19
      printf("Second code is %.2f%% faster\n", ratio*100);
20
    }
21
  } else {
22
    printf("--- Profiler not supported ---\n");
23
    printf("Possible reasons:\n");
24
    printf("\t- Your CPU does not support timestamp counter\n");
25
    printf("\t- RDTSC is a priveleged instruction (only at CPL0)\n");
26
  }
27
}

Эта функция просто выводит результат профилирования:
C++ Source Code:
1
void Prof_Results( void )
2
{
3
  if (__g_ProfilerSupported) {
4
    unsigned __int64 total = __g_ProfilerEnd-__g_ProfilerStart-(__g_ProfilerEnd2-__g_ProfilerEnd);
5
    printf("--- Profile results: %I64d\n", total);
6
  } else {
7
    printf("--- Profiler not supported ---\n");
8
    printf("Possible reasons:\n");
9
    printf("\t- Your CPU does not support timestamp counter\n");
10
    printf("\t- RDTSC is a priveleged instruction (only at CPL0)\n");
11
  }
12
}


Вот и все. Профилировать можно так:
C++ Source Code:
1
Prof_Init();
2
Prof_Start();
3
 
4
//Code 1
5
 
6
Prof_End();
7
Prof_Store();
8
 
9
Prof_Start();
10
 
11
//Code 2
12
 
13
Prof_End();
14
Prof_RatioResults();


Учтите, что при профилировании длительно выполняемого кода неизбежны ошибки. Это следствие вытесняющей многозадачности ОС: она может прервать по собственному желанию выполнение вашего кода и переключить процессор на код ОС. Поэтому во время профилирования не сворачивайте окна, не двигайте мышь и т.п.
Ваше мнение о профайлере? Предложения и замечания приветствуются

__________________
Правдой дорожить, лжи не потакать,
Дальних не судить, ближним помогать,
С тишиной сойтись на исходе дня
Научи меня, Родина моя!

Сообщить модератору | | IP: Записан
Сообщение: 12208

Старое сообщение 02-04-2007 17:55
-
Government-Man
Призрак

Дата регистрации: Apr 2006
Проживает: N/A
Сообщений: 3507

Рейтинг



Награды
 
[1 награда]


По поводу самого кода ничего сказать не могу - ибо в асме я разбираюсь мягко говоря плоховато. А за тутор спасибо - сам искал.

Сообщить модератору | | IP: Записан
Сообщение: 12214

Старое сообщение 03-04-2007 07:50
- За что?
 Дядя Миша
racing for fish

Дата регистрации: Oct 2005
Проживает: Кубань
Сообщений: 32188
Нанёс повреждений: 392 ед.

Рейтинг



Government-Man не переживай, ксерокс этот профайлер тоже не сразу написал, а после соответствующей подготовки.

Сообщить модератору | | IP: Записан
Сообщение: 12225

Старое сообщение 03-04-2007 12:21
-
Government-Man
Призрак

Дата регистрации: Apr 2006
Проживает: N/A
Сообщений: 3507

Рейтинг



Награды
 
[1 награда]


Цитата:
Дядя Миша писал:
после соответствующей подготовки


См. тему "Что вы нюхаете"

Сообщить модератору | | IP: Записан
Сообщение: 12234

Старое сообщение 03-04-2007 14:32
- За что?
Тема: (Опционально)
Ваш ответ:



Переводчик транслита


[проверить длину сообщения]
Опции: Автоматическое формирование ссылок: автоматически добавлять [url] и [/url] вокруг интернет адресов.
Уведомление по E-Mail: отправить вам уведомление, если кто-то ответил в тему (только для зарегистрированных пользователей).
Отключить смайлики в сообщении: не преобразовывать текстовые смайлики в картинки.
Показать подпись: добавить вашу подпись в конец сообщения (только зарегистрированные пользователи могут иметь подписи).

Временная зона GMT. Текущее время 16:40. Новая тема    Ответить
  Предыдущая тема   Следующая тема
HLFX.Ru Forum HLFX.Ru Forum > Теория и практика > Half-Life SDK > Замеряем скорость выполнения кода
Типа профайлер =)
Версия для печати | Отправить тему по E-Mail | Подписаться на эту тему

Быстрый переход:
Оцените эту тему:

Правила Форума:
Вы not можете создавать новые темы
Вы not можете отвечать в темы
Вы not можете прикреплять вложения
Вы not можете редактировать ваши сообщения
HTML Код ВЫКЛ
vB Код ВКЛ
Смайлики ВКЛ
[IMG] Код ВКЛ
 

< Обратная связь - HLFX.ru >

На основе vBulletin
Авторское право © 2000 - 2002, Jelsoft Enterprises Limited.
Дизайн и программирование: Crystice Softworks © 2005 - 2024