LINUX.ORG.RU
ФорумTalks

[ничего не поделаешь, это...] доставляющая история про memcpy


0

2

http://avva.livejournal.com/2323823.html

Для Ъ будут спойлеры:

29 сентября 2010 года. Пользователь "JCHuynh" открывает новый баг на сайте Федоры о том, что 64-битный флэш-плагин от Adobe перестал нормально проигрывать mp3-файлы, выдает все время какой-то треск вместо правильного звука.
В Интеле работают хорошие программисты
А в новой, при копировании от конца к началу, выходит ошибка. Но не всегда, а лишь на некоторых процессорах и в некоторых условиях. И пока что никто этого еще не знает, в конце июня прошлого лета. 

Чипсы это яд. Не жри чипсы, не жри!

★★★★☆
Ответ на: комментарий от geekless

>Я не оцениваю количество софта, использующего UB. Я оцениваю количество софта, работающего на glibc. Подмножеством которого является софт, использующий UB, но остающийся работоспособным. Я надеюсь, количество софта на glibc вы и сами прикинуть можете.

Дилетантский подход. Проблема заключена в небольшой части проприетарного ПО, именно его закрытость и стеснительность Линуса рождают все проблемы.

а весь новый код в добровольно-принудительном порядке пересадим на полное использование memmove.

Мне не кажется, что конкретно ты примешь настолько активное участие, что можно говорить «пересадим».

На счет остальных. Пусть «пересаживают» flash 64 bit, это как раз новое программное обеспечение. Официально никто его ещё не выпускал.

Поясните, а то ничего не понятно.

В линуксе библиотеки могут зависить одна от другой, это элементарные вещи, что тут может быть непонятно.

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

Ок, но пытаться убеждать других использовать туалетную бумагу в качестве стандарта Си тоже не надо.

Это вы сейчас с кем разговаривате? Что именно вы тут собрались отличать и от чего?

Для разных программ нужны разные workarounds. Поэтому программы нужно отличать друг от друга.

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

Вы программист? Судя по постам — нет.

это не ответ на вопрос. Я программист блюдящий спеки :P

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

> Проблема заключена в небольшой части проприетарного ПО

Проблема заключена в том, что в стандарте есть две функции делающие одно и тоже, одна из которых кривая. Данный инцидент только в очередной раз показал проблему. Можно разрешить все подобные неприятности разом и навсегда, а можно так каждый раз и наступать на одни и те же грабли.

Мне не кажется, что конкретно ты примешь настолько активное участие, что можно говорить «пересадим».

Пересадят. Фанатиков среди разрабов glibc хватает, но вот дураков там вряд ли держат. Нужно только волевое решение редхатовского руководства.

Для разных программ нужны разные workarounds. Поэтому программы нужно отличать друг от друга.

В предложенном решении не нужен ни один workaround.

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

> В линуксе библиотеки могут зависить одна от другой, это элементарные вещи, что тут может быть непонятно.

Не понятна вообще ваша сентенция про библиотеки. Какая разница, что из себя являет клиентский код. В данном случае это не имеет никакого значения.

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

> У тебя, в общем-то, тоже нет аргументов в пользу изменения glibc, кроме того, что оно уже сделано.

Ну да. Спор идет о том, стоит ли откатывать изменение (и, по индукции, на что проверяются изменения в glibc - на соотвествие стандартам или bug compatibility).

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

в стандарте есть две функции делающие одно и тоже, одна из которых кривая

ЛПП чуть ли не в каждом слове.

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

в стандарте есть две функции делающие одно и тоже

Ужас, ужас, в стандарте есть несколько типов переменных! Делающих одно и то же! char, int, long int, unsigned long int, etc! Надо полагать все типы кроме одного кривые.

true_admin ★★★★★
()

glibc не нужен. И вообще, это баянище.

Deleted
()
Ответ на: комментарий от geekless

> Проблема заключена в том, что в стандарте есть две функции делающие одно и тоже, одна из которых кривая.

1. Функции делают разные вещи.
2. Обе - прямые.
3. Для одной из них неудачно выбрано название.

