Pull to refresh
0
0
Send message

Может об отсутствии тех самых костылей для компенсации работы с медленной памятью?

Если бы у нас был процессор, который быстро работает с памятью

Если бы у нас была быстрая память

Первая цитата о медленно работающем с памятью процессоре, а ваша цитата о медленной памяти. Это же разные вещи.

Да

Звучит примерно как: аппаратура успешно декодирует видео, а совтферно это сделать нереально. Неужели аппартные оптимизации сделать проще, чем аналогичные компиляторные?

Само по себе не так важно, в какой микрокод и как что-то оттранслировалось. Важно по итогу с какой скоростью мы этот код исполняем. Здесь приведено сравнение, что одну итерацию цикла на Эльбрусе мы исполняем 13 тактов, а на x86 только 3. Т.е. по итогу время исполнения всей задачи будет отличаться на 13/3 = 4.33 раза при условии, что частота Эльбруса будет равна частоте x86. Т.е. таким образом мы рассчитываем микроархитектурную скорость каждого процессора.

Хорошо. Но тогда получается, что вы пытаетесь сравнивать принципиальные характеристики архитектур сравнивая конкретных представителей этих архитектур и возможности конкретных компиляторов.
Ваше утверждение доказывает, что обсуждаемый Эльбрус медленее Core I5, но не доказывает, что VLIW процессоры принципиально медленнее OoO процессоров.

Трудоёмкость разработки под архитектуру Эльбрус, ввиду высокой сложности ассемблера широкой команды и необходимости постоянно проводить анализ кода и его изменение для достижения приемлемых цифр производительности (в Эльбрусе без этого никак, т.к. здесь если компилятор не справился, то аппаратура не подстрахует. А не справляться компилятор будет постоянно по вполне объективным причинам)

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

В итоге, микроархитектурная скорость исполнения данного кода на x86 превышает Эльбрус в 13/3 = 4.33 раза. Т.е. во столько бы раз проиграл Эльбрус, будь он по частоте сопоставим с топовыми RISC/CISC системами.

Опять не совсем понятно. Я конечно не специалист в этой области, но насколько мне известно код x86 в современных микропроцессорах декодируется в некоторый внутренний микрокод, который затем оптимизируется и выполняется.
В Эльбрусе же такого не происходит и VLIW-команда сама по себе является аналогом такого вот внутреннего микрокода.
Но тогда ваше сравнение получается некорректным.
Поправте, пожалуйста, если я ошибся.

зависит. Если у вас сишный код, на каждом шагу жонглирующий (unsigned) char* и сериализующий/десериализующий пустое в порожнее, то да, толку маловато будет. Тем временем потенциальная возможность включить в rust повсеместный strict aliasing является одним из важнейших его selling point'ом в вопросах производительности относительно с++.
Все-таки хотелось бы каких-то реальных примеров. То есть берем некую реальную программу и компилируем ее с оптимизацией strict aliasing и без. И сравниваем производительность.
Если верить изначальному тезису, то производительность с опциями -O3 -f-no-strict-aliasing будет разительно отличаться от просто -O3 и будет приближаться к -O0
Вот смотрите, с т.з. компилятора: если в функцию пришло два внешних указателя — то без шансов что-то про них доказать (в том числе часть случаев — доказать можно было бы возможно, но для этого надо заново запустить межпроцедурный анализ, а уже нельзя, т.к. он делается на другом представлении). Остаётся:
— ничего не оптимизировать;
— дублировать код для случаев «непересекающихся» и «пересекающихся» объектов;
— работать, как будто нет UB;
— взять «rust», с более ограниченным набором возможностей в rust-safe, чем C.
Я думаю, вы исходите из ложной предпосылки, что невозможность доказать отсутствие нарушения strict aliasing будет блокировать остальные оптимизации. Я не согласен с этим.
Вы можете сами проверить свой тезис указав компилятору GCC опцию -fno-strict-aliasing запретив компилятору предполагать, что указатели разных типов обязательно указывают на разные данные.

