Компиляторы и ассемблер
Современные компиляторы хорошо умеют оптимизировать машинный код и обычно делают это гораздо лучше разработчика. Но нужно учитывать тот факт, что программа на некотором языке высокого уровня (ЯВУ) – это не алгоритм, а только запись алгоритма. Соответственно, компилятору принципиально доступны лишь структуры, нашедшие отражение непосредственно в записи, но не сам алгоритм. Один и тот же алгоритм вообще можно записать многими способами и на разных языках. Так что компилятор, в процессе перевода с входного ЯВУ на машинный язык, оптимизирует языковые конструкции. Компилятор не видит алгоритм и не может его оптимизировать. Разработчик, в теории, способен оптимизировать именно алгоритм, это следует из того, что разработчик как раз “переводит” (записывает) алгоритм на ЯВУ (но, конечно, лишь в том случае, если код пишется не силами очередного ИИ/LLM/ChatGPT, выстраивающего “токены” в псевдомарковскую цепь). Поэтому иногда нужен ассемблер.
Есть хрестоматийный “обратный” пример, иллюстрирующий ситуацию обработки структур, которые образует запись алгоритма – “схлопывание” циклов: оптимизирующий компилятор обнаруживает, что промежуточный результат шагов циклического выполнения команд, записанного в программе, не используется, поэтому просто выкидывает цикл, схлопнув структуру, вся внутренняя сложность которой оказалась сводимой к прямому подключению ввода к выводу. Тексты программ не несут смысла сами по себе, а в этом случае за записью программы, как выясняется, стояли разные “алгоритмы”. Разработчик хотел измерить производительность некоторой реализации функции, вызывая её много раз в цикле; а компилятор стремился уменьшить время выполнения программы – количество шагов, приводящее к достижению результата: как говорится, если результат тот же, то зачем тратить больше вызовов?
Компилятор не может видеть алгоритм, но при этом ещё и должен генерировать более или менее универсальный код, пригодный и для исполнения на различных версиях совместимой аппаратуры, и для совсем разных платформ. То есть, уже из-за разнообразия платформ, компилятору затруднительно повсеместно использовать конкретные аппаратные оптимизации даже для конкретных алгоритмических элементов. Ассемблер, в руках разработчика, позволяет это сделать. Тем не менее, так как модели вычислений разных платформ очень близки, то и высокоуровневые решения дают хороший, эффективный результат.
С другой стороны, использование ассемблера вовсе не исключает эффект от “фокусов оптимизации” современных “больших” процессоров (amd64 и пр.): видимые снаружи такты, записанные за выполнением конкретной операции, не обязательно соответствуют реальным тактам – тут накладывается не только параллельное исполнение (его ещё и может быть несколько уровней), но и возможное “предварительное” выполнение, предсказание ветвлений и так далее. Однако ассемблер всё же ближе к аппаратуре, поэтому в целом ряде случаев позволяет сильно повысить именно алгоритмическую точность описания, а не языковое удобство, как в ЯВУ. Типичный пример – использование длинных регистров. Но многое зависит от конкретной ситуации – современный компилятор очень часто генерирует код не хуже, чем написал бы на ассемблере опытный разработчик. Особенно, если учитывать необходимый контроль, которым принято обставлять сложный код для повышения его надёжности: контроль обращений к памяти, адресные таблицы и так далее.
Адрес записки: https://dxdt.ru/2024/03/22/12585/
Похожие записки:
- Криптографическая библиотека для Arduino: дополнение для новых IDE
- Помехи GNSS и распределённые "геосервисы"
- Централизованные мессенджеры и многообразие мест хранения сообщений
- Очевидная математика протокола Диффи-Хеллмана
- Медь в чернилах и точки на полях манускриптов
- Длина "постквантовых ключей" и немного про будущее DNS
- LLM и "решения" задач
- ИИ с перебором
- О квантовой криптографии на сайте IBM
- Представления о квантах и радиостанции
- Квантовые методы коррекции ошибок в СМИ
Написать комментарий