Анализировать код на предмет эффективности? - PullRequest
14 голосов
/ 21 мая 2009

Какие инструменты вы используете для определения эффективности кода? Используете ли вы домашние приложения, которые запускают статистически значимое количество тестов, или какой-либо коммерческий продукт? Используете ли вы свои собственные знания для тестирования определенных областей вашего кода или какой-либо инструмент, который анализирует ваш код на наличие слабых мест?

Ответы [ 9 ]

28 голосов
/ 21 мая 2009

INSERTED: Давайте посмотрим на "статистическую значимость".

Предположим, что где-то есть инструкция вызова функции. Вы не можете обязательно видеть это - класс, или макрос, или компилятор, возможно, вставили его. Рядом есть другие вызовы той же функции, но этот вызов находится в цикле, или его аргументы таковы, что этот вызов занимает много времени. Фактически, так много времени, что если этот вызов может занять нулевое время, то общее время выполнения будет уменьшено на некоторую величину, скажем, на 90%. (Невозможно? Вовсе нет.) Будет ли время точно определять? Нет. Определит ли это график вызовов? Нет. Будет ли кол-во вызовов точно определять это? Нет. Потому что проблема не в уровне функций, а в уровне инструкций вызова.

Каким-то образом программа случайно останавливается в определенный момент времени и проверяется ее состояние. Остановится ли он в те 90% времени, которые будут сохранены, если инструкция может быть "обнулена"? Конечно, с вероятностью 90%, и инструкция будет точно указана в стеке, ожидая завершения своей «работы».

На самом деле, если вы остановите ее случайным образом 20 раз, эта инструкция будет в стеке в среднем 18 раз со стандартным отклонением +/- 1,3 раза.

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

Предположим, процент небольшой, например, 10% или 5%. Применяется тот же принцип.

Фактически, независимо от того, как мало выборок берется, любая инструкция, которая находится на> 1 выборке, является статистически значимой и представляет собой «горячую точку», «узкое место» или как вы хотите это назвать. Если вы могли бы удалить его, назвать его меньше или как-то уменьшить его, это сэкономит значительное время. (Некоторые из них вы не можете, например, «позвонить _main», но другие вы можете. Вам просто нужно их найти.)

Конечно мой код никогда не был бы таким глупым, не так ли? Ну, тогда, докажите это .

Хорошо, теперь вернемся к истории. , .

ОРИГИНАЛЬНЫЙ ОТВЕТ: Я слышал о профилировщиках, еще когда-то, и я думал, что они должны быть довольно аккуратными, но у меня не было доступа к ним / этому. Я работал над встроенным процессором (чип Intel 8086), который, казалось, занимал ужасно много времени, рисуя некоторые числа с плавающей точкой на экране дисплея. Специалисты по аппаратному обеспечению предложили предоставить из своего большого количества - добавление микросхем таймера, чтобы я мог видеть, сколько времени это займет. Однако в один из выходных я запустил его с внутрисхемным эмулятором Intel Blue Box и запустил его. В то время как это было медленно, я задавался вопросом "Какого черта это делает?" Так что я просто остановился, чтобы выяснить это. ПК был в библиотеке с плавающей запятой (там не было микросхемы FP). Это не было неожиданностью, поскольку оно рисовало числа с плавающей точкой, но я хотел знать больше. Поэтому я (кропотливо) читаю шестнадцатеричную память, чтобы следить за стеком вызовов. Угадай, что? Он находился в процессе получения числа, которое нужно нарисовать, деления его на 10, преобразования в целое число, преобразования обратно в число с плавающей точкой, вычитания и т. Д. , чтобы получить следующую цифру для рисования . Само собой разумеется, были лучшие способы сделать , чем , что привело бы к ускорению примерно в 10 раз. Это было найдено с одним (1) образцом!

В другом случае, на чипе 68K, была некоторая медлительность. Опять же, профилировщик не был доступен, но отладчик «adb» был, поэтому, пока он работал медленно, я несколько раз останавливал его. ПК был в математической библиотеке, фактически в процедуре умножения 32-разрядных целых чисел. Посмотрев в стек, я нашел этот код:

struct {...} a[...];

int i;
for (i = 0; i < ...; ++i){ ... a[i] ... }

Там нет призыва умножать там - что происходит? Оказывается, для a[i] компилятор должен умножить i на размер элемента массива. Поскольку i 32-битный (в этом компиляторе), он генерирует вызов 32-битной процедуры умножения, и стек точно определяет эту инструкцию. Объявляя i как short, цикл утроился в скорости!

Какой смысл? Если вы берете сэмплы в случайное время, пока программа работает медленно, ПК сообщит вам, что она делает, но стек вызовов сообщит вам почему и приведет вас к проблеме. Теперь, если проблема не очень серьезная, вам может потребоваться взять несколько образцов. Любое утверждение, которое появляется на> 1 выборке, может вызывать у вас подозрения. Обратите внимание, он точно определяет операторы , инструкции даже не большие куски кода, подобные функциям. Эта техника может быть «быстрой и грязной», но она очень эффективна.

