Оптимизация — всё по этой теме для программистов


Оглавление (нажмите, чтобы открыть):

Оптимизация производительности 1С 8

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

Получите 267 видеоуроков по 1С бесплатно:

Статьи по оптимизации производительности 1С для программистов

Методика повышения производительности 1С

Итак, с чего начать и как действовать правильно.

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

Далее необходимо посмотреть, выполняется ли сервере СУБД регламентные операции, обновляется ли статистика, есть ли дефрагментация индексов? Если регламентные операции не выполняются, то их выполнение нужно настроить, запустить систему и проанализировать, как изменился APDEX. Оцениваем, изменилась ли производительность.

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

После сбора всех необходимый данных смотрим, можно ли ускорить систему без «апгрейда» оборудования. Как это узнать? Если видно, что есть не оптимальные запросы, ожидания на блокировках, то про «апгрейд» пока можно забыть. Есть ещё запас по оптимизации на уровне программного кода.

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

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

К сожалению, мы физически не можем проконсультировать бесплатно всех желающих, но наша команда будет рада оказать услуги по внедрению и обслуживанию 1С. Более подробно о наших услугах можно узнать на странице Услуги 1С или просто позвоните по телефону +7 (499) 350 29 00. Мы работаем в Москве и области.

Оптимизация — всё по этой теме для программистов

Узбекское Агентство
Связи и Информатизации

Ташкентский Университет Информационных Технологий

Кафедра
«Программное обеспечение информационных технологий»

Направления:

5521900 Информатика и
информационные технологии,
5523500 Защита информации,
5523600 Электронная коммерция,
5811200 Сервис (информационный сервис),
5811300 Сервис (электронные и
компьютерные технологии),
5320200 Информатика и
библиотековедение,
5140900 Профессиональное образование
(по направлению
информатика и
информационные технологии).

Выдержки из лекций

Оптимизация программы.

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

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

Частично оптимизацию программы может выполнить оп­тимизирующий транслятор (компилятор). Но в основном этот процесс творческий зависит от квалификации программиста и невозможно дать алгоритм, оптимизирующий любую программу. Можно лишь обратить внимание на те аспекты, где скрыты резервы оптимизации и проиллюстрировать их на примерах.

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

Существуют два подхода к оптимизации программ: «чистка» и перепрограммирование. Оба подхода имеют как достоинства, так и недостатки.

Первый подход заключается в исправлении очевидных неб­режностей в исходной программе. Его достоинство — данный метод требует мало времени. Однако повышение эффективности при этом обычно незначительно.

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

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

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

Рассмотрим основные Машинно-независимые приемы опти­мизации программ.

1) Заголовки сообщений. Если большая часть сообщений со­держит пробелы (или другие повторяющиеся символы), то для экономии памяти ЭВМ следует использовать команды, выпол­няющие заполнение этой части сообщения пробелами (сим-волами).

2) Инициирование переменных. Если начальные значения прис­ваиваются переменным (или константам) одновременно с их
объяв ­­­­ ле ­ нием, то экономится и память, и время выполнения
программы, т.к. в этом случае переменные получают начальные
значения во время компилирования программы, а не во время ее
выполнения.

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

3) Уменьшение числа переменных. Отработанная «временная»
переменная на участке программы (например, управляющая
переменная цикла) продолжает занимать область памяти и
дальше во все время выполнения оставшейся части программы.
Ее надо удалить (очистить).

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

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

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

Рост числа временных и неиспользованных переменных обыч­но происходит у начинающих и неаккуратных программистов. Их типичная ошибка — выбор первой пришедшей в голову структуры данных. Считается хорошим стилем программирования, если в программе нет лишних переменных.

4) Выбор типов данных. Переменные разных типов данных в
ЭВМ обрабатываются с разной затратой времени и памяти. В
данном случае требуется минимальное понимание особенностей
программы.

Например, если элемент массива А(1) — целочисленная, то в операторе FOR I := l ТО 1000 DO A ( I ):= 0.0; произойдут 1000 преобразований типов из вещественного в целый. Здесь надо написать: А(1):= 0;.

5) Удаление излишних операторов присваивания. Рассматри­ваемая процедура состоит в удалении из программы некоторых
операторов присваивания и замене в некоторых других операторах
(присваивания или условного перехода) переменных, являющихся левой частью удаляемых операторов, выражениями, яв­ляющимися правой частью удаляемых операторов, то есть выполняется объединение операторов. Например, следующие четыре оператора присваивания

можно заменить одним

С: = (5 + B 1* D **2 + В + SIN ( R ))*(5 + А(1)*А (2));

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

При этом предполагается, что переменные, являющиеся левой частью удаляемых операторов, в других операторах не используются.

6) Отождествление переменных. Если в программе имеется
оператор вида А:=В, то во всех последующих операторах прог­раммы можно заменить переменную А переменной В или чис­ловым значением переменной В, а оператор А: = В удалить.

Если переменная А является индексируемой переменной, то оператор А: = В остается в программе, а переменная А в неко­торых операторах заменяется переменной В.

7) Удаление тождественных операторов. Суть этой процедуры
состоит в удалении из программы тождественных операторов, т.е.
операторов вида А: = А. Такие операторы могут появляться в
программе в результате выполнения оптимизационных и других
преобразований.

8) Устранение невыполняемых операторов. В реальных прог­раммах могут встретиться участки, содержащие невыполняемые операторы, т. е. такие операторы, которые не выполняются при любых наборах начальных данных.

Появление таких операторов можно объяснить двумя при­чинами:

1) в. процессе отладки программы или ее модификации программист либо забывает о таких операторах, либо не хочет их искать, либо просто не в состоянии проследить за всеми пос­ледствиями, вызванными исправлениями некоторых участков программы;

2) большая логическая или информационная сложность программы не позволяет программисту «увидеть» такие опе-раторы или даже целые невыполняемые участки программы.

Смысл рассматриваемой процедуры состоит в удалении из программы невыполняемых операторов.

9) Использования ввода-вывода.Операции ввода-вывода зани­мают много времени и должны быть сокращены до минимума. Данные, которые можно вычислить внутри программы, вводить не надо!

Две последовательные команды ввода-вывода для одного и того же устройства можно объединить в одну команду. Это сокращает количество обращений к системным подпрограммам ввода-вывода, что, естественно, сокращает время выполнения программы.

Не забудьте после отладки программы изъять все лишние (обычно отладочные) операторы ввода-вывода.

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

10) Выделение процедур (функций). Если в программе имеются
последовательности одинаковых операторов, которые отличаются
только разными идентификаторами и значениями констант, то
может быть полезно выделить их в процедуру (или функцию). Это
дает значительное сокращение текста программы, но замедляет
ее выполнение, т.к. вход-выход процедуры — трудоемкая опе-рация, и работа с параметрами идет медленнее, чем с ло­кальными переменными.

Лучше все же использовать не процедуры, а отдельные мо- дули.

11) Сокращение числа процедур (функций).Связь процедур
(функций) с основной программой обеспечивается операторами
вызова в основной программе, которые замедляют работу прог-раммы.

Когда критерием оптимизации является время счета прог-раммы, то нужно хорошо подумать прежде, чем выделить участок программы в отдельную процедуру (функцию).

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

Сокращение числа процедур (функций) выполняется заменой операторов их вызова телами этих процедур (функций) и заменой

формальных параметров соответствующими им фактическими парамет-рами. Зато увеличивается текст программы на соот­ветствующее число команд.

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

12) Альтернативы.Когда одну переменную нужно сравнить с несколькими значениями, некоторые программисты пишут так (очень плохой стиль программирования):

В этом случае, даже если А = 1, будут выполнены все условные операторы IF .

При использовании конструкции ELSE сравнение будет прекращено, как только будет найдено истинное условие:

ELSE IF A=2 THEN.

ELSE IF A =3 THEN . ;

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

То же замечание касается конструкции выбора ( CASE ).

13) Арифметические операции.Арифметические операции выполняются с разной скоростью.

Перечислим их в порядке возрастания времени их выпол­- нения:

1) сложение и вычитание;

4) возведение в степень.

Иногда бывает целесообразно заменить одну операцию другой. Например, 3*1 может быть заменено I + I + I или Х**2 можно заменить на Х*Х. Тем более, что для возведения в степень обычно требуется библиотечная программа.

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

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

Вместо А/5 можно написать 0.2*А;

Вместо А1 = B / D / E + С можно написать А1 = B /( D * E ) + С;

SQRT ( A ); выполняется быстрее и точнее, чем А**0.5;

14) Преобразование выражений. Предварительное преобра­зование (упрощение) выражений может привести к исключению многих арифметических операций.

Например, X : = 2*У + 2*Т; можно заменить на X : = 2*(У + Т);

Последнее преобразование исключило одну операцию ум­ножения.

15) Оптимизация выражений.Суть процедуры состоит в замене всех сложных семантически эквивалентных подвыражений на одно простое.

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

Оптимизационный эффект в этом случае заключается в сокращении времени выполнения программы и уменьшении объема занимаемой ею памяти.

16) Предварительное вычисление арифметических подвыра­жений. Вместо, например:

А: = ( M * B * C )/( D — E );

К: = D — E — B * C * M ;

Сокращается текст программы и время ее выполнения за счет сокращения количества выполняемых операций. Зато быть может чуть-чуть увеличивается память для Т и U .

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

18) Устранение лишних меток. По ряду причин в программах встречаются метки перед операторами, на которые нет передач управления.

Такие метки являются лишними и их следует удалить из программы.

19) Устранение лишних операторов перехода.После многих опти-мизационных переделок программы, в ней могут появиться операторы безусловного перехода ( GO TO ), которые передают управление оператору с несуществующей меткой. Их надо удалить.

20) Неявные операции.Операция Т:= М(1) требует в 1,5—2 раза больше времени и памяти, чем Т: = А;, а если М — параметр или функция, то в 2,5—3 раза больше. Там, где часто используется М(1), можно использовать прос­тую переменную MI : = M ( I ) и т. д.

Но если индекс I — константа, то индексация выполняться не будет: при трансляции вычисляется сдвиг элемента относи­тельно начала массива, и в процессе выполнения программы он обрабатывается как простая переменная.

21) Чистка циклов.Немного о памяти. Обычно программисты
не заботятся о памяти до тех пор, пока не превысят ее размеры.
Тогда становится очевидным, что память не безразмерна. Име-ются прогнозы, что скоро будем располагать достаточной памятью для решения любой задачи. Но размеры решаемых задач также растут по мере увеличения размера памяти ЭВМ.

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

Время выполнения программы в значительной мере зависит от времени выполнения многократно повторяемых участков — от циклов. Поэтому основное внимание необходимо уделять именно циклам.

Процедура чистки цикла уменьшает время выполнения цикла (сле ­ дова ­ тель ­ но, и программы) путем удаления из его тела арифметических выра ­ жений или их частей, не зависящих от управляющей переменной цикла.

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

FOR I: = 1 ТО 100 DO FOR J: = 1 ТО 10 DO X: = Y*Z + C[I, J];

Здесь Y * Z будет вычисляться тысяча раз, а в следующем примере — только один раз:

FOR I: = 1 ТО 100 DO FOR J: = 1 TO 10 DO X: = YZ + C[I, J];

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

Интересной разновидностью чистки циклов является изме­нение порядка циклов:

Цикл FOR I: = 1 ТО N DO FOR J: = 1 ТО М DO.

при N FOR I: = 1 ТО М DO FOR I: = 1 ТО N DO.

т.к. в первом случае выполняется M * N + N операций орга­низации циклирования, а во втором — M * N + М.

22) Использование циклов. Циклы требуют некоторого допол­нительного количества памяти на инициирование, проверку, изменение управляющей переменной и установку всех констант.

Иногда бывает полезным отказаться от использования циклов.

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

23) Объединение циклов. При трансляции любого цикла с языка высокого уровня в машинные коды в объектной программе появляются операции, реализующие заголовок цикла, т. е. увели-чение управляющей переменной цикла на значение его шага; сравнение управляющей переменной с граничным значением; передачу управления.

Процедура объединения циклов производит соединение нес­кольких циклов с одинаковыми заголовками в один. Например :

FOR I: = 1 ТО 500 DO X[I]: = 0;

FOR J: = 1 ТО 500 DO Y[J]: = 0;

можно объединить в один цикл, что сокращает как время выполнения программы, так и память:

FOR I: = 1 ТО 500 DO BEGIN X[I]: = 0; У [1]: = 0 END;

24) Вынос ветвлений из цикла. Пусть исходный цикл состоит из
двух частей, и в зависимости от выполнения определенного
условия выполняется одна из этих частей.

FOR I = 1 ТО 200 DO

IF К = 2 THEN A(I) = B(I)*C(I) ELSE A (I) = В (I) + 2;

Тогда исходный цикл можно заменить двумя циклами, соот­ветствующими двум частям исходного цикла:

IF К = 2 THEN FOR 1=1 ТО 200 DO A(I) = B(I)*C(I);

ELSE FOR 1=1 TO 200 DO A (I) = В (I) + 2.

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

25) Удаление пустых циклов.Суть этой процедуры состоит в
удалении из программы пустых циклов.

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

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

В общем случае выполнение процедуры устранения пустых циклов экономит время выполнения программы и объем зани­маемой ею памяти.

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

FOR I = А ТО В DO IF I С THEN R(I) = P(I);

Процедура сжатия циклов осуществляет перенос таких огра­ничений в заголовок цикла:

DO I = А ТО С DO R(I) — P(I);

Здесь предполагается, что А <: С < В.

В результате выполнения процедуры сжатия циклов из тела цикла удаляется логический оператор перехода и сокращается число выполнений тела цикла.

27) Управление по выбору. В операторе выбора выполняется первая группа команд, у которой условие выбора истинно.

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

Иными словами, в операторе выбора необходимо первой расположить группу команд, которая наиболее часто должна быть выполнена. Второй — следующую по частоте выполнения группу команд. И так далее. Группа команд, которая выполняется крайне редко, в операторе должна располагаться последней.

Тема 2.8. Оптимизация программ. Оптимизирующие компиляторы

Понятие оптимизации программ

Оптимизация программы — это улучшение какой-либо характеристики программы, называемой критерием оптимизации. Оптимизация программ в основном выполняется по двум основным критериям: быстродействие и объему используемых данных.

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

Основная цель профилировки – это исследование характера поведения приложения во всех его точках. В зависимости от степени детализации в качестве «точки» рассматривается как отдельная машинная команда, так и целая конструкция высокого языка — функция, цикл, процедура. Сложная программа состоит из большого числа функций. Нет смысла оптимизировать их все – трудоемкость такого подхода будет выше выгод, полученных от оптимизации программы целиком. Для начала необходимо локализовать участки кода с максимальной вычислительной трудоемкостью. Участки программы, которые в наибольшей степени влияют на ее производительность, в силу наиболее частого выполнения или своей ресурсоемкости называются критическим кодом. В поиске критического кода программы используют профайлеры (профилировщики) – специальные программы, которые измеряют временные затраты на выполнение участков кода программы. Профилировщики представляют возможности для оптимизации программ. К таким программам относятся Intel VTune, AMD Code Analyst, profile.exe и множество других. Наиболее мощным из них на сегодняшний день является пакет от Intel. Эта программа позволяет измерить время обработки каждой команды и вывести полную статистику о состоянии процессора при выполнении каждой команды.

Большинство современных профилировщиков поддерживают следующий набор базовых операций:

• определение общего времени исполнения каждой точки программы;

• определение удельного времени исполнения каждой точки программы;

• определение причины и/или источника конфликтов;

• определение количества вызовов той или иной точки программы;

• определение степени покрытия программы.

Основные правила оптимизации:

1. Прежде чем приступать к оптимизации, необходимо иметь надежно работающий неоптимизированный вариант.

2. Основной прирост оптимизации дает не учет особенностей системы, а алгоритмическая оптимизация.

3. Обнаружив профилировщиком узкие места необходимо произвести оптимизацию в рамках языка высокого уровня.

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

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

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

1. Производительность программы признана удовлетворяющей;

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

3. Сложность алгоритма настолько высока, что не представляется возможным дальнейшая оптимизация без значительных временных затрат;

4. Критическая зависимость от платформы, когда дальнейшая машинно-зависимая оптимизация приведет к потере совместимости с одной из целевых платформ.

Ко всем методам оптимизации алгоритма предъявляются следующие требования:

1. оптимизация должна быть по возможности максимально машинно- независимой и переносимой на другие платформы (операционные системы) без существенных потерь эффективности.

2. оптимизация не должна увеличивать трудоемкость разработки (в том числе тестирования) приложения более чем на 10-15%.

3. оптимизирующий алгоритм должен давать выигрыш не менее чем на 20-25% в скорости выполнения.

4. оптимизация не должна допускать безболезненное внесение изменений.

Алгоритмические приемы оптимизации

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

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

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

На практике используется весьма широкий набор машинно-независимых оптимизирующих преобразований, что связано с большим разнообразием неоптимальностей. К ним относятся:

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

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

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

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

• реализация действий — это способ повышения быстродействия программы за счет выполнения определенных ее вычислений на этапе трансляции.

• сокращение программы и другие методы.

Машинно-зависимые приемы оптимизации

