Я анализирую различия между двумя проектами, которые обрабатывают миллионы сообщений. Один дизайн использует полиморфизм, а другой — нет, каждое сообщение будет представлено полиморфным подтипом.
Я профилировал оба проекта, используя VTune. Сводные данные высокого уровня, по-видимому, имеют смысл: полиморфный дизайн имеет более высокий показатель «непредсказуемости ветвлений», более высокий CPI и более высокий показатель «промахов ICache», чем неполиморфная версия, реализованная с помощью операторов IF.
У полиморфного дизайна есть строка исходного кода, подобная этой:
object->virtualFunction();
и это называется миллионы раз (где подтип меняется каждый раз). Я ожидаю, что полиморфный дизайн будет медленнее из-за неправильных предсказаний / ошибок инструкций ветви. Как уже говорилось выше, вкладка «Сводка» VTune, кажется, подтверждает это. Однако, когда я иду к метрикам рядом со строкой исходного кода, абсолютно нет метрик, кроме:
Ни у одного из столбцов прогноза ветвления нет данных, и при этом в кеше команд отсутствуют столбцы?
Может ли кто-нибудь прокомментировать, кажется ли это разумным? Для меня это не так — как не может быть никакой ошибки в прогнозировании ветвлений или статистики кэша инструкций для строки полиморфного кода, в которой цель ветвления будет постоянно изменяться в каждом сообщении?
Это не может быть связано с оптимизацией / встраиванием компилятора, потому что компилятор не будет знать подтип объекта для оптимизации.
Как мне профилировать издержки полиморфизма с помощью VTune?
Я постараюсь ответить на эту первую часть вопроса:
Может ли кто-нибудь прокомментировать, кажется ли это разумным? Для меня это
не может быть, как не может быть ошибочного прогнозирования ветки или кеша команд
пропустить статистику для строки полиморфного кода, где целевая ветвь
будет постоянно меняться за сообщение?Это не может быть связано с оптимизацией / встраиванием компилятора, потому что
Компилятор не будет знать подтип объекта для оптимизации.
На самом деле у компилятора есть способ встроить вызовы виртуальных функций, это довольно интересный трюк, и я был удивлен, когда узнал об этом.
Вы можете посмотреть этот разговор Эрика Брумера для более подробной информации, начиная с 22:30 мин., он говорит об оптимизации косвенных вызовов.
По сути, вместо выдачи простой инструкции перехода для этого указателя виртуальной функции, компилятор сначала добавляет несколько сравнений, а для некоторых известных значений указателей прогнозирует конкретную вызываемую виртуальную функцию, а затем этот вызов может быть встроен внутри этой ветви. В этом случае непредсказуемый скачок значения указателя превращается в простое предсказание ветви сравнения, и современные ЦП хороши в этом. Таким образом, если большинство вызовов будут реализованы в одной и той же конкретной реализации виртуальной функции, вы можете увидеть хорошие числа предсказания и низкие числа пропусков кэша команд.
Я бы порекомендовал изучить разборку для этого вызова функции. Честно ли он переходит к коду, используя косвенную указатель vtable, или он избегает перехода через vtable посредством некоторой оптимизации.
Если вызов не оптимизирован компилятором, процессор все еще может спекулировать Целевой буфер филиала. Например, если эта функция вызывается в узком цикле на объекте того же типа, то может не иметь значения, виртуальный он или нет, его адрес может быть предсказан …
НТН.
Вы не видите ошибочных предсказаний ветвления в самой инструкции, потому что выборки будут «агрегированы» в следующей инструкции после ветвления.
То же самое относится ко всем неточным событиям (без _PS
в конце). Это можно легко узнать, просто проверив обычный профиль кода. Например, с более высокой вероятностью можно обнаружить, что есть больше CPU_CLK_UNHALTED
образцы на простом add
чем на тяжелом imul
который пришел как раз перед add
,
Чтобы увидеть «точную» инструкцию, где произошло событие, вы должны использовать точные события, такие как BR_MISP_RETURED.ALL_BRANCHES_PS
,
Я не уверен на 100% в истинной природе этой «проблемы», и я знаю, что ее можно исправить, но по какой-то причине парни из драйвера выборки VTune не хотят этого делать. Я знаю одного парня, который боролся с этой проблемой последние 6 лет, и я принимаю это во внимание каждый раз, когда проверяю профиль asm VTune 🙂
PS. По поводу оригинального теста с виртуальными функциями. Я также проверил это, и он генерирует много предсказаний ветвлений. То же самое верно для указателей на функции. Один из способов исправить это — по возможности использовать шаблоны классов.