Как стать автором
Обновить

Комментарии 42

Я бы не сказал, что из сравнения предварительных анализов Amplifier нельзя объяснить прирост.
Видно, что для matrix_cl

INST_RETIRED 1.20926e+11

а для matrix

INST_RETIRED 5.687e+10

То есть для той же работы потребовалось в два раза меньше инструкций. Если считать, что в среднем время исполнения одной инструкции в обеих версиях программы одинаково, то и получаем двукратное ускорение. Уменьшение количества инструкций сразу наталкивает на использование SSE, а значит и на векторизацию.

Так же из сравнения отчетов видно что есть проблемы с Front-End — это сильное отличие Instruction Starvation, а также сильно отличаются retire stalls.

Хорошо было бы показать распределение клоктиков по коду программы.
Прирост производительности конечно можно объяснить, но нельзя сказать, без анализа алгоритмов приложения, можно или нет получить какой-то выигрыш от векторизации. Нельзя сказать — нет SSE инструкций, значит возможен выигрыш от векторизации. В какой-то совсем оторванной от жизни теории — это так. Но в реальности нужно исследовать есть ли правильные циклы, есть ли в них цикловые зависимости. Ну и обрабатываемые данные должны правильно лежать в памяти, чтобы от векторизации был толк. Разве не так?
Конечно, же так.

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

1. Сократилось количество инструкций.
2. Смотрим ассемблер горячих путей программы.
3. Если находим SSE, то цикл+SSE наводи на мысль о векторизации.
4. Проверяем с помощью отчета компилятора о векторизации.

А если скомпилировать VS 2012, то что получится? Майкрософтовский компилятор тоже поддерживает авто-векторизацию.
Вы слегка поменяли мою мысль. Я спрашиваю, можно ли сделать заключение о том, может или нет производительность быть улучшена, измерив какие-то процессорные события. И привожу в качестве примера оптимизацию автовекторизация — которая действительно значительно улучшает производительность, но заключения о том может ли она быть сделана или нет нельзя получить без исследования кода программы.
Вы же мне показываете, что из сравнения двух рапортов Amplifierа можно понять за счет чего получен положительный эффект. С этим вашим рассуждением я абсолютно согласен. В данном случае можно. Мне было проще. Я когда подбирал тест уже знал чего хочу достичь и сразу использовал опцию -Qvec_report, чтобы увидеть автовекторизацию.
Что же касается сравнений автовекторизации разных компиляторов, то эта хорошая тема для отдельного исследования.
Что касается второй программы.
Вряд ли здесь компилятор что либо может сделать без помощи программиста.

Мы имеем проход по списку. Современные суперскалерные архитектуры очень не любят списки, так как очень сложно что-либо предсказать. Префечеры не срабатывают, начинаются задержки связанные с загрузкой данных из памяти. Фактически out of order режим перестает работать.

Компилятор умеет кое-что делать для таких случаев, в основном пытаясь повысить компактность используемых данных. Есть оптимизации перестановки полей, вынесения холодных полей в отдельные структуры и т.д. Только для этого нужно массу требований выполнить. Т.е. простые оценки опять не помогают — нужно исследовать каждый конкретный случай.
Есть оптимизации перестановки полей, вынесения холодных полей в отдельные структуры и т.д.

Для какого языка возможны эти оптимизации? В случае Си декларация однозначно определяет представление структуры в памяти. Максимум — можно добавить паддинг и выравнивание, но скажем поменять порядок следования полей уже нельзя.
Если вы не планируете отлаживать свое приложение, ставите максимальный уровень оптимизации, то для компилятора нет никаких ограничений в используемых трансформациях вашего кода, кроме выдачи в итоге верного результата. Понятно, если вы обращаетесь к элементам вашей структуры каким-нибудь хитрым способом через офсеты и указатели, то компилятор должен заметить ваш высокий проффесионализм и понять что ему лучше здесь отдыхать и не вмешиваться.
… то для компилятора нет никаких ограничений в используемых трансформациях вашего кода, кроме выдачи в итоге верного результата

Неверно. Есть стандарт языка. Если в результате применения трансформации возникает нарушение стандарта, такая трансформация нелегальна. Как именно должна быть представленна структура в памяти прописано в стандарте, делать по другому вы просто не имеете права.

То, что структура представлена в памяти определенным образом, важно для бинарной совместимости разных единиц трансляции, библиотек и интерфейсов ОС.

Традиционно, работа с бинарными форматами в Си происходит через структуру — инициализируем значения полей (возможно с преобразованием big/little endian), и пишем весь блок памяти целиком в файл или отправили по сети.

