Существует ли простая оценка качества оптимизации приложения?Источник: habrahabr andrei_an
Тише едешь дальше будешь...? Оценка производительности.Больше 7 лет я занимаюсь анализом производительности в составе группы Performance Analysis новосибирского отделения Интел. Мы работаем над улучшением производительности различных приложений, а точнее, ищем способы, с помощью которых ее смог бы улучшить наш компилятор. За это время накопился полезный опыт, который, на мой взгляд, был бы интересен посетителям уважаемого Хабра. Речь в данном случае будет идти не об алгоритмической оптимизации приложений, а о различных модификациях приложений без принципиального изменения их алгоритмов. Понятно, что алгоритмические оптимизации программы тоже имеют право на жизнь, но это совсем другая задача. Я являюсь разработчиком компилятора Интел, поэтому все мои исследования связаны с различными компиляторными оптимизациями, сравнением различных компиляторов (на Windows это, как правило, сравнение интеловского компилятора с компилятором Microsoft Visual Studio). Собственно поэтому прошу не рассматривать мои посты как рекламу или антирекламу. Для иллюстрации моих мыслей я буду использовать различные инструменты, в том числе и разработанные в нашей компании. Надеюсь, что этот пост вырастет в серию статей об оптимизации приложений.
Существует ли простой критерий оценки оптимальности приложения?Понятно, что любая проблема и задача, в том числе задача по улучшению производительности приложения, начинается с исследования текущего состояния дел. Необходима оценка: насколько приложение уже оптимизировано, и имеет ли смысл прилагать усилия чтобы его ускорить. На первый взгляд, задача имеет простое решение. Достаточно измерить загрузку процессора, чтобы такую оценку получить. Различные анализаторы производительности позволяют не только замерить время исполнения различных участков программы, но и подсчитать и привязать к коду программы все внутрипроцессорные события, возникающие при ее выполнении. С помощью этой информации можно оценить загрузку вычислительного ядра. Например, определить сколько тактов процессора в среднем потребовалось на выполнение одной инструкции, и какие причины вызывали задержки исполнения Т.е. предлагаемый критерий связывает эффективность работы ядра с возможностью улучшения производительности приложения. А именно, если ядро работает эффективно, то повода для беспокойства нет - программа работает оптимально, в противном случае приложение может быть улучшено и есть смысл заниматься его анализом. В результате использования такого критерия на свет появляются работы, в которых анализируются какие-то процессорные события, и авторы на основе этого анализа строят предположения о возможностях улучшения производительности приложений. Возможно, такие методы работы действительно полезны для архитекторов вычислительных систем и дают им возможность пофантазировать об улучшении архитектуры процессора. Но, к сожалению, для программиста, размышляющего об улучшении производительности своего приложения, этот метод крайне сомнительный, редко работает и не дает ответа на извечный вопрос русской интеллигенции: "Что делать? и Можно ли есть курицу руками?". #include <stdio.h> void matrix_mul_matrix(int t, int n, double *C, float *A, float *B) { int main() { //… Выделение памяти и инициализация массивов for(i=0;i<10000;i++) printf("%f %f %f\n",C[0],C[1],C[100]); На моей лабораторной машине c Windows Server 2008 R2 Enterprise и процессором Intel Xeon X5570 я компилирую эту программу с помощью компилятора Майкрософт VS 10.0. и Интел Parallel Studio XE2013. Для простоты я работаю с командной строкой и беру опции, соответствующие релизовскому варианту компиляции, используемыми по умолчанию в Visual Studio. cl matrix.c /O2 /GL /GS /GR /W3 /nologo /Wp64 /Zi -Ob0 -Fematrix_cl Выясняется, что время работы matrix_cl равно ~21.9 s, в то время как время работы matrix равно ~9.3 s. Теперь посмотрим, что нам скажет Amplifier о загрузке процессора. Intel VTune Amplifier XE 2011 - это как раз инструмент для оценки производительности, позволяющий работать с процессорными событиями интеловских процессоров.
Обращаем внимание на CPI Rate (Clock per instruction, среднее количество тактов на одну инструкцию). Для моего процессора теоретический минимум этой величины 0.20. (Параллельное исполнение 4-х инструкций на 4-х исполнительных устройствах плюс фьюзинг еще одной. Итого 5 инструкций за такт - теоретический максимум). Число CPI 0.546 считается очень хорошим. Есть конечно и задержки. Но, вроде ничего критического нет. Вычислительное ядро работает с хорошей нагрузкой, и все выглядит вполне прилично. Можно ли из этой оценки понять, что производительность приложения реально улучшить в два раза?
Волшебное улучшение производительности более чем в два раза, практически никак не отразились на основных "рейтингах" вычислений, собираемых Intel VTune Amplifier XE 2011. Т.е. исследование работы процессора в данном случае не дало нам никаких сигналов о том, что производительность может быть кардинально улучшена. Данное улучшение производительности было достигнуто благодаря автовекторизации. Это легко увидеть, если добавить к опциям для интеловского компилятора -Qvec_report. Компилятор выдаст Т.е. производительность приложения была улучшена за счет применения цикловой перестановочной оптимизации. Для того чтобы понять, что такая оптимизация могла быть применена, необходимо было исследовать алгоритм перемножения матриц. Теперь возьмем пример другого рода и создадим программу, которая будет обходить длинную цепочку объектов: #include <stdio.h> struct _planet { planet* init_chain() { int main() { planet_chain=init_chain(); for(i=0;i<1000;i++) { Оба оптимизирующие компилятора создали приложения выполняющиеся ~6.2s. Amplifier сообщает о том, что в данном приложении все плохо:
CPI rate очень плохой, и большую часть времени вычислительное ядро ожидает получения данных для обработки.
заключениеТаким образом, простые вычисления различных процессорных коэффициентов дают мало информации для оценки эффективности приложения. В данном случае простым аналогом задачи по оценке эффективности выполняющегося приложения является спортсмен, двигающийся из точки A в точку B. Если мы возьмем за критерий оптимальной работы спортсмена нагрузку на его мышцы или сравним среднюю его скорость на трассе и максимальную скорость, с которой данный спортсмен может двигаться, то далеко ли мы уйдем с такими критериями? Если спорсмен дурной, хоть и очень сильный, и постоянно ломится через чащу, вместо того чтобы оббежать ее по тропинке, то нужен просто более умный спортсмен. Обратно, если спортсмен бежал медленно, но его путь пролегал по болоту, где приходилось останавливаться, нащупывать путь и даже возвращаться периодически назад, то виноват ли спортсмен? Можно привлечь к решению задачи более тренированного и быстрого атлета (за большие деньги), а можно - грамотного тренера, который на старте проанализирует трассу забега, сильные и слабые стороны бегуна, а затем предложит бегуну оптимальный маршрут, а возможно, научит его принимать на ходу правильное решение в каких-то простых ситуациях. Поэтому, на мой взгляд, не существует простого универсального работающего метода оценки эффективности работы приложения и, следовательно, простых путей его улучшения. Для решения этой задачи нужно подключать мозг и анализировать множество ситуаций, применяя к ним известные методы улучшения производительности. Как и в любом деле, здесь нужна методология подключения мозга. Для успешного решения задачи он должен знать некоторые вещи, например: 1.) Основные проблемы, влияющие на производительность процессора, и методы оптимизации, влияющие на эти проблемы. Соответственно, в дальнейшем я попробую представить образец такой методологии и расскажу об известных мне полезных методах оптимизации приложений. |