Оптимизация основанная на strict aliasing вообще практически бесполезна. А в тех редких случаях когда она играет важную роль, можно оптимизировать вручную, вплоть до кода на ассемблере.
Анализ алиасов указателей в C-коде алгоритмически неразрешим.
Что вот совсем никогда не разрешим? Спорное утверждение. Даже банальное отсутствие принудительных преобразований типов на участке кода говорит об отсутствии нарушений strict aliasing.
И насколько часто в среднестатистических программах на C встречаются места с потенциальным UB связанным с нарушением strict aliasing?
А в программах на C++?
Да, конечно, если сделать поиск с заменой и заменить в стандарте понятие “undefined behavior” на “говнокод”, то, разумеется, оптимизирущий компилятор, опирающиймся не на отсуствие “undefined behavior”, а на отсуствие “говнокода” сделать будет можно.
ШТА? «Да что ты, чёрт возьми, такое несешь?»
Ладно, я полагаю, что все желающие смогли ознакомиться с моими и вашими аргументами и сделать соответствующие выводы. Дальнейшую дискуссию с вами считаю бессмысленной. Оставайтесь при своем мнении.
Трудно сказать. Всякое в жизни случается. Но думаю, что в подавляющем большинстве случаев толку от этой оптимизации с гулькин нос. КМК во многих случаях компилятор способен проанализировав код доказать (а не понадеятся на честное слово), что нарушения strict aliasing не было и сделать соответствующую оптимизацию.
Если я верну обратно const, то функция превратится в простую return 0. Кстати, ack достаточно простая для того, чтобы компилятор видел, что она не имеет сайд-эффектов.
Ага, превратится. Доказательства отсутствия сайд-эффектов недостаточно для свертки констант. Необходимо, чтобы вычисление этой константы требовало бы не слишком болшого количество ресурсов.
Кстати, как вам такой constant propagation?
Великолепный образчик то ли бага, то ли безумия. Разрешить вылезти за пределы массива, и затем просто выкинуть этот кусок кода. Чудненько. В более поздних версиях ситуация стала получше, но все еще недостаточно хороша.

Именно. Про то и речь!
Так речь-то не про то. Я же говорю, вы не читали дискуссию.
Нет, я просто пользуюсь формальной логикой, отталкиваясь от тезиса, что понятие UB и предположение об отсутствии UB в коде программы позволяет компилятору делать некоторые оптимизации.
Значит верно второе мое предположение, что вы на своей волне.

Спор-то не о том, опираются ли текущие реализации компиляторов C/C++ на понятие UB. Очевидно, что в некоторых случаях опираются. С этим я не спорю и не спорил изначально.

Спор о том действительно ли почти все оптимизации в среднестатистической программе опираются на понятие UB? Я с этим категорически не согласен. Это будет верно только для программ, которые почти полностью состоят из переполнений, бесконечных циклов, модификаций констант и так далее. Даже в случае подобных хаков, гипотетический компилятор без учета UB способен в каких-то случаях корректно применить оптимизацию. Для нормальных же участков кода в плане оптимизации у такого гипотетического компилятора ничего не изменится.

Кстати, ваши примеры только лишний раз доказывают, что многие оптимизации, которые опираются на понятие UB бесполезны, и даже вредны.
Именно! Про то и речь! В данном случае он может убрать эту запись, выполнив соответствующую «оптимизацию» именно потому, что это UB.
Ну так с этим и боремся вроде.
Ок, убрал: gcc.godbolt.org/z/751E151M4
Где свёртка константы?
Непонятно, что вы хотели сказать этим примером. Очевидно, что причина в сложности кода функции. Эта сложность, видимо, достаточно большая, чтобы компилятор не смог применить свертку. Помешала ему именно сложность кода, а не то, что вы убрали UB.
Ведь если сделать код чуть-чуть проще, то свертка снова начинает работать: gcc.godbolt.org/z/o13W3Y9bP

У меня сложилось впечатление, что вы нарочно поэтапно усложняли функцию добиваясь «отказа» оптимизатора. Правда непонятно зачем.
Добавьте const в примере выше. Где там правильная свёртка?
Ну так потому что компилятор опирается на понятие UB.