Машинно-зависимые используют особенности устройства и работы конкретной системы. Ярким примером машинно-зависимой оптимизации является векторизация операций, т.е. использование потоковых расширений процессора, таких как MMX (MultiMedia eXtensions), SSE (Streaming SIMD Extensions) и т.п. Машино-зависимую оптимизацию можно выполнять двумя различными способами. Первый способ основан на понимании работы кодогенератора компилятора, его алгоритма и рекомендуется для приложений, в которых компилятор выбирается в начале проекта и в дальнейшем не меняется. При использовании такого способа преобразуется исходный код программы, написанный на языке высокого уровня. Для тех проектов, в которых заранее не известен компилятор (OpenSource проекты, кроссплатформенные приложения) применятся другой способ, основанный на замещении ресурсоемких участков кода ассемблерными вставками. При такой оптимизации ухудшается переносимость кода на другие платформы. Машинно-зависимые способы оптимизации довольно хорошо автоматизируются и большую часть их выполняют оптимизирующие компиляторы. Однако всегда остаются моменты в программе, которые можно оптимизировать вручную.

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: На стипендию можно купить что-нибудь, но не больше. 8980 — | 7233 — или читать все.

Оптимизация

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

Оптимизировать надо то, что тормозит

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

Профайлинг – ключ к успешной оптимизации

Что бы начинать оптимизацию программы, прежде всего необходимо понять, какие именно участки кода создают не нужные “тормоза” – как правило “тормозит” от 1% до 5% кода, весь остальной код просто не оказывает никакого влияния на производительность. Проще всего найти эти участки кода запустив профайлер. Проще всего использовать встроенный в Visual Studio, либо Intel Perfomance Analyzer. Как правило, достаточно 1 раз запустить вашу программу под профайлером и заставить её поработать от нескольких секунд до нескольких минут, а потом просто посмотреть отчёт, сформированный профайлером. Из этого отчёта Вам понадобится лишь несколько первых строк, в которых и находятся те самые участки программы (функции), которые занимают больше всего процессорного времени – именно их и надо оптимизировать в первую очередь. И лишь после того, как Вы это сделаете, надо судить о том, стоит ли продолжать процесс оптимизации или уже пора остановиться – незачем тратить часы и дни работы на то, что бы, например, поднять ФПС игры с 90 до 91 кадра в секунду.

Методы оптимизации

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

  • Локализация данных
  • Векторизация
  • Минимизация вызова функций
  • Инлайн-функции

Оптимизация через локализацию данных

Как известно, CPU обычно имеет внутри себя от одного до нескольких уровней кешей – с ними процессор работает намного (в разы/десятки/сотни раз) быстрее, чем с обычной оперативной памятью. Как только процессор обращается к каким-то данным, которые находятся вне его кеша – он читает эти данные из памяти, располагает их в кеше и потом работает с ними. Работать напрямую с памятью он обычно не умеет. При этом читает он обычно не только те данные, которые ему нужны в данный момент, но и небольшой “запас”, предполагая при этом, что они тоже могут понадобиться. Процесс чтения данных из обычной памяти в кеш не слишком быстрый (если даже не сказать что он очень медленный), а процесс чтения этих данных потом из кеша в процессор – быстрый.

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

Соответственно, совет в данном случае очень простой – просто располагайте данные в памяти последовательно. Например, не создавайте сотни объектов через оператор new, а создавайте сразу массив с помощью оператора new[]. Если количество создаваемых объектов велико (сотни, тысячи), то вы можете получить существенный прирост производительности – иногда даже в сотни раз.

Оптимизация через векторизацию

Если ваши данные локализованы в одном участке памяти и вам необходимо обработать массив этих данных, то очень часто может помочь оптимизация через векторизацию. Обычно всё, что требуется с вашей стороны – это включить соответствующие опции компилятора, как правило это: разрешить использовать SSE/SSE2 и указать максимальный уп=ровень оптимизации. После этого, при обработке массивов данных (в цикле), компилятор сам постарается сделать специальный код, которые будет использовать SSE-инструкции для обработки массивов – при больших размерах массива, часто это может привести к ускорению работы программы в несколько раз.

Оптимизация с помощью минимизации вызова функций

Обычно вызов каждой функции требует от центрального процессора поместить данные, передаваемые функции (параметры функции) в “стек”, вызывать функцию и прочитать результат работы функции (возвращаемое значение) из стека. Фактически, вызов каждой, даже самой простой, функции превращается в кучу работы. Соответственно, если Вы, вместо того, что бы вызывать функцию, опишите операции, которые надо провести над данными непосредственно, без вызова функции – скорее всего вы получите прирост производительности. При этом, как правило, такую операцию имеет смысл делать лишь для достаточно небольших функций – размером не больше нескольких (до десяка-двух) строк кода, не более – для более больших функций разница в скорости будет уже практически незаметна. И наоборот – чем меньше функция, тем более заметен будет результат. При этом надо заметить, что часто компилятор (при включённых опциях оптимизации) сам проводит такую оптимизацию и получает хороший код без участия программиста. Но он не всегда может сам до этого догадаться, потому ему иногда надо помогать, просто прооптимизировав код вручную.

Оптимизация с помощью инлайн-функций

Инлайн-функции, это такие функции, которые компилятор пытается встроить непосредственно в код, вместо создания вызова функции. Потому это правило оптимизации является прямым следствием предыдущего. Обычно для того, что бы функция заинлайнилась надо указать при её декларации ключевое слово inline или __inline – и компилятор заинлайнит её, если посчитает это разумным.

Когда не надо оптимизировать программу?

Ответ на этот вопрос можно дать простой и короткий – программу не надо оптимизировать до того момента, пока работа над ней (её функционалом) полностью не законченна. Т.е. сначала необходимо реализовать полностью весь функционал программы (или её отдельного модуля), потом убедиться что эта программа (или модуль) реально требует оптимизации и лишь после этого приступать к делу.

Если начать делать оптимизацию до того, как вы завершили основную часть работы над функционалом – очень высока вероятность того, что Вам позже придётся вносить какие-то дополнительные изменения в уже прооптимизированный участок кода, а это приведёт одновременно к тому, что вы будете путаться (читать и понимать оптимизированный код обычно сложнее) и при этом Вам потом ещё придётся повторно проводить оптимизацию (т.к. Вы поменяете код и не факт, что после этого он будет работать так же быстро, как и прежде).

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

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

Кстати, после оптимизации обязательно не забудьте ещё раз протестировать ваш исходный код на предмет отсутствия багов – очень часто даже опытные программисты, в погоне за производительностью, допускают много мелких и сложнонаходимых ошибок – будьте внимательны!

P/S Как-нибудь я постараюсь найти время и рассказать и показать на примерах различные виды оптимизаций, в том числе не только самого кода, но и графики, чтения с дисков и прочего.

Способы повышения продуктивности программиста

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

Чтобы не оказаться в подобной ситуации, для программиста-практика критически важным становится выбор подходящих инструментов и методик решения побочных задач, что позволит не отвлекаться на них лишний раз, а сосредоточиться на главном. Хорошей книгой по этой теме является «Продуктивный программист. Как сделать сложное простым, а невозможное – возможным». Рекомендую вам с ней ознакомиться. Те способы, о которых я говорю ниже, во многом основаны на ней.

Способ 1. Освоение среды разработки в совершенстве

Вы ведете разработку в мощной IDE, типа Visual Studio или Eclipse? — Прекрасно, но может быть что-то получается не так, как вам хотелось бы? Или вам для работы хватает простого блокнота? — Если так, то советую вам задуматься о переходе на что-то посерьезнее.

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

  1. Подсветка синтаксиса. Ее использование поможет многократно сократить количество опечаток и незакрытых скобок;
  2. Автозавершение. Чем меньше нужно печатать — тем лучше. Еще лучше, если эта функция будет работать с учетом синтаксиса языка, например, выдавая варианты методов класса с предложением подстановки аргументов;
  3. Макросы (см. Принцип DRY в действии). Макросы позволяют сохранить некую последовательность действий в редакторе и повторять их многократно по необходимости;
  4. Быстрые клавиши. В идеале для любого действия должна быть предусмотрена комбинация клавиш. Старайтесь не использовать мышь вообще. Конечно, ожидается, что вы уже уверенно владеете методом слепой печати. Если это не так, то срочно скачивайте тренажер и учитесь. Для программиста это просто жизненно необходимый навык. Причем, речь в этой ситуации идет не просто о разнице между печатью быстрее и медленнее. Это различие в правильном и неправильном использовании одного из самых главных ваших инструментов — клавиатуры. Вы же не забиваете гвозди отверткой? Вот и клавиатурой нужно пользоваться правильно;
  5. Поиск и замена по регулярному выражению. Думаю, что этот пункт не требует комментариев;
  6. Функции рефакторинга. Как минимум должна быть возможность быстро переименовать переменную, метод или класс. Но и другие возможности никогда не будут лишними. Главное — пользоваться ими, если они есть.

Конечно, это не полный список, но даже выполнение лишь этих условий существенно увеличит вашу продуктивность. Обычно в этом случае в качестве редактора предлагают использовать либо Emacs, либо Vim. Сейчас мы не будем говорить об особенностях этих редакторов, но когда-нибудь мы еще к этому вернемся. Лично я частично остановился на последнем варианте, то есть на Vim. Но что значит частично? Следует учитывать, что Vim — это не полноценная IDE. В этом есть свои плюсы и минусы. И хоть существует огромное количество расширений для него, которые могут решить большинство сложностей, мне все же приятнее работать с полноценной IDE. Поэтому я нашел для себя простой выход. Практически в любой более или менее серьезной интегрированной среде разработки есть возможность использовать режим редактирования в стиле Vim. Где-то она уже встроена, например FakeVim в Qt Creator, а где-то может быть установлена в виде плагина, например vrapper в Eclipse и VsVim в Visual Studio. Однако по опыту работы скажу, что лучше, когда поддержка режима Vim встроена в IDE, поскольку установка плагинов может принести множество побочных проблем: возможные пересечения комбинаций клавиш, нестабильная работа с другими плагинами и т.д.

Способ 2. Эффективное управление файлами

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

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

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

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

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

Способ 3. Больше мониторов

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

О моем опыте работы с несколькими мониторами и о том, почему я к этому пришел, вы можете прочитать в заметке Почему я пользуюсь Openbox?. Лично для себя я решил остановиться на двух мониторах. Все же это самый простой с аппаратной точки зрения вариант. Кроме того, если бы их было больше, то ими было бы труднее управлять, да и у меня на столе уже попросту не хватит места на еще один монитор. Но тут еще зависит от размера мониторов. Есть системы с 4 или 6 относительно небольшими экранами, которые крепятся на кронштейне. Только я предпочитаю не мельчить, поэтому и выбрал два 27-дюймовых монитора, на которых все хорошо видно, а работать приходится в основном с текстом.

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

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

Способ 4. Автоматизация

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

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

Конечно же, не забывайте про возможность генерации кода с помощью утилит. Например, во многих случаях формы UI-интерфейсов удобнее компоновать с помощью специальных инструментов в стиле WYSIWYG. Они позволяют создавать весьма сложные интерфейсы без единой строки кода за считанные минуты. Однако есть мнение, что такие генераторы нужно использовать лишь для создания прототипов или в работе дизайнеров. А окончательную версию уже реализовывать вручную. Нельзя сказать, что какой-то из методов намного лучше другого. Всегда найдутся преимущества и недостатки, ведь все зависит от ситуации, поэтому окончательный выбор остается за вами.

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

Способ 5. Не изобретайте велосипед

Как и обещал, мы возвращаемся к вопросу использования чужих наработок при решении собственных задач. Идея и выгоды достаточно прозрачны, но у многих стоит настоящий психологический барьер по этому поводу. У меня у самого такое было, да и сейчас не на 100% прошло. Ведь всегда хочется сделать свой независимый проект, который будет лучше других.

В большинстве случаев использование чужих результатов не только увеличивает производительность, но и повышает качество вашей работы.

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

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

Однако помехи и правда вполне возможны. А связаны они могут быть с тем, что чужая библиотека или утилита делает ПОЧТИ то, что нужно, но не совсем то.

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

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

Заключение

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

  1. Освойте среду разработки в совершенстве;
  2. Эффективно управляйте файлами;
  3. Используйте больше мониторов;
  4. Автоматизируйте все, что можете;
  5. Не изобретайте велосипед.

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

3 причины, почему роботы не смогут заменить программистов

В своей колонке Java-разработчик Павел Вейник, основатель и преподаватель школы программирования ITStart.by, порассуждал, являются ли программисты «операторами телеграфа 21 века» и не останутся ли они без работы в результате всеобъемлющей автоматизации.

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

Сейчас полетит камень в огород некоторых лидеров мнений. Как правило, люди, довольно далёкие от ИТ — точней, сильно далёкие — замечают тренд по автоматизации, которая происходит во всех отраслях, и экстраполируют его на ИТ. В частности — на программистов.

Это, с моей точки зрения, говорит о том, что они абсолютно не понимают, что такое автоматизация сама по себе и где границы её возможностей.

Индустрии предстоит пройти ещё очень долгий путь, прежде чем искусственный интеллект сможет по-настоящему конкурировать с программистами. Ну разве что существует какая-нибудь компания, которая уже лет 30-40 тратит все свои деньги (если денег у неё много) на исследования такого рода, но при этом о ней никто не слышал. Такой вот чёрный лебедь.

Фактор N1: именно айтишники всё автоматизируют

Во-первых, автоматизируют всё на свете — айтишники. Именно они внедряют правила работы различных процессов в код, чтобы в таком виде оно работало быстрее и точнее, чем если бы делалось руками. Ровно до тех пор, пока сам процесс не изменится — тогда для него придётся писать новый код. Это обычно долго.

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

Уже довольно давно — лет 8 точно — я вижу всевозможные системы, которые автоматизируют написание кода. Но они зачаточные и покрывают ничтожную долю того, что нужно автоматизировать, убирая самые простые, рутинные шаги разработчиков и в очень небольшом количестве случаев. Поэтому заслуживают упоминания лишь как нечто незначительное.

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

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

Фактор N2: технологическая неготовность ИИ к тому, чтобы заменить программистов

Добавлю кое-что как человек, который очень долго занимался не то чтобы ИИ, но некоторыми задачами, которые обычно этому интеллекту приписывают. А именно: анализ данных.

Как всякий молодой (когда-то) студент со взором горящим, я мечтал написать систему, которая будет автоматизировать хотя бы какие-то части работы программиста. Чтобы любой человек, сформулировав более-менее внятное ТЗ, мог получить на выходе рабочую программу. Мечты мальчишки — это прекрасно, но когда я начал углубляться, то понял, что до всего этого ещё страшно далеко.

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

Да, есть нашумевший стартап, который делает дизайн сайтов с помощью какого-то алгоритма. Но дизайн сайтов — это не более чем компоновка и совмещение цветов в соответствии с чёткими, известными правилами.

Фактор N3: Человеческий, или «любовница главного инженера»

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

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

Может, для кого-то это станет сюрпризом, но подобные вещи встречаются на каждом шагу. И таких «главных инженеров» с личными целями на предприятиях много. Они обладают достаточной властью и влиянием, чтобы оттягивать тот момент, когда им придётся остаться не у дел или испытать какой-то дискомфорт.

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

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

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

Водянистый пузырь искусственного интеллекта

Сейчас, когда интерес к теме ИИ вспыхнул с невиданной силой, мы, похоже, попросту стали свидетелями раздувания нового пузыря, на котором некоторые люди здорово проедутся.

То же самое было со всем известным пузырём доткомов и со многими другими пузырями: все возлагали большие надежды, надежды оказались слишком большими. «Ну извините, не получилось».

Скажем, очень много шумели в своё время нейронные сети. Они и сейчас поднимают много шума, но в начале 2000-х на них возлагали просто гигантские надежды, говорили, что это следующий искусственный интеллект, ещё немного — и они решат все проблемы. Однако они остались в узкой нише. Это происходит часто: какие-то яркие алгоритмы сначала провоцируют бум, потом раздуваются в пузырь, а потом лопаются.

Сегодня под ИИ понимают просто чуть более умные и сложные алгоритмы. Под эту марку можно подгрести что угодно, маркетологам всё равно: главное — инвестиции. Назовёмся ИИ — дадут больше денег? Чудно! 99% таких компаний лопнут, а 1% через 20 лет родит что-нибудь стоящее.

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

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

Треть разработчиков боится ИИ, но не понимает, что это такое?

Тем не менее, статистическое исследование, проведенное фирмой Evans Data Corp., свидетельствует: 29% из 550 опрошенных разработчиков ПО беспокоятся, что их на рабочем месте заменит искусственный интеллект (ИИ).

Тут есть серьёзная оговорка: большинство людей не понимает, что обозначает термин ИИ. Ставя перед респондентами этот вопрос, нужно оговорить, что понимается под этим термином.

Я читал книги про ИИ, написанные ещё в 1960-1980, и сейчас тоже почитываю что-то более современное. И вот какая штука: искусственным интеллектом постоянно называют то, чего машина делать ещё не может. Как только она научится это делать, это перестанет называться ИИ и получит какое-то другое название.

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

Если исходить из этого банального людского представления про ИИ — оно не академично, неправильно, но в большинстве голов присутствует — то и получается такая вот ерунда: «я как программист могу быть заменён машиной, которая умеет делать то, чего машина делать не умеет».

Оптимизация кода: «навороченное» удаление лишней переменной vs улучшение процессов

MIT и Adobe научили компьютер оптимизировать старый код быстрее программистов?

Ладно, разберёмся. В той же Java есть 2 уровня оптимизации кода: один происходит прямо при компиляции, другой прямо при выполнении. Эти оптимизации лет за 15 настолько развились, что некоторые ошибки исправляются очень уверенно.

При этом существуют:


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