Проблема гораздо шире. Она заключается в том, что быдлокодеры не хотят вдумываться в то, что они делают (в том числе, не считают нужным читать документацию). Флешплеер был падучим куском говна задолго до изменения в glibc, остался таковым и после. Потому что бездумный говнокод в нем не ограничивается лишь некорректным использованием memcpy.

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

> Датычо.

Представь себе, у них разные контракты. И разное быстродействие.

Проблема может затрагивать любой код. Сколько раз повторять?


man-ы читать надо. Сколько раз повторять?

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

> одна из них намного быстрее //К.О.

Ага, на пару инструкций условного перехода. Быстра как ветер.

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

> Представь себе, у них разные контракты.

Один является подмножеством другого.

И разное быстродействие.

Еще один. Вы размножаетесь там?

man-ы читать надо. Сколько раз повторять?

Любитель решать технические проблемы социальными методами? Если библиотека не бьёт по рукам при нарушении контракта, то маны бесполезны. Или ты тоже из тех, кто всегда пишет идеальный код и никогда не ошибается?

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

> Это задача разработчика клиентского кода — никогда не использовать undefined поведение.

Да, это _обязанность_ клиентского кода.

А задача разработчика реализации — как можно корректнее обрабатывать ситуации undefined behavior, когда они всё имеют место.


Нет. Разработчик реализации может преследовать такие цели как быстродействие, портабельность, масштабируемость - и жертвовать ради них сколько-нибудь вменяемой обработкой UB. На то оно и UB.

А они будут иметь место в силу несовершенности этого мира.


Это баги, и как всякие баги, их нужно выявлять и чинить. Для чего имеются специальные инструменты. В частности, valgrind.

Иной подход — безответственность.


Не нужно безответственность отдельных быдлокодеров вешать тяжелым грузом на всё остальное сообщество. Их баги - это их проблемы, и проблемы их заказчиков.

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

> Если библиотека не бьёт по рукам при нарушении контракта, то маны бесполезны.

Если тебе нужно, чтобы за UB тебя били по рукам, то ты ошибся выбором языка. В с/с++ этого нет, и в обозримом будущем не предвидится.

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

> Не нужно безответственность отдельных быдлокодеров вешать тяжелым грузом на всё остальное сообщество. Их баги - это их проблемы, и проблемы их заказчиков.

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

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

> Так и запишем: преследуют навязчивые идеи, что системное программирование важнее прикладного.

Снова накурился? :D

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

Это баги, и как всякие баги, их нужно выявлять и чинить. Для чего имеются специальные инструменты. В частности, valgrind.

Вменяемый инструмент — это возможность собрать библиотеку с диагностикой нарушений контракта вызова. А valgrind — это подпорка сбоку.

Разработчик реализации может преследовать такие цели как быстродействие, портабельность, масштабируемость - и жертвовать ради них сколько-нибудь вменяемой обработкой UB.

Ага, особенно портабельность.

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

поэтому там и есть _две_ функции — одна специально для скорости, а другая специально для быдлокодинга

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

> одна специально для скорости

Ты так и не разобрался, сколько инструкций занимает выбор способа копирования?

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

> Ты так и не разобрался, сколько инструкций занимает выбор способа копирования?

Ты так и не разобрался, сколько тактов стоит ошибка предсказания перехода? Зачем этот оверхед в корректной программе?

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

А что коммент-то удалил?

ну-ка покажи мне условный переход, который за пару инструкций умудряется проверить пересечение и выделить правильный кусок?!

void *memmove(void *s1, const void *s2, size_t n)
{
	if (n + (char*)s2 < (char*)s1 || n + (char*)s1 < (char*)s2) {
		/* копирование без перекрытия */
	} else {
		/* копирование с перекрытием  */
	}
}
geekless ★★
()
Ответ на: комментарий от Manhunt

> Ты так и не разобрался, сколько тактов стоит ошибка предсказания перехода? Зачем этот оверхед в корректной программе?

Криокамеры подтекают, анабиозники проснулись и лезут наружу.

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

> А что коммент-то удалил?

