Главная - Литература

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 [208] 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

INC ЕАХ Увеличение индекса смещения в массиве.

LOOP EXPAND Повторение цикла.

end;

Переписывание этого кода на ассемблере привело к уменьшению времени выполнения на 41%. Логично предположить, что код, написанный на языке, более подходящем для операций над битами, (скажем, на С++), менее восприимчив к этому виду оптимизации, чем код Delphi. Проверим:

Время выполнения

Время выполнения

Экономия

Язык

высокоуровневого кода

ассемблерного кода

времени

4,25

3,02

Delphi

5,18

3,04

41%

Второй столбец этой таблицы отражает эффективность двух языков в отношении операций над битами. После оптимизации время выполнения стало почти одинаковым - перевод кода на ассемблер свел к минимуму первоначальные различия между Delphi и С++.

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

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

Контрольный список: методики оптимизации кода

Улучшение и быстродействия, и объема

□ Замените сложную логику на обращения к таблице.

□ Объедините циклы.

□ Используйте целочисленные переменные вместо переменных с плавающей запятой.

□ Инициализируйте данные во время компиляции.

□ Используйте константы корректного типа.

□ Вычислите результаты предварительно.

□ Устраните часто используемые подвыражения.

□ Перепишите ключевые методы на низкоуровневом языке.

Улучшение только быстродействия

q Прекращайте проверку сразу же после получения ответа.

□ Упорядочивайте тесты в блоках case и цепочках операторов if-then-else по частоте.



□ Сравните быстродействие похожих структур логики.

□ Используйте методику отложенных вычислений.

□ Разомкните цикл, содержащий оператор if.

□ Выполните развертывание цикла.

□ Минимизируйте объем работы, выполняемой внутри цикла.

□ Используйте сигнальные значения в циклах поиска.

□ Вложите более ресурсоемкий цикл в менее ресурсоемкий, а Снизьте стоимость операций, выполняемых внутри цикла.

□ Замените многомерные массивы на одномерные.

□ Минимизируйте число обращений к массивам.

□ Дополните типы данных индексами.

□ Кэшируйте часто используемые значения.

□ Проанализируйте алгебраические тождества.

□ Снизьте стоимость логических и математических выражений.

□ Остерегайтесь системных методов.

□ Встройте методы.

26.7. Если что-то одно изменяется,

что-то другое всегда остается постоянным

Трудно не согласиться с тем, что за 10 лет, прошедших со времени первого издания этой книги, некоторые параметры производительности систем изменились. Компьютеры стали гораздо быстрее, а объем памяти вырос во много раз. Работая над первым изданием, для получения выразительных измеримых результатов я выполнял большинство тестов этой главы от 10 ООО до 50 ООО раз. При подготовке этого издания мне пришлось выполнять большинство тестов от 1 до 100 млн раз. Если для получения измеримых результатов тест нужно выполнить 100 млн раз, стоит задуматься над тем, заметит ли хоть кто-нибудь последствия выполненной оптимизации в реальной программе. Компьютеры стали столь мощными, что для многих распространенных типов программ виды оптимизации, описанные в этой главе, стали нерелевантными.

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

Необходимость оценки результатов каждой попытки оптимизации кода не теряет актуальности с 1971 п, когда Дональд Кнут опубликовал свое исследование программ Fortran. Судя по данным, приведенным в этой главе, результаты отдельных видов оптимизации на самом деле ccPihlc менее предсказуемы, чем 10 лет назад. Они зависят от языка, компилятора, и его версии, используемых библиотек, их версий, параметров компилятора и многого другого.

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



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

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

Дополнительные ресурсы

По-моему, лучшая работа по оптимизации кода - Writing http: ccae.Gom/2679 Efficient Programs (Bentley Englewood Cliffs, NJ: Prentice Hall,

1982). Это довольно старая книга, и все же постарайтесь ее найти. В ней вы найдете экспертное обсуждение общих вопросов оптимизации кода. Бентли описывает методики обмена времени на пространство и пространства на время, а также приводит несколько примеров перепроектирования типов данных, позволяющего и ускорить код, и сделать его компактнее. Подход Бентли чуть более описателен, чем тот, что принял я, но приведенные им случаи весьма интересны. Бентли проводит несколько методов через несколько этапов оптимизации, позволяя увидеть результаты первой, второй и третьей попыток. Описание главной идеи занимает 135 страниц. Эта книга отличается необычайно высоким отношением «сигнал/шум», что делает ее одним из редких бриллиантов, которые следует иметь каждому практикующему программисту.

В приложении 4 книги Бентли Programming Pearls, 2d ed. (Bentley, Boston, MA: Addison-Wesley, 2000) вы можете найти резюме правил оптимизации кода, описанных в его более ранней книге.

Кроме того, есть целый ряд книг, в которых вопросы опти-Ш>: йс2е,сош/2686 мизации рассматриваются в контексте конкретных техно-

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

Booth, Rick. Inner Loops: A Sourcebook for Fast 32-bit Software Development. Boston, MA: Addison-Wesley 1997.

Gerber, Richard. Software Optimization Cookbook: Higb-Performance Recipes for tbe Intel Architecture. Intel Press, 2002.

Hasan, Jeffrey and Kenneth Tu. Performance Tuning and Optimizing ASP NET Applications. Berkeley CA: Apress, 2003.

Killelea, Patrick. Web Рефгтапсе Tuning, 2d ed. Sebastopol, CA: OReilly & Associates, 2002.

Larman, Craig and Rhett QvXbivt.Java 2 Performance and Idiom Guide. Englewood Cliffs, NJ: Prentice Hall, 2000.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 [208] 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294



0.0031