Помню, нужно было написать алгоритм оптимизации работы машин в таксопарке. Машин было под 300, довольно большой город — американский, конечно. Я выдал хитрый навороченный алгоритм, который много чего учитывал и требовал несколько месяцев на сбор данных разработку, отладку и тестирование. А пара менеджеров или бизнес-аналитиков за вечер придумали решение, которое вовлекает и пассажира, и таксиста, и простейшие данные по всему таксопарку, выбирая наилучшее решение для задачи, причём очень быстро, на лету.

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

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

Называть это шагом к ИИ — всё равно что называть новую модель машины прорывом в космос.

И всё-таки: так кого заменят роботы в ИТ?

Бизнес-аналитиков, менеджеров, дизайнеров (если это не что-то очень банальное), верстальщиков роботы вряд ли заменят.

Что касается тестировщиков, тут чёткая и всем известная тенденция: ручные тестировщики уже гораздо менее востребованы, чем тестировщики-автоматизаторы, которые пишут программы, тестирующие систему.

Эйчары — вот здесь, думаю, не за горами тот момент, когда их работа будет процентов на 80 автоматизирована. Есть модный тренд больших данных, который давно суют во все щели. Могу даже прикинуть, как с его помощью можно автоматизировать большую часть работы рекрутера. Сперва, конечно, кое-что будет сделано криво, но потом дело пойдёт.

Что касается неайтишных профессий, тут всё довольно прозрачно: людям, которые занимаются физическим трудом, а также тем, кто делает конвейерные рутинные операции в любой сфере (чуть позже — ещё и водителям, судя по тренду с самоуправляемыми авто), нужно срочно идти в программисты — чтобы их не заменили роботы.

Колонка подготовлена при участии Натальи Провалинской

*Мнение колумнистов может не совпадать с позицией редакции.

Оптимизация программного кода

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

Сегодня эти мощности вызывают улыбку. Но традиции оптимизации кода сохранились. Как известно, сколько ни наращивай размер диска и объем ОЗУ, все равно будет мало. Потому написанные «неряшливо» приложения, медленные и ресурсоемкие, проигрывают конкурентную борьбу аналогам, даже если они красивы и удобны.

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

Основные принципы оптимизации

Оптимизация стоит на трех «китах» — естественность, производительность, затраченное время. Давайте разберемся подробнее, что они означают.

  1. Естественность. Код должен быть аккуратным, модульным и легко читабельным. Каждый модуль должен естественно встраиваться в программу. Код должен легко поддаваться редактированию, интегрированию или удалению отдельных функций или возможности без необходимости вносить серьезные изменения в другие части программы.
  2. Производительность. В результате оптимизации вы должны получить прирост производительности программного продукта. Как правило, удачно оптимизированная программа увеличивает быстродействие минимум на 20-30% в сравнение с исходным вариантом.
  3. Время. Оптимизация и последующая отладка должны занимать небольшой период времени. Оптимальными считаются сроки, не превышающие 10 – 15 % времени, затраченного на написание самого программного продукта. Иначе это будет нерентабельно.

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

Стоит ли применять Ассемблер

Многие разработчики искренне считают, что критические секции (некоторые называют их «узкими» местами программы) кода удобнее писать на ассемблере, так как он обеспечивает самый быстрый доступ к данным и устройствам.

Многочисленные сравнения результатов оптимизации кода на языке высокого уровня и применения ассемблерных вставок показывают, что в первом случае после компиляции программа будет работать чуть медленнее, чем при использовании ассемблера. Обычно эти цифры измеряются от 2% до 7%. Максимум – разница составляет 20%. Стоит ли ради получения столь малого эффекта тратить время и силы на написание ассемблерной версии? На наш взгляд лучше уделить больше внимания работе с кодом, который написан на ЯП высокого уровня, и оптимизировать работу алгоритма.

Как правильно оптимизировать

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

Начало оптимизации

Первое, что необходимо сделать, это выявить «узкие места» программы. Нет смысла трогать тот кусок программы, где и без вас все работает прекрасно. Здесь вы вряд ли что-то выиграете при оптимизации. В первую очередь, стоит обратить внимание на блоки кода, которые регулярно или часто повторяются в процессе работы – циклы и подпрограммы.

Пример: Если оптимизировать работу цикла хотя бы на 2% за одну итерацию, а число его повторов будет 1000 раз, в итоге мы получаем: 2% × 1000 = 2000%, вполне ощутимый результат при работе кода.

Участки кода, которые не оптимизируются

Не стоит трогать единичные операнды, поскольку работают они крайне редко и толку в их модификации нет никакого. Они отработают один раз, и больше к этому коду обращений не будет. Но при условии, что при внесении изменений вы добьетесь увеличения производительности более чем на 10%, это не лишено смысла. Здесь все зависит от вашего здравого смысла и опыта.

Также вы не сумеете добиться достойных результатов в случае обращения к внешним устройствам и другим программным системам. До и после таких фрагментов можно что-то ускорить. Но там, где задержка может возникать по причине взаимодействия с внешними данными, лучше предусмотрите заглушку типа «Подождите, операция может занять несколько минут».

Еще раз об ассемблере

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

Оптимизировать или нет?

Если вы не уверены, что сможете ускорить работу программы, при этом тестирование не выявляет никаких критичных проблем, оставьте все как есть. Помните старую мудрость программистов: работает – не мешай.

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

Заниматься оптимизацией следует только тогда, когда на программу поступают жалобы пользователей либо на этапе тестирования находятся проблемные участки, на которых программа «подвисает» и тормозит работу устройства. В таких случаях производится отладка, а для уже выпущенных в серию продуктов выпускают новые версии или, так называемые, «заплатки» (patch).

Методы оптимизации программ

Оптимизация кода не слишком отличается от обычного исправления багов. Более того, с их устранения и начинается работа по оптимизации программы.

Первым делом нужно проверить код на наличие устаревших или вообще ненужных фрагментов. Таких исполняемых модулей или веток в большой программе находится обычно много. Что-то написали, но оказалось, что функционал не нужен, и его просто забыли удалить. Другие части оказались не нужны в результате очередного обновления. Все они занимают место. А некоторые продолжают исполняться, хоть в этом нет никакого смысла. И, таким образом, замедляют работу системы.

Пишите аккуратный код. Не забывайте о комментариях. Так вы поможете и себе, и другим разработчикам, понять, что в программе нужно, а что – уже не актуально. Эти общие советы помогают и при отладке, и при поиске багов. В общем, не будьте неряшливым «говнокодером», и ваши программы будут работать быстро и без проблем.

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

Если все равно что-то не работает или «тормозит», придется использовать профилировщики отладочного вывода, в том числе, с учетом записи логов всех запросов SQL, если программа работает с базами данных. В случае поиска вслепую вы потратите много времени и не факт, что сможете добиться положительных результатов.

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

Настройка окружения

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

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

Также обратите внимание на саму операционную систему и мощность «железа». Может быть они вообще не предназначены для работы программного продукта, который вы пытаетесь запустить и ускорить? А, может, устарели и потому «тормозят»?

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

Избавляемся от ненужного функционала

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

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

Мемоизация

Меморизация (от англ. Memoization) означает запоминание. Фактически это простое сохранение результата выполнения определенной функции, которое поможет избежать ее повторного выполнения. Применяя меморизацию, вы сможете повысить производительность программы.

Работает это очень просто. Перед тем, как функция будет выполняться, проверяется условие – исполнялась ли она ранее. По итогам можно получить два варианта:

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

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

Кеширование

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

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

Распараллеливание программ

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

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

«Ленивые» вычисления

Ленивые (Lazy evaluation) или отложенные вычисления – стратегия, которую применяют в некоторых системах счисления. Суть метода заключается в том, что все расчеты откладываются до тех пор, пока не будет затребован их результат.

Такая стратегия позволит существенно снизить общий объем производимых вычислений, так как ненужные операции попросту не будут выполняться. Чтобы метод начал работать, нужно описать зависимости функций (операндов) друг от друга, что поможет отслеживать работу. В итоге вы получите код, который будет выполняться только в том случае, когда он действительно нужен.

Метод приближения

Приближение или аппроксимаация (от лат. proxima — ближайшая или приближе́ние) – метод замены строгого алгоритма на наиболее подходящие приближенные значения, что влечет за собой определенную потерю точности вычислений. Снижение точности экономит память и повышает скорость. Для того чтобы не использовать длинную арифметику, можно воспользоваться обычными float’ами. Но пользоваться таким методом нужно крайне осторожно, не всегда снижение точности допустимо.

Использование сторонних языков

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

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

Существует еще очень много методов оптимизации, как общеизвестных, так и личных находок программистов. Мы постарались рассказать, что такое оптимизация, и познакомить вас с самыми популярными методами. А как вы ускоряете работу своих приложений? Делитесь в комментариях.

Техника Оптимизации Программ (фрагмент) 1/3

TEMPORA MUTANTUR, ET NOS MUTAMUR IN ILLIS (Времена меняются и мы меняемся с ними лат.)

Аннотация

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

Перед вами лежит уникальное практическое пособие по оптимизации программ под платформу IBM PC и операционные системы семейства Windows (UNIX), скрупулезно описывающее архитектуру, философию и принципы функционирования современных микропроцессоров, чипсетов, оперативной памяти, операционных систем, компиляторов и прочих компонентов ПК.

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

Здесь вы найдете и оригинальные приемы программирования, и недокументированные секреты, существование которых Intel и Microsoft хотели бы скрыть, и разъяснение туманных пунктов фирменной документации (включая указания на многочисленные ошибки и неточности!), и перечень типовых ошибок программистов, снижающих производительность системы, и вполне готовые к использованию решения, и:

Основной упор сделан на процессоры AMD Athlon, Intel Pentium-III и Intel Pentium-4 и языки программирования Си/Си ++ (впрочем, описываемые техники не привязаны ни к какому конкретному языку, и знание Си требуется лишь для чтения исходных текстов примеров, приведенных в книге).

Об авторе

Если говорить о себе кратко — «я просто познаю окружающий мир и получаю от этого удовольствие». Компьютерами одержим еще со старших классов средней школы (или еще раньше — уже, увы, не помню).

Основная специализация: разработка оптимизирующих компиляторов и операционных систем реального времени для управления производством.

Из всех языков программирования больше всего люблю ассемблер, но при разработке больших проектов предпочитаю Си (реже Cи ++). Для создания сетевых приложений прибегаю к помощи Perl и Java, ну а макросы для Word и Visual Studio пишу на Бейсике. Эпизодически балуюсь Forth и всякими «редкоземельными» языками наподобие Python. Впрочем, важен не сам язык, а мысли, которые этим языком выражают.

Но все-таки, компьютеры — не единственное и, вероятно, даже не самое главное увлечение в моей жизни. Помимо возни с железом и блужданий в непроходимых джунглях защитного кода, я не расстаюсь с миром звезд и моих телескопов, много читаю, да и пишу тоже (в последнее время как-то больше пишу, чем читаю).

«Техника оптимизации программ» — это уже седьмая по счету моя книга. Предыдущие: «Техника и философия хакерских атак», «Техника сетевых атак», «Образ мышления — дизассемблер IDA», «Укрощение Интернет», «Фундаментальные основы хакерства. Искусство дизассемблирования» и «Предсказание погоды по местным атмосферным признакам» были горячо одобрены читателями и неплохо расходились, несмотря на то, что ориентированы они на очень узкий круг читателей (гораздо более узкий, нежели «Техника оптимизации программ»).

Помимо этого моему перу принадлежит свыше двухсот статей, опубликованных в журналах «Программист», «Открытые системы», «Инфо-бизнес», «Компьютерра», «LAN», «eCommerce World», «Mobile», «Byte», «Remont & Service», «Astronomy», «Домашний компьютер», «Интерфейс», «Мир Интернет», «Магия ПК», «Мегабайт», «Полный ПК», «Звездочет» и др.

Хакерские мотивы моего творчества не случайны и объясняются по-детски естественным желанием заглянуть «под капот» компьютера и малость «потыкать» его «ломом» и «молоточком», выражаясь, разумеется, фигурально — а как же иначе понять как эта штука работает? Если людей, одержимых познанием окружающего мира, считать хакерами, то я хакер.

Адреса электронной почты для связи с автором: kpnc@programme.ru, kpnc@itech.ru.

Введение в книгу

О серии книг «Оптимизация»

Ну вот, — воскликнет, иной читатель, — опять серия! Да сколько же можно этому Касперски объявлять серий?! И что интересно: все серии разные! Выпущен первый том «Техники сетевых атак», но вот уже года три как нет второго. Объявлен трехтомник «Образ мышления -дизассемблер IDA», но до сих пор вышли только первый и третий тома книги, а второго по-прежнему нет и в обозримом будущем даже и не предвидится. Наконец, «Фундаментальные основы хакерства. Искусство дизассемблирования» — это вновь всего лишь первый том! Так не лучше ли автору сконцентрироваться на чем-нибудь одном, а не метаться по всей предметной области?

Кто-то даже сравнил меня с Кнутом — мол обещал семь томов, а выпустил только три. Но если Кнут выпустил три тома одной книги, то Касперски — по одному тому трех разных. Ситуация осложняется тем, что мой издатель по маркетинговым соображением наотрез отказался называть настоящую книгу томом. Хорошо, пусть это будет не «том», пусть это будет «первая книга серии». (Суть дела от этого все равно не меняется).

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

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

Первая книга — представленная вашему вниманию — посвящена оперативной памяти, оптимизации на уровне структур данных и алгоритмов их обработки. Ориентирована на прикладных и системных программистов. Настоящая книга включает лишь половину запланированного материала. Остающаяся часть либо выйдет отдельной книгой, либо (что более вероятно) появится во втором издании настоящей книги. Предполагаемый срок выхода: начало 2003 года.

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

Третья книга посвящена автоматической кодогенерации. В ней предполагается рассмотреть устройство оптимизирующих компиляторов, алгоритмы оптимизации, сравнение качества кодогенерации различных компиляторов, как «помочь» оптимизатору. Книга ориентирована на прикладных и системных программистов. Предполагаемый срок выхода: начало 2005 года.

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

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

Краткая история создания данной книги

Настоящая книга задумывалась отнюдь не ради коммерческого успеха (который вообще сомнителен — ну много ли людей сегодня занимаются оптимизацией?), а писалась исключительно ради собственного удовольствия (как говорится: UTILE DULCI MISCERE (лат.) — соединять приятное с полезным).

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

Вплотную столкнувшись с необходимостью оптимизации еще во времена древних и ныне скоропостижно почивших 8-рязрядных машин, я скорее по привычке, чем по насущной необходимости, сохранил преданность эффективному коду до настоящих дней. А потому, не без оснований считал, что «собаку съел» на оптимизации и искренне надеялся, что писать на эту тему мне будет очень легко. Вот только бы выяснить несколько «темных» мест и объяснить некоторые странности поведения процессора, до анализа которых раньше просто не доходили руки.

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

Поверьте! Я вовсе не мячик гонял, а каждый день проводил за компьютером как минимум по 12-15 часов, благодаря чему большая часть прежде темных мест «вышла» из мрака на свет божий и теперь ярко освещена! Быть может, это и не очень производительный труд (и вообще крайне низкий выход в пересчете на символ в час), тем не менее, проделанной рабой в целом я остался доволен. И не удивительно! Изучать «железки» — это до жути интересно. Перед вами — черный ящик, и все, что вы можете так это планировать и осуществлять различные эксперименты, пытаясь описать их результаты некоторой математической моделью, проверяя и уточняя ее последующими экспериментами. И вот так из черного ящика постепенно начинают проступать его внутренности, и вы уже буквально «чувствуете» как он работает и «дышит»! А какое вселенское удовлетворение наступает, когда бессмысленная и совершенно нелогичная паутина результатов всевозможных замеров наконец-то ложится в стройную картину! Чувство, охватывающее вас при этом, можно сравнить разве что с оргазмом!

Соглашения об условных обозначениях и наименованиях

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

  • Под P6-процессорами понимаются все процессоры с ядром P6, построенные по архитектуре Pentium Pro. К ним принадлежат: сам Pentium Pro, Pentium-II и Pentium-III, а так же процессоры семейства Celeron.
  • Процессоры серии Pentium здесь сокращаются до первой буквы «P» и стоящей за ней суффиксом, уточняющим какая именно модель имеется в виду. Например, «P Pro» обозначает «Pentium Pro», а «P-4» — «Pentium-4». Кстати, обратите особое внимание, что индексы «II» и «III» записываются римскими цифрами, а «4» — арабскими. Так хочет фирма Intel (она уже однажды сделала мне замечание по этому поводу), поэтому не будем ей противоречить. В конце концов, хозяин — барин.
  • Под «MS VC» или даже просто «VC» подразумевается Microsoft Visual C++ 6.0, а под «BC» — Borland C++ 5.5. Соответственно, «WPP» обозначает «WATCOM C++ 10.0».
  • Кабалистическое выражение наподобие «P-III 733/133/100/I815EP» расшифровывается так: «процессор Intel Pentium-III с тактовой частой 773 МГц, частой системной шины 133 МГц и частой памяти 100 МГц, установленный в материнскую плату, базирующуюся на чипсете Intel 815 EP». Соответственно, по аналогии, «AMD Athlon 1050/100/100/VIA KT 133» обозначает: «процессор AMD Athlon с тактовой частотой 1050 МГц, частотой системной шины 100 МГц и частотой работы памяти 100 МГц, уставленный в материнскую плату, базирующуюся на чипсете VIA KT 133».
  • Да, чуть не забыл сказать. «Сверхоперативная память» — это русский эквивалент американского термина «cache memory». Здесь он будет использоваться вовсе не из-за самостийной гордости, а просто для того, чтобы избежать излишней тавтологии (частого повторения одних и тех же слов).

Введение в оптимизацию

Pro et contra 1 целесообразности оптимизации