Ну и обращаться к полям структуры «хитрым способом через офсеты и указатели» вполне легально в рамках языка Си.
Вы так оставите без работы массу людей, которые пишут умные книги типа «Optimization compilers for modern architectures». Они, наивные, используют в своей жизни детский принцип «Если мама не увидит, это маму не обидит» :)
На самом деле никакого противоречия с бинарной совместимостью не возникает, поскольку все такие оптимизации делаются при создании исполняемого файла при наличии полного набора исходников. В объектных файлах и библиотеках вы ничего подобного не увидите.
Согласен. В рамках языка Cи много легальных вещей, которые осложняют жизнь компиляторам да и самим разработчикам. Иногда даже вводяться правила типа ansi_alias rules, чтобы ограничить креативность разработчиков. Задача компилятора сделать консервативный анализ, то есть доказать, что та или иная оптимизация корректна и не изменяет результаты работы приложения.
Справедливости ради, спецификация языка Си написана так, чтобы максимально «развязать руки» компиляторщикам. Например, порядок вычисления аргументов в функциях может быть любым, и так далее.

Задача оптимизации представления структур данных в Си, так чтобы никто не «поймал за руку», адски сложная и мало перспективная в плане возможного выигрыша в производительности задача. ИМХО.

Спрошу прямо: компилятор интела умеет делать такую оптимизацию для Си? Или другого языка?
Ну я думаю вы сильно ошибаетесь в оценках полезности таких оптимизаций для производительности. Я надеюсь приведу в будущем пару примеров, которые вас удивят.
Не вижу никакой сложности в изменении порядка полей в структуре.
Компилятор умеет делать такие оптимизации, но здесь сложно бывает доказать именно корректность. Руками программист может все делать гораздо эффективнее, но для этого нужно понимать, на что такие модификации влияют.
Не вижу никакой сложности в изменении порядка полей в структуре. Компилятор умеет делать такие оптимизации, но здесь сложно бывает доказать именно корректность.

А я вижу. Можно подробности? Какой компилятор, активна ли эта оптимизация по умолчанию или как ее включить?

Ну я думаю вы сильно ошибаетесь в оценках полезности таких оптимизаций для производительности.

Оптимизация важная, спора нет. Только это задача программиста, ИМХО.

Руками программист может все делать гораздо эффективнее....

Вот именно. У программиста банально больше возможностей в проектировании своих структур данных.
Есть в интеловском компиляторе такой набор опций — Qprof_use и -Qprof_gen. С этими опциями компилятор сначала делает инструментированный код, затем собирается статистика про выполнение приложения (тестовые прогоны) и на основе сбора этой статистики приложение еще раз пересобирается с ее учетом. Понятно, что приложение должно гоняться на представительном наборе данных. Тогда появляется возможность оценить вес использования тех или иных полей. Компановка вместе наиболее часто используемых полей должна снижать нагрузку на шину данных. Плюс к этому, наверняка, должна быть включена межпроцедурная оптимизация, чтобы проверить, что поля можно двигать. Как-то так, если коротко.
А если длинно, то нужно сделать отдельный пост по этой теме.
Про другие компиляторы не скажу — не изучал вопрос.
Удовлетворяет такой ответ?
Конкретики от вас видимо не дождешься)

Я поискал статьи на тему автоматической оптимизации структур данных; нашлось несколько штук [1,2,3]. У всех масса ограничений, которые ставят под сомнение применимость твкой техники в автоматическом режиме в языке Си.

Но будем считать, что Intel удалось совершить чудо.
Ну если выше не конкретика, то я пас.
Про ограничения я написал.
И Да! Мы здесь в Intel делаем чудеса :)
Хотя чудес я тут не вижу. Нужно посмотреть какие-то конкретные примеры и оценить область применимости данных оптимизаций. Она, скорее всего достаточно узкая.
Разумеется, это не конкретика.

Смотрите — есть оптимизация, про которую на сайте интел написано «structure spliting and field reordering», а еще сказано, что нужно для этого активировать IPO. И все.

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

Далее. Компилятор может давать советы о переупорядочивании полей. Это меня как раз не удивляет. А вот то, что можно в автоматическом режиме убедиться, что код не сломается, если переставить поля — вот это похоже на магию. В контексте языка Си, разумеется.
Так «неконкретное» поведение компилятора характерно практически для каждой оптимизации. Сначала нужно доказать, что оптимизацию можно делать. Доказательство может быть сложным и требовать много ресурсов, поэтому в любой момент компилятор может отказаться от дальнейшего исследования и отказаться от оптимизации. Далее нужно как-то оценить выгоду от оптимизации. И здесь может быть много факторов. Если взять для примера автовекторизатор, то он может сообщить о зависимостях, о плохой структуре цикла, о том что векторизовать невыгодно и т.д. В результате спрогнозировать, какие оптимизации будут применены в том или ином случае достаточно сложно.
Компиляторные оптимизации действительно работают часто как дополнительный бонус и многих это устраивает.
В чем магия-то? В том что нужно проверить все исходные файлы и убедиться что поля структуры всегда адресуются через их имена и никогда через указатели с какими-нибудь офсетами?
Так «неконкретное» поведение компилятора характерно практически для каждой оптимизации.

