Раньше я писал много ассемблера назад. Дело не только в том, что компиляторы стали лучше, но и в том, что большая часть аппаратного обеспечения теперь имеет много логики, предназначенной для неупорядоченного выполнения кода. Настоящая микро-проблема - это планирование, большинство компьютерных инструкций требуют нескольких машинных часов для получения результата, а загрузка памяти, которая пропускает кеш, может занять несколько сотен! Таким образом, идея состояла в том, чтобы запланировать другие инструкции, чтобы сделать что-то полезное, вместо ожидания результата. А современные машины могут выдавать несколько инструкций за такт. Как только мы начали использовать HW для нестандартного исполнения, я обнаружил, что попытки добиться высокой производительности с помощью ручного кодирования стали игрой в кружки. Во-первых, вышедший из строя HW не будет выполнять инструкции в тщательно продуманном порядке, новая причудливая архитектура HW позволила снизить количество неоптимального планирования программного обеспечения настолько, что компилятор обычно находился в пределах нескольких процентов от вашей производительности. Также я узнал, что компиляторы теперь реализуют хорошо известные, но сложные приемы генерации, такие как развертывание, загрузка снизу, конвейерная обработка программного обеспечения и т. Д. Суть в том, что вам нужно действительно очень усердно работать, пропустить некоторые из этих приемов, и компилятор вас превзойдет. Используйте их все, и количество необходимых вам ассемблерных инструкций увеличится в несколько раз!
Возможно, что еще более важно, большинство проблем с производительностью связаны не с частотой команд, а с передачей данных в ЦП. Как я упоминал выше, задержка памяти теперь составляет сотни циклов, и процессор может выполнять несколько инструкций за такт, поэтому, если программа - и особенно структуры данных не спроектированы так, чтобы частота обращений в кэш-память была чрезвычайно высокой, микротонирование по команде уровень не будет иметь никакой выгоды. Так же, как военные говорят, что любители говорят о тактике, профессионалы говорят о логистике. Программирование производительности в настоящее время составляет более 90% логистики (перемещение данных). И это трудно определить количественно, поскольку современное управление памятью обычно имеет несколько уровней кэша, а страницы виртуальной памяти обрабатываются аппаратным модулем, называемым TLB. Кроме того, выравнивание адресов низкого уровня становится важным, так как фактические данные передаются не в байтах, или даже 64-битные long-long, но они приходят в единицах строк кэша. Тогда у большинства современных машин есть оборудование, которое пытается предсказать, какая строка кэша пропустит вас, возможно, потребуется в ближайшем будущем, и выполнить автоматические предварительные выборки, чтобы поместить их в кэш. Таким образом, реальность такова, что с современными процессорами модели производительности настолько сложны, что их практически невозможно понять. Даже подробные аппаратные симуляторы никогда не смогут соответствовать точной логике чипов, поэтому точная настройка просто невозможна.
Есть еще место для ручного кодирования. Математические библиотеки (как, например, функция exp), так же как и более важные операции линейной алгебры (например, умножение матриц), все еще обычно пишутся вручную экспертами, которые работают на поставщика оборудования (то есть Intel, AMD или IBM), но они, вероятно, только нужна пара первоклассных ассемблерных программистов на мегакомпьютерную корпорацию.