Это в наше-то время говорить об оптимизации программ? Бросьте! Не лучше ли сосредоточиться на изучении классов MFC или технологии .NET? Современные компьютеры так мощны, что даже Windows XP оказывается бессильна затормозить их!

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

  • «. я применяю относительно медленный и жадный до памяти язык Perl, поскольку на нем я фантастически продуктивен. В наше время быстрых процессоров и огромной памяти эффективность — другой зверь. Большую часть времени я ограничен вводом/выводом и не могу читать данные с диска или из сети так быстро, чтобы нагрузить процессор. Раньше, когда контекст был другим, я писал очень быстрые и маленькие программы на C. Это было важно. Теперь же важнее быстро писать, поскольку оптимизация может привести к столь малому росту быстродействия, что он просто не заметен», — говорит Robert White;
  • «. а стоит ли тратить усилия на оптимизацию и чего этим можно достичь? Дело в том, что чем сильнее вы будете адаптировать вашу программу к заданной архитектуре, тем, с одной стороны, вы достигнете лучших результатов, а, с другой стороны, ваша программа не будет хорошо работать на других платформах. Более того, «глубокая» оптимизация может потребовать значительных усилий. Все это требует от пользователя точного понимания чего он хочет добиться и какой ценой», — пишет в своей книге «Оптимизация программ под архитектуру CONVEX C» М. П. Крутиков;
  • «Честно говоря, я сам большой любитель «вылизывания» кода с целью минимизации используемой памяти и повышения быстродействия программ. Наверное, это рудименты времен работы на ЭВМ с оперативной памятью в 32 Кбайт. С тем большей уверенностью я отношу «эффективность» лишь на четвертое место в критериях качества программ», — признается Алексей Малинин — автор цикла статей по программированию на Visual Basic в журнале «Компьютер Пресс».

С приведенными выше тезисами, действительно, невозможно не согласиться. Тем не менее, не стоит бросаться и в другую крайность. Начертавший на своем знамени лозунг «на эффективность — плевать» добьется только того, что плевать (причем дружно) станут не в эффективность, а в него самого. Не стоит переоценивать аппаратные мощности! И сегодня существуют задачи, которым не хватает производительности даже самых современных процессоров. Взять хотя бы моделирование различных физических процессов реального мира, обработку видео-, аудио- и графических изображений, распознавание текста: Да что угодно, вплоть до элементарного сжатия данных архиватором a la Super Win Zip!

Да, мощности процессоров растут, но ведь параллельно с этим растут и требования к ним. Если раньше считалось нормальным, поставив программу на выполнение, уйти пить пиво, то сегодняшний пользователь хочет, чтобы все операции выполнялись мгновенно, ну если и не мгновенно, то с задержкой, не превышающей нескольких минут. Не стоят на месте и объемы обрабатываемых данных. Признайтесь, доводилось ли вам находить на своем диске файл размером в сотню-другую мегабайт? А ведь буквально вчера емкость целого жесткого диска была на порядок меньше!

Цель — определяет средства. Вот из этого, на протяжении всей книги, мы и будем исходить. Ко всем оптимизирующим алгоритмам будут предъявляется следующие жесткие требования:

  • оптимизация должна быть максимально машинно-независимой и переносимой на другие платформы (операционные системы) без дополнительных затрат и существенных потерь эффективности. То есть никаких ассемблерных вставок! Мы должны оставаться исключительно в рамках целевого языка, причем, желательно использовать только стандартные средства, и любой ценой избегать специфичных расширений, имеющихся только в одной конкретной версии компилятора;
  • оптимизация не должна увеличивать трудоемкость разработки (в т. ч. и тестирования) приложения более чем на 10%-15%, а в идеале, все критические алгоритмы желательно реализовать в виде отдельной библиотеки, использование которой не увеличивает трудоемкости разработки вообще;
  • оптимизирующий алгоритм должен давать выигрыш не менее чем на 20%-25% в скорости выполнения. Приемы оптимизации, дающие выигрыш менее 20% в настоящей книге не рассматриваются вообще, т. к. в данном случае «овчинка выделки не стоит». Напротив, основной интерес представляют алгоритмы, увеличивающие производительность от двух до десяти (а то и более!) раз и при этом не требующие от программиста сколь ни будь значительных усилий. И такие алгоритмы, пускай это покажется удивительным, в природе все-таки есть!
  • оптимизация должна допускать безболезненное внесение изменений. Достаточно многие техники оптимизации «умерщвляют» программу, поскольку даже незначительная модификация оптимизированного кода «срубает» всю оптимизацию на корню. И пускай все переменные аккуратно распределены по регистрам, пускай тщательно распараллелен микрокод и задействованы все функциональные устройства процессора, пускай скорость работы программы не увеличить и на такт, а ее размер не сократить и на байт! Все это не в силах компенсировать утрату гибкости и жизнеспособности программы. Поэтому, мы будем говорить о тех, и только тех приемах оптимизации, которые безболезненно переносят даже кардинальную перестройку структуры программы. Во всяком случае, грамотную перестройку. (Понятное дело, что «кривые» руки угробят что угодно — против лома нет приема).

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

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

И в заключении позвольте привести еще одну цитату:

«Я программирую, чтобы решать проблемы, и обнаружил, что определенные мысли блокируют все остальные мысли и творческие цели, которые у меня есть. Это мысли об эффективности в то время, когда я пытаюсь решить проблему. Мне кажется, что гораздо логичнее концентрироваться полностью на проблеме, решить ее, а затем творчески запрограммировать, затем, если решение медленное (что затрудняет работу с ним), то. « Gary Mason.

О чем и для кого предназначена эта книга

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

Она ориентирована на прикладных программистов, владеющих (хотя бы в минимальном объеме) языком Си, а так же на системных программистов, знающих ассемблер. Описываемые техники не привязаны ни к какому конкретному языку, и знание Си требуется лишь для чтения исходных текстов примеров, приведенных в книге.

В не меньшей степени «Техника оптимизации» будет интересна и лицам, занимающимся сборкой и настройкой компьютеров, поскольку подробно описывает устройство «железа» и разбирает «узкие места» распространенных моделей комплектующих.

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

Материал книги в основном ориентирован на микропроцессоры AMD Athlon и Intel Pentium-II, Pentium-III и Pentium-4, но местами описываются и более ранние процессоры.

Семь китов оптимизации или

Жизненный цикл оптимизации

Часто программист (даже высококвалифицированный!), обнаружив профилировщиком «узкие» места в программе, автоматически принимает решение о переносе соответствующих функций на ассемблер. А напрасно! Как мы еще убедимся (см. Часть III. «Смертельная схватка: ассемблер VS-компилятор»), разница в производительности между ручной и машинной оптимизацией в подавляющем большинстве случаев крайне мала. Очень может статься так, что улучшать уже будет нечего, — за исключением мелких, «косметических» огрехов, результат работы компилятора идеален и никакие старания не увеличат производительность, более чем на 3%-5%. Печально, если это обстоятельство выясняется лишь после переноса одной или нескольких таких функций на ассемблер. Потрачено время, затрачены силы: и все это впустую. Обидно, да?

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

Назовем ряд правил оптимизации.

Правило I

Прежде, чем оптимизировать код, обязательно следует иметь надежно работающий не оптимизированный вариант или «. put all your eggs in one basket, after making sure that you’ve built a really *good* basket» («. прежде, чем класть все яйца в одну корзину — убедись, что ты построил действительно хорошую корзину»).аким образом прежде, чем приступать к оптимизации программы, убедись, что программа вообще-то работает.

Создание оптимизированного кода «на ходу», по мере написания программы, невозможно! Такова уж специфика планирования команд — внесение даже малейших изменений в алгоритм практически всегда оборачивается кардинальными переделками кода. Потому, приступайте к оптимизации только после тренировки на «кошках», — языке высокого уровня. Это поможет пояснить все неясности и «темные» места алгоритма. К тому же, при появлении ошибок в программе подозрение всегда падает именно на оптимизированные участки кода (оптимизированный код за редкими исключениями крайне ненагляден и чрезвычайно трудно читаем, потому его отладка — дело непростое), — вот тут-то и спасает «отлаженная кошка». Если после замены оптимизированного кода на не оптимизированный ошибки исчезнут, значит, и в самом деле виноват оптимизированный код. Ну, а если нет, то ищите их где-нибудь в другом месте.

Правило II

Помните, что основой прирост оптимизации дает не учет особенностей системы, а алгоритмическая оптимизация. Никакая, даже самая «ручная» оптимизация не позволит существенно увеличить эффективность пузырьковой сортировки или процедуры линейного поиска. Правильное планирование команд и прочие программистские трюки ускорят программу в лучшем случае в несколько раз. Переход к быстрой сортировке (quick sort) и двоичному поиску сократят время обработки данных как минимум на порядок, — как бы криво ни был написан программный код. Поэтому, если ваша программа выполняется слишком медленно, лучше поищите более эффективные математические алгоритмы, а не выжимайте из изначально плохого алгоритма скорость по капле.

Правило III

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

Правило IV

Прежде, чем порываться переписывать программу на ассемблер, изучите ассемблерный листинг компилятора на предмет оценки его совершенства. Возможно, в неудовлетворительной производительности кода виноват не компилятор, а непосредственно сам процессор или подсистема памяти, например. Особенно это касается наукоемких приложений, жадных до математических расчетов и графических пакетов, нуждающихся в больших объемах памяти. Наивно думать, что перенос программы на ассемблер увеличит пропускную способность памяти или, скажем, заставит процессор вычислять синус угла быстрее. Получив ассемблерный листинг откомпилированной программы (для Microsoft Visual C++, например, это осуществляется посредством ключа /FA), бегло просмотрите его глазами на предмет поиска явных ляпов и откровенно глупых конструкций наподобие: MOV EAX, [EBX]\MOV [EBX], EAX. Обычно гораздо проще не писать ассемблерную реализацию с чистого листа, а вычищать уже сгенерированный компилятором код. Это требует гораздо меньше времени, а результат дает ничуть не худший.

Правило V

Если уж взялись писать на ассемблере, пишите максимально «красиво» и без излишнего трюкачества. Да, недокументированные возможности, нетрадиционные стили программирования, «черная магия», — все это безумно интересно и увлекательно, но: плохо переносимо, непонятно окружающим (в том числе и себе самому после возращения к исходному коду десятилетней давности) и вообще несет в себе массу проблем. Автор этих строк неоднократно обжигался на своих же собственных трюках, причем самое обидное, что трюки эти были вызваны отнюдь не «производственной необходимостью», а: ну, скажем так, «любовью к искусству». За любовь же, как известно, всегда приходится платить. Не повторяйте чужих ошибок! Не брезгуйте комментариями и непременно помещайте все ассемблерные функции в отдельный модуль. Никаких ассемблерных вставок — они практически непереносимы и создают очень много проблем при портировании приложений на другие платформы или даже при переходе на другой компилятор. Единственная предметная область, не только оправдывающая, но, прямо скажем, провоцирующая ассемблерные извращения, это — защита программ, но это уже тема совсем другого разговора.

Если ассемблерный листинг, выданный компилятором, идеален, но программа без видимых причин все равно исполняется медленно, не отчаивайтесь, а загрузите ее в дизассемблер. Как уже отмечалось выше, оптимизаторы крайне неаккуратно подходят к выравниванию переходов и кладут их куда «глюк» на душу положит. Наибольшая производительность достигается при выравнивании переходов по адресам, кратным шестнадцати, и будет уж совсем хорошо, если все тело цикла целиком поместится в одну кэш-линейку (т. е. 32 байта). Впрочем, мы отвлеклись. Техника оптимизации машинного кода — тема совершенно другого разговора. Обратитесь к документации, распространяемой производителями процессоров — Intel и AMD.

Правило VI

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

Правило VII

Распространенные заблуждения

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

Заблуждение I

За меня все оптимизирует мой компилятор!

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

Изначально «кривой» код не исправит никакой компилятор, и оптимизирующий — в том числе. Не сваливайте все заботы по эффективности на транслятор! Лучше постарайтесь в меру своих сил и возможностей ему помогать. Как именно помогать, — это тема отдельного большого разговора, которому планируется посвятить третью книгу настоящей серии. Краткий же перечень возможностей машинной оптимизации содержится в третей части данной книги.

Заблуждение II

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

Перенос программы на ассемблер только в исключительных случаях увеличивает ее эффективность. При трансляции качественного исходного кода, оптимизирующие компиляторы отстают от идеальной ручной оптимизации не более чем на 10%-20%. Конечно, это весьма ощутимая величина, но все же не настолько, чтобы оправдать трудоемкость программирования на чистом ассемблере!

Подробнее о сравнении качества машинной и ручной оптимизации см. Часть III. «Смертельная схватка: ассемблер VS-компилятор».

Заблуждение III

Человек, в отличии от оптимизирующего компилятора, просто физически не способен учесть все архитектурные особенности процессора

Вообще говоря, кроме компиляторов, разрабатываемых Intel, никакие другие компиляторы не умеют генерировать оптимально спланированный с точки зрения микроархитектуры процессора код. Несколькими страницами далее (см. «Практический сеанс профилировки с VTune») вы собственноручно сможете убедиться в этом, а пока же просто поверьте автору на слово.

Под оптимальностью обычно понимается глобальный экстремум некоторой оценочной функции. При оптимизации по скорости ищут абсолютный минимум числа тактов. Очевидно, этот минимум зависит от входных данных. В лучшем случае компилятору можно передать данные тестового прогона (так называемый profiler feedback). На основании этих данных компилятор может более аккуратно присвоить частоты выполнения разным последовательностям инструкций, не более того. Компиляторы Intel ни коим образом не генерируют оптимального кода. Исходя из определения, оптимальная по скорости программа не может быть переписана с сохранением смысла так, что начнет исполняться быстрее. Мне приходилось переписывать вручную порожденный этим компилятором код так, что он становился быстрее.

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

Тем не менее, современные процессоры с одной стороны достаточно умны и самостоятельно оптимизируют переданный им на выполнение код. С другой стороны оптимального кода для всех процессоров, все равно не существует и архитектурные особенности процессоров P-II, P-4, AMD K6 и Athlon отличаются друг от друга столь разительно, что все позывы к ручной оптимизации гибнут прямо на корю.

Исключение составляет небольшой круг весьма специфичных задач (например, парольных переборщиков), требования которых к производительности более чем критичны. В этом случае ручная оптимизация действительно «рвет» компилятор, как Тузик грелку.

Заблуждение IV

Процессоры семейства x86 — полный «отстой», вот на PowerPC, например, действительно есть место, где развернуться!

Как гласит народная мудрость «Хорошо там, — где нас нет». Сам я, правда, ничего не оптимизирую под PowerPC, но хорошо знаком с людьми, разрабатывающими под него оптимизирующие компиляторы. И могу сказать, что они далеко не в восторге от его «закидонов», коих у него, поверьте уж, предостаточно.

Да, семейству процессоров x86 присущи многие проблемы и ограничения. Но это ничуть не оправдывает программистов, пишущих «уродливый» код, и палец о палец не ударяющих, чтобы хоть как-то его улучшить.

А «язык» x86 процессоров, между прочим, очень интересен. На сегодняшний день они имеют едва ли не самую сложную систему команд, дающую системным программистам безграничные возможности для самовыражения. Прикладные программисты даже не догадываются сколько красок мира у них украли компиляторы!

Часть 1

Профилировка программ

Профилировкой здесь и на протяжении всей книги мы будем называть измерение производительности как всей программы в целом, так и отдельных ее фрагментов, с целью нахождения «горячих» точек (Hot Spots), — тех участков программы, на выполнение которых расходуется наибольшее количество времени.

Согласно правилу «10/90», десять процентов кода «съедают» девяносто процентов производительности системы (равно как и десять процентов людей выпивают девяносто процентов всего пива). Если время, потраченное на выполнение каждой машинной инструкции, изобразить графически в порядке возрастания их линейных адресов, на полученной диаграмме мы обнаружим несколько высоченных пиков, горделиво возвышающихся над практически пустой равниной, усеянной множеством низеньких холмиков (пример показан далее на рисунке разд. » Практический сеанс профилировки с VTune в десяти шагах») Вот эти самые пики — «горячие» точки и есть.

Почему «температура» различных участков программы столь неодинакова? Причина в том, что подавляющее большинство вычислительных алгоритмов так или иначе сводятся к циклам, — т. е. многократным повторениям одного фрагмента кода, причем зачастую циклы обрабатываются не последовательно, а образуют более или менее глубокие иерархии, организованные по типу «матрешки». В результате, львиную долю всего времени выполнения, программа проводит в циклах с наибольшим уровнем вложения, и именно их оптимизация дает наилучший прирост производительности!

Громоздкие и тормозные, но редко вызываемые функции оптимизировать нет ни какой нужды, — это практически не увеличит быстродействия приложения (ну разве что только в том случае, если они совсем уж будут «криво» написаны).

Когда же алгоритм программы прост, а ее исходный текст свободно умещается в сотню-другую строк, то «горячие» точки нетрудно обнаружить и визуальным просмотром листинга. Но с увеличением объема кода это становится все сложнее и сложнее. В программе, состоящей из тысяч сложно взаимодействующих друг с другом функций (часть из которых это функции внешних библиотек и API — Application Programming Interface, интерфейс прикладного программирования — операционной системы) далеко не так очевидно: какая же именно из них в наибольшей степени ответственна за низкую производительность приложения. Естественный выход — прибегнуть к помощи специализированных программных средств.

