Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

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

65K
01 июля 2011 года
FiloXSee
18 / / 01.07.2011
Написал статью по оптимизации кода на С++. Ее можно почитать тут:
http://itw66.ru/blog/c_plus_plus/13.html

А вы какие еще способы оптимизации кода знаете? (я не говорю про оптимизацию алгоритмов. Речь идет про код вообще)
2.1K
01 июля 2011 года
Norgat
452 / / 12.08.2009
 
Код:
x = array[ i++ ]; - более эффективно, чем
x = array[ ++i ];


Это ж две разные операции будет, разве нет?


п.с. имхо, такая экономия на спичках нужна в исключительно редких случаях, ибо, зачастую, узкое место сидит именно в кривом алгоритме.
65K
01 июля 2011 года
FiloXSee
18 / / 01.07.2011
Да, это разные операции. Вот только программист может организовать код так, чтобы использовать любую из них.

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

Допустим идет разработка системы частиц (particle system). Каждая частица будет апдейтиться в каждом кадре. Если частиц 10000 то любая лишняя операция будет сказываться на производительности. А если добавить несколько if то можно вообще ее убить.
245
01 июля 2011 года
~ArchimeD~
1.4K / / 24.07.2006
Не углядел упоминания про ++iter и iter++ (речь об итераторах stl-контейнеров)
65K
01 июля 2011 года
FiloXSee
18 / / 01.07.2011
Цитата: ~ArchimeD~
Не углядел упоминания про ++iter и iter++ (речь об итераторах stl-контейнеров)


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

245
01 июля 2011 года
~ArchimeD~
1.4K / / 24.07.2006
Цитата: FiloXSee
К stl этот пример не относится. Он показывает, что процессор одновременно может делать разные операции, например обращаться к памяти и проводить арифметические операции. Операции ++iter и iter++ это вызовы функций, где может быть написано что угодно. Так что они не имеют отношения к примеру в статье.



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

260
01 июля 2011 года
Ramon
1.1K / / 16.08.2003
Цитата: Norgat
 
Код:
x = array[ i++ ]; - более эффективно, чем
x = array[ ++i ];


Это ж две разные операции будет, разве нет?


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



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

А в общем, это не те "оптимизации", "которые должен знать каждый профессиональный программист".

7
01 июля 2011 года
@pixo $oft
3.4K / / 20.09.2006
Афтару настоятельно рикаминдую подучить рюске езыг
65K
29 декабря 2011 года
FiloXSee
18 / / 01.07.2011
Мной написаны еще несколько статей по написанию эффективного кода. Надеюсь они будут вам полезны:
http://itw66.ru/blog/c_plus_plus/571.html - Эффективный код на С++
http://itw66.ru/blog/c_plus_plus/491.html - Методы оптимизации памяти
277
29 декабря 2011 года
arrjj
1.7K / / 26.01.2011
Цитата:

2. Объявляйте переменные там, где они будут использоваться, давая им наименьшую область видимости. Это способствует выполнению пункта 1.


и как будет быстрее так
int a,b;
for(int x=0;x<100500;x+=1)
{
int tmp;
tmp=a;
a=b;
b=tmp;
}
или так
int a,b,tmp;
for(int x=0;x<100500;x+=1)
{
tmp=a;
a=b;
b=tmp;
}
?

Цитата:

6. Используйте int вместо char, short для локальных переменных и для переменных структур, если нет цели минимизировать потребление памяти. int будет работать быстрее. При использовании переменных char и short, они будут конвертироваться в int во всех арифметических операциях.


Схренали? Так только у мелкософта typedef int BOOL; typedef int LONG; да и то у них typedef char CHAR; typedef short SHORT;.

Цитата:

10. Используйте конструкцию if() вместо if-else везде, где это возможно. Помните, что ветвление — очень дорогая операция (точнее дорогая операция jump, т.к. она ломает конвейер команд процессора). В случае if-else, прыжок происходит в любом случае, а в случае команды if только в одном.


Как то сильно сомнения вызывает...

16K
29 декабря 2011 года
asmforce
186 / / 05.01.2010
Честно говоря, у меня многие приёмы оптимизации автора вызывают сильные сомнения.
Да и вообще, где же пруф? Недостаточно того факта, что теоретически оно должно работать быстрее.

Важно понимать, что эта оптимизация должна быть портабельной. Также стоит заметить, что оптимизирующий компилятор может инвертировать Вашу оптимизацию своей. ;) Таким образом, где-то вы получите прирост в 0.2%, а где-то потеряете 25%. Кому это нужно?

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

Взять хоть Ваш пример п.9 отсюда:
Код:
#include <iostream>
#include <ctime>

int array[10000];

void func1()  {
  for( int i = 0; i < 10000; ++i )
    array++;
}

void func2()  {
  int *p = array;
  for( int i = 0; i < 10000; ++i, ++p )
    ++*p;
}


int main( int argc, char **argv )
{
  clock_t elps1, elps2;
  clock_t stamp = clock();

  for( int i = 0; i < 100000; ++i )
    func1();
  elps1 = clock() - stamp;
  stamp = clock();

  for( int i = 0; i < 100000; ++i )
    func2();
  elps2 = clock() - stamp;
  stamp = clock();

  for( int i = 0; i < 100000; ++i )
    func2();
  elps2 += clock() - stamp;
  stamp = clock();

  for( int i = 0; i < 100000; ++i )
    func1();
  elps1 += clock() - stamp;
  stamp = clock();

  std::cout << elps1 << ":" << elps2 << std::endl;

  return 0;
}


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