ДОБАВЛЕНО: Если вы делаете это несколько раз, вы можете решить проблему за проблемой в том же программном обеспечении. Например, если вы получили ускорение в 3 раза, небольшие проблемы с производительностью, которые раньше могли быть незначительными, теперь будут в 3 раза больше оставшегося времени. Это значительно облегчает их попадание в образцы. Возможно, вам придется добавить временный внешний цикл, чтобы он работал достаточно долго для выборки. Таким образом, я видел составные коэффициенты ускорения более чем в 40 раз .

17 голосов
/ 21 мая 2009

Это называется профилирование . Существует множество готовых инструментов, которые помогут вам определить узкие места в ваших приложениях для всех типов языков. Например, набор инструментов TPTP для Java может показать вам, где узкие места производительности снижаются до уровня отдельного метода, если вы этого хотите. Конечно, иногда все, что вам действительно нужно, это несколько чтений системного таймера, чтобы получить общее представление о разделе кода.

3 голосов
/ 21 мая 2009

Профилировщики очень полезны для определения того, в каком коде вы проводите больше всего времени. Существует множество инструментов профилирования, обычно они специфичны для вашей платформы / среды разработки.

Для небольших случаев в коде я использовал простые таймеры (системное время в конце действия - системное время в начале действия).

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

2 голосов
/ 21 мая 2009

Я использую Valgrind и его инструмент Callgrind. Это отличный инструмент. Valgrind - это виртуальная машина:

Valgrind по сути является виртуальным машина, использующая оперативность (JIT) методы составления, в том числе динамическая перекомпиляция. Ничего из оригинальная программа когда-либо запускается прямо на хост-процессоре. Вместо этого Valgrind сначала переводит программа во временную, более простую форму называется промежуточное представительство (IR), который является нейтральным к процессору, Форма на основе SSA. После преобразования инструмент (см. ниже) бесплатен какие бы преобразования он ни хотел на ИК, до того, как Valgrind переводит ИК обратно в машинный код и позволяет хост-процессор запускает его. Даже если он может использовать динамический перевод (что есть, хост и целевые процессоры от разных архитектур), это не делает. Valgrind перекомпилирует двоичный файл код для запуска на хосте и цели (или смоделировано) Процессоры одинаковые архитектура.

Callgrind - это профилировщик, основанный на этом. Основным преимуществом является то, что вам не нужно запускать приложение в течение нескольких часов, чтобы получить надежный результат. Достаточно нескольких секунд, потому что Callgrind является профайлером без зондирования ,

Еще один инструмент, построенный на Вальгринде, - Массив. Я использую его для профилирования использования памяти кучи. Он отлично работает, он дает вам снимки использования памяти - подробная информация, ЧТО содержит какой процент памяти, и ВОЗ поместила его туда.

Еще один инструмент Valgrind - DRD (и Helgrind). Я использую их для отслеживания мертвых блокировок и скачек данных в моем коде, а также для злоупотребления API потоков.

2 голосов
/ 21 мая 2009

Честно говоря, я использую NUnit . Если у меня есть код, который занимает слишком много времени или кажется не масштабируемым, я пишу тест, имитирующий ту часть приложения, которая работает плохо. Затем я смотрю на строгие замены в коде, чтобы сократить время выполнения и убедиться, что я ничего не сломал.

Если это все еще не дает вам то, что вам нужно, тогда вам нужно найти и применить профилировщик, но у вас по крайней мере будет тестовый пример, на котором вы можете проверить свои предположения без необходимости открывать / загружать приложение, отслеживать вызовы элементов приложения, которые не связаны с поставленной задачей.

2 голосов
/ 21 мая 2009

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

В Linux я использую Valgrind , который поставляется с некоторыми полезными инструментами для профилирования вашего кода. Что касается домашней страницы Valgrind:

Работает на следующих платформах: X86 / Linux, AMD64 / Linux, PPC32 / Linux, PPC64 / Linux.

.. и это бесплатно (как в бесплатном пиве) и с открытым исходным кодом.

Хотя я не использовал их так часто, на другой платформе вы можете использовать Purify / Quantify (продукты IBM). Это коммерческие инструменты. Как сообщал Уилл, они поставляются в пакете PurifyPlus, и Quantify поможет вам в профилировании вашего приложения.

Это все, что я использовал ...: -)

1 голос
/ 21 мая 2009

Я слышал доброе слово о Yourkit для профилирования Java. Для веб-сайтов я пробовал JMeter , который обладает базовыми функциями для простого параметризованного профилирования.

1 голос
/ 21 мая 2009

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

Кстати, кто-то упомянул Purify; есть также его родственный продукт Quantify.

0 голосов
/ 21 мая 2009

Для .NET я бы порекомендовал NDepend .

...