Профилировщик (так же называемый «профайлером») — основной инструмент оптимизатора программ. Оптимизация «в слепую» редко дает хороший результат. Помните пословицу «самый медленный верблюд определяет скорость каравана»? Программный код ведет себя полностью аналогичным образом, и производительность приложения определяется самым узким его участком. Бывает, что виновницей оказывается одна-единственная машинная инструкция (например, инструкция деления, многократно выполняющаяся в глубоко вложенном цикле). Программист, затратив воистину титанические усилия на улучшение остального кода, окажется премного удивлен, что производительность приложения едва ли возросла процентов на десять-пятнадцать.

Правило номер один: ликвидация не самых «горячих» точек программы, практически не увеличивает ее быстродействия. Действительно, сколько не подгоняй второго сзади верблюда — от этого караван быстрее идти не будет (случай, когда предпоследней верблюд тормозит последнего — это уже тема другого разговора, требующего глубоких знаний техники профилировки, а потому и не рассматриваемая в настоящей книге).

Цели и задачи профилировки

Основная цель профилировки — исследовать характер поведения приложения во всех его точках. Под «точкой» в зависимости от степени детализации может подразумеваться как отдельная машинная команда, так целая конструкция языка высокого уровня (например: функция, цикл или одна-единственная строка исходного текста).

Большинство современных профилировщиков поддерживают следующий набор базовых операций:

  • определение общего времени исполнения каждой точки программы (total [spots] timing);
  • определение удельного времени исполнения каждой точки программы ([spots] timing);
  • определение причины и/или источника конфликтов и пенальти (penalty information);
  • определение количества вызовов той или иной точки программы ([spots] count);
  • определение степени покрытия программы ([spots] covering).

Общее время исполнения

Сведения о времени, которое приложение тратит на выполнение каждой точки программы, позволяют выявить его наиболее «горячие» участки. Правда, здесь необходимо сделать одно уточнение. Непосредственный замер покажет, что, по крайней мере, 99,99% всего времени выполнения профилируемая программа проводит внутри функции main, но ведь очевидно, что «горячей» является отнюдь не сама main, а вызываемые ею функции! Чтобы не вызывать у программистов недоумения, профилировщики обычно вычитают время, потраченное на выполнение дочерних функций, из общего времени выполнения каждой функции программы.

Рассмотрим, например, результат профилировки некоторого приложения профилировщиком profile.exe, входящего в комплект поставки компилятора Microsoft Visual C++.

Листинг 1.1. Пример профилировки приложения профилировщиком profile.exe

В средней колонке (Func+Child Time) приводится полное время исполнения каждой функции, львиная доля которого принадлежит функции main (ну этого и следовало ожидать), за ней с минимальным отрывом следует gen_pswd со своими 99,6%, далее идет do_pswd — 98,9% и, сильно отставая от нее, где-то там на отшибе плетется CheckCRC, оттягивая на себя всего лишь 3,0%. А функцией CalculateCRC, с ее робким показателем 1,6%, на первый взгляд можно и вовсе пренебречь! Итак, судя по всему, мы имеем три «горячих» точки: main, gen_pswd и do_pswd (рис. 1.1).

Впрочем, функцию main можно откинуть сразу. Она, понятное дело, ни в чем не «виновата». Остаются функции gen_pswd и do_pswd. Если бы это были абсолютно независимые функции, то «горячих» точек было бы и впрямь две, но в нашем случае это не так. И, если из полного времени выполнения функции gen_pswd, вычесть время выполнения ее дочерней функции do_pswd у «матери» останется всего лишь. 0,7%. Да! Меньше процента времени выполнения!

Обратимся к крайней левой колонке (листинг 1.1) таблицы профилировщика (Funct Time), чтобы подтвердить наши предположения. Действительно, в программе присутствует всего лишь одна «горячая» точка — do_pswd, и только ее оптимизация способна существенно увеличить быстродействие приложения (рис. 1.2).

Хорошо, будем считать, что наиболее «горячая» функция определена и теперь мы горим желанием ее оптимизировать. А для этого недурно бы узнать картину распределения «температуры» внутри самой функции. К сожалению, профилировщик profile.exe (и другие подобные ему) не сможет ничем нам помочь, поскольку его разрешающая способность ограничивается именно функциями.

Но, на наше счастье существуют и более «продвинутые» профилировщики, уверенно различающие отдельные строки и даже машинные команды! К таким профилировщикам в частности относится VTune от Intel. Давайте запустим его и заглянем внутрь функции do_pswd (подробнее о технике работы с VTune см. «Практический сеанс профилировки с VTune»).

Вот теперь совсем другое дело — сразу видно, что целесообразно оптимизировать, а что и без того уже «вылизано» по самые помидоры. «Горячие» точки главным образом сосредоточены вокруг конструкции pswd[p], — она очень медленно выполняется. Почему? Исходный текст не дает непосредственного ответа на поставленный вопрос и потому совсем не ясно: что конкретно следует сделать для понижения «температуры» «горячих» точек.

Приходится спускаться на уровень «голых» машинных команд (благо профилировщик VTune это позволяет). Вот, например, во что компилятор превратил безобидный на вид оператор присвоения pswd[p] = ‘!’

Смотрите! В одной строке исходного текста происходит целых три обращения к памяти! Сначала указатель pswd загружается в регистр EDX, затем он суммируется с переменной p, которая так же расположена в памяти, и лишь затем по рассчитанному смещению в память благополучно записывается константа ‘!’ (021h).

Тем не менее, все равно остается не ясно, почему загрузка указателя pswd занимает столько времени? Может быть, кто-то постоянно вытесняет указатель pswd из кэша, заставляя процессор обращаться к медленной оперативной памяти? Так ведь нет! Программа работает с небольшим количеством переменных, заведомо умещающихся в кэше второго уровня.

Удельное время выполнения

Если время выполнения некоторой точки программы не постоянно, а варьируется в тех или иных пределах (например, в зависимости от рода обрабатываемых данных), то трактовка результатов профилировки становится неоднозначной, а сам результат — ненадежным. Для более достоверного анализа требуется: а) определить действительно ли в программе присутствуют подобные «плавающие» точки и, если да, то: б) определить время их исполнения в лучшем, худшем и среднем случаях.

Очень немногие профилировщики могут похвастаться способностью определять удельное время выполнения машинных команд (иначе называемое растактовкой). К счастью, профилировщик VTune это умеет! Обратимся к сгенерированному им протоколу динамического анализа. Быть может, он поможет нам разрешить загадку «неповоротливости» загрузки указателя pswd?

Ну, вот опять, — все команды, как команды, а загрузка указателя pswd «разлеглась» прямо как объевшаяся свинья, «сожравшая» целых тринадцать тактов, в то время как остальные свободно укладываются в один-два такта, а некоторые и вовсе занимают ноль, ухитряясь завершиться одновременно с предыдущей инструкций.

За исключением команды, загружающей содержимое переменной y в регистр ECX, время выполнения всех остальных команд строго постоянно и не меняется от случая к случаю. Наша же «подопечная» в зависимости от еще не выясненных обстоятельств, может «отъедать» даже восемьдесят тактов, что на время делает ее самой «горячей» точкой данного фрагмента программы. Восемьдесят тактов — это вообще полный беспредел! И пускай среднеарифметическое время ее выполнения составляет всего лишь семь тактов, а минимальное — и вовсе ноль, мы не успокоимся пока не выясним: на что и при каких именно обстоятельствах уходит такое количество тактов?

Информация о пенальти

Уже сам факт существования «горячей» точки говорит о том, что в программе что-то неправильно. Хорошо, если это чисто алгоритмическая ошибка, которую видно невооруженным глазом (например, наиболее узким местом приложения оказалась пузырьковая сортировка). Хуже, если процессорное время исчезает буквально на пустом месте без всяких видимых на то причин. Еще хуже, если «хищения» тактов происходят не систематически, а совершаются при строго определенном стечении каких-то неизвестных нам обстоятельств.

Возвратимся к предыдущему вопросу: почему указатель pswd загружается так долго? И при каких именно обстоятельствах загрузка переменной y «подскакивает» со своих обычных семи до восьмидесяти тактов? Судя по всему, процессору что-то не понравилось и он обложил эти две машинные команды «штрафом» (penalty), на время притормозив их исполнение. Можем ли мы узнать, когда и за какой «проступок» это произошло? Не прибегая к полной эмуляции процессора — вряд ли (хотя современные процессоры x86 с некоторыми ограничениями позволяют получить эту информацию и так).

Гранды компьютерной индустрии — Intel и AMD уже давно выпустили свои профилировщики, содержащие полноценные эмуляторы выпускаемых ими процессоров, позволяющие визуализировать нюансы выполнения каждой машинной инструкции.

Просто щелкните по строке mov ecx, DWORD PTR [ebp-28] и профилировщик VTune выдаст всю, имеющуюся у него информацию (листинг 1.5).

Листинг 1.5. Вывод профилировщиком VTune дополнительной информации о выполнении инструкции

Так, кажется, наше расследование превращается в самый настоящий детектив, еще более запутанный, чем у Агаты Кристи. Если приложить к полученному результату даже самый скромный арифметический аппарат, получится полная чепуха и полное расхождение «дебита с кредитом». Судите сами. Полное время выполнения инструкции — 80 тактов, причем, известно, что она выполнялась 11 раз (см. в листинге 1.3 колонку count отчета профилировщика). А наихудшее время выполнения инструкции составило. 80 тактов! А наихудшее время декодирования и вовсе — 86! То есть, худшее время декодирования инструкции превышает общее время ее исполнения и при этом в десяти итерациях она еще ухитряется простаивать как минимум один такт за каждую итерацию по причине занятости блока расчета адресов. Да. тут есть от чего «поехать крышей»!

Причина такого несоответствия заключается в относительности самого понятия времени. Вы думаете время относительно только у Эйнштейна? Отнюдь! В конвейерных процессорах (в частности процессорах Pentium и AMD K6/Athlon) понятие «времени выполнения инструкции» вообще не существует в принципе (см. подразд. » Конвейеризация или пропускная способность VS-латентность» гл. 1). В силу того, что несколько инструкций могут выполняться параллельно, простое алгебраическое суммирование времени их исполнения даст значительно больший результат, нежели исполнение занимает в действительности.

Ладно, оставим разборки с относительностью до более поздних времен, а пока обратим внимание на тот факт, что в силу отсутствия нашей инструкции в кэше (она как раз находится на границе двух кэш-линеек) и вытекающей отсюда необходимости загружать ее из основной памяти, в первой итерации цикла она выполняется значительно медленнее, чем во всех последующих. Отсюда, собственно, и берутся эти пресловутые восемьдесят тактов.

При большом количестве итераций (а при «живом» исполнении программы оно и впрямь велико) временем начальной загрузки можно и пренебречь, но. Стоп! Ведь профилировщик исполнил тело данного цикла всего 11 раз, в результате чего среднее время выполнения этой инструкции составило 7,3 тактов, что совершенно не соответствует реальной действительности!

Ой! Оказывается, это вовсе не «горячая» точка! И тут совершенного нечего оптимизировать. Если мы увеличим количество прогонов профилировщика хотя бы в четыре раза, среднее время выполнения нашей инструкции понизится до 1,8 тактов и она окажется одним из самых «холодных» мест программы! Точнее — это вообще абсолютный ноль, поскольку эффективное время исполнения данной инструкции — ноль тактов (т. е. она завершается одновременно с предыдущей машинной командой). Словом, мы «промахнулись» по полной программе.

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

Короткое лирическое отступление на тему: почему же все так произошло. По умолчанию VTune прогоняет профилируемый фрагмент 1.000 раз. Много? Не спешите с ответом. Наш хитрый цикл устроен так, что его тело получает управление лишь каждые ‘z’ ‘!’ = 0x59 итераций (см. листинг 1.2). Таким образом, за все время анализа тело цикла будет исполнено всего лишь 1.000/89 = 11 раз! Причем, ни в коем случае нельзя сказать, что это надуманный пример. Напротив! В программном коде такое встречается сплошь и рядом.

Листинг 1.6. Демонстрация кода, некоторые участки которого прогоняются профилировщиком относительно небольшое количество раз, что искажает результат профилировки

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

Впрочем нет, постойте. Нам еще предстоит разобраться со второй «горячей» точкой и на удивление медленной скоростью загрузки указателя pswd. Опытные программисты, вероятно, уже догадались в чем тут дело.

Действительно, — строка pswd[p] = ‘!’ — это первая строка тела цикла, получающая управление каждые 0x59 итераций, что намного превосходит «проницательность» динамического алгоритма предсказания ветвлений, используемого процессором для предотвращения остановки вычислительного конвейера.

Следовательно, данное ветвление всегда предсказывается ошибочно и выполнение этой инструкции процессору приходится начинать с нуля. А процессорный конвейер — длинный. Пока он заполниться. Собственно, тут виновата вовсе не команда mov edx, DWORD PTR [ebp+0ch] — любая другая команда на ее месте исполнялась бы столь же непроизводительно! «Паяльная грелка, до красна нагревающая» эту точку программы, находится совсем в другом месте!

Поднимем курсор чуть выше, на инструкцию условного перехода предшествующую этой команде, и дважды щелкнем мышкой. Профилировщик VTune выдаст следующую информацию:

Наша гипотеза полностью подтверждается. Это ветвление тринадцать раз предсказывалось неправильно, о чем VTune и свидетельствует! Постой, как тринадцать?! Ведь тело цикла исполняется только одиннадцать! Да, правильно, одиннадцать. Но ведь процессор наперед этого не знал, и дважды пытался передать на него управление, и лишь затем, «увидев», что ни одно из двух предсказаний не сбылось, «плюнул и поклялся», что никогда-никогда не поставит свои фишки на эту ветку.

ОК. Когда загадки разрешаются — это приятно. Но главный вопрос несколько в другом: как именно их разрешать? Хорошо, что в нашем случае непредсказуемый условный переход находился так близко к «горячей» точке, но ведь в некоторых (и не таких уж редких) случаях «виновник» бывает расположен даже в других модулях программы! Ну что на это сказать. Подходите к профилировке комплексно и всегда думайте головой. Пожалуй, ничего более действенного я не смогу посоветовать.

Определение количества вызовов

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

Например, пусть у нас есть две «горячие» точки, в которых процессор проводит одинаковое время, но первая из них вызывается сто раз, а вторая — сто тысяч раз. Нетрудно догадаться, что, оптимизировав последнюю хотя бы на 1%, мы получим колоссальный выигрыш в производительности, в то время как, сократив время выполнения первой из них вдвое, мы ускорим нашу программу всего лишь на четверть.

Таким образом, часто вызываемые функции в большинстве случаев имеет смысл «инлайнить» (от английского in-line), т. е. непосредственно вставить их код в тело вызываемых функций, что сэкономит какое-то количество времени.

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

Определение степени покрытия

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

Итак, покрытие — это процент реально выполненного кода программы в процессе его профилировки. Кому нужна такая информация? Ну, в первую очередь, тестерам — должны же они убедиться, что весь код приложения протестирован целиком и в нем не осталось никаких «темных» мест.

С другой стороны, оптимизируя программу, очень важно знать, какие именно ее части были профилированы, а какие нет. В противном случае многих «горячих» точек можно просто не заметить только потому, что соответствующие им ветки программы вообще ни разу не получили управления!

Рассмотрим, например, как может выглядеть протокол покрытия функций, сгенерированный профилировщиком profile.exe для нашего тестового примера pswd.exe (о самом тестовом примере см. разд. «Практический сеанс профилировки с VTune в десяти шагах» гл. 2)

Из листинга 1.7 следует, что лишь 60% функций получили управление, а остальные 40% не были вызваны ни разу! Разумно убедиться: а вызываются ли эти функции когда ни будь вообще или представляют собой «мертвый» код, который можно безболезненно удалить из программы, практически на половину уменьшив ее в размерах?

Если же эти функции при каких-то определенных обстоятельствах все же получают управление, нам необходимо проанализировать исходный код, чтобы разобраться: что же это за обстоятельства и воссоздать их, чтобы профилировщик смог пройти и остальные участки программы. Имена покрытых и непокрытых функций перечислены в секции Covered Function. Покрытые отмечаются знаком «*», а непокрытые — «.»

Вообще же, для определения степени покрытия существует множество узкоспециализированных приложений (например, NuMega Code Coverage), изначально направленных на решение именно этой задачи и со своей работой они справляются намного лучше любого профилировщика.

Фундаментальные проблемы профилировки «в малом»

Профилировкой «в малом» мы будем называть измерение времени выполнения небольших фрагментов программы, а то и отдельных машинных команд.

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

Конвейеризация или пропускная способность VS-латентность

Начнем с того, что в конвейерных системах такого понятия как «время выполнения одной команды» просто нет. Уместно провести такую аналогию. Допустим, некоторый приборостроительный завод выпускает шестьсот микросхем памяти в час. Ответьте: сколько времени занимает производство одной микросхемы? Шесть секунд? Ну конечно же нет! Полный технологический цикл составляет не секунды, и даже не дни, а месяцы! Мы не замечаем этого лишь благодаря конвейеризации производства, т. е. разбиении его на отдельные стадии, через которые в каждый момент времени проходит, по крайней мере, одна микросхема.

Количество продукции, сходящей с конвейера в единицу времени, называют его пропускной способностью. Легко показать, что пропускная способность в общем случае обратно пропорциональна длительности одной стадии, — действительно, чем короче каждая стадия, тем чаще продукция сходит с конвейера. При этом количество самих стадий (попросту говоря, длина конвейера) не играет абсолютно никакой роли. Кстати, обратите внимание, что практически на всех заводах каждая стадия представляет собой элементарную операцию, — вроде «накинуть ключ на гайку» или «стукнуть молотком». И не только потому, что человек лучше приспосабливается к однообразной монотонной работе (наоборот, он, в отличии от автоматов, ее терпеть не может!). Элементарные операции, занимая чрезвычайно короткое время, обеспечивают конвейеру максимальную пропускную способность.

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