Такое впечатление, что вы либо троллите, либо вообще не читали, о чем собственно идет дискуссия и пишете что-то на своей волне.
Радует, что кто-то понял, о чем я говорю.
Конечно же нет. Но только в этом случае компилятор программу компилирует без ошибок, но запись в эту переменную игнорирует.
Ну так если убрать из стандарта, что модификация константы это UB, то компилятор уже не смог бы игнорировать эту запись. И он ее не игнорирует, если снять константность и тем самым вынудить компилятор не делать ошибочных предположений. То бишь убирание в данном случае UB не мешает компилятору применить свертку константы. ЧТД.
Конечно же нет. По ссылке выше со снятием константности результат меняется, и компилятору его неизменность не получится доказать при всём желании.
Нет, но он мог бы. Мы же тут гипотетическую возможность обсуждаем, а не текущее положение дел. В данном случае компилятору не нужно доказывать неизменность, ему достаточно доказать, что оптимизация не меняет конечный результат. И компилятор определенно может это сделать без опоры на предположения об отсутствии UB. И он это делает, если убрать константность. То бишь, попытка надуть компилятор выполнив изменение через указатель не сработала, он отлично просекает такие «хитрости» и в состоянии сделать правильную свертку.
Ясно. “Гуманитарная одарённость” есть, знания русского языка нет. Wikipedia, может помочь: ru.wikipedia.org/wiki/%D0%AD%D0%BD%D0%B0%D0%BD%D1%82%
Вы бы сами прочитали свою статью. Описываемое там явление не имеет ничего общего с тем, что происходит у вас.
Сегодня это во много раз важнее, чем “много лет назад”. Именно потому, что раньше процессоры были маломощными и вам не нужно было, скажем, стараться кешировать значения в регистрах.
Это отдельная дискуссия, мне она не особо интересна, если честно. Могу только сказать, что разница в два раза это очень даже серьезно. Ради нее определенно стоит оптимизировать. Ну и существуют довольно ресурсоемкие оптимизации (та же свертка констант) для которых ваша аргументация не работает.
Не упростить, а “сделать возможным”. Ибо в случае с C и C++ огромнейшее количнество, как вы выражатесь, “говнокода” не может появиться в программе только потому, что попытка его использовать будет считаться UB.
Не согласен. Люди не говнокодят не из страха перед UB (хотя и это тоже немного влияет), а потому что говнокод сложно поддерживать. Если убрать понятие UB, то компилятор перестанет оптимизировать говнокод (туда ему и дорога), а нормальный чистый код будет оптимизироваться прекрасно.
Даже и близко нет. Все (ну или почти все) оптимизации в реально существующих компиляторах опираются на отсуствие UB.
В данном случае я говорил не о компиляторах C/C++, а о бэкендах, например GCC/LLVM, которые умеют кучу оптимизаций для самых разных языков, как с опорой на отсутствие UB так и без него. То есть все уже сделано, достаточно просто желания разработчика компилятора.
Скажем без запрета на обращение к переменным вне их области видимости (что происходит в примере, который вызвал у вас такую неприязнь) мало чего вообще можно наоптимизировать
Почему это вы так решили? Еще раз. Компилятор в состоянии доказать, что вот в этом вот куске программы нет никакого обращения к переменным вне области видимости, и соответственно его можно безопасно оптимизировать.
Понимаете?

