LINUX.ORG.RU

Различие в отношении rdtsc и clock_gettime() для разных функций

 , , , ,


0

1

Проводил я тут сравнение скорости двух функций, которые делают по смыслу одно и то же, но записаны по-разному (одна через таблицу поиска, другая же через кучу if-ов), и там я замерял одновременно время двумя способами, впрочем смотрите сами http://pastebin.ca/3797458

Так вот, отношение величин gettime()/rdtsc() для функции f1 и функции f2 различаются, т.е. если построить по этим значениям график, то получим две полоски. Чем можно объяснить данный эффект?

Запускал я естественно через taskset 0x00000001 и sudo cpufreq-set -c 0 -f 2000MHz, проц Intel Core 2 Quad Q9300 в 64-bit режиме

http://pastebin.ca/3797465 - вывод программы

★★★★

Возможно, точность измерения порядка 1мкс для clock_gettime это недостижимо. Я бы сделал тест (раз по пять) для каждой задержки (10, 100, 300, 1000, 3000... циклов внутри for()), измерил время clock_gettime() и rdtsc и посмотрел на линейность графика. rdtsc я доверяю больше.

Для бенчмарков производительности также полезно пользоваться аппаратными счетчиками. Например, вот https://github.com/david-grs/geiger

Кроме того, нужно понимать, что какая функция лучше, зависит также от того, насколько она влияет на другой код (одна может работать быстрее, но сожрать кеши L1i, L1d, кеш декодированных инструкций и кеш TLB, а другая чуть медленнее, но оставить почти все кеши нетронутыми). В результате другой код либо будет грузиться после измеряемой функции из дальних кешей, либо из L1 и кеша декодированных инструкций. Поэтому бенчмарки полезно проводить на работающем коде, чтобы понять, сколько тактов (количество инструкций за такт) заняло выполнение конкретного участка кода в живой программе и сколько промахов кеша и разных предсказателей в нем было (а не когда все переходы предсказаны, все инструкции и данные в кешах, инструкции декодированы и только и ждут выполнения, потому что в таком режиме вызов виртуальной функции не отличается по времени от обычной).

P.S. Вообще, интересная зависимость. Мне бы и в голову не пришло измерять время gettime'ом на таких временных интервалах (а потому и эффект я бы не увидел).

anonymous ()

Ну и до кучи, у тебя код такой:

clock_gettime();
rdtsc();
// измеряемая функция в цикле
rdtsc()
clock_gettime(); 
то есть время, получаемое в gettime() - это измеряемой время + два вызова rdtsc + вызов ~одного gettime(). Время, получаемое rdtsc() - это измеряемое время + ~одного вызова rdtsc(). (я тут считаю, что gettime(); gettime() даст время на один вызов gettime(), а
uint64_t begin = rdtsc();
uint64_t   end = rdtsc();
даст примерно разницу равную времени одного вызова rdtsc().

А вообще, понятно же, что по результату f1 быстрее.

anonymous ()

А расскажи зачем ты сравниваешь время и количество циклов процессора?

xpahos ★★★★★ ()
Ответ на: комментарий от anonymous

Ну и до кучи, у тебя код такой:
...
то есть время, получаемое в gettime() - это измеряемой время + два вызова rdtsc + вызов ~одного gettime().

Вот немного переделал с учетом этого замечания http://pastebin.ca/3797535 - теперь для rdtsc и clock_gettime отдельные циклы используются. Эффект «двух полосок» сохраняется

SZT ★★★★ ()
Ответ на: комментарий от xpahos

Хотел посмотреть, насколько пропорционально увеличивается время и количество циклов процессора при замере производительности. Вот мои тесты показывают, что для разного кода это отношение разное. Хочется понять, почему так происходит

SZT ★★★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от anonymous

Для бенчмарков производительности также полезно пользоваться аппаратными счетчиками. Например, вот https://github.com/david-grs/geiger

Там rdpmc инструкция? А чем оно лучше (точнее) rdtsc? Надо будет тоже попробовать, втулю новых асмовставок https://software.intel.com/en-us/forums/software-tuning-performance-optimizat...

SZT ★★★★ ()
Ответ на: комментарий от SZT

Вот мои тесты показывают, что для разного кода это отношение разное. Хочется понять, почему так происходит

Разные инструкции занимают разное количество циклов. Можно попробовать сделать objdump, например, и посмотреть сколько какая инструкция жрет циклов.

https://godbolt.org/g/t3i3qh Как минимум у f2 куча джампов, которые могут занимать до 20 циклов, а тот же movq 6 циклов на одном и том же процессоре.

xpahos ★★★★★ ()

Почему не использовать perf из утилит ядра?

anonymous ()
Ответ на: комментарий от xpahos

Разные инструкции занимают разное количество циклов.

Это понятно, меня интересует ответ на вопрос, почему количество циклов по-разному (в зависимости от тестируемого кода) соотносится со временем выполнения конкретного фрагмента, полученным от clock_gettime() ?

SZT ★★★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от anonymous

Почему не использовать perf из утилит ядра?

Да, можно будет попробовать.

SZT ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.