хочу вынести срач в отдельный топик и на более глобальном уровне ;)

тем более я знаю, какой у тебя ответ заготовлен: подумаешь, выполним на 10 инструкций больше и заставим вместо линейного копирования прыгать по условиям, современные процессоры быстрые как ветер, всё стерпят. Что здесь нового?

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

> подумаешь, выполним на 10 инструкций больше и заставим вместо линейного копирования прыгать по условиям, современные процессоры быстрые как ветер, всё стерпят. Что здесь нового?

Это как раз то, что сделали в текущей версии в memcpy, ага.

выполним на 10 инструкций больше

Определение нужной ветки занимает в среднем полторы операции сложения и полторы операции перехода. Экономь и дальше на спичках.

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

> и полторы операции вычитания

Ололо.

http://people.redhat.com/wcohen/Fedora12OprofileTutorial.txt

On a modern processor a branch misprediction costs 10 to 20 clock cycles. On processors with deeper pipelines the cost is higher.

> Криокамеры подтекают, анабиозники проснулись и лезут наружу.

Это ты к чему ляпнул?

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

Определение нужной ветки занимает в среднем полторы операции сложения и полторы операции перехода. Экономь и дальше на спичках.

этому треду не хватает кода и тестов.

мой вариант:

#include <string.h>


int main()
{
  char x[] = "1234567890123456789012345678901 hi isden!";
  char y[42];

  for (long i = 0; i < 100000000; i++)
          for (int j=0; j < sizeof(x); j++)
                  y[j] = x[j];
}
#include <string.h>


int main()
{
  char x[] = "1234567890123456789012345678901 hi isden!";
  char y[42];

  for (long i = 0; i < 100000000; i++)
          memcpy(y, x, sizeof(x));
}
#include <string.h>


int main()
{
  char x[] = "1234567890123456789012345678901 hi isden!";
  char y[42];

  for (long i = 0; i < 100000000; i++)
          memmove(y, x, sizeof(x));
}

ну и время выполнения, соответственно:

for.bin

real    0m28.315s
user    0m24.407s
sys     0m0.041s


memcpy.bin

real    0m7.301s
user    0m6.374s
sys     0m0.005s


memmove.bin

real    0m9.362s
user    0m8.312s
sys     0m0.019s

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

Не верный вариант, т.к. во-первых, ничего не известно о вашей glibc и опциях сборки, а во-вторых, тестировать надо не текущие реализации memcpy и memmove, а оверхед приведенного мной условия if (n + (char*)s2 < (char*)s1 || n + (char*)s1 < (char*)s2), по сравнению с прямым вызовом memcpy.

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

>Если есть словари, нужно ими руководствоваться. ИдеОлогия исправлять правильно написанные слова в угоду твоему владению языком - ущербна.

FXD

Рыба гниет с головы

Ивану Крылову тоже есть что сказать об этом твоем высказывании... Но повторяться не хочется.

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

>Определение нужной ветки занимает в среднем полторы операции сложения и полторы операции перехода. Экономь и дальше на спичках.

На любом процессоре?

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

Я думаю всё же главное это то что спеки были нарушены и теперь программизды индусокода выступают против законных изменений.

Т.е. проблема в политической плоскости. А +-10 инструкций действительно фигня, кому нужна скорость тот давно свои функции заинлайнил и вообще libc не слишком-то использует в критических местах. Говорю так потому что щас плотно общаюсь с оптимизаторами.

Адобу, конечно, ничто уже не поможет.