Если ваша программа сплошь и рядом состоит из непрозрачных «грязных» хаков, то да, соглашусь, компилятор практически ничего не сможет соптимизировать. Но в реальности люди уже давно так не пишут. Даже в программах с жестким реальным временем, даже если каждый такт и байт на счету.
Поэтому практически любой современный код может быть проверен компилятором на отсутствие «сюрпризов» и соптимизирован. Проверен не так как сейчас в C/C++: «мамой кланус тут нэт UB», а с математическим доказательством.
Переделывать язык тотально не обязательно. Просто в случае Rust компилятор будет оптимизировать немного чаще, чем в C/C++.
Ваша категоричность совершенно не в тему.
Критерии допустимости изменений результата могут варьироваться в зависимости от конкретных требований программиста. Поэтому оно может быть «верно», а может быть и «неверно». Общий случай рассматривать бессмысленно.
В подавляющем большинстве случаев изменение времени выполнения и размера кода являются приемлемыми. Более того они являются целью оптимизации.
Я уже упоминал ранее, что на практике случаются ситуации, когда изменения времени выполнения оказываются недопустимыми. Для таких случаев в компиляторах предусмотрены различные конструкции вплоть до ассемблерной вставки.
Ничего не понял. Почему вы банальность, достойную Капитана Очевидность называете супертезисом?
Потому что с точки зрения русского языка эта банальность некорректна. «Опираться на баги» и «опираться на отсутствие багов» — прямо противоположные утверждения. В общем-то это был камень в форму вашего первоначального изречения:
Вообще-то, внезапно, все оптимизации (ну или почти все) опираются на UB.
Но, вероятно, камень был несправедливым, потому что вы имели в виду само понятие UB. То есть оптимизации опираются на сам факт присутствия понятия UB в стандарте языка. С этим трудно спорить, возможно так и есть. Ведь это может сильно упростить реализацию оптимизаций в компиляторе. Особенно это было важно как раз много лет назад, когда и компьютеры были относительно маломощными.

Но мой главный тезис немного о другом, а именно:
наличие понятия UB в стандарте не является необходимым условием для сколь-нибудь значимой оптимизации. То есть можно обойтись и неплохо оптимизировать. Да, для этого придется серьезно усложнить компилятор. Но, по моим прикидкам это уже сделано.
С тех пор, как вы сказали “От любого UB только вред. В нём нет пользы”.
И как из этого следует ваше определение инициализации?
Соотвественно компилятор может полагаться на то, что программист такого не делает.
А может и не полагаться. Текущий C полагается, но если вдруг перестанет, он не станет от этого неоптимизируемым.
Вау! В голове у пациента обнаружен мозг! Ды, вы правы, оптимизации действительно на всё это опираются!
Вау! У пациента обнаружен переход на личности Только вот такое обобщение ваших тезисов абсолютно бесполезно и бессмысленно. Как в том анекдоте про Холмса на воздушном шаре и математика.
Вы тут уже многократно завляли бред: что программы на C можно оптимизировать, не опираясь на отсутствие в них UB.
Возможно какое-то тотальное непонимание. Может я недостаточно ясно выражаюсь, не знаю. Попробую еще раз.

Компилятору на данный момент разрешено опираться на предположение об отсутствии UB, игнорируя реальное положение дел. Например, он видит const и делает предположение, что переменная не будет далее меняться, а она на самом деле меняется. Но введение UB в стандарт разрешило компилятору плевать на реальность. Fail.
А теперь выбрасываем из стандарта вообще само понятие UB. Все, нет никакого UB. Все разрешено, кроме непосредственно ошибок компиляции.
Что получаем. Компилятор больше не может делать никаких предположений, он обязан применять оптимизации только в тех случаях, в которых он в состоянии доказать, что ничего кроме времени выполнения и размера кода не поменяется. Если доказать не может (в принципе невозможно или слабый анализатор кода или просто ради скорости компиляции, не важно), то данная часть программы не оптимизируется, а выполняется в точности как написано в исходнике. Win.

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