С одной стороны и хорошо, — конвейер крутится как угорелый, выполняя до 6 микроинструкций за такт и какое нам собственно дело до его длины? А вот какое! Вернемся к нашей аналоги с приборостроительным заводом. Допустим, захотелось нам запустить в производство новую модель. Вопрос: через какое время она сойдет с конвейера? (Бюрократическими проволочками можно пренебречь). Ни через шесть секунд, ни через час новая модель готова не будет и придется ждать пока весь технологический цикл не завершится целиком.

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

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

Малоприятным следствием становится невозможность определения реального времени исполнения компактного участка кода (если, конечно, не прибегать к эмуляции процессора). До тех пор, пока время выполнения участка кода не превысит латентность конвейера (30 тактов для P6), мы вообще ничего не сможем сказать ни о коде, ни о времени, ни о конвейере!

Неточность измерений

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

А чем можно измерять время работы отдельных участков программы? В персональных компьютерах семейства IBM PC AT имеются как минимум два таких механизма: системный таймер (штатная скорость: 18,2 тика в секунду, т. е. 55 мс, максимальная скорость — 1 193 180 тиков в секунду или 0,84 мкс), часы реального времени (скорость 1024 тика в секунду т. е. 0,98 мс). В дополнении к этому в процессорах семейства Pentium появился так называемый регистр счетчик — времени (Time Stamp Counter), увеличивающийся на единицу при каждом такте процессорного ядра.

Теперь разберемся со всем этим хозяйством подробнее. Системный таймер (с учетом времени, расходующегося на считывание показаний) обеспечивает точность порядка 5 мс, что составляет более двух десятков тысяч тактов даже в системе с частотой 500 МГц! Это — целая вечность для процессора. За это время он успевает перемолотить море данных, скажем, отсортировать сотни полторы чисел. Поэтому, системный таймер для профилирования отдельных функций непригоден. В частности, нечего и надеяться с его помощью найти узкие места функции quick sort! Да что там узкие места — при небольшом количестве обрабатываемых чисел он и общее время сортировки определяет весьма неуверенно.

Причем, прямого доступа к системному таймеру под нормальной операционной системой никто не даст, а минимальный временной интервал, еще засекаемый штатной Си-функций clock(), составляет всего лишь 1/100 сек, а это годиться разве что для измерения времени выполнения всей программы целиком.

Точность часов реального времени так же вообще не идет ни в какое сравнение с точность системного таймера (перепрограммированного, разумеется).

Остается надеяться лишь на Time Stamp Counter. Первое знакомство с ним вызывает просто бурю восторга и восхищения «ну наконец-то Intel подарила нам то, о чем мы так долго мечтали!». Судите сами: во-первых, операционные системы семейства Windows (в том числе и «драконическая» в этом плане NT) предоставляют беспрепятственный доступ к машинной команде RDTSC, читающий содержимое данного регистра. Во-вторых, поскольку он инкрементируется каждый такт, создается обманчивое впечатление, что с его помощью возможно точно определять время выполнения каждой команды процессора. Увы! На самом же деле это далеко не так!

Начнем с того, что в конвейерных системах, как мы уже помним, вообще нет такого понятия как время выполнения команды, и следует говорить либо о пропускной способности, либо латентности. Сразу же возникает вопрос: а что же все-таки команда RDTSC меряет? Документация Intel не дает прямого ответа, но судя по всему, RDTSC считывает содержимое регистра счетчика-времени в момент прохождения данной инструкции через соответствующее исполнительное устройство. Причем, RDTSC — это неупорядоченная команда, т. е. она может завешаться даже раньше предшествующих ей команд. Именно так и произойдет, если предшествующая ей команда простаивает в ожидании операндов.

Рассмотрим крайний случай, когда измеряется время выполнения минимальной порции кода (одна машинная команда уходит на то, чтобы сохранить считанное значение в первой итерации):

Листинг 1.8. Попытка замера времени выполнения одной машинной команды

При прогоне этого примера на P-III он выдаст 32 такта, вызывая тем самым риторический вопрос: «а почему, собственно, так много?» Хорошо, оставим выяснение обстоятельств «похищения процессорных тактов» до лучших времен, а сейчас попробуем измерять время выполнения какой-нибудь машинной команды, ну скажем, INC EAX, увеличивающей значение регистра EAX на единицу. Поместим ее между инструкциями RDTSC и перекомпилируем программу.

Вот это да! Прогон показывает все те же 32 такта. Странно! Добавим-ка мы еще одну INC EAX. Как это так — снова 32 такта?! Зато при добавлении сразу трех инструкций INC EAX контрольное время исполнения скачкообразно увеличивается на единицу, что составляет 33 такта. Четыре и пять инструкций INC EAX дадут аналогичный результат, а вот при добавлении шестой, результат изменений вновь возрастает на один такт.

Но ведь процессор Pentium, имея в наличии всего лишь одно арифметическое устройство, никак не может выполнять более одного сложения за такт одновременно! Полученное нами значение в три команды за такт — это скорость их декодирования, но отнюдь не исполнения! Чтобы убедиться в этом запустим на выполнение следующий цикл (листинг 1.9).

Листинг 1.9. Измерение времени выполнения 6х1000 машинных команд INC

На P-III выполнение данного цикла займет отнюдь не

2 000, а целых 6 781 тактов, что соответствует, по меньшей мере, одному такту, приходящемуся на каждую математическую инструкцию! Следовательно, в предыдущем случае, при измерении времени выполнения нескольких машинных команд, инструкция RDTSC «вперед батьки пролезла в пекло», сообщив нам совсем не тот результат, которого мы от нее ожидали!

Вот если бы существовал способ «притормозить» выполнение инструкции RDTSC до тех пор, пока полностью не будут завершены все предшествующие ей машинные инструкции. И такой способ есть! Достаточно поместить перед RDTSC одну из команд упорядоченного выполнения. Команды упорядоченного выполнения начинают обрабатываться только после схода с конвейера последней предшествующей ей неупорядоченной команды и, до тех пор пока команда упорядоченного выполнения не завершится, следующие за ней команды мирно дожидаются своей очереди, а не «лезут как толпа дикарей» вперед на конвейер.

Подавляющее большинство команд упорядоченного выполнения — это привилегированные команды (например, инструкции чтения/записи портов ввода-вывода) и лишь очень немногие из них доступны с прикладного уровня. В частности, к таковым принадлежит инструкция идентификации процессора CPUID.

Многие руководства (в частности и Ангер Фог в своем руководстве «How to optimize for the Pentium family of microprocessors» и технический документ «Using the RDTSC Instruction for Performance Monitoring» от корпорации Intel) предлагают использовать приблизительно такой код (листинг 1.10).

Листинг 1.10. Официально рекомендованный способ вызова инструкции RDTSC для измерения времени выполнения

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

(Кстати, и у Intel, и Ангера Фога есть одна грубая ошибка — в их варианте программы перед инструкцией CPUID отсутствует явное задание аргумента, который эта инструкция ожидает «увидеть» в регистре EAX. А, поскольку, время ее выполнения зависит от аргумента, то и время выполнения профилируемого фрагмента не постоянно, а зависит от состояния регистров на входе и выходе. В предлагаемом мною варианте инициализация EAX осуществляется явно, что страхует профилировщик от всяких там наведенных эффектов).

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

Если профилируемый код задействует те же самые узлы процессора, что и команды RDTSC/CPUID, время его выполнения окажется совсем иным нежели в действительности! Никаким ухищрениями нам не удастся достигнуть точности измерений до одного-двух тактов!

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

Отсюда следствие: штатными средствами процессора измерять время выполнения отдельных команд невозможно.

Аппаратная оптимизация

На мгновение отвлечемся от компьютеров и зададимся вопросом: можно ли с помощью обычной ученической линейки измерить толщину листа принтерной бумаги? На первый взгляд, тут без штангенциркуля ну никак не обойтись. Но, если взять с полсотни листов бумаги и плотно сложить их друг с другом. вы уже поняли куда я клоню? Пусть погрешность измерения толщины образовавшегося «кирпича» бумаги составит 1 мм, тогда — точность определения толщины каждого отдельно взятого листа будет не хуже чем 0,02 мм, что вполне достаточно для большинства повседневных целей!

Почему бы ни применить эту технику для измерения времени выполнения машинных команд? В самом деле, время выполнения одной команды так мало, что просто ничем его не измерить (см. подразд. «Неточность измерений»), но если мы возьмем сто или даже сто тысяч таких команд, то. Но, увы! Машинные команды ведут себя совсем не так, как листы бумаги. Неоднородность конвейера приводит к тому, что зависимость между количеством и временем выполнения команд носит ярко выраженный нелинейный характер.

К тому же, современные процессоры слишком умны, чтобы воспринимать переданный им на выполнение код буквально. Нет! Они подходят к этому делу весьма творчески. Вот, допустим, встретится им последовательность команд MOV EAX, 1; MOV EAX, 1; MOV EAX, 1, каждая из которых помещает в регистр EAX значение «1». Думаете, процессор как полный недоумок, исполнит все три команды? Да как бы не так! Поскольку, результат двух первых присвоений никак не используется, процессор отбросит эти команды как ненужные, затратив время лишь на их декодирование, и ощутимо сэкономит на их выполнении!

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

Низкая «разрешающая способность»

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

Под «разрешающей способностью» здесь и далее понимается протяженность «горячей» точки более или менее уверенно распознаваемой профилировщиком.

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


Фундаментальные проблемы профилировки «в большом»

Профилировкой «в большом» мы будем называть измерение времени выполнения структурных единиц программы (функций, многократно выполняемых циклов и т.д.), а то и всей программы целиком.

Профилировке «в большом» присущи свои проблемы. Это и непостоянство времени выполнения, и проблема «второго прохода», и необходимость учета наведенных эффектов. Словом, здесь есть над чем поработать!

Непостоянства времени выполнения

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

Причин такого непостоянства существует, по меньшей мере, две:

  • программное непостоянство, связанное с тем, что в многозадачных операционных системах (в частности в Windows) профилируемая программа попадает под влияние чрезвычайно изменчивой окружающей среды;
  • аппаратное непостоянство, вызванное внутренней «многозадачностью» самого железа.

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

Оптимизация Windows — проверенные способы

Под словом «оптимизация» пользователи чаще всего подразумевают ускорение работы компьютера. На самом деле это ошибочное мнение. Каким бы быстрым не был компьютер, без быстро работающего пользователя толку от него будет чуть более, чем никакого. Если ваша цель — получить от компьютера результат как можно быстрее, то оптимизируйте в первую очередь свою работу: создайте ярлыки часто используемых программ на Рабочем столе, приведите в порядок закладки браузера, выучите «горячие клавиши», уберите/отключите/удалите все лишнее.

Три способа оптимизации Windows

Теперь собственно о ускорении работы компьютера: существует три способа оптимизации.

Способ 1. Переустановка Windows и программ.

Если все сделать правильно, то после переустановки Windows и всех программ мы получим компьютер словно «с иголочки» — быстрый, резво откликающийся на действия пользователя. К сожалению, переустанавливать Windows каждый раз, когда что-то идет не так, не выход, так как правильная установка Windows и программ требует много времени. Сизифов труд, не более.

Способ 2. Покупка новых комплектующих.

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

Способ 3. Оптимизация Windows и программ.

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

Оптимизировать нужно не только операционную систему, но и программы, так как мы работаем с программами, а Windows — всего лишь посредник.

Чего нельзя достичь оптимизацией

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

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

Суровая реальность такова: у каждого компьютера есть своя вычислительная мощность (измеряется в флопсах, кстати), повысить которую без замены комплектующих нельзя. Более того, всю эту вычислительную мощь задействовать не получится — нет такой задачи, которая заставит компьютер «напрячься» на все сто процентов.

Все зависит и от поставленных задач. Каждый компьютер решает задачи с разной скоростью. Причина — набор установленных программ и имеющееся «железо». Например, первая версия программы создания спецэффектов для фильмов/сериалов/рекламы/прочей видеопродукции Adobe AfterEffects умела использовать только центральный процессор компьютера, поэтому скорость создания спецэффекта зависела в первую очередь от вычислительной мощи процессора. Современные версии AfterEffects используют более быстрые алгоритмы и могут задействовать всю мощь видеокарт — значит, если в компьютере будет установлена подходящая видеокарта, подходящий драйвер и новейшая версия, спецэффекты будут «рисоваться» в десятки и сотни раз быстрее, чем если бы использовался только процессор.

Максимум — можно немного повысить «отзывчивость» системы на действия пользователя. Достигается это отключением якобы «ненужных» функций Windows, что плохо сказывается на стабильности системы.

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

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

Этапы оптимизации

Ко всему надо подходить с умом. Разделим весь процесс на три этапа:

1. Предварительная подготовка.

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

2. Оптимизация.

Собственно оптимизация — приводим в порядок автозагрузку, удаляем ненужные файлы, делаем дефрагментацию и другие полезные «процедуры».

3. Периодическое повторение.

Как только становится заметно замедление производительности — снова повторяем первые два этапа. Обычно это возникает через полгода-год. Если вы часто устанавливаете программы и игры, то раньше.

Первый этап: предварительная подготовка

Благодаря предварительной подготовке выявляются проблемы, вызывающие нестабильную и медленную работу компьютера. Также появляется возможность вернуть «все как было», если в процессе оптимизации что-то сделали не так (см. Восстановление системы).

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

Проверяем компьютер на перегрев

Компьютер (ноутбук) стал шуметь и тормозить? Не поленитесь проверить его на перегрев. Там все просто — вам всего лишь надо скачать программу и посмотреть данные в ней. Если вы обнаружили перегрев — сначала разберитесь с ним.

Чтобы увидеть температуру процессора, можете скачать и поставить программу Ускоритель компьютера. В разделе Инструменты — Системный монитор будет видна температура процессора.

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

Проверяем жесткий диск на ошибки

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

Как проверить диски в Windows XP, Vista, 7: Меню Пуск — Компьютер — Правой кнопкой по диску — Свойства — вкладка Сервис — Проверка диска — Отметить галку «Автоматически исправлять системные ошибки» — Запуск — Подождать:

Дальше может произойти одно из двух:

1. Проверка диска запустится сразу, при этом индикатор проверки будет показан в окне.

2. Проверка диска не запустится, при этом появится окно с надписью «Windows не может проверить диск, который в данный момент используется». Это не проблема, просто нажмите «Расписание проверки диска»:

Затем перезагрузите компьютер и подождите — вместо Рабочего стола появится экран проверки диска:

Проверка диска при включении компьютера

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

Как проверить диски в Windows 8: Открываем Проводник. Если не знаете, как это делать, то на экране Пуск введите слово «Компьютер»:

Находим Проводник (окно Компьютер)

В Компьютере правой кнопкой мыши по диску — Свойства — Сервис — Проверить:

Запуск проверки диска в Windows 8

Проверка диска в Windows 8 выглядит просто:

И работает быстро.

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

Создаем точку восстановления

Чтобы в случае ошибочных действий повысился шанс восстановить систему, обязательно сделайте точку восстановления Windows. Как это сделать, я рассказал в своей статье про AVZ — 2.1. Как создать точку восстановления.

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

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

Проверяем компьютер на вирусы

Даже если у вас установлен антивирус с самыми свежими антивирусными базами и вы посещаете только проверенные сайты, уязвимости в вашей системе и на сайтах никто не отменял. Так что обязательно проверяем компьютер любым одноразовым антивирусом по вкусу. Мой выбор — Dr.Web CureIt.

Обновляем систему

Microsoft периодически выпускает «заплатки», закрывающие уязвимости в Windows, Office и некоторых других программах, а также исправляющие кое-какие ошибки. Нужно обязательно обновлять систему.

Как обновить Windows:

В старушке Windows XP: Пуск — Все программы — Windows Update.

В Windows Vista/7: Пуск — Все программы — Центр обновления Windows.

В Windows 8: На стартовом экране Пуск ввести «Панель управления» — открыть её — Центр обновления Windows.

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

Внимание! Если у вас установлена сборка Windows (например, «Windows Zver», «Windows MegaSuperGame Edition» или какая-нибудь еще) и/или вы делали что-либо с системой «оптимизаторами», обновление Windows может работать со сбоями или не работать вовсе. Выводы о полезности сборок делайте сами. Пользуйтесь только оригинальными, не измененными «очумелыми ручками» изданиями Windows.

Ставим свежие драйвера

Данный пункт можно пропустить, если вы начинающий пользователь. Однако вам следует знать: производительность компьютера зависит не только от его «железной» части, но и от драйверов. Особенно это касается драйверов для видеокарт: новые версии включают оптимизации под недавно вышедшие игры. Именно так было в случае с Crysis 3 — nVidia и AMD «подсуетились» сразу после выхода этой игры и выпустили драйвера, с которыми эта очень требовательная игра стала работать на 5-30% быстрее, прирост производительности был ощутим

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

Примечание: если вы (или вам) только что установили Windows и у вас тормозят игры — скорее всего, вы (вам) не установили драйвер на видеокарту. В этом случае, как ни крути, придется решать этот вопрос. Без драйвера на видеокарту с официального сайта производителя быстрой работы компьютера в играх вы не получите.

Внимание: для автоматического поиска и обновления драйверов я не рекомендую использовать посторонние программы — зачастую драйвера в их базах старые и лишены части компонентов, из-за чего Windows и программы будут работать с ошибками.

Второй этап: оптимизация

