15 мая 2012

Оптимизация как необходимость

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

Когда надо?

Всегда, если это ничего не стоит. Как правило самое ценное у разработка это время. Так вот. Если ТЫ можешь сделать это быстро и сразу, делай. Когда ты говоришь себе: "Я вернусь к этому позже.", мы знаем что это значит. Как правило, никогда. Да. Да. Я верю что ты исключение, но мы некому не скажем.

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

Когда это уместно?

Как лучше написать:

int size = 64 * 64;

или

int size = 4096;

?

Лучше конечно так:

const int height = 64;
const int width = 64;
int size = height * width;

Но если исходить из вариантов выше, то разницы нет. В итоги вы все равно получите 4096. Хоть сразу напишите это число, хоть сначала 64 * 64. Все одно.

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

Что значит сразу?

При разработке вам придется, нет, ПРИДЕТСЯ чаще запускать отладочную версию программы, а это значит минимум оптимизаций и куча отладочной информации. Она будет работать медленно.

Например вот эту структуру массивов будет легче перебирать в цикле,

struct Foos
{
  int x[1000000000];
  int y[1000000000];
  int z[1000000000];
};

чем

struct Foos
{
  int x;
  int y;
  int z;
};

Foos foos[1000000000];

Знаете почему? Из-за выравнивания. Причем если убрать переменную z все измениться (для 64 битных машин). По крайней мере если не включать оптимизацию. В общем g++ -S -g вам в помощь. Да и с структурой массивов некоторые действия выполнять проще, чем с массивом структур.

Зачем смотреть под капот?

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

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

Вместо ссылок

Для игр которые должны работать на скромных аппаратных возможностях телефонов это необходимость. Да и для игр важно работать быстро всегда.

О простоте мы еще поговорим и к структурам массивов вернемся. Код как красивая девушка, чем больше смотришь, тем больше в ней изъянов, а если нет изъянов то только пока молчит.