На остальной ваш текст отвечать не буду, так как там либо выпады основаные, вероятно, на непонятых моих тезисах, либо попытки оскорбить, либо отсылки к ложному авторитету аудитории Хабра.
Кстати, почему так много вроде бы неглупых людей, искренне считающих оскорблением слово «гуманитарий»? Какая-то забавная инфантильность.
К чему эта странная дихотомия? Вы не допускаете ситуации, когда какие-то участки программы оптимизируются, а какие-то нет?
В таком случае вы должны уметь объяснить как оптимизировать все те программы, которые мы 0xd34df00d напридлумывали. Вперёд и с песней.
Приведенный пример со сверткой констант, как раз таки оптимизируется на раз. Достаточно чтобы компилятор перестал учитывать константность при оптимизации. Может вы наивно полагаете, что свертка констант работает только для const-переменных? Тогда вы глубоко заблуждаетесь.
Не будет она работать. Так как компилятор может тупо не видеть того кода, который констранту будет модифицировать. В конце-концов я могу этот адрес записать файлик, а потом, совсем в другой функции, прочитать и константу модифицировать. И всё, и нельзя будет константы сворачивать.
Ну так в таком случае оптимизация не проводится. Компилятор оптимизирует в том случае, если он может доказать, что конечный результат оптимизируемого участка не изменится в результате этой самой оптимизации.
Далее упираемся в критерии, что именно считать тем же результатом. Например, изменение времени выполнения ни один компилятор не считает изменением результата (иногда это мешает, к счастью существуют средства объяснить компилятору, что время в данном месте тоже надо учитывать). Брать ли в расчет отсутствие UB или не брать — опциональное решение не особо влияющее на качество оптимизации даже в C.
Проблема в том, что он опирается на подобное предположение не в некоторых случаях, а почти во всех. Ну разве что 2 * 2 вы на 4 можете безболезненно заменить. И то только тогда, когда обе двойки у вас прямо в коде написаны. Если хотя бы одна из них константа — всё, уже ничего менять нельзя. И переменные в регистры со стека поднимать нельзя. И вообще много чего нельзя.
Неверно. Если вы хотите модифицировать константу просто не делайте ее константой. UB пропадет, а оптимизация, если она была с константой, останется. Можно, наверное, придумать какие-то замысловатые случаи, но они погоды не сделают.
Я много пишу на D, в том числе и довольно низкоуровнего кода, но к UB я прибегаю крайне редко (когда надо обойти несовершенство языка или баг компилятора, а не ради ручных оптимизаций). И, внезапно, все оптимизируется шикарно, особенно свертка констант меня радует.
Вы, видимо, плохо себе представляете возможности современных компиляторов. Застряли в 60-х?
Здравствуйте, я ваша тётя. Кто сказал что они неинициализированы? Они в одной функции инициализируются, в другой используются. В чём проблема?
С каких это пор в C это называется инициализацией? Вы опять изобретаете свою собственную терминологию и применяете ее в качестве аргументов.
Вы издеваетесь или как? Разумеется если вы замените j на 2, то результат будет 6.
Это как раз вы издеваетесь. Потому что это совершенно не разумеется. По крайней мере в языке C версии этого тысячелетия.
Фишка этой программы в том, что тут нет “неиницилизированных переменных”. Они инициализируются. В функции foo. А потом используются. В функции bar
Единственная фишка этой программы в том, что она ломается от малейшего чиха. Даже если компилятор и его режимы заморожены намертво.
Поскольку переменные инициализированы, то мы знаем ответ.
В том-то и дело, что мы не знаем ответ, мы можем только догадываться и надеятся, что он всегда будет таким.
Это был нормальный и поддерживаемый стиль в 60е. Более того, на калькуляторах этот стиль и сегодня используют, почитайте про ans: tibasicdev.wikidot.com/68k:ans
А причем тут C в 2021 году?
А про то, что программы с UB вы умеете как-то оптимизировать — это ж вы сказки поёте, не я.
По-моему, вы ударились в чистую демагогию. Рассуждая по-вашему мы приходим к выводу, что оптимизации опираются на все что угодно: на отсутствие багов в железе, на допустимый температурный режим работы процессора, на наличие мозга и отсутствие кривых рук у программиста в конце-концов. Вы только посмотрите, сенсация, оптимизации сущестуют только благодаря говнокоду родом из 60-х. Принимаем вашу логику и терминологию и идем еще дальше, супер тезис: корректность любой программы опирается на баги (ну то есть на их отсутствие).
Оптимизируйте. Ну или расскажите, хотя бы, как вы собрались это делать, чтобы подобный класс программ не ломался.
Я уже рассказывал, но вы отказываетесь понимать.
1

Information

Rating
Does not participate
Registered
Activity