В AMD SOG (для amd64) пишут:
Цитата:

C allows the use of either the array operator ([]) or pointers to access the elements of an array.
However, the use of pointers in C makes work difficult for optimizers in C compilers. Without
detailed and aggressive pointer analysis, the compiler has to assume that writes through a pointer can
write to any location in memory, including storage allocated to other variables. (For example, *p and
*q can refer to the same memory location, while x[0] and x[2] cannot.) Using pointers causes
aliasing, where the same block of memory is accessible in more than one way. Using array notation
makes the task of the optimizer easier by reducing possible aliasing.



А выводы делайте сами. Не наступайте на грабли, на которых побывали ступни многих программеров. Делайте свою работу, а оптимизатору не мешайте делать свою.

P.S. Разве что, как хобби.

260
29 декабря 2011 года
Ramon
1.1K / / 16.08.2003
Автора продолжают терзать последствия проблем связанных с его упорным нежеланием читать документацию.
65K
29 декабря 2011 года
FiloXSee
18 / / 01.07.2011
Цитата: arrjj
Схренали? Так только у мелкософта typedef int BOOL; typedef int LONG; да и то у них typedef char CHAR; typedef short SHORT;


Не понял комментария. Я написал, что сложить два числа типа int будет быстрее чем сложить числа типа char, short. Это по тому, что прежде чем складывать числа их придется достать из памяти. Получение char дольше чем int, т.к. придется память выравнивать и отсекать соседние байты, вместо того, чтобы просто получить данные из ячейки по адресу.

65K
29 декабря 2011 года
FiloXSee
18 / / 01.07.2011
Цитата: asmforce
Важно понимать, что эта оптимизация должна быть портабельной. Также стоит заметить, что оптимизирующий компилятор может инвертировать Вашу оптимизацию своей. ;) Таким образом, где-то вы получите прирост в 0.2%, а где-то потеряете 25%. Кому это нужно?



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

Простой пример: есть статья как проводилась оптимизация в игре Uncharted2. Берется цикл, который выполняется за 280ms и реорганизацией кода + побитовыми операциями + разверткой цикла + векторизацией некоторых данных доводится до 34 милисекунд, а после переводится на асемблер и выполняется 7ms. Про асемблер я нечего не говорил, но и без него оптимизация в 8 раз. Понятно, что сразу такое не написать. Это была оптимизация уже конкретного кода под конкретную платформу.

Те приемы которые я описал это информация к сведению. Если вы столкнетесь, с необходимостью оптимизации, то статьи подскажет вам некоторые варианты реорганизации кода, которые могут помочь. Некоторые пункты в статьях подходят как best practice (вроде инициализации переменных класса в списке инициализации, а не в теле конструктора. Но нужно проверять это все индивидуально для платформы, окружения и расположения данных в памяти.

277
29 декабря 2011 года
arrjj
1.7K / / 26.01.2011
Это я к тому что
Цитата:
Используйте int вместо char, short для локальных переменных и для переменных структур.


1) В теории компилятор должен сам использовать регистры соответствующего размера - al ax eax rax.
2) Если программист создает переменную char то врядли собирается в ней хранить число, так что советовать ему хранить любые данные в Int это неправильно.
3) А теперь мини проверка:

Код:
#include <iostream>
#include <ctime>
#include <string.h>

int array[10000];
short array2[10000];
char array3[10000];

void func1()  {
  for( int i = 0; i < 10000; ++i )
    array+=0x1000000;
}

void func2()  {
  for( int i = 0; i < 10000; ++i )
    array2+=0x100;
}

void func3()  {
  for( int i = 0; i < 10000; ++i )
    array3+=0x1;
}


int main( int argc, char **argv )
{
  clock_t elps1, elps2, elps3;
  clock_t stamp = clock();

memset(&array,0,sizeof(int)*10000);
memset(&array2,0,sizeof(short)*10000);
memset(&array3,0,sizeof(char)*10000);

  for( int i = 0; i < 100000; ++i )
    func1();
  elps1 = clock() - stamp;
  stamp = clock();

  for( int i = 0; i < 100000; ++i )
    func2();
  elps2 = clock() - stamp;
  stamp = clock();

  for( int i = 0; i < 100000; ++i )
    func3();
  elps3 = clock() - stamp;
  stamp = clock();

  std::cout <<"Int :"<<elps1 << " Short:" <<elps2<<" Char:"<<elps3<<std::endl;
  return 0;
}

Результат:
 
Код:
Int :6520000 Short:6310000 Char:7070000

Char лишь немного медленнее, а short даже быстрее чем int.
412
29 декабря 2011 года
grgdvo
323 / / 04.07.2007
А вы случайно плагиатом не занимаетесь?
Если Ваши статьи основаны на каких-то других, хорошо бы включать авторство:
1. Например, вот очень похоже на Ваше.
2. Может быть мне одному кажется, что что-то уже было разжевано в советах от Мейерса?!

Дальше не хочу копать, надеюсь на честность ТС.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог