П>>One of my friends got 96MB of memory on his machine to test that we didn’t tank under “insanely huge memory configurations” and we all drooled.
ЕМ>То есть, если Вам вдруг приспичит подключить к одной машине, скажем, 25 или 50 последовательных портов, и система откажется грузиться, Вы воспримете это, как должное?
Нет. Но вот почему-то когда речь заходит о линуксе, там сразу начинают говорить, что покупайте совместимое оборудование. А тут наоборот — если мне надо подключить 25-50 портов, то я бы озадачился вопросом, какая ОС позволит мне работать с таким количеством портов. Если ОС не грузиться — хорошо, вычеркиваем эту ОС из списка.
Re[9]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>видимый размер ATA дисков обрезался до остатка от деления на 32GB. N>>в целом сам стиль кодирования на C/C++ провоцирует на такие ошибки. ЕМ>Да ладно. В каком языке есть хоть какая-то защита от неправильного применения хоть деления с остатком, хоть обычного деления?
Смотря что считать защитой и что — языком.
В современных процессорах, как правило, деление на 0 или деление с переполнением не вызывает исключения. RISC-V обещает, что беззнаковое деление на 0 даст ~0 (как UINT_MAX).
Язык может генерировать исключение на это или подставлять такой же безопасный дефолт. Если исключение отражается в видимой диагностике, это можно было бы написать.
Но я не про деление как таковое (кстати, почему ты думаешь про деление? может, там что-то другое было), а про вообще подход, что не предполагается обрабатывать ошибки в арифметике, потому что нет возможности их отобразить в результате операции.
ЕМ>С 480 Мб для Win 95 косяк был не в том, что выбрали фиксированный разумно достаточный размер пула, а то, что вместо игнорирования "лишней" памяти получился отказ в загрузке всей системы. Если и ставился вопрос "а вдруг памяти окажется до хренища?", то ответ "в таком случае надо выйти из ситуации корректно" явно не фигурировал.
Ты не знаешь, что там точно было.
Я не знаю, что там точно было.
Вот тебе вариант совершенно навскидку, но для меня выглядит правдоподобно: сначала код получал объём памяти через вызов B-1588. Тот отдаёт килобайты после 0x100000 в AX, соответственно, предел в 64MB (плюс 640KB). Они заточились чуть наперёд на то, что его можно расширить, например, до 256MB, если кто-то отрапортует новыми средствами, и соответственно рассчитали размеры таблиц. Потом кто-то другой в другом месте перевёл запрос доступной памяти на использование вызова B-15E801, который способен отдать к нему дополнительно "DX = configured memory above 16M, in 64K blocks", соответственно до 4GB, а код в построителе таблиц для пейджинга просто не обновили соответственно. Оно выдержало и 256MB, и много следующих размеров типа 384MB, но на 480MB стало падать.
В результате, проблема не техническая, а административная: если бы результаты второй правки были адекватно отрапортованы в первую, то проблемы бы не было. А использовать тотальный defensive programming между собственными микро-компонентами в пределах одной службы... как по мне, это избыточно в 99.99% случаев, толку нет.
Если возражаешь — покажи код. Я подозреваю, что код старта Windows 95 где-то давно утёк, только я, увы, в существующих утечках видел только сильно более поздние версии. Пока кода нет — обсуждать дальше нет смысла.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>С 480 Мб для Win 95 косяк был не в том, что выбрали фиксированный разумно достаточный размер пула, а то, что вместо игнорирования "лишней" памяти получился отказ в загрузке всей системы. Если и ставился вопрос "а вдруг памяти окажется до хренища?", то ответ "в таком случае надо выйти из ситуации корректно" явно не фигурировал.
Вряд ли такой дизайн был. Банальный баг, скорее. Ну в момент выхода системы, предназначенной для 386sx/4V, не пришло в голову тестить её с 480 Мб памяти. Если вообще в тот момент такую конфигурацию вообще можно было собрать, в чем я сомневаюсь
Re[10]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, netch80, Вы писали:
N>В современных процессорах, как правило, деление на 0 или деление с переполнением не вызывает исключения
И это очень странно. Из каких соображений это делается?
N>RISC-V обещает, что беззнаковое деление на 0 даст ~0 (как UINT_MAX).
Такой подход ломает одно из основных свойств целочисленного деления (модуль частного не больше модулей делимого и делителя).
N>Язык может генерировать исключение на это или подставлять такой же безопасный дефолт.
В чем "безопасность" такого дефолта? Вот имеем байтовое смещение, делим на размер элемента, ожидаем получить индекс элемента. Вместо размера по ошибке делим на нуль, получаем UINT_MAX, применяем в качестве индекса. В соседней теме
смотрим, какая доля участников высказалась против автоматической вставки проверок индексов. Какую перспективу имеем?
N>Если исключение отражается в видимой диагностике, это можно было бы написать.
N>вообще подход, что не предполагается обрабатывать ошибки в арифметике, потому что нет возможности их отобразить в результате операции.
Почему нет? Или предусмотреть перехват возможного исключения, или проверить операнд(ы) перед выполнением операции.
N>Ты не знаешь, что там точно было.
Почему? Я точно знаю, что система переставала загружаться.
N>Я не знаю, что там точно было.
N>Потом кто-то другой в другом месте перевёл запрос доступной памяти на использование вызова B-15E801, который способен отдать к нему дополнительно "DX = configured memory above 16M, in 64K blocks", соответственно до 4GB, а код в построителе таблиц для пейджинга просто не обновили соответственно.
А можно было просто иметь одну функцию вроде GetMemorySize, которая определяет объем памяти любым удобным образом, тогда и части кода согласовывать не придется.
N>использовать тотальный defensive programming между собственными микро-компонентами в пределах одной службы... как по мне, это избыточно в 99.99% случаев, толку нет.
В ортогональности и унификации всегда есть толк.
Re[11]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>В современных процессорах, как правило, деление на 0 или деление с переполнением не вызывает исключения ЕМ>И это очень странно. Из каких соображений это делается?
We considered raising exceptions on integer divide by zero, with these exceptions causing a trap in most execution environments. However, this would be the only arithmetic trap in the standard ISA (floating-point exceptions set flags and write default values, but do not cause traps) and would require language implementors to interact with the execution environment’s trap handlers for this case. Further, where language standards mandate that a divide-by-zero exception must cause an immediate control flow change, only a single branch instruction needs to be added to each divide operation, and this branch instruction can be inserted after the divide and should normally be very predictably not taken, adding little runtime overhead.
The value of all bits set is returned for both unsigned and signed divide by zero to simplify the divider circuitry. The value of all 1s is both the natural value to return for unsigned divide, representing the largest unsigned number, and also the natural result for simple unsigned divider implementations. Signed division is often implemented using an unsigned division circuit and specifying the same overflow result simplifies the hardware.
N>>RISC-V обещает, что беззнаковое деление на 0 даст ~0 (как UINT_MAX). ЕМ>Такой подход ломает одно из основных свойств целочисленного деления (модуль частного не больше модулей делимого и делителя).
Попытка деления на 0 вообще бессмысленна в пределах целых чисел. Что именно возвращать в таком легко детектируемом случае — вопрос реализации. См. выше.
N>>Язык может генерировать исключение на это или подставлять такой же безопасный дефолт. ЕМ>В чем "безопасность" такого дефолта? Вот имеем байтовое смещение, делим на размер элемента, ожидаем получить индекс элемента. Вместо размера по ошибке делим на нуль, получаем UINT_MAX, применяем в качестве индекса. В соседней теме
смотрим, какая доля участников высказалась против автоматической вставки проверок индексов. Какую перспективу имеем?
Сейчас тебе точно так же ни C ни C++ ничего не гарантируют. А должны были по умолчанию генерировать исключение, если по разуму, а не по комитету или кто там рулит. Так что тут без разницы. А вот возможность лёгкой проверки на такую ситуацию одной командой достаточна для устранения проблемы там, где она реально может быть.
N>>Если исключение отражается в видимой диагностике, это можно было бы написать.
N>>вообще подход, что не предполагается обрабатывать ошибки в арифметике, потому что нет возможности их отобразить в результате операции.
ЕМ>Почему нет? Или предусмотреть перехват возможного исключения, или проверить операнд(ы) перед выполнением операции.
Ну покажи это в современном языке. Я вот хочу видеть что-то в духе C# c = (checked)(a+b); — контекстно и в самом языке. А вместо этого должен писать свои оболочки или использовать от какого-то странного вендора (Boost ещё лучший по свойствам, но API у этого модуля кошмарненький).
N>>Потом кто-то другой в другом месте перевёл запрос доступной памяти на использование вызова B-15E801, который способен отдать к нему дополнительно "DX = configured memory above 16M, in 64K blocks", соответственно до 4GB, а код в построителе таблиц для пейджинга просто не обновили соответственно.
ЕМ>А можно было просто иметь одну функцию вроде GetMemorySize, которая определяет объем памяти любым удобным образом, тогда и части кода согласовывать не придется.
Так она и была. И было установлено при написании кода VM, что она не даст значение выше 64MB.
(В рамках того же предполагаемого сценария)
N>>использовать тотальный defensive programming между собственными микро-компонентами в пределах одной службы... как по мне, это избыточно в 99.99% случаев, толку нет. ЕМ>В ортогональности и унификации всегда есть толк.
Здравствуйте, netch80, Вы писали:
N>Попытка деления на 0 вообще бессмысленна в пределах целых чисел. Что именно возвращать в таком легко детектируемом случае — вопрос реализации.
Я так и не понял, в чем смысл. Какая разница, что с чем сравнивать — частное с -1, или делитель с нулем?
А если они хотели избавить разработчиков языков от необходимости поддерживать системные механизмы обработки исключений, то они фактически предложили создавать реализации языков так, чтобы любое некорректное обращение к памяти сразу и наглухо валило всю программу, без возможности это обработать.
N>Сейчас тебе точно так же ни C ни C++ ничего не гарантируют.
И поэтому решили сделать очередной кривой костыль?
N>должны были по умолчанию генерировать исключение
Процессор его и генерирует. Вроде никогда не возникало сколько-нибудь значимых проблем с реализацией обработки.
N>Ну покажи это в современном языке. Я вот хочу видеть что-то в духе C# c = (checked)(a+b); — контекстно и в самом языке. А вместо этого должен писать свои оболочки или использовать от какого-то странного вендора
Эти вопросы задавайте разработчикам языков и их реализаций. Я сам уже лет тридцать, как в изумлении от того, насколько упорно не желают реализовать даже самые примитивные и дешевые средства, сильно упрощающие жизнь.
N>И было установлено при написании кода VM, что она не даст значение выше 64MB.
Так и ограничили бы принудительно прямо внутри функции — она и не давала бы никогда.
Re[13]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>Попытка деления на 0 вообще бессмысленна в пределах целых чисел. Что именно возвращать в таком легко детектируемом случае — вопрос реализации. ЕМ>Я так и не понял, в чем смысл. Какая разница, что с чем сравнивать — частное с -1, или делитель с нулем?
Второе честнее.
ЕМ>А если они хотели избавить разработчиков языков от необходимости поддерживать системные механизмы обработки исключений,
Прочитайте ещё раз. Ну пожалуйста.
EM> то они фактически предложили создавать реализации языков так, чтобы любое некорректное обращение к памяти сразу и наглухо валило всю программу, без возможности это обработать.
Мне сложно себе представить, что в том, что я написал, могло быть прочитано с таким выводом.
N>>должны были по умолчанию генерировать исключение ЕМ>Процессор его и генерирует.
Уже нет (если мы про новые архитектуры).
N>>Ну покажи это в современном языке. Я вот хочу видеть что-то в духе C# c = (checked)(a+b); — контекстно и в самом языке. А вместо этого должен писать свои оболочки или использовать от какого-то странного вендора
ЕМ>Эти вопросы задавайте разработчикам языков и их реализаций. Я сам уже лет тридцать, как в изумлении от того, насколько упорно не желают реализовать даже самые примитивные и дешевые средства, сильно упрощающие жизнь.
Спасибо, вы очень помогли.
N>>И было установлено при написании кода VM, что она не даст значение выше 64MB. ЕМ>Так и ограничили бы принудительно прямо внутри функции — она и не давала бы никогда.
И снова не хотите читать написанное русским по фоновому.
The God is real, unless declared integer.
Re[14]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, netch80, Вы писали:
ЕМ>>Какая разница, что с чем сравнивать — частное с -1, или делитель с нулем?
N>Второе честнее.
Тогда для чего здесь какие-то телодвижения со стороны разработчиков архитектуры? Сравнивать делитель с нулем — задача программиста или разработчика языка.
N>Прочитайте ещё раз.
Я до этого прочитал дважды. Давайте перечитаем в третий раз:
However, this ... would require language implementors to interact with the execution environment’s trap handlers for this case
Здесь написано, что разработчики архитектуры вроде бы заботятся о разработчиках языков, и отказ от формирования исключения вроде бы имеет целью избавить разработчиков языков от поддержки обработки аппаратных исключений.
Если я, по-Вашему, снова понял неправильно — попробуйте привести перевод, из которого следует что-то иное.
ЕМ>>Процессор его и генерирует.
N>Уже нет (если мы про новые архитектуры).
А при обращении по нулевому адресу генерирует? Если да, то для чего?
N>Спасибо, вы очень помогли.
Я мог бы помочь как-то иначе?
ЕМ>>Так и ограничили бы принудительно прямо внутри функции — она и не давала бы никогда.
N>И снова не хотите читать написанное русским по фоновому.
Скорее тупо не могу понять оправданий, выдаваемых за объяснения. Если бы Чен написал "в нашем коде была ошибка, из-за которой система переставала грузиться вместо того, чтобы просто игнорировать лишнюю память", то и возражений бы не было. Но он ведь не признал, что это был их косяк, оправдывая это маловероятностью. И Вы их оправдываете в том же ключе.
Re[15]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>>>Какая разница, что с чем сравнивать — частное с -1, или делитель с нулем? N>>Второе честнее. ЕМ>Тогда для чего здесь какие-то телодвижения со стороны разработчиков архитектуры? Сравнивать делитель с нулем — задача программиста или разработчика языка.
Движения у них очень просты:
1. Решили, что ситуация некорректности операции деления не заслуживает того, чтобы (по крайней мере в базовом ISA) требовать для этого механизм исключений.
Можно было бы это списать на подход RISC-V, где явно декларируется метод "мы позволяем самые минимальные реализации, если кому-то нужно, и постепенное расширение", но ARM/64, который совсем не планировался компактным, делает то же самое. Значит, соображения у них примерно одного плана: оно не заслуживает настолько особой обработки.
2. Если команда не делает исключения, то надо вернуть какое-то осмысленное значение в качестве частного. Варианты — ближайшее к бесконечности с нужной стороны (лучше всего), просто ближайшее к бесконечности, ноль, что-то иное. ARM/64 выбрал ноль, и мне это решение кажется достаточно нелепым. В RISC-V посмотрели с вот какой стороны: простейший итерационный делитель в железе, returning или non-returning типа, на такое выдаст ответ из всех единичных битов, если специально не делать проверку на ноль. Ну, значит, его и потребуем. (Это может не расширяться на знаковое деление само по себе, но тут уже обобщили.)
N>>Прочитайте ещё раз.
ЕМ>Я до этого прочитал дважды. Давайте перечитаем в третий раз:
ЕМ>
ЕМ>However, this ... would require language implementors to interact with the execution environment’s trap handlers for this case
ЕМ>Здесь написано, что разработчики архитектуры вроде бы заботятся о разработчиках языков, и отказ от формирования исключения вроде бы имеет целью избавить разработчиков языков от поддержки обработки аппаратных исключений.
ЕМ>Если я, по-Вашему, снова понял неправильно — попробуйте привести перевод, из которого следует что-то иное.
Да, именно так. Если бы деление на ноль вызывало исключение, то для внедрителей языков была бы дополнительная забота взаимодействия со сложным механизмом (traps) вместо простого (одна проверочная команда там, где это нужно).
Что не так?
ЕМ>>>Процессор его и генерирует. N>>Уже нет (если мы про новые архитектуры). ЕМ>А при обращении по нулевому адресу генерирует? Если да, то для чего?
Зависит от системы защиты памяти. Обычно DAT настраивается так, что страница с адресом 0 недоступна для любого доступа по крайней мере для юзерленда. (Случай ядра — зависит от местной практики. Обычно полезно, да, перемапить её на что-то другое. Но могут и не делать.)
А какая связь? Сам по себе механизм защиты памяти уже системный и требует настройки.
N>>Спасибо, вы очень помогли. ЕМ>Я мог бы помочь как-то иначе?
Да, конструктивным рассмотрением вопросов дискуссии.
ЕМ>>>Так и ограничили бы принудительно прямо внутри функции — она и не давала бы никогда.
N>>И снова не хотите читать написанное русским по фоновому.
ЕМ>Скорее тупо не могу понять оправданий, выдаваемых за объяснения. Если бы Чен написал "в нашем коде была ошибка, из-за которой система переставала грузиться вместо того, чтобы просто игнорировать лишнюю память", то и возражений бы не было. Но он ведь не признал, что это был их косяк, оправдывая это маловероятностью. И Вы их оправдываете в том же ключе.
Это вы серьёзно — всё, что вы хотите, это чтобы Чен явно сказал "это была наша ошибка"? И если бы он сказал, вы бы вообще не подняли тему?
Тогда это как минимум оффтопик для данного подфорума. В чикаге было 100500 ошибок, недоделок, неоптимальных решений и прочего, и они постепенно правились — или не правились. Ни у кого нет бесконечного количества ресурсов на разработку и учёт всего. Результат оптимизируется под типовые пути работы, и часто различие лежит в том, этих типовых 1 или хотя бы 5. У хорошего разработчика 5. У отличного 10. У плохого 1, или 2, если начальство применило ключ достаточного размера для бития по башке.
Я не вижу смысла считать данную ситуацию какой-то существенной ошибкой потому, что оно не приводило к искажению данных, потере данных, неожиданной критической неработоспособности и т.п. — по крайней мере при нормальном админ. процессе у пользователя. Апгрейд железа или переход на новое это всегда особое событие, проверка на новом необходима перед переводом рабочей нагрузки на неё. Система не поддерживает какую-то не свойственную для её обычного профиля конфигурацию? Да таких профилей были реально тысячи! Масса нестандартного железа, и не только в сторону неожиданно хороших характеристик — как правило, это были локальные кривости всех видов.
А самое прямое для данной дискуссии — это что вы ввели тут уже сильно позже исходного сообщения какую-то необходимость извиняться, когда этого в вашем начальном сообщении не было и вы вместо этого обсуждали "уровень студента-второкурсника". Почему и зачем вы ввернули это только сейчас и походя, и теперь на этом основании чего-то требуете уже от меня?
Нехорошо, товарисч.
The God is real, unless declared integer.
Re[7]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>Так они тоже не сами к этому пришли. Лучше переформулировать, что жрёт не браузер, а сайты в нём. ЕМ>Это вечная проблема перекладывания ответственности. "Наркоторговцы не виноваты — они лишь отвечают на возрастающий спрос, работайте с потребителями".
Сравнение вебостроителей с наркоторговцами — это, конечно, сильный полемический приём. Ценю. Но согласиться не могу.
N>>Я честно не думаю, что от замены JS на что-то другое, менее тупое, тут стало бы сильно легче. ЕМ>Сильно легче стало бы не от замены, а от изначального ограничения активности ваб-страницы чем-нибудь вроде расширенного CSS, где реализован разумный набор средств взаимодействия (те же спойлеры, деревья, простые реакции на действия пользователя и т.п.). Для подавляющего большинства информационных сайтов этого бы хватило, а кому надо интерактивности — делайте приложения, хоть нативные под ОС, хоть универсальные под единую VM, роль которой сейчас исполняют браузеры.
Ну вот и посмотрите теперь сами, что получается. Вы предлагаете некое разделение между "расширенным CSS" и "приложениями", которые могут при этом работать в такой же "единой VM". Тогда в чём разница, если любой автор приложения может легко получить реализацию того же в "единой VM", и не полагаться вообще на "расширенный CSS"?
Вы будете ставить ему платную границу?
JS тем и оказался хорош, что он _плавно_ внедряется в HTML+CSS среду. Можно не иметь ни единого скрипта. Можно 1-2 крошечных. Можно сделать снежинки и не трогать остальное (любимая фишка района 2000 на Новый год). На серверной стороне точно так же плавно въезжал PHP, на чём и получил популярность. А вы предлагаете рисовать какую-то искусственную границу.
Сейчас она по факту определяется тем, что пользователь закроет слишком толстый сайт — и таких будет какая-то доля процентов, чтобы определить "вот эта правка убила 3% пользователей, откатываем назад". И это нормально работает в подавляющем большинстве случаев.
ЕМ>Хреново ведь стало вовсе не от того, что появился JS, а от того, что его впихнули в заведомо неподходящее средство. Человеку нужно средство доступа к базовым сетевым сервисам, а в нагрузку он получает еще один компьютер.
Он просто получает использование средств своего компьютера. А проблема не в этом, а в том, что в отличие от ситуации "вот это приложение весит 2GB, я сознательно принял решение потратить этот объём своего диска на него" получается, что контроля за объёмами затраченных ресурсов нет, или ресурсы слишком быстро меняются, чтобы успевать за ними.
EM> То же самое случилось и с телефонами — человеку нужно средство связи, а в нагрузку он получает кучку средств доставки рекламы и привязки к поставщикам услуг.
Вопрос монетизации сервисов для "средства связи" (и не только связи — я вот перешёл на смартфон, когда мне потребовался навигатор) это другой вопрос и смешивать его с текущим уже нехорошо.
N>>веб тут в целом сам по себе болезнь ЕМ>Болезнь — не веб, а его превращение в балаган.
Мы примерно ровесники, мне кажется. И почему я не стал на такую, откровенно говоря, старперско-брюзгливую позицию?
The God is real, unless declared integer.
Re[16]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, netch80, Вы писали:
N>Решили, что ситуация некорректности операции деления не заслуживает того, чтобы (по крайней мере в базовом ISA) требовать для этого механизм исключений.
Если вопрос в том, чтобы вовсе не иметь в реализации механизма исключений, то это вполне разумно. Но тогда разумно ввести соответствующий флаг состояния, по аналогии с переполнением, а не возвращать результат, который, не будучи специально проверен, почти гарантированно наделает бед. Когда такое решение приходит в одну больную голову, это еще можно понять, но когда оно принимается коллегиально, это уже что-то запредельное.
Если же механизм исключений имеется, но решено отказаться от возбуждения исключения, то это непонятно вообще.
N>Можно было бы это списать на подход RISC-V, где явно декларируется метод "мы позволяем самые минимальные реализации, если кому-то нужно, и постепенное расширение", но ARM/64, который совсем не планировался компактным, делает то же самое. Значит, соображения у них примерно одного плана: оно не заслуживает настолько особой обработки.
N>Если команда не делает исключения, то надо вернуть какое-то осмысленное значение в качестве частного. Варианты — ближайшее к бесконечности с нужной стороны (лучше всего), просто ближайшее к бесконечности, ноль, что-то иное.
Значение, ближайшее к бесконечности, можно считать осмысленным только для деления с плавающей точкой. Для деления с фиксированной оно, наоборот, абсурдно.
N>ARM/64 выбрал ноль, и мне это решение кажется достаточно нелепым.
Мне тоже, Скорее уж единицу.
N>простейший итерационный делитель в железе, returning или non-returning типа, на такое выдаст ответ из всех единичных битов, если специально не делать проверку на ноль. Ну, значит, его и потребуем.
Если они стремятся экономить такты или логические связи, то именно в конкретной ситуации это тоже абсурдно.
N>Если бы деление на ноль вызывало исключение, то для внедрителей языков была бы дополнительная забота взаимодействия со сложным механизмом (traps) вместо простого (одна проверочная команда там, где это нужно).
И какова вероятность того, что в языке, реализованном для архитектуры, мало-мальски сложной (имеющей тот же диспетчер памяти), вообще не будут поддерживаться механизмы исключений?
Если уж они решили одновременно и упростить, и унифицировать, и оставить возможность масштабирования, то единственно правильное решение — это устанавливать флаг состояния. При наличии механизма исключений можно было бы добавить возбуждение исключения, как и для переполнения при умножении.
N>А какая связь? Сам по себе механизм защиты памяти уже системный и требует настройки.
Связь такая, что у программы должна быть возможность получать информацию о нештатных ситуациях при ее выполнении. Когда процессор эту информацию имеет, но не отдает, либо отдает в неадекватном виде, это требует экстраординарных оснований. Такие основания есть?
ЕМ>>Я мог бы помочь как-то иначе?
N>Да, конструктивным рассмотрением вопросов дискуссии.
И что конструктивного я мог бы сказать по поводу отсутствия в языках даже самых простых в реализации средств контроля исполнения? Я действительно не знаю, почему в индустрии преобладает стремление внедрять свистоперделки, порой достаточно дорогие в реализации, но упорно избегать внедрения дешевых и эффективных средств.
N>всё, что вы хотите, это чтобы Чен явно сказал "это была наша ошибка"? И если бы он сказал, вы бы вообще не подняли тему?
Да, именно так. Он высказался в стиле "у нас все было правильно, просто никто не ожидал". Я в подобной ситуации всегда признаю, что было-то ведь неправильно и ненадежно, но или не обратил внимания, или понадеялся на лучшее.
N>Тогда это как минимум оффтопик для данного подфорума.
Это был лишь очередной пример проблемы, к которой привел произвольный выбор фиксированной константы. И ведь того, что выбор константы в 2 Гб тоже был неудачным, они тоже не признают.
N>Ни у кого нет бесконечного количества ресурсов на разработку и учёт всего.
Да ладно бы такая ошибка была в сколько-нибудь объемном коде, с неочевидными зависимостями, которые трудно проследить в уме. Но в достаточно компактном коде загрузчика, который заполняет массив фиксированного размера, отсутствие адекватных действий при переполнении должно было насторожить.
N>вы ввели тут уже сильно позже исходного сообщения какую-то необходимость извиняться
Не извиняться, а признавать свои ошибки.
Re[8]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, netch80, Вы писали:
N>Вы предлагаете некое разделение между "расширенным CSS" и "приложениями", которые могут при этом работать в такой же "единой VM".
Верно.
N>Тогда в чём разница, если любой автор приложения может легко получить реализацию того же в "единой VM", и не полагаться вообще на "расширенный CSS"?
Разница достаточно большая. Во-первых, это позволило бы сохранить браузер именно в виде браузера (универсального инструмента для просмотра информации в сети), а не уродливого монстра, напоминающего текстовый процессор с прикрученными к нему позднее сбоку компилятором, отладчиком и дизассемблером. То есть, у любого пользователя был бы компактнй и безопасный инструмент для взаимодействия с информационной частью сети, а для коммерческо-развлекательной были бы отдельные инструменты.
Во-вторых, это умерило бы аппетиты сайтостроителей. В ситуации, когда у любого пользователя гарантированно есть средство для "разумно-активного" взаимодействия, но средства для "полноценного" (с точки зрения сайтостроителя) взаимодействия может не быть, многие предпочли бы ограничиться менее навороченным, но более доступным и надежным вариантом.
В-третьих, легкий и ненапряжный для пользователя переход по ссылке в браузере не создавал бы ему лишних рисков, а для установки приложения, пусть и универсального в единую подсистему ОС, уже требовалось бы явное разрешение.
N>JS тем и оказался хорош, что он _плавно_ внедряется в HTML+CSS среду.
А плох тем, что у этой плавности нет верхней границы. Уже давно подобрали хороший пример — это как пустить представителя организации, с которой нужно поддерживать отношения, жить к себе домой. Да, он может обещать вести себя хорошо, и он может быть наказан за нарушения, но доверять ему придется, как любому члену семьи.
И этот подход в итоге привел к фантастически уродливым решениям вроде запуска отдельных процессов, со специальными режимами защиты памяти, для обработки вкладок. То есть, дом, в котором изначально предполагались "все свои", теперь разгорожен на отсеки стенами повышенной прочности, в двери установлены замки повышенной надежности, но конца этому процессу не видно, он идет параллельно процессу развития любой ОС, создающей среду для разнородных приложений.
N>Сейчас она по факту определяется тем, что пользователь закроет слишком толстый сайт
Самое смешное, что толстый сайт с наибольшей вероятностью закроет пользователь, которому этот сайт не был бы нужен и тонким.
N>будет какая-то доля процентов, чтобы определить "вот эта правка убила 3% пользователей, откатываем назад".
Вы действительно верите, что нынче найдется хоть сколько-нибудь заметное количество людей, способных хотя бы на такой анализ, не говоря уже о возможности организовать откат?
ЕМ>>Человеку нужно средство доступа к базовым сетевым сервисам, а в нагрузку он получает еще один компьютер.
N>Он просто получает использование средств своего компьютера.
Да — через представителя, поселяемого дома. А они, как та лисичка — сперва лапку, потом другую...
N>в отличие от ситуации "вот это приложение весит 2GB, я сознательно принял решение потратить этот объём своего диска на него" получается, что контроля за объёмами затраченных ресурсов нет
Установленные приложения уже давно занимают ресурсы, даже близко не соответствующие заявленным. Вроде качаешь 50 Мб, а по факту оно занимает 300, и через короткое время откуда-то берет еще 200. Но так они хоть гадят в более-менее известные места ФС, а не в профиль браузера, где сам черт не разберется, и откуда их потом не выковырять без радикальных мер.
N>Мы примерно ровесники, мне кажется. И почему я не стал на такую, откровенно говоря, старперско-брюзгливую позицию?
Возможно, у Вас больше веры в разум человечества. У меня такая позиция была и в тридцать лет.
Re[17]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>Решили, что ситуация некорректности операции деления не заслуживает того, чтобы (по крайней мере в базовом ISA) требовать для этого механизм исключений. ЕМ>Если вопрос в том, чтобы вовсе не иметь в реализации механизма исключений, то это вполне разумно. Но тогда разумно ввести соответствующий флаг состояния, по аналогии с переполнением, а не возвращать результат, который, не будучи специально проверен, почти гарантированно наделает бед. Когда такое решение приходит в одну больную голову, это еще можно понять, но когда оно принимается коллегиально, это уже что-то запредельное.
Что вы решили назвать тут флагом состояния?
Вот, например, самая первая операция, которую рассматривают — сложение. Пусть у нас байтовые параметры. Сложив 0x01 и 0xFF, мы получаем 0x00. Но в знаковой интерпретации это нормально, а в беззнаковой это переполнение. Мы должны детектировать это переполнение? Если да, как выглядит этот "флаг состояния"?
Архитектура типа RISC-V намеренно лишена аналога Flags в x86. Даже не как в ARM, где у большинства команд этой группы можно управлять, есть там флаги или нет. Не знаю, насколько правильно в самом глобальном смысле это решение само по себе. Но если оно сделано, то явная проверка требуется не только на деление. Сложение, вычитание, умножение — они все требуют проверок на валидность результата, не был ли он усечён (после чего об его корректности вообще нет смысла говорить, лучше считать тупо мусором). В чём особенность тут одного деления по сравнению с остальными?
Пусть у нас теперь есть Flags в варианте, например, как в x86. Все операции ставят флаги. Мы можем добавлять JO или INTO после команды. Мы можем добавлять JC. Вопрос: почему нет парной к ней INTC?
(Да, я буду регулярно сравнивать с x86. Это "а у вас негров линчуют", я заранее согласен.)
Есть один вариант решения: флагов нет, ставьте явные проверки по диапазонам и конкретным значениям, где нужно. Есть другой: флаги есть, можно реагировать на них. Тут уже вопрос, кто и что как ставит. Я бы не против, если б SDIV ставила OF (как бы они ни звались) в случаях деления на 0 или MIN/-1. Но вводить ещё и фолт для одного-единственного случая — точно явный и неуместный перекос. Когда это сделали в S/360, там было понятно — откровенно пионерная архитектура. Когда это сделали в 8086 через 14 лет — зачем это было? Неужели не было уже понятно по опыту развития, что в этом нет смысла?
Кстати, я ни в одной архитектуре кроме POWER не видел "накопительного" флага переполнения, и то там есть такой только для знакового. А обычные надо проверять после каждой операции.
ЕМ>Если же механизм исключений имеется, но решено отказаться от возбуждения исключения, то это непонятно вообще.
Механизм появляется вместе с более высокими уровнями реализации (в RISC-V). Но его принудительная ориентация на обработку в супервизоре избыточна.
N>>Если команда не делает исключения, то надо вернуть какое-то осмысленное значение в качестве частного. Варианты — ближайшее к бесконечности с нужной стороны (лучше всего), просто ближайшее к бесконечности, ноль, что-то иное.
ЕМ>Значение, ближайшее к бесконечности, можно считать осмысленным только для деления с плавающей точкой. Для деления с фиксированной оно, наоборот, абсурдно.
И опять же. Сложили 0x01 и 0xFF в беззнаковом контексте, получили 0 вместо 0x100. Не заметили, пошли дальше, нарвались на что-то и приветъ. Будем трапаться на таком или нет? Я согласен только на универсальный подход, потому что в упор не вижу, чем деление тут должно быть таким особенным.
N>>Если бы деление на ноль вызывало исключение, то для внедрителей языков была бы дополнительная забота взаимодействия со сложным механизмом (traps) вместо простого (одна проверочная команда там, где это нужно). ЕМ>И какова вероятность того, что в языке, реализованном для архитектуры, мало-мальски сложной (имеющей тот же диспетчер памяти), вообще не будут поддерживаться механизмы исключений?
Да вообще-то на таком уровне ровно 100%. В C нет никаких исключений. Если где-то вы видите, например, обработчик SIGFPE (в который по POSIX мапится деление на 0, если трапается), то в нём всё равно нельзя без платформенно-специфичных средств вернуться на ту же команду. Максимум это через siglongjmp() вернуться на какую-то заранее придуманную контрольную точку. Если речь про Windows, то SEH это тоже не элемент языка, а расширение для конкретной платформы.
ЕМ>Если уж они решили одновременно и упростить, и унифицировать, и оставить возможность масштабирования, то единственно правильное решение — это устанавливать флаг состояния. При наличии механизма исключений можно было бы добавить возбуждение исключения, как и для переполнения при умножении.
Да, такое определено в IEEE754. Там накопительные флаги и возможность управления ими. А теперь покажите мне такое в x86 или SystemZ (где деление на 0 трапается) такие накопительные флаги?
N>>А какая связь? Сам по себе механизм защиты памяти уже системный и требует настройки. ЕМ>Связь такая, что у программы должна быть возможность получать информацию о нештатных ситуациях при ее выполнении. Когда процессор эту информацию имеет, но не отдает, либо отдает в неадекватном виде, это требует экстраординарных оснований. Такие основания есть?
Отлично, жду ваших оснований для отсутствия накопительных флагов переполнения в x86.
ЕМ>И что конструктивного я мог бы сказать по поводу отсутствия в языках даже самых простых в реализации средств контроля исполнения? Я действительно не знаю, почему в индустрии преобладает стремление внедрять свистоперделки, порой достаточно дорогие в реализации, но упорно избегать внедрения дешевых и эффективных средств.
В языках-то оно есть. Возьмите какую-нибудь Ada и там всё будет под полным контролем.
N>>всё, что вы хотите, это чтобы Чен явно сказал "это была наша ошибка"? И если бы он сказал, вы бы вообще не подняли тему? ЕМ>Да, именно так. Он высказался в стиле "у нас все было правильно, просто никто не ожидал".
Не вижу в его словах такого акцента.
N>>Тогда это как минимум оффтопик для данного подфорума. ЕМ>Это был лишь очередной пример проблемы, к которой привел произвольный выбор фиксированной константы.
Лучше бы вспомнили историю ATA геометрий — она красочнее. В общем же случае я думаю, что каждое расширение какого-то реального параметра в 2-3 раза приводит к наступанию на очередной предел.
EM> И ведь того, что выбор константы в 2 Гб тоже был неудачным, они тоже не признают.
Он был 99.99% удачен. Остальных давно ждал 64-битный режим. На это я уже отвечал.
N>>Ни у кого нет бесконечного количества ресурсов на разработку и учёт всего.
ЕМ>Да ладно бы такая ошибка была в сколько-нибудь объемном коде, с неочевидными зависимостями, которые трудно проследить в уме. Но в достаточно компактном коде загрузчика, который заполняет массив фиксированного размера, отсутствие адекватных действий при переполнении должно было насторожить.
Тогда на всём экономили.
Вон загрузчик MS-DOS где-то аж до версии 5 должен был получать io.sys первым в корневом каталоге, иначе беда. А всё потому, что решили, что нефиг в FAT даже на винче выдать десяток секторов на более умный промежуточный читатель FS. В котором из FAT это стало обязательным? Чуть ли не в 32м.
Про саму проблему трёх областей видимости (20, 32 и 64 бита адреса) уже и не вспоминаю, там и сейчас есть где плясать часами на костях.
N>>вы ввели тут уже сильно позже исходного сообщения какую-то необходимость извиняться ЕМ>Не извиняться, а признавать свои ошибки.
Этому вообще весь блог посвящён в целом. "Old new thing" — о древностях, замшелостях и откуда они такие растут. Каждая из них это какая-то ошибка, отсталость, влияние древнего ограничения или просто недосмотр.
Это не требуется прописывать каждый раз.
The God is real, unless declared integer.
Re[9]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>Тогда в чём разница, если любой автор приложения может легко получить реализацию того же в "единой VM", и не полагаться вообще на "расширенный CSS"?
ЕМ>Разница достаточно большая. Во-первых, это позволило бы сохранить браузер именно в виде браузера (универсального инструмента для просмотра информации в сети), а не уродливого монстра, напоминающего текстовый процессор с прикрученными к нему позднее сбоку компилятором, отладчиком и дизассемблером. То есть, у любого пользователя был бы компактнй и безопасный инструмент для взаимодействия с информационной частью сети, а для коммерческо-развлекательной были бы отдельные инструменты.
"Информационная" часть сети может и часто должна пользоваться теми же механизмами. На этом уровне их невозможно различить.
ЕМ>Во-вторых, это умерило бы аппетиты сайтостроителей. В ситуации, когда у любого пользователя гарантированно есть средство для "разумно-активного" взаимодействия, но средства для "полноценного" (с точки зрения сайтостроителя) взаимодействия может не быть, многие предпочли бы ограничиться менее навороченным, но более доступным и надежным вариантом.
Это было типовым в период, условно говоря, 1995-2005. Тогда было легче встретить сайт, который без JS работал на 99%, только без некоторых фишек, чем наоборот.
И тем не менее это закончилось. Сейчас мы имеем противоположную обстановку. И причина — таки желания пользователей, чтобы у них была одна платформа — браузер — для всего, иначе просто лень.
N>>JS тем и оказался хорош, что он _плавно_ внедряется в HTML+CSS среду. ЕМ>А плох тем, что у этой плавности нет верхней границы.
Да.
EM> Уже давно подобрали хороший пример — это как пустить представителя организации, с которой нужно поддерживать отношения, жить к себе домой. Да, он может обещать вести себя хорошо, и он может быть наказан за нарушения, но доверять ему придется, как любому члену семьи.
ЕМ>И этот подход в итоге привел к фантастически уродливым решениям вроде запуска отдельных процессов, со специальными режимами защиты памяти, для обработки вкладок. То есть, дом, в котором изначально предполагались "все свои", теперь разгорожен на отсеки стенами повышенной прочности, в двери установлены замки повышенной надежности, но конца этому процессу не видно, он идет параллельно процессу развития любой ОС, создающей среду для разнородных приложений.
Это все понимают, вы тут реально кэпствуете. Но альтернативы не видят. В отдельные приложения сейчас больше идёт то, что в браузере непригодно.
N>>будет какая-то доля процентов, чтобы определить "вот эта правка убила 3% пользователей, откатываем назад". ЕМ>Вы действительно верите, что нынче найдется хоть сколько-нибудь заметное количество людей, способных хотя бы на такой анализ, не говоря уже о возможности организовать откат?
Типовое умение в конторе больше условных 5 человек.
ЕМ>>>Человеку нужно средство доступа к базовым сетевым сервисам, а в нагрузку он получает еще один компьютер. N>>Он просто получает использование средств своего компьютера. ЕМ>Да — через представителя, поселяемого дома. А они, как та лисичка — сперва лапку, потом другую...
Ну пока что дальше браузера дело не идёт. Даже Microsoft со своим тем что развилось из Active Desktop, или Electron — просто используют механизмы браузера для своих задач.
N>>Мы примерно ровесники, мне кажется. И почему я не стал на такую, откровенно говоря, старперско-брюзгливую позицию? ЕМ>Возможно, у Вас больше веры в разум человечества. У меня такая позиция была и в тридцать лет.
Веры в "разум человечества" у меня нет. Просто я, наверно, лучше представляю себе, что происходит от тупизны, условно говоря, самих программистов, а что — от неизбежного следования запросам пользователей.
The God is real, unless declared integer.
Re[18]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, netch80, Вы писали:
N>Что вы решили назвать тут флагом состояния?
Классический флаг состояния процессора, используемый с незапамятных времен.
N>в знаковой интерпретации это нормально, а в беззнаковой это переполнение. Мы должны детектировать это переполнение?
Если у процессора в ходе выполнения программы возникает любая информация, которая с высокой вероятностью будет полезна этой программе, то да. Именно это и делает тот же x86 с флагами CF/OF, детектируя сразу обе ситуации.
N>Архитектура типа RISC-V намеренно лишена аналога Flags в x86.
И как, этим она существенно выигрывает у архитектур, где флаги есть?
N>Сложение, вычитание, умножение — они все требуют проверок
Именно так. Реализация этих проверок в топологии/микрокоде процессора всегда дешевле, чем в каждой из выполняемых на нем программ.
N>Мы можем добавлять JO или INTO после команды. Мы можем добавлять JC. Вопрос: почему нет парной к ней INTC?
Потому, что перенос очень часто является следствием нормального выполнения, и как-то специально его обрабатывать не требуется, а знаковое переполнение в большинстве случаев является нештатной ситуацией. Но флаги-то есть, и любое сочетание всегда можно обработать с ничтожными затратами.
N>Есть один вариант решения: флагов нет, ставьте явные проверки по диапазонам и конкретным значениям, где нужно.
Это откровенно убогий вариант, как и возврат из функции единственного результата, некоторые значения которого резервируются под коды ошибок. Оправдывается только в случае крайней экономии ресурсов.
N>Я бы не против, если б SDIV ставила OF (как бы они ни звались) в случаях деления на 0 или MIN/-1.
Это было бы следуюшим по разумности вариантом при отказе от исключения.
N>вводить ещё и фолт для одного-единственного случая — точно явный и неуместный перекос.
Почему, если механизм исключений уже поддерживается аппаратурой? Порождать исключения для арифметических переполнений нет смысла, поскольку они очень часто возникают в совершенно нормальных, запланированных ситуациях. А вот в какой нормальной, запланированной ситуации могло бы возникнуть деление на нуль, результат которого можно было бы далее использовать без проверки?
Это ж, по сути, то же самое, для чего вводились исключения в C++ — чтобы в ситуации, когда что-то пошло не так, не было риска забыть проверить возвращаемое значение в ситуации, когда не существует заведомо безопасного значения для нештатной ситуации.
N>Неужели не было уже понятно по опыту развития, что в этом нет смысла?
Тогда и в плюсовых исключениях тоже нет смысла. Не в их неправильном использовании, а в механизме, как твковом.
ЕМ>>Если же механизм исключений имеется, но решено отказаться от возбуждения исключения
N>Механизм появляется вместе с более высокими уровнями реализации (в RISC-V). Но его принудительная ориентация на обработку в супервизоре избыточна.
Если команда деления может присутствовать в архитектуре, не поддерживающей обработку исключений, или возбуждение исключения может быть запрещено, то наиболее разумным решением будет использование флага состояния.
N>Сложили 0x01 и 0xFF в беззнаковом контексте, получили 0 вместо 0x100. Не заметили, пошли дальше, нарвались на что-то и приветъ.
Да, возможность нарваться есть. Но она есть наравне с возможностью использовать это поведение для реализации естественных действий — тех же операций по модулю. А вот какие естественные операции могли бы выполняться командой целочисленного деления, возвращающей максимально возможное значение при нулевом делителе?
N>В C нет никаких исключений.
C — не язык "в себе". В C изначально закладывались на то, что исключения, если они есть в архитектуре, поддерживаются средой исполнения.
N>Если где-то вы видите, например, обработчик SIGFPE (в который по POSIX мапится деление на 0, если трапается), то в нём всё равно нельзя без платформенно-специфичных средств вернуться на ту же команду.
Возможность вернуться и повторить — это уже определенная роскошь. Основной является возможность реагировать на нештатную ситуацию без явных проверок.
N>покажите мне такое в x86 или SystemZ (где деление на 0 трапается) такие накопительные флаги?
Зачем нужны непременно накопительные? Как часто в них возникает потребность?
N>В языках-то оно есть. Возьмите какую-нибудь Ada и там всё будет под полным контролем.
А какой ценой?
N>Лучше бы вспомнили историю ATA геометрий — она красочнее.
Там были хоть какие-то объективные основания — разрядности шин, регистров, стоимость тогдашних микросхем и т.п.
N>В общем же случае я думаю, что каждое расширение какого-то реального параметра в 2-3 раза приводит к наступанию на очередной предел.
Это как раз понятно. Непонятно стремление вводить константы вместо переменных, хотя в основе математики лежала противоположная идея.
EM>>выбор константы в 2 Гб тоже был неудачным
N>Он был 99.99% удачен. Остальных давно ждал 64-битный режим
Тогда выбор одного гигабайта вместо двух был бы "удачным на 99.95%". А выбор 512 Мб — "на 99.9%". А фишка в том, что увеличение этой вероятности до максимальной не стоило бы практически ничего, но в итоге цена получилась вполне ощутимой.
N>Тогда на всём экономили.
В загрузчиках MBR/VBR — да. В загрузчике Win95 не было ни малейших причин экономить байты и такты.
Re[19]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>Что вы решили назвать тут флагом состояния? ЕМ>Классический флаг состояния процессора, используемый с незапамятных времен.
Нет такого общего понятия. Есть много разных флагов, каждый со своим поведением.
N>>в знаковой интерпретации это нормально, а в беззнаковой это переполнение. Мы должны детектировать это переполнение? ЕМ>Если у процессора в ходе выполнения программы возникает любая информация, которая с высокой вероятностью будет полезна этой программе, то да. Именно это и делает тот же x86 с флагами CF/OF, детектируя сразу обе ситуации.
Тему с накопительным поведением вы проигнорировали.
N>>Архитектура типа RISC-V намеренно лишена аналога Flags в x86. ЕМ>И как, этим она существенно выигрывает у архитектур, где флаги есть?
Авторы считают, что отсутствие зависимости по скрытому значению — да, помогает в реализации. И она не одна такая. Вон MIPS ещё как минимум.
А теперь бинго — у x86 то же самое в векторных операциях... потому что не может быть одного флага результата на 4-8-16 разных операций впараллель
N>>Сложение, вычитание, умножение — они все требуют проверок ЕМ>Именно так. Реализация этих проверок в топологии/микрокоде процессора всегда дешевле, чем в каждой из выполняемых на нем программ.
Ну и где они в x86?
N>>Мы можем добавлять JO или INTO после команды. Мы можем добавлять JC. Вопрос: почему нет парной к ней INTC? ЕМ>Потому, что перенос очень часто является следствием нормального выполнения, и как-то специально его обрабатывать не требуется,
Нет здесь такой несимметричности.
N>>Есть один вариант решения: флагов нет, ставьте явные проверки по диапазонам и конкретным значениям, где нужно. ЕМ>Это откровенно убогий вариант, как и возврат из функции единственного результата, некоторые значения которого резервируются под коды ошибок. Оправдывается только в случае крайней экономии ресурсов.
Ну где говорят про экономию ресурсов, а где про резкое облегчение дизайна за счёт отсутствия единого регистра флагов и за счёт этого лучшую параллельность.
Заметьте, Intel в своём проекте APX намеревается сделать то же самое.
N>>Я бы не против, если б SDIV ставила OF (как бы они ни звались) в случаях деления на 0 или MIN/-1. ЕМ>Это было бы следуюшим по разумности вариантом при отказе от исключения.
Как раз более разумно, чем исключение
N>>вводить ещё и фолт для одного-единственного случая — точно явный и неуместный перекос. ЕМ>Почему, если механизм исключений уже поддерживается аппаратурой? EM> Порождать исключения для арифметических переполнений нет смысла, поскольку они очень часто возникают в совершенно нормальных, запланированных ситуациях.
Кажется, единственный вариант, при котором это возможно, это арифметика "по модулю". Назвать такое "очень часто" — это слишком сильная натяжка. От общего количества разных операций такого минимум и сконцентрированы они в некоторых совершенно конкретных областях: длинная арифметика, операции с кольцевыми счётчиками вроде seqnum в сетевых протоколах. А вот в, не побоюсь, 99% остальных если и кажется, что они есть, то это такие, в которых значение после переполнения проверяется на его выход за пределы ожидаемого множества. Например, в недавней дискуссии о роли беззнаковых — переход 0 -> ~0. А если не проверяется, а переполнение возможно, то код просто некорректен.
Уточню: я имею в виду вариант, когда тип значения обозначен. CF=1 при беззнаковом или OF=1 при знаковом.
EM> А вот в какой нормальной, запланированной ситуации могло бы возникнуть деление на нуль, результат которого можно было бы далее использовать без проверки?
Раз мы знаем, что "нормальных, запланированных" ситуаций с переполнениями почти нет, то уже нет тут никаких особых свойств деления. Некорректные входные данные дают некорректный результат, и если он распространяется на дальнейшую работу, то важно то, насколько рано (в идеале — сразу) ситуация поймана и опознана.
ЕМ>Это ж, по сути, то же самое, для чего вводились исключения в C++ — чтобы в ситуации, когда что-то пошло не так, не было риска забыть проверить возвращаемое значение в ситуации, когда не существует заведомо безопасного значения для нештатной ситуации.
Ну и почему на это плюют во всяких x86 для трёх операций из четырёх (это ещё и если не считать сдвиги за арифметику со степенью двойки, тогда окажется, что в 7 из 8)?
N>>Неужели не было уже понятно по опыту развития, что в этом нет смысла? ЕМ>Тогда и в плюсовых исключениях тоже нет смысла. Не в их неправильном использовании, а в механизме, как твковом.
Передёргиваете. Я ясно сказал, что возможность проверки есть и там, где её применяют, проблема детектируется. Может, чуть заморочно.
ЕМ>>>Если же механизм исключений имеется, но решено отказаться от возбуждения исключения N>>Механизм появляется вместе с более высокими уровнями реализации (в RISC-V). Но его принудительная ориентация на обработку в супервизоре избыточна. ЕМ>Если команда деления может присутствовать в архитектуре, не поддерживающей обработку исключений, или возбуждение исключения может быть запрещено, то наиболее разумным решением будет использование флага состояния.
Да. Если он есть.
ЕМ>C — не язык "в себе". В C изначально закладывались на то, что исключения, если они есть в архитектуре, поддерживаются средой исполнения.
Ну предположим.
N>>Если где-то вы видите, например, обработчик SIGFPE (в который по POSIX мапится деление на 0, если трапается), то в нём всё равно нельзя без платформенно-специфичных средств вернуться на ту же команду. ЕМ>Возможность вернуться и повторить — это уже определенная роскошь. Основной является возможность реагировать на нештатную ситуацию без явных проверок.
Тогда её нет с x86 для всего кроме деления — а там оно нужно сильно чаще, чем для деления.
Ситуацию незамеченного деления на 0 за весь свой опыт я видел только одну, а случаи проблем из-за непойманного переполнения при остальных трёх арифметических операциях — уже десятки.
N>>В языках-то оно есть. Возьмите какую-нибудь Ada и там всё будет под полным контролем. ЕМ>А какой ценой?
Проверка каждого результата при укладке в целевую переменную, на её границы, плюс операций с базовым размером значения (как int и long в C) на переполнения. Не сильно большая цена за реальную безопасность.
N>>Лучше бы вспомнили историю ATA геометрий — она красочнее. ЕМ>Там были хоть какие-то объективные основания — разрядности шин, регистров, стоимость тогдашних микросхем и т.п.
Все эти "разрядности" и "стоимости" это фактор ровно того же плана: суммарная цена решения.
N>>В общем же случае я думаю, что каждое расширение какого-то реального параметра в 2-3 раза приводит к наступанию на очередной предел. ЕМ>Это как раз понятно. Непонятно стремление вводить константы вместо переменных, хотя в основе математики лежала противоположная идея.
Ну вот вы почему-то постановили, что константы разрядности в виде 32 и 64 они оправданны, а остальные — нет. А я могу вспомнить жалобы при переходе на S/360, что 32-битный float был заметно хуже 36-битного по свойствам. Последствия этого убрали только в IEEE754, и то по мнению некоторых недостаточно качественно. Надо было таки оставить разрядности типа 36 и 72?
EM>>>выбор константы в 2 Гб тоже был неудачным N>>Он был 99.99% удачен. Остальных давно ждал 64-битный режим ЕМ>Тогда выбор одного гигабайта вместо двух был бы "удачным на 99.95%". А выбор 512 Мб — "на 99.9%". А фишка в том, что увеличение этой вероятности до максимальной не стоило бы практически ничего, но в итоге цена получилась вполне ощутимой.
В том и дело, что увеличение выше 2GB реально стоило — мороки программистам и производительности ядру. Сплошная перекачка данных между буферами.
N>>Тогда на всём экономили. ЕМ>В загрузчиках MBR/VBR — да. В загрузчике Win95 не было ни малейших причин экономить байты и такты.
Я уже ответил, что считаю, что причина в несогласовании между сотрудниками (отделами), а не в намеренной чрезмерной экономии.
The God is real, unless declared integer.
Re[20]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, netch80, Вы писали:
N>Тему с накопительным поведением вы проигнорировали.
Я задал вопрос: "Зачем нужны непременно накопительные? Как часто в них возникает потребность?". Вы не ответили.
N>Авторы считают, что отсутствие зависимости по скрытому значению — да, помогает в реализации.
В каком смысле это значение более "скрыто", нежели значения регистров или ячеек памяти? По состояниям отдельных флагов можно выполнить переход, их можно использовать в операциях, можно прочитать явно.
N>у x86 то же самое в векторных операциях... потому что не может быть одного флага результата на 4-8-16 разных операций впараллель
Насколько часто при векторных операциях необходимы ветвления по промежуточным результатам? Там, как правило, безусловные, "пакетные" алгоритмы.
ЕМ>>Реализация этих проверок в топологии/микрокоде процессора всегда дешевле, чем в каждой из выполняемых на нем программ.
N>Ну и где они в x86?
Во флагах состояния, вестимо. Пусть и не все, хотелось бы больше.
ЕМ>>Потому, что перенос очень часто является следствием нормального выполнения, и как-то специально его обрабатывать не требуется,
N>Нет здесь такой несимметричности.
Если сейчас навскидку скачать любой бинарник и дизассемблировать его — уверены, что действий со знаковыми величинами, при которых штатно возникает переполнение, найдем примерно столько же, сколько и для беззнаковых?
N>где говорят про экономию ресурсов
Экономия на флагах состояния на фоне сложности любого процессора даже 30-40-летней давности — это фикция, тех ресурсов там совершенно ничтожное количество, исчисляемое единицами логических элементов.
N>где про резкое облегчение дизайна за счёт отсутствия единого регистра флагов и за счёт этого лучшую параллельность.
Тоже непонятно, где здесь может быть "резкое облегчение". Параллельное выполнение даже простых арифметических операций требует наличия нескольких полноценных АЛУ, а флаги состояния из такого АЛУ выходят либо сами по себе, либо путем добавления единиц логических элементов. Некоторое упрощение получить можно, "резкое" — тупо неоткуда.
N>Заметьте, Intel в своём проекте APX намеревается сделать то же самое.
В последнее время явно видна тенденция сращивания функций процессора и компилятора. Если существующие архитектуры еще предполагали написание программы человеком на ассемблере, то новые уже предполагают только машинную генерацию кода. В таких условиях разумно целиком оптимизировать связку "компилятор+процессор" — возможно, в ней флаги состояния действительно получаются избыточными.
Но и x86, и ARM проектировались во времена, когда написание кода человеком на ассемблере использовалось достаточно широко.
ЕМ>>Это было бы следуюшим по разумности вариантом при отказе от исключения.
N>Как раз более разумно, чем исключение
Если предполагается, что программа всегда будет генерироваться автоматически, и статистика показывает, что затраты на проверку после каждого деления потеряются на общем фоне, то да.
EM>> Порождать исключения для арифметических переполнений нет смысла, поскольку они очень часто возникают в совершенно нормальных, запланированных ситуациях.
N>Кажется, единственный вариант, при котором это возможно, это арифметика "по модулю". Назвать такое "очень часто" — это слишком сильная натяжка.
Например, там, где нуль/ненуль нужно преобразовать в 0/1 или 0/-1, компиляторы вовсю используют комбинации из neg, sbb, inc и and. А счетчики с переполнением часто используются для отслеживания небольших временнЫх интервалов в алгоритмах реального времени.
N>мы знаем, что "нормальных, запланированных" ситуаций с переполнениями почти нет
Хорошо Вам, что "вы знаете". Я вот их использую регулярно, и столь же регулярно вижу в коде, который делает компилятор (те же преобразования int в bool). А вот операций с заведомо знаковыми величинами, при которых знаковое же переполнение было бы штатной ситуацией, и не требовало специальных действий, я с ходу даже не припомню, как и в случае деления на нуль.
ЕМ>>чтобы в ситуации, когда что-то пошло не так, не было риска забыть проверить возвращаемое значение в ситуации, когда не существует заведомо безопасного значения для нештатной ситуации.
N>Ну и почему на это плюют во всяких x86 для трёх операций из четырёх (это ещё и если не считать сдвиги за арифметику со степенью двойки, тогда окажется, что в 7 из 8)?
Где можно найти примеров, в которых это "наплевательство" требуется обставлять ловушками?
ЕМ>>Тогда и в плюсовых исключениях тоже нет смысла. Не в их неправильном использовании, а в механизме, как твковом.
N>Передёргиваете. Я ясно сказал, что возможность проверки есть и там, где её применяют, проблема детектируется. Может, чуть заморочно.
Пытаюсь увидеть разницу, но не вижу. Если в процессоре не возбуждать исключения при делении на нуль, а возвращать специальное значение, необходимо добавлять проверку после каждого деления; случаев, когда программа может безопасно использовать специальное значение, найдется очень мало. В C++ тоже можно обойтись без исключений, возвращая специальное значение, и тоже далеко не всегда его можно подобрать так, чтобы продолжение без проверки было безопасным. Разницу вижу только в том, что код для процессора сейчас преимущественно делает компилятор, который не забудет добавить проверку, а программы на C++ преимущественно делает человек, который может забыть.
N>Ситуацию незамеченного деления на 0 за весь свой опыт я видел только одну
Удивлен. Уж насколько я всегда избегал математики в своих программах, но у меня и делений хватает, и случаев ошибочного деления на нуль было предостаточно. Если б они не порождали исключений, и компилятор не спасал бы автоматической проверкой, я бы вздернулся их все разыскивать.
N>случаи проблем из-за непойманного переполнения при остальных трёх арифметических операциях — уже десятки.
Этих тоже хватало. Но, если б каждое такое переполнение порождало исключение, было бы еще хуже.
N>Проверка каждого результата при укладке в целевую переменную, на её границы, плюс операций с базовым размером значения (как int и long в C) на переполнения. Не сильно большая цена за реальную безопасность.
Это было бы полезно во всех без исключения языках, но не безусловно, а при возможности независимого управления каждым видом проверок.
N>Ну вот вы почему-то постановили, что константы разрядности в виде 32 и 64 они оправданны, а остальные — нет.
Это не "мы постановили", это непосредственно вытекает из физических, железных характеристик архитектуры. А числа вроде 2 Гб для границы АП, или 480 Мб для бессбойной загрузки Win95, ниоткуда не вытекают, а возникают произвольно.
N>жалобы при переходе на S/360, что 32-битный float был заметно хуже 36-битного по свойствам.
Вроде неудивительно. Чем не устраивал 64-битный?
N>Надо было таки оставить разрядности типа 36 и 72?
Они и так оставались доступными через 64- и 128-разрядные. Или Вы о хранении чисел в памяти?
N>увеличение выше 2GB реально стоило — мороки программистам и производительности ядру. Сплошная перекачка данных между буферами.
Почему при границе в 2 Гб "сплошной перекачки" нет, а при смещении на те же 3 Гб вдруг потребовалась?
Re[21]: Откуда такая неизбывная приверженность к константам?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>Тему с накопительным поведением вы проигнорировали. ЕМ>Я задал вопрос: "Зачем нужны непременно накопительные? Как часто в них возникает потребность?". Вы не ответили.
На примере IEEE754 мы видим, как именно они нужны. Не проверять после каждой операции, а проверять после группы операций. Так как?
N>>Авторы считают, что отсутствие зависимости по скрытому значению — да, помогает в реализации. ЕМ>В каком смысле это значение более "скрыто", нежели значения регистров или ячеек памяти?
В том, что не названо явно в команде, но присутствует в ряде команд. Причём в вариантах x86, PDP-11, VAX, M68k и пачки других — неустранимо. ARM позволяет у большинства команд их не менять, и это уже большой прогресс.
(У тех архитектур ещё и во времена до тотального OoO любили ставить правило, что команда те флажки, которые ей не нужно ставить согласно логике, жёстко объявлены неизменными. А это и значит зависимость от предыдущего значения — то, от чего при OoO стараются уйти.
N>>у x86 то же самое в векторных операциях... потому что не может быть одного флага результата на 4-8-16 разных операций впараллель ЕМ>Насколько часто при векторных операциях необходимы ветвления по промежуточным результатам? Там, как правило, безусловные, "пакетные" алгоритмы.
А вы посмотрите, как их укладывают в этом случае. Часто приводят пример с операцией типа r[j] = (a[j] > b[j]) ? c[j] : d[j] в цикле; это, конечно, пример искусственный настолько же, насколько вычисление чисел Фибоначчи, но именно этим и показателен. В реале часто встречаются менее жёсткие версии, но всё же где надо делать развилки. Я получал лично такое в своём коде, когда векторизовывался какой-нибудь проход по тексту с поиском конкретных символов.
ЕМ>>>Реализация этих проверок в топологии/микрокоде процессора всегда дешевле, чем в каждой из выполняемых на нем программ. N>>Ну и где они в x86? ЕМ>Во флагах состояния, вестимо. Пусть и не все, хотелось бы больше.
Ну вот и проверяются у всех, кроме деления, явной командой типа jc или jo. А у деления — неявно и неустранимо. Неаккуратненько-с.
ЕМ>>>Потому, что перенос очень часто является следствием нормального выполнения, и как-то специально его обрабатывать не требуется, N>>Нет здесь такой несимметричности. ЕМ>Если сейчас навскидку скачать любой бинарник и дизассемблировать его — уверены, что действий со знаковыми величинами, при которых штатно возникает переполнение, найдем примерно столько же, сколько и для беззнаковых?
Да. С поправкой опять же на явные modulo типа счётчиков и номеров позиций. Или для беззнаковых даже больше таких ситуаций — см. вами же поднятую тему пару лет назад, где сравнивались итерирования по переменной в окрестностях нуля.
N>>где говорят про экономию ресурсов ЕМ>Экономия на флагах состояния на фоне сложности любого процессора даже 30-40-летней давности — это фикция, тех ресурсов там совершенно ничтожное количество, исчисляемое единицами логических элементов.
А теперь просто рассмотрите это как ещё 4 регистра (а в x86 даже 6, есть ещё PF и AF), которые надо отдельно учитывать во всём дизайне включая переименование регистров.
N>>где про резкое облегчение дизайна за счёт отсутствия единого регистра флагов и за счёт этого лучшую параллельность. ЕМ>Тоже непонятно, где здесь может быть "резкое облегчение". Параллельное выполнение даже простых арифметических операций требует наличия нескольких полноценных АЛУ, а флаги состояния из такого АЛУ выходят либо сами по себе, либо путем добавления единиц логических элементов. Некоторое упрощение получить можно, "резкое" — тупо неоткуда.
Ну здесь я могу сослаться только на авторитет тех товарищей, что на этом сильно больше собак съели — типа Ватермана.
N>>Заметьте, Intel в своём проекте APX намеревается сделать то же самое. ЕМ>В последнее время явно видна тенденция сращивания функций процессора и компилятора. Если существующие архитектуры еще предполагали написание программы человеком на ассемблере, то новые уже предполагают только машинную генерацию кода. В таких условиях разумно целиком оптимизировать связку "компилятор+процессор" — возможно, в ней флаги состояния действительно получаются избыточными.
О. Значит, таки это при каких-то условиях возможно?
ЕМ>Но и x86, и ARM проектировались во времена, когда написание кода человеком на ассемблере использовалось достаточно широко.
Верно. Вся линия RISC уже открыто декларировалась на то, что код будет в основном генерироваться компилятором и надо ему облегчать работу, а не человеку. "Под нож" в первую очередь попали в этом случае сложные методы адресации — как PDP-11 и вслед ей VAX и M68k любили всякие @(Rn)+ ... а x86 не успел их ввести и поэтому меньше пострадал в начале 90-х.
ЕМ>>>Это было бы следуюшим по разумности вариантом при отказе от исключения. N>>Как раз более разумно, чем исключение ЕМ>Если предполагается, что программа всегда будет генерироваться автоматически, и статистика показывает, что затраты на проверку после каждого деления потеряются на общем фоне, то да.
Достаточно не "всегда", а в подавляющем большинстве случаев. Что и имеем.
EM>>> Порождать исключения для арифметических переполнений нет смысла, поскольку они очень часто возникают в совершенно нормальных, запланированных ситуациях. N>>Кажется, единственный вариант, при котором это возможно, это арифметика "по модулю". Назвать такое "очень часто" — это слишком сильная натяжка. ЕМ>Например, там, где нуль/ненуль нужно преобразовать в 0/1 или 0/-1, компиляторы вовсю используют комбинации из neg, sbb, inc и and.
Я читал Hackerʼs Delight, да. Там таких примеров много. Но для x86 всё-таки test + setcc проще. Для ARM аналогично, с поправкой, что test == ands, и варианты csel позволяют сразу формировать значения типа -1 (csinv по условию). Для RISC-V, для сравнения, bool(rs==0) пишется как sltiu rd,rs,1, а bool(rs!=0) — sltu rd,x0,rs. Вообще одна команда. Ну если нужно -1, то да, ещё инвертировать знак (sub rd,x0,rd). То есть в таком режиме действие даже упрощается. И никакого таки скрытого переполнения
EM> А счетчики с переполнением часто используются для отслеживания небольших временнЫх интервалов в алгоритмах реального времени.
И от общего количества кода для процессора таких будет где-то 0.001%. Вряд ли больше. Ну ладно, в очень embedded — 0.1%.
N>>мы знаем, что "нормальных, запланированных" ситуаций с переполнениями почти нет ЕМ>Хорошо Вам, что "вы знаете". Я вот их использую регулярно, и столь же регулярно вижу в коде, который делает компилятор (те же преобразования int в bool).
И он регулярно использует эту извращённую последовательность из четырёх команд? Зачем?
EM> А вот операций с заведомо знаковыми величинами, при которых знаковое же переполнение было бы штатной ситуацией, и не требовало специальных действий, я с ходу даже не припомню, как и в случае деления на нуль.
Да, их мало. Я действительно не могу вспомнить характерные примеры.
Но вы сделали ошибку вот в чём: вы отождествляете беззнаковые и модульные типы. А это разные типы, в нормальных местах, а не извращенческих вроде C/C++.
В честных беззнаковых тоже переполнение как штатная ситуация как-то не присутствует.
ЕМ>>>чтобы в ситуации, когда что-то пошло не так, не было риска забыть проверить возвращаемое значение в ситуации, когда не существует заведомо безопасного значения для нештатной ситуации. N>>Ну и почему на это плюют во всяких x86 для трёх операций из четырёх (это ещё и если не считать сдвиги за арифметику со степенью двойки, тогда окажется, что в 7 из 8)? ЕМ>Где можно найти примеров, в которых это "наплевательство" требуется обставлять ловушками?
Вообще-то где угодно, где нет гарантии согласно проверенным локально данным, что переполнения нет.
ЕМ>>>Тогда и в плюсовых исключениях тоже нет смысла. Не в их неправильном использовании, а в механизме, как твковом. N>>Передёргиваете. Я ясно сказал, что возможность проверки есть и там, где её применяют, проблема детектируется. Может, чуть заморочно. ЕМ>Пытаюсь увидеть разницу, но не вижу. Если в процессоре не возбуждать исключения при делении на нуль, а возвращать специальное значение, необходимо добавлять проверку после каждого деления; случаев, когда программа может безопасно использовать специальное значение, найдется очень мало.
И в этом предложении можно заменить "деление" на "умножение", "сложение", "вычитание" с ровно таким же успехом. Только вместо деления на 0 будет какое-то из переполнений. Почему тогда не делать, что любая подобная операция вызывает исключение?
N>>случаи проблем из-за непойманного переполнения при остальных трёх арифметических операциях — уже десятки. ЕМ>Этих тоже хватало. Но, если б каждое такое переполнение порождало исключение, было бы еще хуже.
Чем хуже? Везде некорректное значение, которое ломает дальнейшую логику.
N>>Проверка каждого результата при укладке в целевую переменную, на её границы, плюс операций с базовым размером значения (как int и long в C) на переполнения. Не сильно большая цена за реальную безопасность. ЕМ>Это было бы полезно во всех без исключения языках, но не безусловно, а при возможности независимого управления каждым видом проверок.
Да, и я примерно в эту же сторону комментирую при каждой возможности последние надцать лет.
N>>Ну вот вы почему-то постановили, что константы разрядности в виде 32 и 64 они оправданны, а остальные — нет. ЕМ>Это не "мы постановили", это непосредственно вытекает из физических, железных характеристик архитектуры.
Нет. Тотальная двоичная иерархия размеров, сложившаяся в последние десятилетия, это чисто вопрос базового удобства на несколько процентов. Другие размеры тоже существуют и используются.
EM> А числа вроде 2 Гб для границы АП, или 480 Мб для бессбойной загрузки Win95, ниоткуда не вытекают, а возникают произвольно.
Половина всего адресного размаха — что тут произвольного?
N>>жалобы при переходе на S/360, что 32-битный float был заметно хуже 36-битного по свойствам. ЕМ>Вроде неудивительно. Чем не устраивал 64-битный?
Дороже в разы.
N>>Надо было таки оставить разрядности типа 36 и 72? ЕМ>Они и так оставались доступными через 64- и 128-разрядные. Или Вы о хранении чисел в памяти?
Нет, я о том, что был 36-битный формат float соответственно размеру слова машины, и у него были нормальные характеристики. А когда S/360 форсировала те же 32 бита слова, и пришлось влезать в 32 бита для float, пришлось делать диверсии в формате — начиная с base16 вместо base2, от чего резко ухудшилась точность.
64-битный float был сильно дороже, 128-битного не было.
N>>увеличение выше 2GB реально стоило — мороки программистам и производительности ядру. Сплошная перекачка данных между буферами. ЕМ>Почему при границе в 2 Гб "сплошной перекачки" нет, а при смещении на те же 3 Гб вдруг потребовалась?
Это зависело не от границы, а от объёма RAM. Чтобы не было перекачек, нужно, чтобы виртуальное адресное пространство полностью покрыло 2*RAM+MMIO, ещё и с потерями на фрагментацию каталогов. При переходе примерно к 1.5GB RAM это перестало выполняться. Хотеть деление виртуального пространства 3:1 или 3.5:0.5 начали уже при наличии 4-8GB RAM, до этого не было таких желающих.