Линус предлагает нормальное решение(#define memcpy memmove), но мотивирует он его неправильно. Юзеры, конечно, ни в чём не виноваты, но перекладывать проблему с больной головы(адоб и сквашфс) на нормальную(глибц) это бред. Чем меньше костылей в библиотеках тем лучше, ядро и glibc и так понапичканы ими, зачастую(судя по комментам) баги тянутся чуть ли не с первой половины 90-х.

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

На любом процессоре?

Даже любопытно стало как это сделано в андройде... Щас сырцы посмотрим...

true_admin ★★★★★
()

Сходил по ссылкам, оттуда по ссылкам, почитал каменты тут, опечален. Походу, никто не понимает, в чём проблема, споря лишь о конкретных реализациях.

Постараюсь рассказать, как я вижу эту ситуацию, начну с очевидного. ОС - уровень абстракции над железом, позволяет писать программы быстрее, вынося наиболее полезные операции из программ. Например, можно писать программы, не заботясь о многозадачности, ФС на диске и отрисовке на экране. Это, безусловно, плюс. Следствие - уровень абстракции с точки зрения приложения должен быть одинаков везде, иначе он нафиг не нужен.

Разработчики глибц это поломали. Их новая функция memcpy делает разные вещи на разном железе. Это баг и этот код должен быть выпилен в пользу кода, который одинаково работает на любом железе.

Проблема в том, что открытый баг разработчики глибц видят как «криво написанный флеш-плагин не работает на вашем глибц, пофиксите» и активно возражают. Да, флеш-плагин написан криво. Но пофиксить глибц нужно не затем, чтобы он заработал. Например, фикс когда memcpy всегда и везде копирует задом-наперёд будет фиксом для глибц, но флеш останется поломанным.

Путей фикса я вижу ровно три:

1) Сохраняем стратегию «тупой и быстрый memcpy, умный и медленный memmove»

Разработчики этого явно не хотят, их кривой патч существенно усложняет memcpy.

2) Забиваем на исторические причины и делаем «умный memcpy».

По очевидным причинам - в этом случае не следует содержать несколько одинаковых сущностей - memcpy должен стать алиасом на memmove. Этот путь предлагает Линус Торвальдс.

3) Считаем, что behavior is undefined означает, что периодически memcpy может попытаться приготовить пользователю кофе.

Дрепперу и иже с ним я предлагаю следующую реализацию memcpy: обычно работаем как memmove, но каждый чётный понедельник забиваем область пересечения рандомом в качестве напоминания девелоперам об исторических корнях memcpy и выявления криворуких кодеров.

З.Ы. по моим собственным измерениям, старая тупая реализация memcpy лишь на 20-25% быстрее memmove. Новая реализация memcpy медленнее. Но даже в случае со старой перехода с одного на другое в подавляющем большинстве случаев никто не заметит. Поэтому я голосую за путь, предложенный Линусом.

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

Разработчики глибц это поломали

Разработчики glibc НИЧЕГО НЕ ЛОМАЛИ! memcpy работала по стандарту, работает по стандарту, и будет работать по стандарту!

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

behavior is undefined означает,

Что функция иногда может пристрелить пользователя. В прямом смысле - из монитора высунется дуло и пристрелит идиота.

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

а вы сами то в курсе, сколько стоит ошибка предсказания перехода, и при каких условиях она не происходит?

код memmove просто ставится позже кода memcpy делаются два сравнения и два условных перехода вперёд. ~3 клока, по дефолту переход вперед не предпринимается.

а memmove все равно будет фэйлить на ошибках предсказания. много там не наоптимизировать.

ckotinko ☆☆☆
()
Ответ на: комментарий от Xellos

memcpy работала по стандарту, работает по стандарту, и будет работать по стандарту!

Вот и нет. В стандарте на случай пересечения - undefined, т.е. стандарт поведение не регламентирует вовсе.

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

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

ЗЫ: memcpy нужна, тупая как пень и копирующая быстро 20-100 байт памяти. не часто требуется перегнать кучу килобайт.

ckotinko ☆☆☆
()

"...но виновен не жираф, а тот кто крикнул из ветвей - жираф большой, ему видней" (с)

shty ★★★★★
()

И да, у Криса Касперски есть хорошая статья по memcpy/memmove и их оптимизации

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

> Что функция иногда может пристрелить пользователя. В прямом смысле - из монитора высунется дуло и пристрелит идиота.

С нетерпением жду, когда система пристрелит тебя из-за ошибки в одном из сотен пакетов, стоящих у тебя в системе. Да-да, лично тебя из-за ошибки совершенно незнакомого тебе чувака.

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