Как только вы убедитесь, что причина медленной работы компьютера не в перегреве, не в ошибках на диске, а также сделаете точку восстановления — можно приступать к оптимизации Windows. Советы подходят для Windows Vista, 7 и Windows 8, в меньшей степени — для устаревшей Windows XP.

Применяйте их в том порядке, в котором они написаны — так будет наиболее эффективно и быстро.

Удаляем ненужные данные

По ряду причин чем больше свободного места на жестком диске — тем лучше. Придерживайтесь следующих правил:

1. Храните все данные упорядоченными по папкам. Если вы знаете, где хранятся все ваши документы, фильмы, музыка, то риск «потерять» где-то на жестком диске большой файл минимален.

2. Не храните свои файлы на Рабочем столе. И дело даже не в том, что их можно случайно удалить. Дело в том, что информация о файлах на рабочем столе постоянно просматривается системой, что замедляет работу компьютера в целом. Если хранить документы на Рабочем столе вам жизненно необходимо, создайте на нем папку и переместите все файлы туда — так будет лучше. Старайтесь удалять ярлыки ненужных программ — в случае чего из «Пуска» их по-прежнему можно запустить, Windows станет чуточку «легче» показывать вам Рабочий стол.

3. Периодически очищайте папку «Загрузки«. Там хранятся все загруженные вами файлы из Интернета. В Windows XP эта папка находится в Моих документах\Загрузки. В Windows Vista/7/8 — C:\Пользователи (или Users)\Имя пользователя\Загрузки (или Downloads). Наведите там порядок, все нужное рассортировав по папкам, ненужное удалите.

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

Установка CCleaner для удаления ненужных файлов

Для быстрой очистки жесткого диска от ненужных файлов потребуется программа Piriform CCleaner.
Среди подобных себе CCleaner выделяется двумя преимуществами:

  1. Работа CCleaner полностью «прозрачна» — в любой момент можно узнать, какие файлы программа хочет удалить.
  2. Программа не обещает чудодейственного прироста скорости, не проводит пользователя «за ручку» по непонятным пунктам, не показывает «высосанные из пальца» проценты ускорения работы компьютера. Как любой хороший инструмент, она просто честно работает.

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

Скачиваем CCleaner отсюда (3 мб, облегченная версия без рекламных дополнений).

Во время установки не забываем указать русский язык:

Все остальное можно оставить по умолчанию. При первом запуске программа задаст вам вопрос о выборе «cookies» — ответьте «Нет» («No»), потому что эта функция не нужна.

Удаляем ненужные файлы

В программе CCleaner на вкладке «Очистка» надо отметить только указанные пункты:

Очистка компьютера с помощью CCleaner

Эти пункты теоретически никак не могут навредить программам, зато помогут освободить максимум места на жестком диске.

Нюансы при работе с CCleaner:

  • Если вы пользуетесь каким-либо другим браузером, отличным от представленных на скриншоте, отметьте и его Интернет-кэш тоже, если подобный пункт будет в списках.
  • CCleaner показывает пункты с оглядкой на то, какие программы установлены у вас на компьютере, поэтому некоторые пункты у вас могут отсутствовать.
  • Не делайте очистку реестра — это бесполезно и в некоторых случаях может вызвать трудноразрешимые проблемы.
  • Галку на пунктах «Сжатие баз данных» ставить рекомендуется только в том случае, если вы не хотите пользоваться программой SpeedyFox (о ней будет ниже).

Оптимизация баз данных браузеров

Замечали, что со временем браузеры запускаются медленнее? Все дело в том, что браузеры хранят свои данные в базах данных, которые имеют свойство фрагментироваться и замедлять свою работу. CCleaner умеет оптимизировать базы данных браузеров, но лучше воспользоваться специализированным инструментом — бесплатной SpeedyFox. Программа умеет оптимизировать базы данных многих популярных браузеров, кроме Opera — она не хранит свои данные в SQLite базе данных. Возможно, в будущем будет поддерживаться новая Opera на «движке» Chromium, пока остается пользоваться CCleaner для ее оптимизации.

Скачайте программу по ссылке, закройте все браузеры, запустите SpeedyFox и нажмите Optimize:

SpeedyFox проста, как апельсин

Разница в скорости запуска браузеров до и после работы SpeedyFox видна невооруженным глазом.

Чистка автозагрузки

Для отключение ненужных программ из автозагрузки можно использовать множество программ: Autoruns, Ускоритель компьютера, CCleaner и другие. Между ними есть различия в функционале, но в целом это дело личных предпочтений каждого.

Подробнее про автозагрузку я рассказал в статье Автозагрузка Windows и Autoruns — инструкция для начинающих.

Например, в CCleaner контроль автозагрузки находится на вкладке Сервис — Автозагрузка — Windows:

Очистка автозагрузки Windows

Откроется список программ, запускающихся при загрузке Рабочего стола. Нужно сократить его до минимума.

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

Возникает вопрос: какие программы удалять из автозагрузки?

К сожалению, универсального ответа не существует. Придется немного попотеть. Бездумно удалять пункты нельзя — часть программ должна запускаться при старте для корректной работы компьютера. Например, «ctfmon» от Microsoft позволяет работать индикатору раскладки клавиатуры на Панели задач.

Вам пригодятся несколько правил чистки автозагрузки:

1. Узнайте, какая программа за что отвечает.

Если название записи ни о чем не говорит, смотрите столбец «Файл».

Пример: запись «SyncManPath» ни о чем не скажет, пока не посмотрите путь к файлу программы: «C:\Users\Имя пользователя\AppData\Roaming\Yandex\YandexDisk\YandexDisk.exe«. Поблагодарим разработчиков программы Яндекс.Диск за странное название записи автозагрузки.

Также никто не отменял Гугл и Яндекс — поиск по имени записи и файла может дать вам требуемую информацию.

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

3. Отключение автозагрузки программы в CCleaner или аналогичной программе не всегда срабатывает. Дело в том, что программы могут снова добавить себя в автозагрузку. Если вы столкнулись с такой проблемой, решение простое: ищите в настройках самой программы опцию автозагрузки и отключайте автозапуск программы через нее. Или, если она не нужна, удалите через «Программы и компоненты» в Панели управления.

Чистка контекстного меню — неочевидная, но полезная оптимизация

Это поможет избавиться от тормозов при открытии меню папок, файлов и на Рабочем столе. Также это может помочь в том случае, если Рабочий стол у вас тормозит, в то время как остальные программы работают нормально.

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

Еще в 2010 году на сайте acerfans.ru я писал об этом способе оптимизации Windows. Удивительно, но до сих пор избавление от ненужных компонентов меню до сих пор не получило популярности. Скорее всего, причина в том, что статьи про оптимизацию Windows пишутся под одну кальку: очистка диска, очистка реестра, очистка автозагрузки и… всё. Исправлю ситуацию.

Вопрос №1: про какое меню речь?

Ответ: когда мы нажимаем правой кнопкой мыши по Рабочему столу, мы видим меню. Похожее меню появляется при нажатии на файлы и папки. Оно часто бывает разным, отсюда и название такого меню — контекстное, оно меняется в зависимости от того, вызываем ли мы его для Рабочего стола, папки или файла определенного типа.

Это меню — часть Проводника Windows. Проводник — системная программа, в которой обычно пользователи видят файлы. Когда мы открываем окно Компьютер, то на самом деле тоже видим Проводник. Рабочий стол — тоже часть Проводника. Все это вместе принято называть оболочкой.

Несмотря на то, что существуют альтернативы Проводнику — например, Total Commander, меню файлов и папок в таких программах на самом деле также принадлежат Проводнику. Проще говоря, Проводник есть везде и никуда от него не деться. Это часть операционной системы Windows.

Вопрос №2: зачем «чистить» это меню?

Ответ: посторонние программы добавляют в меню Проводника свои пункты. В некоторых случаях это может вызвать проблемы — замедление открытия меню или сбои в работе Проводника (ошибки процесса «explorer.exe» ). Отключение таких дополнений исправит ситуацию.

Пункты бывают двух типов:

1. Созданные путем добавления всего лишь нескольких ключей в реестр Windows. Путем таких манипуляций трудно нарушить работу проводника. Если у вас все-таки это получилось — буду рад, если пришлете мне «рецепт». CCleaner такие пункты не показывает, хотя в меню Проводника они видны.

2. Расширения оболочки (что такое «оболочка», я говорил выше). О них и будет дальше речь.

Расширения оболочки — полноценные программные компоненты, которые «внедряются» в Windows и изменяют ее. Расширения полезны. Например, в меню появляются пункты проверки файла антивирусом, добавляются новые вкладки в окно «Свойства» папок и файлов и многое другое (отсюда и название — расширения. Они расширяют возможности Windows).

Тем, кому интересно, что это за расширения такие — есть целый сборник статей, посвященный им.

Проблема в том, что в некоторых случаях подобное вмешательство не проходит даром — меню начинает открываться медленно, Рабочий стол может «зависать» или вовсе закрываться. С этим мы и попробуем сейчас бороться.

Отсюда вывод: если чистка контекстного меню не помогла (процесс «explorer.exe» по-прежнему закрывается с ошибками или Проводник ведет себя не так, как раньше), есть более радикальный способ отключить вообще все посторонние расширения оболочки с помощью программы Autoruns — смотрите раздел статьи «Ошибки, зависания Проводника (explorer.exe)» по этой ссылке. Однако подобные манипуляции чреваты последствиями — можно «потерять» некоторые стандартные функции Проводника.

Чистить контекстное меню предельно легко: в CCleaner открываем Сервис — Автозагрузка — Контекстное меню и… дальше все будет понятно:

Удалять расширения не рекомендую, достаточно их выключить. Можно смело отключать всё, что вам не нужно. После перезагрузки компьютера отключенные компоненты перестанут беспокоить Проводник в Windows, пункты меню исчезнут, как и «глюки» (если они были вызваны этими компонентами). В случае каких-то проблем можно включить их обратно.

Нюансы чистки контекстного меню:

  1. Чтобы увидеть изменения, нужно перезагрузить компьютер.
  2. Некоторые программы блокируют столь бесцеремонное отключение своих компонентов. Например, расширения оболочки, добавляемых Антивирусом Касперского, у вас вряд ли получится отключить. Впрочем, оно и не нужно — расширения оболочки, что ставятся вместе с антивирусами, обычно не вызывают проблем со стабильностью Windows.
  3. Отключать все пункты подряд имеет смысл только в том случае, если меню папок и файлов открывается с задержкой (тормозит). Так как вы наверняка не знаете, какой компонент вызвал эти тормоза, придется отключить все. Потом можно включать пункты по очереди и проверять работу Рабочего стола и Проводника. Вместо перезагрузки компьютера можно завершать все процессы explorer.exe, чтобы оценить результат (к сожалению, это не всегда срабатывает и проблема может быть не в компоненте меню).

Удаление ненужных программ

Один из способов оптимизации компьютера — удалить неиспользуемые программы. Это не только освободит место на жестком диске, но и заставит ваш компьютер «забегать» быстрее. Дело в том, что с программами могут устанавливаться службы, драйвера, различные компоненты, которые снижают отзывчивость системы.

Программы можно удалять разными способами:

  1. Правильный — запуск программы удаления какой-либо программы и следование ее инструкциям (BCUninstaller).
  2. Неправильный — ручное удаление папок с программами в «C:\Program Files» и «C:\Program Files (x86)».

Обычно «неправильный» способ используется тогда, когда другого выхода нет — по каким-либо причинам программа удаления (деинсталляции) отказывается работать.

Автор статьи не несет ответственности за ваши действия!

Идем в Панель управления — Программы и компоненты. Если вы не знаете, где находится эта штука, наберите в меню Пуск фразу «Удаление программы». В Windows 8 после набора фразы придется нажать кнопку Параметры.

Установка и удаление программ

В появившемся окне отобразится список установленных на вашем компьютере программ. Как и в случае с Автозагрузкой, универсального способа указать на ненужные программы не существует. Вам придется самим решать вопрос, имея в качестве советчика Гугл или Яндекс. Вам также может пригодиться сервис «Should I Remove It?«, который покажет рейтинг программ. Если за удаление программы проголосовало много людей, ее индикатор будет красным:

Рейтинг программ на сайте «Should I Remove It?».

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

Несколько советов от меня:

  1. Если поиск описания программы в интернете был безуспешным — не удаляйте либо спрашивайте в комментариях под статьей — постараюсь помочь.
  2. Не пользуйтесь «специальными программами» для якобы полного удаления программ. Стандартные способы удаления программ работают вполне нормально.
  3. Оставлять программу «на потом», рассчитывая, что когда-нибудь (через месяц/год/столетие) ею воспользуетесь не имеет смысла. Лучше удалить и в будущем, когда она потребуется, поставить новую версию, где появятся новые интересные возможности.

Дефрагментация и прочая оптимизация жестких дисков

О фрагментации и дефрагментации

Жесткий диск можно назвать «главным тормозом» в системе. Производительность компьютера зависит не только от скорости процессора, но и скорости доступа к данным, чего жесткий диск в полной мере обеспечить не может из-за своей конструкции. Ситуацию усугубляет процесс под названием «фрагментация«. Что такое фрагментация файлов, можно увидеть на следующей картинке:

Как видно из рисунка, файлы на диске могут быть разделены на фрагменты. В принципе, подобная организация файлов — норма, но тормоза от этого никуда не денутся.

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

Почему фрагментация замедляет доступ к данным

Все дело в недостатке конструкции жесткого диска.

Итак, он состоит из вращающихся «блинов», по которым бегает головка, считывающая и записывающая данные:

Пластин (т.е. «блинов» и, соответственно, считывающих головок) обычно бывает несколько. Более подробно про устройство жесткого диска можно почитать на Википедии.

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

Несмотря на все ухищрения, причина тормозов никуда не денется: у жестких дисков есть не только такие параметры, как скорость чтения/записи, но и скорость произвольного доступа к данным. В этом и заключается загвоздка: даже если жесткий диск будет считывать и записывать данные с бесконечно быстрой скоростью, головке чтения/записи всегда потребуется время, чтобы «доползти» до нужного сектора пластины с данными. Flash-память такого недостатка лишена — доступ к данным осуществляется почти мгновенно, поэтому компьютер с SSD-диском в качестве основного работает гораздо быстрее.

Попробуем оценить масштаб проблемы медленного доступа к данным. В настоящий момент у жестких дисков домашних компьютеров время доступа составляет около 8 миллисекунд. Если файл будет состоять из 100 фрагментов, «разбросанных» по жесткому диску, то для его чтения в идеальных условиях на бесконечно быстром диске потребуется 800 миллисекунд, т.е. 0,8 секунды. Подобное «зависание» будет заметным — все программы «замрут» на время, ожидая в очереди на запись или чтение данных. Если за диск будут «бороться» несколько программ, зависания будут длиться больше секунды.

Вывод: если у вас есть деньги, купите качественный SSD-диск и установите туда систему. Это даст реально ощутимый прирост производительности. Если такой возможности нет, старайтесь следовать советам в статье.

Дефрагментация MFT или Почему надо держать на жестком диске минимум

13% свободного места.

При желании просто прокрутите страницу вниз или нажмите ссылку [↓Вниз].

Данные на жестком диске хранятся не абы как, а упорядоченно. Если вы интересуетесь этим, вот статьи на тему: Жёсткий диск, Раздел диска, Файловая система, NTFS. Не буду пересказывать их, а сразу перейду к проблемам файловой системы NTFS, которая используется на компьютерах с Windows Vista, 7 или 8. Надеюсь, ваших знаний достаточно для понимания разницы между разделами и диском. Если же нет, прочтите хотя бы статью про разделение жестких дисков на разделы, чтобы понимать терминологию.

Если вы читаете эту статью в 2014 году или позже, вам может повезти — в Windows 8 SP1 (возможно, информация еще не подтверждена) и поздних версиях Windows (а это уже наверняка) можно будет использовать новую файловую систему ReFS , которая описанных ниже недостатков с MFT лишена.

Когда люди форматируют диск или флешку в файловую систему NTFS, то иногда впадают в недоумение: диск кажется пустым, но в «Свойствах» диска видно, что место чем-то занято. Это «что-то» — служебные файлы, необходимые для работы NTFS. Наибольшее место занимает файл MFT (Master File Table — Главная файловая таблица).

В MFT хранится информация о всех файлах, папках и их физическом местоположении, информация о самой MFT и многое другое. Без MFT вся информация на разделе станет просто неупорядоченным набором байтов.

Для быстрой работы с файлом MFT Windows резервирует свободное место непосредственно после Главной файловой таблицы:

MFT и резервирование места

При этом место на диске не отбирается. «Резервирование места» всего лишь означает, что данные в эту область диска можно будет записать только в самую последнюю очередь, когда все остальное пространство «забито». Тогда место резервирования делится пополам — сначала примерно 6,25% отдается под запись файлов пользователя, затем еще 3,12% и так далее, до полного исчерпания свободного места на разделе.

Для наглядности иллюстрация этого процесса:

Вывод: всегда оставляйте как минимум 12,5% свободного места на разделе!

Тем не менее, если на диске осталось мало места, волноваться не следует. Фрагментация MFT — частый случай на компьютерах пользователей, которые не следят за свободным местом на жестком диске, но серьезных тормозов это не вызывает. Экспериментальным путем я выяснил, что заметные тормоза при открытии папок и работе с файлами начинаются при MFT, разделенной примерно на 50 фрагментов, чего в реальных условиях достичь проблематично. Такое встречается преимущественно на компьютерах 10-летней давности с Windows XP, где дефрагментатор никогда не запускался.