Ну согласитесь, что на некоторые оптимизации можно положиться. Например нет смысла умножение на степень двойки кодировать битовым сдвигом (как было принято в 90-е), компилятор сделает это сам.

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

Не только. Еще нужно убедиться, что структура в бинарном виде никогда не покидает пределы системы (сохранение в файлы и тп). Еще к полям может осуществляться доступ через структуру другого типа (распространенный Си трюк для эмуляции наследования).
Увидел ссылку на перестановку полей в памяти, и сразу же подумал на PGO. PGO — единственная оптимизация, которая может переставлять поля в памяти?
Думаю PGO и использование динамического профилировщика здесь действительно необходимо, потому что оценить частоту использования полей с помощью статического профилировщика проблематично, хотя в каких-то вырожденных случаях (поля вообще не используются) такое в принципе возможно.
Спасибо за вопрос.
Часто стиль написания кода сам по себе сильно мешает компилятору оптимизировать.
На днях наткнулся на интересную особенность в GCC (возможно справедливо и для остальных компиляторов, я не проверял) — при векторизации циклов результат зависит от мест слагаемых из-за редукции:
Векторизуется
for(i=0;i<n;i++) s += a[i] + b[i];
и
for(i=0;i<n;i++) s = a[i] + b[i] + s;
Не векторизуется
for(i=0;i<n;i++) s = s + a[i] + b[i];
А параметры компиляции можно в студию? Как то не верится что всё вот так просто.

s = s + (хвост)

и

s = (голова) + s

должны нормально векторизоваться… попробуй так

s = (a[i] + b[i]) + s

и

s = s + (a[i] + b[i])

Так как по умолчанию, скобки расставляются так:

s = s + (a[i] + (b[i]))

То есть разница в построенном дереве AST, как мне кажется, и оптимизации

s = s + (хвост) в s += (хвост)
В параметрах ничего особенного не было. Разница тут действительно в построенном дереве и в том, что получает векторизатор в виде SSA — в случае с векторизуемым циклом получается s_23 = _22 + s_33 и подобное, а в другом случае:
_21 = _20 + s_33;
_22 = MEM;
s_23 = _21 + _22;
и два сложения с s ставят компилятор в тупик.
Хотя по логике обработки сложений всё правильно.
Ответ очевиден. С точки зрения скорости работы. В некоторых процессорах перемножение матриц может быть осуществлено за один такт. В некоторых нет. Давайте сравним возможности.

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

Неэтично сравнивать Бугатти Вайерон и пирожок. Мне лично не хочется комфортно врезаться на полной скорости в какую-нибудь отсталую архитектуру, вроде 386. Поэтому, предлагаю, взять в зубы MASM, включить хедеры для последних нововведений в процессорах SSE3/SSE4, и сравнить с оптимизацией руками и головой, на конкретных алгоритмах типа FFT, нейронные сети, поиск на графах. Если человеку не удастся заставить выполняться программу быстрее, значит выиграет компилятор.

А так — странно даже. VC10 будет всегда работать хуже, так как известно, что Intel скрывается важная информация о внутреннем устройстве процессора, что называется «для внутреннего пользования», поэтому все ваши посты превратятся в рекламу вашего нового продукта Parallel Studio 2013.

Будет лучше, если вы будете сравнивать ваш продукт с самим собой. Например, чем продукт 2013 года лучше установленного продукта 2012, прогоните на тех же самых примерах из поста и, думаю, вы не увидите никакой разницы.

По моему будет лучше сравнивать gcc c++ с максимальными настройками для векторизации и оптимизации, а не мучить старушку VC 10. Она вам лично ничего плохого не сделала.

Сравнивайте компиляторы Intel только с компиляторами Intel.

