Каким должен быть язык программирования? Анализ и критика Описание языка Компилятор
Отечественные разработки Cтатьи на компьютерные темы Компьютерный юмор Новости и прочее

Поддержка профилирования кода программы на низком уровне

Тема этой заметки навеяна жалобами программистов на неудобные или недостаточно полные средства профилирования кода программы, используемые при поиске «узких мест» с точки зрения производительности. Например, вот: http://rsdn.org/forum/cpp.applied/7731507.flat

На мой взгляд, одной из причин этого является почти полное отсутствие поддержки такого профилирования на низком уровне, т.е. со стороны процессора.

Помнится, в начале 90-х у меня был настольный компьютер (к сожалению, забыл марку, по-моему, немецкий), у которого на передней панели был спидометр! Я не шучу. На его передней панели был индикатор из светодиодных сегментов для трех цифр. Согласно очень мутному описанию, он показывал число команд в штуках, то ли в среднем за такт, то ли за какой-то фиксированное время. В общем, он показывал какое-то число, обычно близкое к 1.00 и чем оно было выше, тем более производительным был в этот момент процессор. Прекрасная вещь для поиска «узких мест»! И, главное, специально для замеров в программе делать ничего не надо было: поменял очередной раз код, запустил тестовый прогон и смотришь на индикатор. Тактовые частоты тогда были невысокие, считалось все относительно медленно, вполне можно было разглядеть любые незначительные отклонения производительности.

С его помощью я, отчасти из спортивного интереса, отчасти из уязвленного самолюбия, пытался ускорить работу транслятора с ассемблера RASM-86. Он выполнял тест за 23.4 секунды, а борландовский MASM выполнял этот тест за 8.3 секунды. С помощью этого волшебного индикатора я быстро нашел все узкие места и неудачные команды (конечно, они оказались в лексическом анализаторе) и добился выполнения теста за 5.6 секунды.

Вроде бы сейчас, имея в Windows диспетчер задач с его графиками производительности, не нужны никакие другие индикаторы. Однако в современной многоядерной и многопоточной системе трудно бывает понять, что на что влияет. Хотелось бы более простых и понятных средств.

По-моему, аппаратно это несложно добавить в любой современный процессор. Поскольку я хорошо знаю лишь архитектуру x86, попробуем помечтать на её примере. В этой системе команд есть операция RDTSC, которая возвращает число тактов с момента включения процессора и к ней можно обращаться в любой момент. Всякие тонкости, вроде того, что она дает такты с учетом простоев для текущего ядра и при переключении ядер можно получить меньше тактов, чем при предыдущем запросе, не будем учитывать.

Вся доделка для этой команды, ну, или для новой гипотетической команды RDTSC1 заключается в том, что для неё можно задавать параметры: начальный и конечный адрес и способ их учета. Кстати, параметры можно задавать через порты самого процессора и тогда его систему команд можно и вообще не менять.

Смысл в том, что при задании начального и конечного адресов внутренний счетчик тактов обнуляется и работает только, когда указатель RIP/EIP попадает внутрь заданного диапазона адресов. В другом режиме — счетчик начинает работу, когда RIP/EIP строго совпадает с начальным адресом и заканчивает, когда строго совпадает с конечным адресом.

Такая незначительная доработка процессора позволит использовать его для профилирования без какого либо изменения кода анализируемой программы.

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

В большинстве же случаев можно не ставить никаких специальных отладочных вызовов, не использовать никаких прерываний и вообще никак не влиять на работу кода. И в результате получать некоторую количественную характеристику производительности выполнения анализируемого участка кода. И при попытках улучшения сравнивать не все время работы огромной программы, а лишь с такой же предыдущей количественной характеристикой, т.е. становится возможным увидеть изменения производительности в масштабах микро- и наносекунд, не запуская миллионы циклов теста.

Таких команд, правда, пока нет. Но, возможно, что-то похожее именно для поддержки профилирования в будущем и появится.



Автор: Д.Ю.Караваев. 06.06.2020

Опубликовано: 2020.06.06, последняя правка: 2020.06.08    18:10

ОценитеОценки посетителей
   █████████████ 3 (30%)
   █████████████████ 4 (40%)
   █████████ 2 (20%)
   █████ 1 (10%)

Отзывы

✅  2020/06/08 18:19, Автор сайта          #0 

Когда-то читал легенду, что программисты Silicon Graphics были теми, кто «заказывали» себе систему команд и архитектуру процессора. Что для них был первичен софт, а вот железо они под себя подбирали. Но, правда, подтверждения этих легенд я нигде не встречал. Но, наверное, счастливые были люди — программисты Silicon Graphics :)

Шансов на то, что Ваши пожелания Intel учтёт, даже не ничтожны. Их просто нет. Все коды уже заняты какими-то командами. Незанятых кодов так мало, что их «растягивают», задают новым командам очень большую длину, чтобы оставить ещё какой-то резерв. От этого коды новых команд очень длинны, что не есть хорошо.

Жаль, что для программистов самый низкий доступный уровень — это уровень команд, в то время, как ещё существует уровень микрокоманд. Вот была бы возможность написать пользовательскую микропрограмму и вызвать её по коду «пользовательская команда». Тогда «хотелки» было бы проще реализовать :)

борландовский MASM

Вроде бы MASM — это Microsoft, а у Borland был TASM? Или я заблуждаюсь?

✅  2020/06/08 21:53, kt          #1 

Шансов на то, что Ваши пожелания Intel учтёт, даже не ничтожны. Их просто нет.

Да, я тоже не рассчитываю, что разработчики Intel прислушаются к моим советам.
Но вероятность, что они сами введут что-нибудь подобное, отлична от нуля. Там же тоже полно программистов и у них тоже стоят проблемы оптимизации.

