Здравствуйте, remark, Вы писали:
R>Здравствуйте, sokel, Вы писали:
S>>Интересуют предложения по оптимизации.
R>Оптимизация таких вещей — это всегда платформенно-зависимая вещь. R>Во-первых, тебе надо определиться, для чего ты хочешь применять эту функцию. Варианты: для копирования маленьких областей, для копирования очень больших областей, для всего подряд. R>Например для копирования очень больших областей на x86 тебе надо применять non-temporal сохранения + non-temporal предвыборку в L1$ + барьер на запись. Смотри описание и гугли по инструкциям MOVNTQ, PREFETCHNTA, SFENCE.
А потом, когда все сделаешь, надо замерить время выполнения приложения, и увидеть что твоя ф-ия копирования занимает меньше 1% времени. и выкинуть ее.
Здравствуйте, Сергей Мухин, Вы писали:
СМ>Здравствуйте, remark, Вы писали:
R>>Здравствуйте, sokel, Вы писали:
S>>>Интересуют предложения по оптимизации.
R>>Оптимизация таких вещей — это всегда платформенно-зависимая вещь. R>>Во-первых, тебе надо определиться, для чего ты хочешь применять эту функцию. Варианты: для копирования маленьких областей, для копирования очень больших областей, для всего подряд. R>>Например для копирования очень больших областей на x86 тебе надо применять non-temporal сохранения + non-temporal предвыборку в L1$ + барьер на запись. Смотри описание и гугли по инструкциям MOVNTQ, PREFETCHNTA, SFENCE.
СМ>А потом, когда все сделаешь, надо замерить время выполнения приложения, и увидеть что твоя ф-ия копирования занимает меньше 1% времени. и выкинуть ее.
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, sokel, Вы писали:
S>>Предлагаю на растерзание функцию копирования строк, аналог strncpy, без недостатков оной. Не заполняет остаток нулями, всегда в конце вставляет 0. На входе принимает размер буфера назначения, на выходе дает число скопированных символов. Интересуют предложения по оптимизации.
N>Прокомментирую не только по оптимизации
N>Во-первых, интерфейс strncpy() действительно немного неадекватен обычному использованию — дело в том, что эта функция была придумана в Unix именно для заполнения полей фиксированного размера так, чтобы они потом были пригодны для memcmp (а не с ограничением по размеру), поэтому там доливание нулями. Поэтому все тесты, в которых размер приёмника больше размера источника, заведомо неадекватны; сравнивать надо не с классической strncpy(), а с, лучше всего, strcpy_s() или strncpy_s() (ISO drafts, из платформ — последние MSVC). Если же смотреть на приведённые дальше сравнения скоростей, Ваша strncpy заметно проигрывает штатной memcpy(), а это показывает, что таки старания на Си не дают достаточного результата, и ассемблер тут таки прогрессивнее. (Разумеется, если надо так делать. Я не премину повторить, что NUL-terminated strings — зло, и от них надо избавляться при любой возможности.)
не имеет смысла сравнивать strncpy не должна заменять memcpy, а то что memcpy быстрей, это и ежу понятно, фиксированный размер копируемой области, отсутствие проверки на 0.
N>Во-вторых, если strlen(src)>=dst_size, я бы делал не так — буфер заполняется полностью, \0 в него не дописывается, а возвращается dst_size. (Кстати, оригинальная strncpy делает именно так.) Это позволяет немедленно проверять на переполнение; у Вас же не отличить переполнения от полного заполнения буфера. Если кому нужна в таком случае урезанная строка, он может и вручную дописать \0 в конец буфера.
Проверить на переполнение просто — достаточно сравнить с нулем источник, по возвращенному смещению. А если такая проверка не нужна, то надо постоянно дописывать 0, то есть писать в конец буфера, который может быть довольно большим, опять таки cache latency.
Здравствуйте, remark, Вы писали:
R>Здравствуйте, sokel, Вы писали:
S>>Интересуют предложения по оптимизации.
R>Оптимизация таких вещей — это всегда платформенно-зависимая вещь. R>Во-первых, тебе надо определиться, для чего ты хочешь применять эту функцию. Варианты: для копирования маленьких областей, для копирования очень больших областей, для всего подряд. R>Например для копирования очень больших областей на x86 тебе надо применять non-temporal сохранения + non-temporal предвыборку в L1$ + барьер на запись. Смотри описание и гугли по инструкциям MOVNTQ, PREFETCHNTA, SFENCE. R>Во-вторых, погляди, не можешь ли ты наложить какие-то дополнительные ограничения на входные данные. R>Например ты можешь потребовать, что бы обе области были выровнены на 16 байт + размер памяти под области тоже кратен 16 байтам. Тогда ты можешь не обрабатывать отдельным образом начало и конец области, а сразу и до конца шпарить по 16 байт. Я думаю, это должно дать выигрыш для маленьких областей, т.к. функция будет маленькой и простой и без дополнительных ветвлений. R>Если же ты хочешь функцию портируемую, для всех размеров областей и без дополнительных ограничений на входные данные, то тут и никакого простора для оптимизаций нет. Остаётся только оставить функцию как есть и надеяться на оптимизатор компилятора. Но тут ты скорее всего всегда будешь отставать от библиотечной memcpy() и от intrinsic'а компилятора.
R>
Нужна была именно портируемая функция для любых размеров. Оптимизация интересна в плане С. memcpy конечно быстрей, но тут речь всё таки о строках, memcpy на 0 не проверяет. А вот дополнительные реализации, не требующие проверки на выравнивание источника и/или назначения — хорошая мысль.
Здравствуйте, sokel, Вы писали:
N>>Во-вторых, если strlen(src)>=dst_size, я бы делал не так — буфер заполняется полностью, \0 в него не дописывается, а возвращается dst_size. (Кстати, оригинальная strncpy делает именно так.) Это позволяет немедленно проверять на переполнение; у Вас же не отличить переполнения от полного заполнения буфера. Если кому нужна в таком случае урезанная строка, он может и вручную дописать \0 в конец буфера. S>Проверить на переполнение просто — достаточно сравнить с нулем источник, по возвращенному смещению.
Это значительно более громоздко писать, чем проверку вида if(strlcpy(dst,src,size)>=size){типа всё плохо;}
S> А если такая проверка не нужна, то надо постоянно дописывать 0, то есть писать в конец буфера, который может быть довольно большим, опять таки cache latency.
"Если такая проверка не нужна" — случай, когда надо просто усечь строку без всяких других последствий — крайне редок. Даже если пишешь отладочный лог (а я с ходу что-то не найду другое применение такому усечению), надо как-то указать, что строка закончилась раньше, чем допустимое место в записи в логе. А вот нормальная проверка — нужна постоянно.