Windows довольно успешно борется с этой напастью. Если заканчивается место в резервной зоне, а затем освобождается где-то еще, то часть освободившегося места будет новой резервной зоной, чтобы MFT не «раскидало» по всему жесткому диску. Многие дефрагментаторы (стандартные «дефраги» Windows Vista, 7 и 8 тоже) умеют «собирать» кусочки MFT воедино.

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

Как делать дефрагментацию

Переходим к практике!

Как ни странно, стандартные дефрагментаторы Windows Vista, 7 и 8 умеют корректно оптимизировать файлы. Оптимизируют даже MFT, вопреки убеждениям некоторых (пускай и не очень эффективно).

Про дефрагментатор из состава Windows XP скромно промолчим — он не умеет ничего.

Если вы не трогали настроек, в Windows Vista, 7 и 8 дефрагментация запускается автоматически раз в неделю. К сожалению, эта опция может быть выключена (замечал 3-4 раза на установленных Windows Vista и 7 с лицензионных дисков), поэтому не лишним будет все проверить и заодно запустить дефрагментацию вручную.

Закройте все программы, какие только возможно. Программ, видимых в трее (значки возле часов) это тоже касается.

Windows Vista: Пуск — Все программы — Стандартные — Служебные — Дефрагментация диска:

Запуск дефрагментации в Windows Vista

Обратите внимание на пункт «Выполнять по расписанию (рекомендуется)». Можно настроить автоматическую дефрагментацию на то время, когда компьютер включен, но вы им не пользуетесь (одного раза в месяц достаточно), а затем вообще забыть про то, что ее надо запускать — система все сделает сама.

Можно запустить и вручную (если вы не уверены, что дефрагментация проводилась ранее). Для этого нажмите кнопку «Выполнить дефрагментацию», отметьте галками ваши жесткие диски и затем «ОК».

Windows 7: Пуск — Все программы — Все программы — Стандартные — Служебные — Дефрагментация диска:

Дефрагментация в Windows 7

В отличии от дефрагментатора Висты, который автоматически запускает анализ дисков, здесь нужно выделить строчки с дисками (с зажатым Ctrl щелкните поочередно на дисках) и нажать «Анализировать диски». Запускать дефрагментацию желательно тогда, когда фрагментировано больше 20%, так как именно тогда компьютеры начинают подтормаживать (не все и не сильно, просто личный опыт). Дефрагментация запускается аналогично — выделяем нужные строчки и нажимаем «Дефрагментация дисков».

Windows 8: просто наберите слово «Оптимизация» на экране Пуск:

Дефрагментация в Windows 8

Как и в дефрагментаторе Windows 7, нужно выделить нужные строчки с дисками и нажать «Анализировать все». Кстати, странное название для кнопки, которая анализирует не все, а только выбранные диски.

Нажатие на «Оптимизировать все» запустит процесс дефрагментации.

Вопросы и ответы о дефрагментации

Вопрос №1: Как часто нужно проводить дефрагментацию?

Ответ: Одного раза в месяц достаточно. Иногда реже, если процент фрагментированных файлов меньше 20%.

Вопрос №2: Дефрагментация чистит жесткий диск от ненужных файлов?

Ответ: Нет. Ничего не удаляется. Исключение — некоторые сторонние дефрагментаторы в процессе оптимизации могут нарушить работу VSS. Обычно этот момент оговаривается в справке дефрагментатора.

Вопрос №3: Как долго идет дефрагментация?

Ответ: Все зависит от скорости жесткого диска, его заполненности, степени фрагментации и того, что вы (не) делаете за компьютером во время этого процесса.

Вопрос №4: Можно ли работать за компьютером во время дефрагментации?

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

Вопрос №5: Сделал дефрагментацию и все удалилось! Что делать?

Ответ: Скорее всего, вы перепутали дефрагментацию с форматированием — частая ошибка новичков, любящих нажимать все кнопки подряд. Паниковать рано — есть шанс восстановить данные.

Вопрос №6: Есть ли у дефрагментации негативные последствия?

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

Вопрос №7: Нужно ли дефрагментировать флешки, карты памяти и SSD диски?

Ответ: Это бессмысленно из-за того, что в такой памяти доступ к любому биту информации осуществляется примерно за одинаковое время, поэтому фрагментация не замедляет чтение и запись данных. Еще и вредно — ячейки flash-памяти быстро изнашиваются, из-за нагрузки она может выйти из строя раньше планируемого.

Этап третий: повторение — мать оптимизации

Повторять подобную «оптимизацию» можно как раз в пару месяцев, так и раз в год. Чаще оптимизировать смысла нет — это будет пустой тратой времени.

Несколько полезных советов:

1. Проверять компьютер на перегрев следует тогда, когда вы видите следующие симптомы:

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

2. Проверять жесткий диск на ошибки можно раз в пару месяцев или реже.

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

4. Дефрагментацию запускать вручную совершенно не обязательно — достаточно настроить ее автоматический запуск и забыть о ней. Это не настолько серьезная проблема, чтобы уделять ей много времени.

5. Чистить автозагрузку следует тогда, когда включение компьютера ощутимо замедлилось. Вполне возможно, что в автозагрузке как раз накопилось много программ.

6. Оптимизацию с помощью SpeedyFox делайте тогда, когда браузер станет заметно подтормаживать. Делать «чтобы было» не рекомендую — если в процессе оптимизации будет сбой (например, выключится свет), можете потерять важную информацию.

7. Очищать жесткий диск с помощью упомянутых мною утилит можно когда угодно. Хватит раз в неделю.

Разрушаем мифы: оптимизация работы компьютера

Вокруг слова «оптимизация» вертится много мифов. Это на руку нехорошим людям, которые проталкивают «в массы» бесполезные программы вроде оптимизаторов оперативной памяти или чистильщиков реестра. Также популярен такой класс программ, как ускорители интернета, которые на самом деле не ускоряют, а оптимизируют: их целью является не увеличение скорости интернета (выше тарифного плана и технических возможностей не прыгнешь), а регулировка сетевых параметров, чтобы снизить пинг (задержки при передаче данных) и оптимизировать ряд других процессов.

Относитесь недоверчиво к советам «тонкой настройки» Windows

По своей природе человек всегда верит в то, что вещи можно сделать лучше. В какой-то мере это действительно так, но не везде и не всегда. Например, нельзя какими-либо «тонкими настройками» Windows заставить компьютер работать по-настоящему быстрее.

Боромир всё знает

Чистка реестра, всякие «секретные» ключи в реестре Windows — звучит многообещающе, на деле полный «пшик». Вы где-нибудь видели серьезные тесты скорости работы компьютера до и после такой «оптимизации»? Любые бенчмарки типа 3DMark, PassMark и подобные при тестах покажут всю правду об этих «оптимизациях». Если не верите — проверьте сами.

Относитесь недоверчиво к различным советам, потому что эффект «плацебо» никто не отменял — веря в ускорение, вы увидите ускорение там, где его нет.

Программы для оптимизации — это бизнес!

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

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

Тысячи долларов радуют всегда! Фото © The Consumerist.

Для привлекательности большинство программ для оптимизации имеет ряд особенностей:

  • Внешний вид таких программ дает ложное ощущение полного контроля над ситуацией. На самом деле вас «проводят за ручку» по всем этапам: от созерцания устрашающих надписей о найденных проблемах до автоматического решения этих проблем.
  • Описания настроек упрощены в ущерб информативности. На мой взгляд, это сделано для того, чтобы пользователь чувствовал себя всезнающим и не задумывался о том, чтобы изучить вопрос подробнее.
  • Программы стараются выглядеть как можно более эффективными, находя тысячи «проблем», которые надо срочно исправить. Например, вы можете с удивлением узнать, что на только что установленной Windows есть тысячи ошибок в реестре. Кстати, из-за такого поведения оптимизатор 360Amigo System Speedup добавлен в базу антивируса Eset Nod32 как «потенциально нежелательная программа Win32/360Amigo«. Возможно, остальные оптимизаторы отправятся туда же.
  • Опять-таки для повышения видимой эффективности программами эксплуатируются бесполезные или вредные способы оптимизации. Например, чистка реестра и отключение ненужных служб присутствуют в любой программе оптимизации, ориентированной на начинающих пользователей. Иногда к ним присоединяется оптимизация оперативной памяти — несмотря на бесполезность и даже вредность этого метода, в ускорение работы компьютера таким способом верят многие пользователи. Пример программы-оптимизатора, где используются все три способа такой «оптимизации» — Glary Utilities Pro.
  • «Оптимизация Windows и программ» — понятие растяжимое. Это не только попытка сделать систему более отзывчивой, но и изменение настроек, повышающих безопасность системы и улучшающих комфорт при работе с компьютером. К сожалению, все это сваливается в одну кучу, путая пользователей. Пример: вкладка «Советник» в целом хорошей программы Auslogics BoostSpeed устроена так, что хочется отметить галочкой все перечисленные ошибки (на то, что это именно ошибки, намекает кнопка «Исправить отмеченное»), хотя на самом деле нам предлагают как банальные процедуры по очистке жесткого диска, так и в ряде случаев потенциально вредное отключение системных служб. Программа BoostSpeed неплоха, но вводит в заблуждение неподготовленного пользователя. Получается, что многие программы для оптимизации действительно работают как надо, просто пользователь ждет от них другого эффекта.
  • Изменение настроек Windows без соответствующих знаний может вызвать обратный эффект — пользователь получит ошибки и тормоза. К сожалению, на сайтах программ-оптимизаторов об этом в лучшем случае сообщают очень скупыми фразами, в худшем — умалчивают. Тем не менее, это не прямой обман, потому что: а) почти все программы для оптимизации перед своим вмешательством предупреждают о риске и делают резервные копии настроек; б) в самой Windows есть такая полезная штука, как «Восстановление системы» и резервные точки восстановления. Т.е. и овцы целы, и волки сыты.

Нужно ли клеймить «оптимизаторы» как программы, обманывающие пользователей? Нет. Есть такие, которые в умелых руках действительно работают как надо. CCleaner, например, позволит браузерам и Windows запускаться и работать чуть быстрее (настройки для этого я привел выше). Еще пример — мощная программа дефрагментации O&O Disk Defrag может на пару десятков секунд сократить время загрузки системы и заметно снизить тормоза при работе с диском. К сожалению, эффективна только платная версия этого дефрагментатора, поэтому про нее здесь не буду подробно рассказывать.

Оптимизация не должна красть время, иначе ваш труд не имеет смысла

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

Время — ценный ресурс, который надо сберечь. Вот зачем нужна оптимизация. Фото © beggs.

Пример: допустим, на чтение этой статьи и оптимизацию системы по моим рецептам вы потратите полчаса. Дефрагментацию, которая работает в фоновом режиме, не отнимая у вас время, в расчет не берем. После оптимизации, допустим, компьютер стал включаться на 30 секунд быстрее, браузер — на 10 секунд, остальные 10 гипотетических программ — на 2 секунды каждая. Если вы включаете компьютер, запускаете браузер и программы по три раза в день, выигрыш от оптимизации составляет 3 минуты. Таким образом, реальный выигрыш от оптимизации появится через 10 дней и далее — когда те полчаса, потраченные на оптимизацию, вернутся к вам за счет возросшей скорости работы компьютера.

Оптимизация и игры

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

Нюанс: не забывайте про настройки графики в играх. Установив минимальное разрешение и качество графики в игре, можно играть на относительно старом «железе». Минимальные требования к компьютеру, написанные на коробке с игрой, говорят о том, что на таком компьютере можно играть с минимальным качеством графики.

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

Оптимизация — всё по этой теме для программистов

Некоторые задачи часто могут быть выполнены более эффективно. Например, рассмотрим следующую программу на языке Си, которая суммирует все целые числа от 1 до N:

Этот код может быть (подразумевая, что нет переполнения) переписан, используя математическую формулу, в следующем виде:

Термин «оптимизация» обычно подразумевает, что система сохраняет ту же самую функциональность. Однако, значительное улучшение производительности часто может быть достигнуто с помощью решения насущной проблемы и удаления избыточной функциональности. Например, если обоснованно допустить, что программе не требуется поддерживать более, чем (скажем) 100 элементов при вводе, то возможно использовать статическое выделение памяти вместо медленного динамического.

Уступки (tradeoffs)

Оптимизация в основном фокусируется на одиночном или повторном времени выполнения, использовании памяти, дискового пространства, пропускной способности или некотором другом ресурсе. Это обычно требует уступок — один параметр оптимизируется за счёт других. Например, увеличение размера кэша улучшает производительность времени выполнения, но также увеличивает потребление памяти. Другие распространённые уступки включают прозрачность кода и его выразительность. Сложные специализированные алгоритмы требуют больше усилий по отладке и увеличивают вероятность ошибок.

Различные области

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

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

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

Узкие места

Для оптимизации требуется найти узкое место: критическую часть кода, которая является основным потребителем необходимого ресурса. Улучшение примерно 20 % кода влечёт за собой изменение 80 % результатов (см. также принцип Парето).

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

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

См. также

  • Оптимизация в Java
  • Оптимизация в C++
  • Абстрактная интерпретация
  • Метрика хорошести
  • Кэширование
  • Принцип KISS
  • Граф передачи управления
  • Ленивые вычисления
  • Низкоуровневая виртуальная машина
  • Мемоизация
  • Окрестность памяти
  • Профилирование (анализ производительности)
  • Теория очередей
  • Симулятор
  • Гипотетическое исполнение
  • Время выполнения наихудшего случая

Ссылки

  • Programming Optimization
  • C,C++ optimization
  • C optimization tutorial
  • Software Optimization at Link-time And Run-time
  • Profiling and optimizing Ruby code
  • Article «A Plea for Lean Software» by Niklaus Wirth
  • Description from the Portland Pattern Repository
  • Улучшаем производительность приложения путем перераспределения кода (рус.)
  • ПОИСК ГЛОБАЛЬНОГО ОПТИМУМА
  • Оптимизация 64-битных программ (рус.)

Литература

  • Jon Bentley. Writing Efficient Programs. ISBN 0-13-970251-2
  • Дональд Кнут. Основные алгоритмы // Искусство программирования = The Art of Computer Programming, vol.1. Fundamental Algorithms. — 3-е изд. — М.: Вильямс, 2006. — Т. 1. — 720 с. — ISBN 0-201-89683-4
  • Дональд Кнут. Получисленные методы // Искусство программирования = The Art of Computer Programming, vol.2. Seminumerical Algorithms. — 3-е изд. — М.: Вильямс, 2007. — Т. 2. — 832 с. — ISBN 0-201-89684-2
  • Дональд Кнут. Сортировка и поиск // Искусство программирования = The Art of Computer Programming, vol.3. Sorting and Searching. — 2-е изд. — М.: Вильямс, 2007. — Т. 3. — 824 с. — ISBN 0-201-89685-0

Wikimedia Foundation . 2010 .

Смотреть что такое «Оптимизация (программирование)» в других словарях:

оптимизация — Процесс отыскания варианта, соответствующего критерию оптимальности [Терминологический словарь по строительству на 12 языках (ВНИИИС Госстроя СССР)] оптимизация 1. Процесс нахождения экстремума функции, т.е. выбор наилучшего варианта из множества … Справочник технического переводчика

Оптимизация — [optimization] 1. Процесс нахождения экс­тремума функции, т.е. выбор наилучшего варианта из множества возможных, процесс выработки оптимальных решений; 2. Процесс приведения системы в наилучшее (оптимальное) состояние. Иначе говоря, первое… … Экономико-математический словарь

Оптимизация (математика) — У этого термина существуют и другие значения, см. Оптимизация. Оптимизация в математике, информатике и исследовании операций задача нахождения экстремума (минимума или максимума) целевой функции в некоторой области конечномерного векторного … Википедия

Оптимизация (информатика) — Эта статья об оптимизации программ и данных вообще; об оптимизациях, применяемых компиляторами см.: Оптимизация компилятора. У этого термина существуют и другие значения, см. Оптимизация. Оптимизация модификация системы для улучшения её… … Википедия

Программирование в ограничениях — Парадигмы программирования Агентно ориентированная Компонентно ориентированная Конкатенативная Декларативная (контрастирует с Императивной) Ограничениями Функциональная Потоком данных Таблично ориентированная (электронные таблицы) Реактивная … Википедия

ОПТИМИЗАЦИЯ — (от лат. optimus наилучший) в химической технологии. Под О. обычно понимают целе направл. деятельность, заключающуюся в получении наилучших результатов при соответствующих условиях. Постановка задачи О. предполагает наличие ее объекта, набора… … Химическая энциклопедия

Оптимизация — (от лат. optimum наилучшее) процесс нахождения экстремума (глобального максимума или минимума) определённой функции или выбора наилучшего (оптимального) варианта из множества возможных. Наиболее надёжным способом нахождения наилучшего… … Большая советская энциклопедия

Скалярная оптимизация — [sca­lar optimization] совокупность методов решения задач математического программирования, целевая функция которых представляет собой скаляр. Боль­­шинство задач, рассматриваемых в словаре (см. Линейное программирование, Нелинейное… … Экономико-математический словарь

скалярная оптимизация — совокупность методов решения задач математического программирования, целевая функция которых представляет собой скаляр. Большинство задач, рассматриваемых в словаре (см. Линейное программирование, Нелинейное программирование, Дискретное… … Справочник технического переводчика

Поисковая оптимизация — У этого термина существуют и другие значения, см. Оптимизация. Поисковая оптимизация (англ. search engine optimization, SEO) комплекс мер для поднятия позиций сайта в результатах выдачи поисковых систем по определенным запросам… … Википедия

Мастер Йода рекомендует:  Стартовало обучение в Яндекс.Лицее
Добавить комментарий