Все коды уже заняты какими-то командами. Незанятых кодов так мало, что их «растягивают», задают новым командам очень большую длину

Это мелочь. Ведь к гипотетическим командам профилирования не нужно будет часто обращаться, в отличие от системных вызовов, которые расставляют профилировщики.
Да и не все коды заняты. Вспомните несчастную INTO. Кроме этого, возможно чтение-запись через порты самого процессора, тогда никаких новых команд не требуется, достаточно уже имеющихся RDMSR/WRMSR или RDPMC на все случаи жизни.

Жаль, что для программистов самый низкий доступный уровень — это уровень команд, в то время, как ещё существует уровень микрокоманд.

Возможность менять микрокод физически, вероятно, есть. Исправляли же ошибки перепрограммированием процессоров в каждом компьютере. Правда, информацией о таких работах никто делиться не спешит.

К слову, опубликовано «Руководство по эффективному программированию на платформе .Эльбрус», наконец, с описанием настоящих команд этого процессора. На мой взгляд, это надо было делать лет 30 назад, но тогда тоже никто не спешил с публикованием.

TurboASM и MakroASM, да, перепутал.

Добавить свой отзыв

Написать автору можно на электронную почту
mail(аt)compiler.su

Авторизация

Регистрация

Выслать пароль

Карта сайта


Содержание

Каким должен быть язык программирования?

Анализ и критика

Описание языка

Компилятор

Отечественные разработки

Cтатьи на компьютерные темы

●  О превращении кибернетики в шаманство

●  Про лебедей, раков и щук

●  О замысле и воплощении

●  О русском ассемблере

●  Арифметика синтаксиса-3

●  Концепция владения в Rust на примерах

●●  Концепция владения в Rust на примерах, часть 2

●●  Концепция владения в Rust на примерах, часть 3

●  Суть побочных эффектов в чисто функциональных языках

●  О неулучшаемой архитектуре процессоров

●  Двадцать тысяч строк кода, которые потрясут мир?

●  Почему владение/заимствование в Rust такое сложное?

●  Масштабируемые архитектуры программ

●  О создании языков

●●  Джоэл Спольски о функциональном программировании

●  Почему Хаскелл так мало используется в отрасли?

●  Программирование исчезнет. Будет дрессировка нейронных сетей

●  О глупости «программирования на естественном языке»

●  Десятка худших фич C#

●  Бесплатный софт в мышеловке

●  Исповедь правового нигилиста

●  ЕС ЭВМ — это измена, трусость и обман?

●  Русской операционной системой должна стать ReactOS

●  Почему обречён язык Форт

●  Программирование без программистов — это медицина без врачей

●  Электроника без электронщиков

●  Программисты-профессионалы и программирующие инженеры

●  Статьи Дмитрия Караваева

●●  Идеальный транслятор

●●  В защиту PL/1

●●  К вопросу о совершенствовании языка программирования

●●  Опыт самостоятельного развития средства программирования в РКК «Энергия»

●●  О реализации метода оптимизации при компиляции

●●  О реализации метода распределения регистров при компиляции

●●  О распределении памяти при выполнении теста Кнута

●●  Опыты со стеком или «чемпионат по выполнению теста Кнута»

●●  О размещении переменных в стеке

●●  Сколько проходов должно быть у транслятора?

●●  Чтение лексем

●●  Экстракоды при синтезе программ

●●  Об исключенных командах или за что «списали» инструкцию INTO?

●●  Типы в инженерных задачах

●●  Непрерывное компилирование

●●  Об одной реализации специализированных операторов ввода-вывода

●●  Особенности реализации структурной обработки исключений в Win64

●●  О русском языке в программировании

●●  Формула расчета точности для умножения

●●  Права доступа к переменным

●●  Заметки о выходе из функции без значения и зеркальности get и put

●●  Модификация исполняемого кода как способ реализации массивов с изменяемыми границами

●●  Ошибка при отсутствии выполняемых действий

●●  О PL/1 и почему в нём не зарезервированы ключевые слова

●●  Не поминайте всуе PL/1

●●  Скорость в попугаях

●●  Крах операции «Инкогнито»

●●  Предопределённый результат

●●  Поддержка профилирования кода программы на низком уровне

●●  К вопросу о парадигмах

●  Следующие 7000 языков программирования

●●  Что нового с 1966 года?

●●  Наблюдаемая эволюция языка программирования

●●  Ряд важных языков в 2017 году

●●  Слоны в комнате

●●  Следующие 7000 языков программирования: заключение

Компьютерный юмор

Новости и прочее




Последние отзывы

2024/12/07 20:54 ••• Клихальт
Переключатель

2024/12/06 18:44 ••• Анкнав
Русский язык и программирование

2024/12/01 00:00 ••• alextretyak
Продолжение цикла и выход из него

2024/11/29 23:08 ••• Вежливый Лис
О русском ассемблере

2024/11/26 23:53 ••• Бурановский дедушка
ЕС ЭВМ — это измена, трусость и обман?

2024/11/25 18:31 ••• Деньги на WWWетер
Ресурсы, посвящённые созданию языков программирования и компиляторов

2024/11/12 20:24 ••• Вежливый Лис
Правила языка: строки, комментарии

2024/11/12 13:10 ••• Вежливый Лис
Новости и прочее

2024/11/12 00:32 ••• Автор сайта
Оценка надёжности функции с несколькими реализациями

2024/11/06 02:50 ••• Иван
Энтузиасты-разработчики компиляторов и их проекты

2024/11/05 23:51 ••• Борис К.
Изменение приоритетов операций

2024/11/05 23:38 ••• Борис К.
Шестнадцатиричные и двоичные константы

2024/11/01 12:11 ••• ИванАс
Русской операционной системой должна стать ReactOS