Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Для новичков > memcpy |
Автор: ForceKeeper 6.9.2011, 02:44 | ||
Из праздного интереса сравнил производительность на своем ПК родного memcpy и такого цикла
Дефолтная функция оказалась в 10-11 раз быстрее. Может кто знает, что за сильное колдунство в ней применено? P.S. mas - интовский массив, так что, если я ничего не путаю, проблем с выравниванием по вордам не должно быть |
Автор: boostcoder 6.9.2011, 02:50 |
копирование двойными словами или четвертными словами. |
Автор: newbee 6.9.2011, 02:53 |
AFAIK в memcpy используются какие-то специальные ассемблерные функции. Как msvc не знаю, а GCC при -03 выравнивает производительность memcpy и наколеночной реализации. Добавлено через 1 минуту и 9 секунд Утром исходник посмотрю. |
Автор: volatile 6.9.2011, 02:58 | ||
Посмотрите исходники. все ран-таймовские сорцы должны быть. Вот исходник от 2008 студии (2010 под рукой нет, но думаю там ничего кардинального с memcpy не произошло)
Такая разница из-за того что вы скорей всего в дебаге собрали. Нужно собирать в релизе, с ключами оптимизации на скорость. к тому-же шорты немного медленней чем инты, или чары. Но главное оптимизация! |
Автор: volatile 6.9.2011, 03:11 |
Почему позор? |
Автор: boostcoder 6.9.2011, 03:12 |
побайтное копирование! ![]() Добавлено через 6 минут и 56 секунд volatile, посмотри на это? http://lxr.linux.no/linux+v3.0.4/arch/x86/include/asm/string_32.h#L168 выше реализованы использованные в ней функции. Добавлено через 8 минут и 31 секунду одна из них в другом файле: http://lxr.linux.no/linux+v3.0.4/arch/x86/lib/mmx_32.c#L28 |
Автор: volatile 6.9.2011, 03:27 |
Где-то в старом борланде я видел асмовую memcpy, с копированиями 32-разрядными словами. Внешне очень красивая. с трюками и развернутыми циклами. щас не могу найти. может завтра.. Но в реале она боюсь окажется не на много быстрее... Это связано с современными процессорами. Там основное время тратится на не попадание в внутренний кеш процессора. (страница памяти). И это невелирует различия побайтного и пословного копирования. Вообще может сравню раельную производительность, если будет время. |
Автор: boostcoder 6.9.2011, 03:33 | ||
кеш может на что-то повлиять, если происходит копирование массивов размером меньше линии кеша. это первое. второе - т.к. массивов два(источник-приемник), то тогда оба массива должны попасть каждый в свою линию(иначе толку от одного кеша не будет). а это маловероятно. третье - копирование словами/двойными_словами - всегда быстрее. сравни. |
Автор: volatile 6.9.2011, 03:45 | ||
Пример: 1. Побайтое копирование читаем первый байт, который не находится в кеше. тратим на это 1000 тактов. (грубо) читаем второй байт (а он уже в кеше) тратим на это 2 такта читаем 3 -ий байт тратим 2 такта читаем 4 -ый байт тратим 2 такта итого 1006 тактов. 2. Теперь читаем словами. читаем слово, не попадаем в кеш, тратим 1000 тактов. итого разница между побайтным и пословным копированием 1000 против 1006. Цифры взял с потолка, просто чтоб объяснить свою мысль. не спорю. просто возможно что не на много. Реально может сравню. |
Автор: boostcoder 6.9.2011, 03:53 | ||
размер линии кеша - 64 байта. а теперь посчитай сколько тактов потребуется для копирования массива объемом 128 байт, к примеру ;) |
Автор: Silent 6.9.2011, 09:38 | ||||||||
Решил проверить, делая ставку на стандартную memcpy:
Результат неожиданный:
Конфигурация - VS2010, WinXP SP3, i3, 2Gb. Проверил на VS2008 - результат аналогичный. Посмотрел в ассемблерный листинг - самописанные процедуры в обоих студиях записались так:
(копирование строки с адреса ds:esi в адрес es:edi) А вот memcpy - вызов внешней функции:
Эм... дефолтная функция не умеет использовать процессор на всю катушку? |
Автор: boostcoder 6.9.2011, 09:52 |
volatile же показал код memcpy() используемой в VC2008. чего он нее ожидать-то? ![]() |
Автор: Silent 6.9.2011, 11:35 |
ну я не знаю... надеялся на оптимизационные способности компилятора ))) |
Автор: volatile 6.9.2011, 12:21 | ||||
Ребята, современные процессоры, довольно сложные штуковины. там 3 уровня кеша. К тому-же GetTickCount(); слишком груба чтобы сравнивать промежутки времени меньше минуты у нее слишком большая дискретность. Но дело здесь не в этом. Здесь дело в страничном выделении памяти. Первая процедцра копирования работает с не выделенной памятью и тратит кучу времени на выделение этой памяти. Вторая уже работает с выделенной памятью. Просто поменяйте функции местами, и скорость получится не в вашу пользу с точность до наоборот
Просто меняю очередность вызовов местами:
Функции брал ваши без переделки. ![]() |
Автор: Estranged 6.9.2011, 14:56 |
Реализация в VS 2010 на ASM. Влезьте внутрь, все увидите. |
Автор: volatile 6.9.2011, 15:07 |
Estranged, куда влезать то? В бинарник? Дык там конечно асмовые инструкции. Просто приведите исходник, все исходники CRT идут со студией. 2010 студии под рукой нет, просто интуитивно, не думаю что в 2010 стали переписывать стандартные библиотеки на асме, времена не те... |
Автор: voral 6.9.2011, 16:20 |
Вон, что гугл наше на микрософтовом сайте http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/memcpy.c.htm Правда есть и такое C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\intel\memcpy.asm |
Автор: Silent 6.9.2011, 21:07 |
А ведь есть еще великий и могучий SSE - никто не пользовался MOVDQA (sse2) или MOVNTDQA (sse4)? |
Автор: boostcoder 6.9.2011, 21:24 |
вот: http://stackoverflow.com/questions/269408/memcpy-performance-differences-between-32-and-64-bit-processes говорят что 2Гб/сек ![]() |
Автор: volatile 6.9.2011, 23:28 | ||
Да действительно, асмовая версия тоже есть. Видимо подставляются разные в зависимости от способа вызова (intrinsic/ not intrinsic), и от ключей оптимизации. Добавлено через 5 минут и 48 секунд Один мой знакомый программер как-то добивался максимальной скорости копирования. (игрушку делал) И он уверял, что именно с SSE ему удалось добиться самой максимальной скорости копирования памяти. (чуть ли не в разы) Но в подробности я не вникал, так как для моих задач и системной вполне хватает. |
Автор: ForceKeeper 6.9.2011, 23:37 | ||||
Насчет ассемблера, открыл в Олли откомпиленый под релизом экзеншник, зашел в memcpy и вот, какой цикл там нашел
P.S.
Та же история) |
Автор: boostcoder 7.9.2011, 00:00 |
значит с этим все в порядке. ForceKeeper, покажи этот же асм-код но только с адресами. повторюсь. я тоже копал в этом направлении. но оказалось, что стандартная функция работает быстрее всех реализаций использующих MMX/3DNow которые я нашел. я показал почему ;) Добавлено через 5 минут и 21 секунду только что обратил внимание на такой момент. MMX регистров восемь. но оба кода(последний и тот что я приводил из исходников linux-kernel) работают следующим образом: 1. из источника копируется в 4 регистра. 2. из этих регистров в приемник. 3. из источника копируется в остальные 4 регистра. 4. из них в приемник. а почему не сразу из источника в 8 регистров? |
Автор: volatile 7.9.2011, 00:09 |
ForceKeeper, ну раз так, то это в очередной раз показывает, что погоду в скорости копирования вносит не столько сам код, сколько попадания/промахи кеша. (верней разных кешей). У вас ведь этот код работал медленней вашей самодельной, насколько я понял? |
Автор: boostcoder 7.9.2011, 00:13 | ||
запутался ![]() |
Автор: voral 7.9.2011, 00:16 | ||
Кстати у Страуструпа есть примерно следующая реализация копирования массива. Реально дает прирост по отношению к простому поэлементному копированию. (обсуждали както на киберфоруме)
|
Автор: volatile 7.9.2011, 00:21 |
Ну он говорил, что системная работает медленней (почти в 2 раза) чем самодельная (с шортами) |
Автор: ForceKeeper 7.9.2011, 00:24 | ||||
Адреса команд этого кода в памяти?
Код в моих последних двух постах из родного memcpy и он работал многократно быстрее, чем мой примитивный тапок, копирующий по словам. |
Автор: boostcoder 7.9.2011, 00:26 |
да. спасибо. |
Автор: volatile 7.9.2011, 00:33 | ||||||
А это кто писал, или это было не из родного memcpy ?
|
Автор: boostcoder 7.9.2011, 00:33 | ||
поясни. откуда такие выводы? |
Автор: volatile 7.9.2011, 00:40 |
Почитайте последний пост на первой странице. От простой перестановки вызовов функций, скорость меняется в 3 раза. Впрочем, возможно скоро займусь этим вопросом поближе, и сам все тщательно проверю. О результатах сообщу, если будет интересно. |
Автор: boostcoder 7.9.2011, 00:49 |
тот пост подтверждает пользу привносимую кешированием самой ОС. но никак не кешем проца. ибо я понял что ты говоришь про именно про него. |
Автор: ForceKeeper 7.9.2011, 00:56 | ||
Это был не я. Кстате, вот касательно выделения памяти. Когда ковырял свой тестирующий код и поменял местами выполнение своего цикла и родного memcpy так, чтобы дефолтная функция шла первой, так ее отработка стала медленнее (но все равно быстрее моего цикла). После этого я прямо перед ней кинул цикл, в котором пробегал весь массив и кидал туда числа - скорость отработки memcpy стала преждней (т.е. быстрой)
Почему неинициализированный мусор медленнее копируется? P.S. Пока писал пост, тут уже успели упомянуть кэш операционки... |
Автор: volatile 7.9.2011, 01:09 | ||
ForceKeeper, упс, сорри. спутал вас. действительно сорри!!
Я вообще говорю о разных кешах. И о том что правильно измерить скорость очень трудно. Сам не раз убеждался что от простой перестановки функций, скорость может меняться в 3-4 раза. Поэтому судить о скорости по единичному измерениию не стоит. ForceKeeper, еще раз сорри! |
Автор: boostcoder 7.9.2011, 01:19 |
уже ответил. ты знаешь...из последних нескольких постов, сложно понять о каком кеше ты говоришь ![]() |
Автор: volatile 7.9.2011, 01:30 |
я говорю просто о других (кроме кода) причинах (и кеши в том числе) влияющих на скорость. |
Автор: xvr 8.9.2011, 12:26 |
Видимо что бы не забить каналы чтения в память. Их ограниченное число и если запустить чтений больше, чем каналов, то те команды, на которые не хватило каналов, будут остановлены. |
Автор: boostcoder 8.9.2011, 12:49 | ||
не знал о таком. точнее - не задумывался. |
Автор: ForceKeeper 8.9.2011, 21:34 | ||
В итоге я наковырял такую функцию, она хоть и значительно быстрее простого цикла, но все равно на ПК медленнее где-то на 30-40%, а на нетбуке на 50-70% чем memcpy из VS2010
|
Автор: boostcoder 8.9.2011, 21:35 |
фигасе функция ![]() |
Автор: ForceKeeper 8.9.2011, 22:17 |
Основной цикл копирования моей функции в результирующем бинарнике идентичен тому, что в мемцпу (равзе что у меня счетчик в ecx, а в родной функции в edx) Но ощутимое отстование в скорости все равно есть, хотя во всем остальном коде есть еще только 3 цикла и то, они каждый на 64, 16 и 16 соотвественно итераций макисмум. P.S. наверно родная функция еще что-то делает с данными, т.к. при увеличение объема копируемой информации разрыв в скорости растет, а основной цикл копирования идентичен, в то время как весь окруающий его код в моей функции можно принять сложность за константу |