Откуда такая уверенность, что Майкрософт не имеет доступ к информации? Проблема скорее всего в том, что нет достаточного количества специалистов, чтобы все это реализовать в компиляторе.
Нужно обращаться сразу с претензиями к Spec.org. Они делают перечисленные вами неэтичные вещи и постоянно сравнивают коды полученные с помощью разных компиляторов на разных вычислительных архитектурах. Да еще деньги за это получают.
Понятно, что разные компиляторы делают разные наборы оптимизаций с одним и тем-же набором опций, но в данном случае сравнение компиляторов — вовсе не тема данной статьи.
Собственно, я мог бы сравнит «старушку» VS2010 c каким-нибудь «древним» интеловским компилятором. Но результата это бы не изменило, поскольку автовекторизатор в интеловских компиляторах появился давно, а в VS только в VS2012.
Открою вам тайну, есть много людей, которые полагают, что Microsoft скрывает важную информацию об устройстве своих операционных систем.
Почему вы ограничиваете меня в инструментах по познанию мира :)?
Нужно ребятам из VTune/Aplifier намекнуть, что наличие высокоуровневых отчетов «для блондинок» вроде «Ваше приложение оптимизировано. Можно расслабиться.» или «Чувак, ты это пьяный писал?» — очень полезная вещь. Не всем нужно понимать все эти юниты, клок-тики, метрики, события, семплы и т.д. Кроме того, из поста я понял, что можно практически определить степень оптимизации кода, на основе метрики: тики на инструкции. Ведь так?
Не совсем — скорее наоборот.
Если спортсмен бежит с полным напряжением сил по длинной дороге, то он в итоге может уступить и черепахе, идущей коротким путем.
Кстати да. Не подумал о том, что может быть изначально выбран не тот алгоритм. Но с другой стороны, это уже точно не проблема тула, анализирующего код. Он (тул) просто смотрит на сколько оптимально выполняются инструкции на конкретном железе. Т.е. детали реализации его мало интересуют. Так что, тулу вполне себе можно говорить, о том «на сколько оптимально код работает на железе», а не «на сколько оптимально он решает поставленную задачу».
Согласен. Тул при анализе полезен и во многих случаях хорошо помогает. Но он очевидно не панацея и делать какие-то далеко идущие оценки без анализа приложения довольно бесперспективно.
Почему Vtune 2011, а на 2013?
В будущем исправлюсь.
Эксперимент проводили на Xeon X5570, процессор 2009 года выпуска. Так что особого смысла в VTune 2013 нет.

Вот если бы что-то из серии E7.
Ну в 2013 много полезного кроме поддержки более свежего железа и java. Надеюсь коллеги напишут топик, а то только про инспектор 2013 писали недавно.
Это не совсем то, как мне кажется. Этот стандарт больше для менеджмента и репортинга.
Ну, тут просто от результата идет весь процесс, т.е. мы сначала задаем целевые показатели, а потом начинаем оптимизировать. Если у нас нет четких критериев, какова должна быть производительность для пользователя — оптимизация бессмысленна.
Насколько я понял из описания, все сводится к одной чиселке, которая зависит от числа удовлетворенных пользователей. Получили тестовую версию продукта. От группы тестеровщиков получили отзывы. Посчитали чиселку. Вышло ниже заданного показателя. Значит нужно улучшать качество продукта. Эта оценка говорит нужно ли проводить оптимизацию или нет, но она не может сказать возможно ли провести оптимизацию. Так же эта оценка позволяет оценить качество проделанной работы.

В статье же ставится вопрос: Если необходимо улучшить производительность приложения, то на основании каких оценок можно понять, что это возможно. Было показано, что эффективная загрузка процессора является необходимым, но не достаточным критерием. При хорошей эффективной загрузке, можно было ускорить программу не переписывая ее.
Статья не дает ответ на вопрос: а что если выбран в принципе не тот алгоритм? если инструмент/библиотека не оптимальны для таких случаев? И т.п. Она дает ответ на вопрос только «насколько существующий алгоритм использует возможности моего процессора». Зачастую маленькое изменение бизнес-логики (или пересмотр используемых индексов, или нахождение другой реализации задачи, или даже выполнение проверок в другом порядке) дает намного более существенный прирост, чем тонкая оптимизация из-за неоптимального доступа к памяти, который не дает использовать какие-нибудь инструкции от SSE. Я, конечно, говорю об учетных и бизнес системах. В играх и научных расчетах ситуация может отличаться существенно (хотя уже почти везде начинают решать задачи «в лоб», полагаясь на огромную производительность современных компьютеров).
В идеале деле у инструмента оценки производительности должно быть две опции: оценка производительности реализации существующего алгоритма на данном CPU и оценка оптимальности самого алгоритма. Последнее можно делать просто по базе алгоритмов — типа «вот вы тут простые числа ищете, а для этого есть алгоритмы в пять раз лучше». Шучу, конечно, но хотелось бы такого.
Ну какие уж тут шутки. Интелосвский компилятор уже двигается в этом направлении и умеет распознавать некоторые алгоритмы. Например — умножение матриц, которое он, при соответствующей опции может заменить на вызов в MKL. Получается пишешь глупый код, который работает медленно, а компилятор просто заменяет его на один вызов и все летает.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий