Почему вы программируете в сборке?
У меня есть вопрос обо всех хардкорных хакерах с низким уровнем. Я просмотрел это предложение в блоге. Я действительно не думаю, что источник имеет значение (это Хаак, если вы действительно заботитесь), потому что это похоже на общее утверждение.
Например, многие современные 3-D игры имеют свой высокопроизводительный ядро, написанный на С++ и Assembly.
Что касается сборки - это код, написанный на сборке, потому что вы не хотите, чтобы компилятор выдавал дополнительные инструкции или использовал избыточные байты, или вы используете лучшие алгоритмы, которые вы не можете выразить в C (или можете " t выражать без компилятора, разматывающего их)?
Я полностью понимаю, что важно понимать материал низкого уровня. Я просто хочу понять, почему программа в сборке после того, как вы ее понимаете.
Ответы
Ответ 1
Я думаю, вы неправильно читаете это утверждение:
Например, многие современные 3-D игры имеют свой высокопроизводительный ядро, написанный на С++ и Assembly.
Игры (и большинство программ в наши дни) не "написаны на сборке" так же, как они "написаны на С++". Этот блог не говорит, что значительная часть игры сконструирована в сборке или что команда программистов сидит и развивается в сборке в качестве основного языка.
Что это на самом деле означает, что разработчики сначала пишут игру и получают ее работу на С++. Затем они просматривают его, выясняют, что такое узкие места, и, если это стоит, они оптимизируют из них сборку. Или, если они уже есть опыт, они знают, какие части будут узкими местами, и у них есть оптимизированные части, сидящие вокруг из других игр, которые они создали.
Точка программирования в сборке такая же, как и всегда: скорость. Было бы смешно писать много кода в ассемблере, но есть некоторые оптимизации, о которых компилятор не знает, и для достаточно маленького окна кода человек будет делать лучше.
Например, для с плавающей запятой компиляторы имеют тенденцию быть довольно консервативными и могут не знать о некоторых более сложных функциях вашей архитектуры. Если вы согласны принять некоторую ошибку, вы обычно можете сделать лучше, чем компилятор, и стоит написать немного кода в сборке, если вы обнаружите, что на это потрачено много времени.
Вот еще несколько примеров:
Примеры из игр
-
Статья от Intel об оптимизации игрового движка с использованием встроенных функций SSE. Конечный код использует intrinsics (не встроенный ассемблер), поэтому количество чистой сборки очень мало. Но они смотрят на сборщик, выводящий компилятор, чтобы выяснить, что именно оптимизировать.
-
Quake быстрый обратный квадратный корень. Опять же, в рутине нет ассемблера, но вам нужно знать что-то о архитектуре для такой оптимизации. Авторы знают, какие операции выполняются быстро (умножить, сдвинуть) и медленные (делить, sqrt). Таким образом, они придумывают очень сложную реализацию квадратного корня, которая полностью исключает медленные операции.
Высокопроизводительные вычисления
-
Вне области игр люди в научных вычислениях часто оптимизируют дерьмо из вещей, чтобы заставить их быстро работать на новейшем оборудовании. Думайте об этом как о играх, где вы не можете обманывать физику.
Недавним примером этого является Решетчатая квантовая хромодинамика (решетчатая КХД). В этой статье описывается, как проблема в значительной степени сводится к одному очень маленькому вычислительному ядру, который был сильно оптимизирован для PowerPC 440 на IBM Blue Gene/L. Каждый 440 имеет два FPU, и они поддерживают некоторые специальные тернарные операции, которые сложно использовать для компиляторов. Без этих оптимизаций, Lattice QCD будет работать намного медленнее, что дорого, когда ваша проблема требует миллионов часов процессора на дорогих машинах.
Если вам интересно, почему это важно, ознакомьтесь с статьей в Science, которая вышла из этой работы. Используя решеточную КХД, эти парни вычислили массу протона с первых принципов и показали в прошлом году, что 90% массы происходит от сильной силы связи, а остальные от кварков. Это E = mc 2 в действии. Здесь сводка.
Для всех вышеперечисленных приложений не, разработанных или написанных на 100% в сборке, даже не закрываются. Но когда людям действительно нужна скорость, они сосредоточены на написании ключевых частей своего кода, чтобы летать на определенном оборудовании.
Ответ 2
Я не кодировал язык ассемблера в течение многих лет, но могу привести несколько причин, которые я часто видел:
-
Не все компиляторы могут использовать определенные оптимизации и набор процессоров (например, новые наборы команд, которые Intel добавляет время от времени). Ожидание компилятора, чтобы догнать, означает потерю конкурентного преимущества.
-
Легче сопоставить фактический код с известной архитектурой и оптимизацией процессора. Например, все, что вы знаете о механизме выборки, кешировании и т.д. Это должно быть прозрачным для разработчика, но дело в том, что это не так, поэтому авторы компилятора могут оптимизировать.
-
Доступ к аппаратным уровням возможен только на языке ассемблера (например, при написании драйвера устройства).
-
Формальное рассуждение иногда проще для языка ассемблера, чем для языка высокого уровня, так как вы уже знаете, что представляет собой окончательный или почти окончательный формат кода.
-
Программирование некоторых 3D-графических карт (около 1990-х годов) в отсутствие API-интерфейсов часто было более практичным и эффективным на языке ассемблера, а иногда и невозможным на других языках. Но опять же, это включало действительно игры на уровне экспертов, основанные на архитектуре ускорителя, такие как ручное перемещение данных в определенном порядке.
Я сомневаюсь, что многие люди используют язык ассемблера, когда язык более высокого уровня будет работать, особенно когда этот язык является C. Ручная оптимизация большого количества кода общего назначения непрактична.
Ответ 3
Существует один аспект ассемблерного программирования, о котором другие не говорили - чувство удовлетворения, которое вы получаете, зная, что каждый байт в приложении является результатом ваших собственных усилий, а не компилятора. Я бы не хотел, чтобы второй захотел вернуться к написанию целых приложений на ассемблере, как я это делал в начале 80-х, но иногда мне это не хватает...
Ответ 4
Обычно сборка непрофессионала медленнее C (из-за оптимизации C), но многие игры (я отчетливо помню Doom) должен был иметь определенные разделы игры в сборке, чтобы он работал нормально на обычных машинах.
Вот пример, к которому я обращаюсь.
Ответ 5
Я начал профессиональное программирование на ассемблере в моей первой работе (80-е годы). Для встроенных систем требования к памяти - RAM и EPROM - были низкими. Вы можете написать жесткий код, который был бы легким по ресурсам.
К концу 80 я переключился на C. Код был легче писать, отлаживать и поддерживать. Очень маленькие фрагменты кода были написаны на ассемблере - для меня это было, когда я писал переключение контекста в вашей собственной RTOS. (Что-то вы не должны делать больше, если это не "научный проект".)
Вы увидите фрагменты ассемблера в коде ядра Linux. Совсем недавно я просмотрел его в spinlocks и другом коде синхронизации. Эти части кода должны получить доступ к атомным операциям тестирования и настройки, манипулировать кешами и т.д.
Думаю, вам будет сложно оптимизировать современные компиляторы C для большинства общих программ.
Я согласен с @altCognito, что ваше время, вероятно, лучше потрачено на размышление о проблеме и улучшение ситуации. По какой-то причине программисты часто сосредотачиваются на микроэффективности и игнорируют макроэффективность. Язык ассемблера для повышения производительности - это микроэффективность. Переход к более широкому представлению системы может выявить проблемы макросов в системе. Решение макроэкономических проблем часто может привести к повышению производительности.
Как только проблемы макросов будут решены, тогда сверните на микроуровне.
Я думаю, что микро-проблемы находятся под контролем одного программиста и в меньшем домене. Изменение поведения на макроуровне требует общения с большим количеством людей - вещь, которую избегают некоторые программисты. Этот ковбой против команды.
Ответ 6
"Да". Но следует понимать, что по большей части преимущества написания кода на ассемблере не стоят затраченных усилий. Вознаграждение, полученное за написание его в сборке, как правило, меньше, чем простое сосредоточение внимания на том, чтобы усерднее думать о проблеме и тратить свое время на размышления о лучшем способе решения проблемы.
Джон Кармак и Майкл Абраш, которые были в значительной степени ответственны за написание Quake и весь высокопроизводительный код, который входил в идентификаторы игровых движков, подробно рассматриваются в этой книге.
Я также согласен с Олафуром Вейджем в том, что сегодня компиляторы довольно умны и часто используют много методов, которые используют скрытые архитектурные улучшения.
Ответ 7
В эти дни, по крайней мере, для последовательных кодов, достойный компилятор почти всегда превосходит даже очень опытного программиста на ассемблере. Но для векторных кодов это другая история. Широко развернутые компиляторы не выполняют такую большую работу, используя, например, векторно-параллельные возможности блока SSE x86. Я писатель компилятора, а , использующий SSE, возглавляет мой список причин, чтобы идти самостоятельно, а не доверять компилятору.
Ответ 8
Код SSE лучше работает в сборке, чем встроенные средства компилятора, по крайней мере, в MSVC. (т.е. не создает дополнительных копий данных).
Ответ 9
Некоторые команды/флаги/элементы управления просто отсутствуют на уровне C.
Например, проверка переполнения на x86 - это простой флаг переполнения. Этот параметр недоступен в C.
Ответ 10
Дефекты имеют тенденцию работать в строке (оператор, кодовая точка и т.д.); в то время как верно, что для большинства проблем сборка будет использовать гораздо больше строк, чем языки более высокого уровня, иногда случаются случаи, когда лучшие (самые краткие, наименьшие строки) сопоставляются с проблемой. Большинство из этих случаев связаны с обычными подозреваемыми, такими как драйверы и бит-биение во встроенных системах.
Ответ 11
В моих источниках три или четыре подпрограммы на ассемблере (размером около 20 МБ). Все они SSE (2) и связаны с операциями с (довольно большими - например, 2400x2048 и более) изображениями.
Для хобби я работаю над компилятором, и там у вас есть больше ассемблер. Динамические библиотеки довольно часто заполнены ими, большинство из них связано с вещами, которые не поддаются нормальному процессуальному режиму (например, помощники для исключений и т.д.)
У меня нет ассемблера для моего микроконтроллера. Большинство современных микроконтроллеров имеют настолько много периферийного оборудования (счетчики с контролем прерываний, даже весь квадратурный кодер и последовательные строительные блоки), что использование ассемблера для оптимизации циклов часто больше не требуется. С текущими ценами на флэш-память то же самое относится и к памяти кода. Кроме того, часто существуют линейки совместимых по выводам устройств, поэтому масштабирование, если у вас систематически заканчивается питание процессора или место на флэш-памяти, часто не является проблемой.
Если вы действительно не отправите 100000 устройств, а программист на ассемблере не позволит реально сэкономить, просто поместив флэш-чип в категорию меньшего размера. Но я не в этой категории.
Многие люди думают, что встраивание - это оправдание ассемблеру, но их контроллеры имеют большую мощность процессора, чем машины, на которых была разработана Unix. (Микрочип поставляется с 40 и 60 микроконтроллерами MIPS менее чем за 10 долларов США).
Однако многие люди застряли в наследство, поскольку изменить архитектуру микрочипа нелегко. Кроме того, код HLL сильно зависит от архитектуры (поскольку он использует аппаратную периферию, регистры для управления вводом/выводом и т.д.). Так что иногда есть веские причины продолжать поддерживать проект на ассемблере (мне повезло, что я смог наладить работу на новой архитектуре с нуля). Но часто люди обманывают себя тем, что им действительно нужен ассемблер.
Мне все еще нравится ответ профессора, когда мы спросили, можем ли мы использовать GOTO (но вы также можете прочитать его как ASSEMBLER): "если вы считаете, что стоит написать эссе на 3 страницы о том, зачем вам нужна эта функция, вы можете ее использовать. Пожалуйста, отправьте эссе с вашими результатами. "
Я использовал это как руководящий принцип для низкоуровневых функций. Не будьте слишком стеснены, чтобы использовать это, но убедитесь, что вы мотивируете это должным образом. Даже бросьте искусственный барьер или два (как эссе), чтобы избежать запутанных рассуждений как оправдания.
Ответ 12
Другая причина может заключаться в том, что доступный компилятор недостаточно хорош для архитектуры, а объем кода, необходимый в программе, не так уж и длинный или сложный, как для программиста, чтобы он потерялся в нем. Попробуйте программировать микроконтроллер для встроенной системы, обычно сборка будет намного проще.
Ответ 13
Помимо других упомянутых вещей, все высшие языки имеют определенные ограничения. Вот почему некоторые люди выбирают программу в ASM, чтобы иметь полный контроль над своим кодом.
Другие пользуются очень маленькими исполняемыми файлами в диапазоне 20-60 КБ, например, проверьте HiEditor, который реализован автором HiEdit контроль, превосходный мощный редактор для Windows с подсветкой синтаксиса и вкладками всего в ~ 50 кб). В моей коллекции у меня есть более 20 таких золотых элементов управления от Excell, как ssheets, на html-рендеринг.
Ответ 14
Я думаю, что многие разработчики игр будут удивлены этой информацией.
Большинство игр, которые я знаю, используют как небольшую сборку, как это возможно. В некоторых случаях вообще нет, а в худшем случае одна или две петли или функции.
Эта цитата чрезмерно обобщена и нигде не близка к истине, как это было десять лет назад.
Но эй, просто факты не должны мешать истинному крестовому походу хакера в пользу сборки.;)
Ответ 15
Если вы программируете 8-разрядный микроконтроллер низкого уровня с 128 байтами оперативной памяти и 4K программной памяти, у вас нет большого выбора в использовании сборки. Иногда, хотя при использовании более мощного микроконтроллера необходимо определенное действие, которое должно выполняться в точное время. Язык ассемблера полезен тогда, так как вы можете подсчитать инструкции и так измерять тактовые циклы, используемые вашим кодом.
Ответ 16
Если бы вы были вокруг всех усилий по восстановлению Y2K, вы могли бы заработать много денег, если бы знали сборку. В нем все еще есть много устаревшего кода, и этот код иногда нуждается в обслуживании.
Ответ 17
В прошлый раз, когда я писал в ассемблере, я не мог убедить компилятор генерировать свободный от libc, независимый от позиции код.
В следующий раз, вероятно, будет по той же причине.
Конечно, у меня были другие причины.
Ответ 18
Помимо очень маленьких проектов на очень маленьких процессорах, я бы не собирался программировать весь проект в сборке. Тем не менее, обычно обнаруживается, что узкое место производительности можно устранить с помощью стратегического ручного кодирования некоторых внутренних циклов.
В некоторых случаях все, что действительно необходимо, - это заменить какую-либо конструкцию языка инструкцией, согласно которой оптимизатор не может рассчитывать на то, как использовать. Типичный пример - в приложениях DSP, где векторные операции и операции умножения-накапливания трудно обнаружить оптимизатору, но легко передать код.
Например, некоторые модели SH4 содержат матрицу 4x4 и 4 векторные инструкции. Я видел огромное улучшение производительности в алгоритме цветокоррекции путем замены эквивалентных операций C на матрице 3x3 соответствующими инструкциями при минимальной стоимости увеличения матрицы коррекции до 4x4 в соответствии с допуском аппаратного обеспечения. Это было достигнуто, написав не более дюжины строк сборки и неся соответствующие корректировки соответствующих типов данных и хранилища в нескольких местах в окружающем C-коде.
Ответ 19
Это, похоже, не упоминается, поэтому я подумал, что добавлю: в разработке современных игр я думаю, что хотя бы часть написанной сборки не для процессора вообще. Это для GPU, в виде шейдерных программ.
Это может потребоваться по разным причинам, иногда просто потому, что любой используемый язык затенения более высокого уровня не позволяет точно выражать точную операцию в точном количестве желаемых инструкций, чтобы соответствовать ограничениям по размеру, скорости, или любой комбинации. Как обычно, с программированием на ассемблере, я думаю.
Ответ 20
Почти каждый средний или большой игровой движок или библиотека, которые я видел на сегодняшний день, имеют некоторые оптимизированные вручную версии сборки, доступные для матричных операций, таких как конкатенация матрицы 4x4. Кажется, что компиляторы неизбежно упускают некоторые из умных оптимизаций (повторное использование регистров, развертка циклов максимально эффективным способом, использование машинных команд и т.д.) При работе с большими матрицами. Эти функции манипуляции с матрицами почти всегда являются "горячими точками" в профиле.
Я также видел, что сборка с ручной кодировкой использовала много для персонализированной отправки - такие вещи, как FastDelegate, но компилятор и конкретная машина.
Наконец, если у вас есть процедуры обслуживания прерываний, asm может внести все изменения в мир - есть определенные операции, которые вы просто не хотите встречаться при прерывании, и вы хотите, чтобы ваши обработчики прерываний "встали и вышли" быстро "... вы почти точно знаете, что произойдет в вашем ISR, если оно будет в asm, и это побуждает вас держать кровавые вещи короткими (что является хорошей практикой в любом случае).
Ответ 21
Единственное ассемблерное кодирование, которое я продолжаю делать, - это встроенное оборудование с ограниченными ресурсами. Как упоминает leander, сборка все еще хорошо подходит для ISR, где код должен быть быстрым и понятным.
Вторая причина для меня - сохранить знания о функциях сборки. Возможность проверить и понять шаги, которые процессор делает для моих ставок, просто чувствует себя хорошо.
Ответ 22
Игры довольно голодны и, хотя тем временем оптимизаторы довольно хороши, "мастер-программист" по-прежнему способен выжать еще больше производительности, вручную кодируя правильные части сборки.
Никогда не начинайте оптимизировать свою программу, не профилируя ее в первую очередь. После того, как профилирование должно быть способно идентифицировать узкие места, и если поиск лучших алгоритмов и т.п. Больше не сокращает его, вы можете попытаться передать код в сборке.
Ответ 23
Я только лично поговорил с одним разработчиком о его использовании сборки.
Он работал над прошивкой, которая касалась элементов управления для портативного mp3-плеера.
Выполнение работы в сборке имело две цели:
- Скорость: задержки должны быть минимальными.
- Стоимость: будучи минимальным с кодом, аппаратное обеспечение, необходимое для его запуска, может быть немного менее мощным. Когда массовое производство миллионов единиц, это может сложить.
Ответ 24
Больше нет скорости, но Контроль. Скорость иногда возникает из-за контроля, но это код только для сборки кода. Каждая другая причина сводится к контролю (например, SSE и другая ручная оптимизация, драйверы устройств и код, зависящий от устройства, и т.д.).
Ответ 25
Если мне удастся превзойти GCC и Visual С++ 2008 (известный также как Visual С++ 9.0), тогда люди будут заинтересованы в собеседовании со мной о том, как это возможно.
Вот почему на данный момент я просто читаю вещи в сборке и просто пишу __asm int 3, когда это необходимо.
Я надеюсь, что эта помощь...
Ответ 26
Я не писал в сборке несколько лет, но по двум причинам, которые я использовал:
- Задача вещи! Я прошел через несколько месяцев
назад, когда я напишу все в сборка x86 (дни DOS и Windows
3.1). Он в основном научил меня куску операций низкого уровня, аппаратное обеспечение I/O и т.д.
- Для некоторых вещей он сохранил размер небольшой (снова DOS и Windows 3.1 при написании TSR s)
Я снова смотрю на сборку кодирования, и это не что иное, как вызов и радость вещи. У меня нет других причин для этого: -)
Ответ 27
Однажды я взял проект DSP, который предыдущий программист написал в основном в ассемблере, за исключением логики распознавания тона, которая была написана на C, с использованием плавающей запятой (на DSP с фиксированной точкой!). Логика обнаружения тона работает примерно в 1/20 от реального времени.
Я закончил переписывать почти все с нуля. Почти все было в C, за исключением некоторых небольших обработчиков прерываний и нескольких десятков строк кода, связанных с обработкой прерываний и низкочастотным детектированием частоты, который работает более чем в 100 раз быстрее, чем старый код.
Важно помнить, что во многих случаях будет гораздо больше возможностей для повышения скорости с небольшими программами, чем крупные, особенно если рукописный ассемблер может поместить все в регистры, а компилятор не справится. Если цикл достаточно велик, что он все равно не может хранить все регистры, тем меньше возможностей для улучшения.
Ответ 28
Dalvik VM, которая интерпретирует байт-код для Java-приложений на телефонах Android, использует ассемблер для диспетчера. Этот фильм (около 31 минуты, но его стоит посмотреть весь фильм!) Объясняет, как
"Есть еще случаи, когда человек может сделать лучше, чем компилятор".
Ответ 29
Я этого не делаю, но я поставил точку, по крайней мере, попробовать и попытаться в какой-то момент в будущем (скоро надеюсь). Не может быть плохо, чтобы узнать больше о материалах низкого уровня и о том, как все работает за кулисами, когда я программирую на языке высокого уровня. К сожалению, время трудно найти с полной занятостью в качестве разработчика/консультанта и родителя. Но я дам приходить в свое время, это точно.
Ответ 30
Многие люди любят клеветать на ассемблере, потому что они никогда не учились кодировать с ним и лишь смутно сталкивались с ним, и это оставляло их либо в ужасе, либо несколько запугивало. Истинно талантливые программисты поймут, что бессмысленно разбивать C или Assembly, потому что они бесплатны. на самом деле преимущество одного является недостатком другого. Организованные синтаксические правила C улучшают ясность, но в то же время отказываются от всех силовых сборок от отсутствия каких-либо структурных правил! Инструкция C-кода предназначена для создания неблокирующего кода, который, как можно утверждать, вызывает ясность замысла программирования, но это потеря мощности. В Си компилятор не разрешает переход внутри if/elseif/else/end. Либо вам не разрешено писать два цикла for/end для различных переменных, которые перекрывают друг друга, вы не можете писать самоизменяющийся код (или не можете легко и просто) и т.д. Обычные программисты пугаются вышеупомянутым и могут понятия не имею, как даже использовать силу этих подходов, поскольку они были подняты, чтобы следовать общепринятым правилам. Вот истина: сегодня у нас есть машина с вычислительной мощностью, чтобы делать гораздо больше, чем приложение, для которого мы их используем, но человеческий мозг слишком неспособен кодировать их в среде программирования без правил (= сборка) и нуждается в ограничительных правилах, которые в значительной степени уменьшить спектр и упрощает кодирование. Я сам написал код, который не может быть написан на C-коде, не становясь чрезвычайно неэффективным из-за вышеупомянутых ограничений. И я еще не говорил о скорости, которая, по мнению большинства людей, является основной причиной написания на ассемблере. Что ж, если вы ограничены умением думать на С, то вы навсегда останетесь рабом своего компилятора. Я всегда думал, что мастера шахматистов будут идеальными программистами на ассемблере, а программисты на Си просто играют в "Дам".