Re: Выносить вычисление длины выше цикла уже не нужно?
От: Tilir Россия http://tilir.livejournal.com
Дата: 04.07.11 03:52
Оценка: 24 (6) +6 -2
Здравствуйте, sanx, Вы писали:

S>Звучит вопрос глупо, но вдруг есть какие-то интересные, но не очевидные для меня нюансы.


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

Берём сферический случай в вакууме.

void test(void)
{
  int i;
  int size = get_size();
  for(i = 0; i < size; ++i) {
    call_smth();
  }
}

void test2(void)
{
  int i;
  for(i = 0; i < get_size(); ++i) {
    call_smth();
  }
}


Компилируем gcc-4.4.3 на уровне O2 до стадии GIMPLE, смотрим дамп

;; Function test (test)

test ()
{
  int size;
  int i;

<bb 2>:
  size = get_size ();
  if (size > 0)
    goto <bb 3>;
  else
    goto <bb 5>;

<bb 3>:
  i = 0;

<bb 4>:
  call_smth ();
  i = i + 1;
  if (size > i)
    goto <bb 4>;
  else
    goto <bb 5>;

<bb 5>:
  return;

}


Обратите внимание -- вычисление происходит один раз.

;; Function test2 (test2)

test2 ()
{
  int i;
  int D.1607;

<bb 2>:
  i = 0;
  goto <bb 4>;

<bb 3>:
  call_smth ();
  i = i + 1;

<bb 4>:
  D.1607 = get_size ();
  if (i < D.1607)
    goto <bb 3>;
  else
    goto <bb 5>;

<bb 5>:
  return;

}


Обратите внимание -- колбасим каждый цикл.

Сейчас я вам коротко объясню почему это так происходит и, я так полагаю, всегда будет время от времени при определённых условиях происходить на любом оптимизирующем компиляторе. В общем случае -- мы не знаем что делает функция get_size. Она где-то в другой единице линковки и мы не представляем что этой единице линковки происходит. Чёрт, она может быть вообще скомпилирована отдельно! Да, компилятор может иногда смухлевать. Есть межпроцедурные оптимизации. Есть инлайнинг. Например в gcc опция combine вообще заставляет трактовать все входные файлы как один. Но в самом общем случае, компилятор *не понимает*, что семантически get_size вычисляет и возращает каждый раз один и тот же размер. Он не может это доказать и поэтому ведёт себя максимально консервативно, а именно -- даже на высоких уровнях оптимизации делает ровно то, что вы ему сказали.

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

---
With best regards, Konstantin
Re[4]: А вот и фиг!
От: Wissenschaftler http://rsdn_user.livejournal.com
Дата: 05.07.11 19:20
Оценка: +1 -2
Здравствуйте, Tilir, Вы писали:

W>>Элементарные вещи типа get_size() в большинстве библиотек инлайнятся. Соответственно, компилятор все раскрутит и вынесет.


T>Не стоит на это уповать. Есть много случаев -- деревья, списки и прочие динамические структуры данных где инлайнить вычисление размера нерационально (см. std::list). Новичку как правило сложно отличить места где магия сработает от мест, где не сработает. Поэтому лучше на неё не надеяться.

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

T>Кстати, написанный с явной переменной для размера код будет проще и отлаживать -- есть на что ставить watchpoint, есть где посмотреть что у нас размер оказывается -1 и всё такое.

Отладчик MSVS кагбэ умеет визуализировать STL-контейнеры, начиная с 2005й студии.
Запретное обсуждение модерирования RSDN:
http://rsdn-user.livejournal.com/652.html
Re: Выносить вычисление длины выше цикла уже не нужно?
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 04.07.11 06:48
Оценка: 13 (2)
Подробно разобрано тут: http://users.livejournal.com/_winnie/20905.html
Ce n'est que pour vous dire ce que je vous dis.
Re: Выносить вычисление длины выше цикла уже не нужно?
От: _nn_ www.nemerleweb.com
Дата: 04.07.11 06:16
Оценка: 1 (1) +1
Здравствуйте, sanx, Вы писали:

S>Правильно ли я понимаю что все современные компиляторы без проблем оптимизируют код типа:


S>for(int i = 0; i < s.size; ++i) {


S>и писать типа


S>int size = s.size();

S>for(int i = 0; i < size; ++i) {

Зачем переменная size за областью for ?
for (size_t i = 0, size = s.size(); i < size; ++i)
  ...


Точно также и в итераторах
for (Container::iterator it = c.begin(), it_end = c.end(); it != it_end; ++it)
  ...


Но тут уже будет проще Boost.Foreach чем это
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Выносить вычисление длины выше цикла уже не нужно?
От: Pavel Dvorkin Россия  
Дата: 04.07.11 06:23
Оценка: 1 (1) +1
Здравствуйте, sanx, Вы писали:

S>Ну и понятное дело, я говорю о ситуации когда длина не меняется в теле for


Это тебе совершенно очевидно, что длина не меняется в теле for. Компилятору это может быть совсем не очевидно, и он только в достаточно простых случаях может определить, что она не меняется.


for(int i = 0; i < s.size; ++i) 
  f(&s);


Поди тут пойми, меняется s.size или нет, особенно если f описана в другом файле или вообще в библиотеке какой-то.
With best regards
Pavel Dvorkin
Re[11]: не выпендривайся и не найдёшь много новых граблей
От: Erop Россия  
Дата: 05.07.11 12:41
Оценка: 1 (1) -1
Здравствуйте, IROV.., Вы писали:

IRO>>>Кстати, еще — сайз в нутри и снаружи это разная семантика.

E>>Мы вроде как о случаях, когда одинаковая? То есть, когда выносить .end ТАКИ МОЖНО...
IRO>Вроде? я вот уточнил, а ты?

Я не очень понимаю предмет обсуждения.
Если семантика разная, то только одни из двух вариантов верный. То есть речь идёт не об оптимизации, а о РАЗНЫХ алгоритмах. При чём тут вообще этот топик?

IRO>правильно, в этом коде это запись в память.

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


IRO>std::vector

Это хорошо бы показать явно. Если цель в читабельном примере, конечно.

E>>2) Если это таки std::vector<интегральный тип>, то принятым способом итерации будет таки или через итератор или через стандартный алгоритм какой...

IRO>Кем принятый? Ты понимаешь что это имеет разную смысловую нагрузку?
Принятый при разработке на С++. Авторы STL и компилятора рассчитывают на такой сценарий и оптимизируют именно его.
IRO>Вдруг мне нужен индекс.
Я не понял. Мы обсуждаем конкретно этот пример или что-то, что тебе может понадобиться вдруг.


E>>3) На каком компиляторе/опциях оптимизации достигается заявленный разрвы в 2-3 раза?

IRO>http://virtul.livejournal.com/8714.html
Э-э-э? Где?
Там, собственно получили, в конце концов, что если в цикле практически ничего, кроме итерации не делать, то вариант
for(iterator it = v.begin(), it_end = v.end(); it != it_end; ++it) {
    *it = ...
}
является практически лучшим. Вторым по лучшести, уступая всего лишь ПРОЦЕНТЫ является классический для STL way
for( iterator i = v.begin(); i != v.end(); ++i ) {
    *i = ...;
}


Что и требовалось доказать. Общий принцип "не выпендривайся и не найдёшь много новых граблей" работает и тут.

IRO>http://virtul.livejournal.com/8714.html

Это ни разу не пример РЕАЛЬНОГО кода.
И, тем не менее, даже если рассмотреть вариант, что нам надо вот так заполнить вектор зачем-то, то единственным существенным ускорением этого кода было переписывание функции rand...
Всё остальное -- проценты от производительности.

IRO>Они использовали ID -> std::string

Ну это ОЧЕНЬ зависит от того, что программа делает.
Если она работает со строками, то вообще std::string лучше не использовать, если речь идёт о выжимании перфоманса. Это довольно тормозной шаблон, вообще-то. Его достоинства -- якобы удобство и якобы надёжность, но не скорость...
В частности, если у них строки между нитями не передаются, то можно было завести любую COW-строку, а ещё лучше не любую, а с пулом буферов, устойчивым к фрагментации и lock-free. Но это если это реально основная функциональность и основные тормоза там живут.
А если это просто в лог/отчёт чего-то пишут, то просто пофиг как оно там передаётся.
Ergo: обычно std::string передавать по значению можно. Так как, если надо быстро, то нельзя сам std::string...

IRO>У меня был свой код.

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

IRO>Трололо +1

IRO>Трололо +2
О! У тебя проснудась самокритика.
Так что там с примером РЕАЛЬНОГО цикла, который делает что-то нужное, и который ускоряется в 2-3 раза при переносе .end?
Про ускорение ВСЕГО ЗАПРОСА я даже и не говорю. ХОтя бы ускорение цикла в разы посмотреть бы...

Моё утверждение состоит в том, что такой пример привести не удастся. Вернее удастся, но это будет какой-то редкий, эксклюзивный цикл, нужный в каких-то зитрых условиях и без того вылизываемый до крайности.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: А вот и фиг!
От: IROV..  
Дата: 06.07.11 10:29
Оценка: -1 :)
Здравствуйте, MasterZiv, Вы писали:

MZ>On 05.07.2011 20:18, Tilir wrote:


>> Не стоит на это уповать. Есть много случаев -- деревья, списки и прочие

>> динамические структуры данных где инлайнить вычисление размера нерационально
>> (см. std::list).

MZ>size_type size() const

MZ>{
MZ> return (_Size);
MZ>}

MZ>Объясни, что тут нерационально инлайнить.

Есть листы в которых O(N) не size() а splice()
я не волшебник, я только учусь!
Re[18]: Перешёл на личности -- значит слил.
От: IROV..  
Дата: 06.07.11 11:24
Оценка: -2
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, IROV.., Вы писали:


IRO>>

IRO>>В любом случае, обычно компилятор формальные проверки делает лучше, чем человек. Так что писать for( int i = 0; i < c.size(); i++) { body(); } НАДЁЖНЕЕ!


E>С чего ты взял, что c -- это std::vector, и вообще, что он из stl?

С того что в моем случае, это не зависит от твоего "сьезда".

IRO>>18900.4 — i < v.size();

IRO>>8985.34 — i < i_end;

IRO>>~2 раза

E>Так я за то самое и ратую, что надо с stl-контейнерами работать через итераторы, а не через индексы...

В любом случае, обычно компилятор формальные проверки делает лучше, чем человек. Так что писать for( int i = 0; i < c.size(); i++) { body(); } НАДЁЖНЕЕ!

Даже если у тебя size(){ return this->m_size;} то этот сайз будет всегда читаться из памяти, со всеми вытикающими бедами.

IRO>>Ты стесняешься своей личности? facepalm

E>1) Слово "тограш" эмоционально окрашено, и вообще тут не уместно.
Ты уже посмотрел ролик про соузпарк и Тома Круза, который я тебе сбросил?

E>2) Моя личность -- офтопик в форуме по С++

Мой моск это не понял.

IRO>>Есть индустрия — купи-продай, а есть производство, вот ты самый низкий пласт — торгаш.

E>Ну тебе уже пора извиниться.
Ты уже пожаловался модераторам? а то пацан сказал пацан не сделал, как то не помужски

З.Ы. и вообще я завязываю, моей целью не стоит напостить по 40 сообщений в день как у тебя

42667 / (06.07.11 — 31.03.05) ~ 40

я не волшебник, я только учусь!
Re[2]: Выносить вычисление длины выше цикла уже не нужно?
От: Erop Россия  
Дата: 04.07.11 18:10
Оценка: 8 (1)
Здравствуйте, Tilir, Вы писали:

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


Согласен, с небольшой оговоркой. Если тебе таки надо проитерировать контейнер, то делай это прямо, так, как это принято делать с такими контейнерами.
Тогда есть большие шансы на то, что авторы библиотеки и компилятора предпримут какие-то усилия и всё таки получится. В отличии от ситуации, когда ты делаешь что-то необычное. Но, пир этом всё равно не стоит надеяться на то, что в компиляторе есть блок телепатии
Ну и не надо надеяться на то, что у того, кто будет этот код поддерживать, тоже есть развитые телепатические способности. А то ведь оптимизация может отвалиться не сразу, а попозже...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Выносить вычисление длины выше цикла уже не нужно?
От: IROV..  
Дата: 05.07.11 16:51
Оценка: 8 (1)
Здравствуйте, Tilir, Вы писали:

T>Да, кстати, верное замечание. Контейнер всегда лучше пробегать его стандартными средствами, чем голым циклом поверх. STL например, в большинстве реализаций, просто хранит специальную затычку на месте end(), которая будет проинлайнена и там будет всё хорошо если написать от begin() до end().

Тут нужно еще одну вещь понимать,
for( TVector::iterator it = v.begin(); it != v.end(); ++it);


Хоть v.end() будет заинлайнена, но само значение он будет постояно брать из &v.

Что бы это избежать нужно кешировать.
for( TVector::iterator it = v.begin(), it_end = v.end(); it != it_end; ++it);


я не волшебник, я только учусь!
Re[2]: Выносить вычисление длины выше цикла уже не нужно?
От: minorlogic Украина  
Дата: 04.07.11 06:48
Оценка: +1
Возможно автор подразумевал шаблонную функцию, доступ к реализации которой у компилятора есть.
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[2]: А вот и фиг!
От: Wissenschaftler http://rsdn_user.livejournal.com
Дата: 04.07.11 18:35
Оценка: +1
Здравствуйте, Tilir, Вы писали:

T>Здравствуйте, sanx, Вы писали:


S>>Звучит вопрос глупо, но вдруг есть какие-то интересные, но не очевидные для меня нюансы.


T>Нет, вы неправильно думаете. Это общее заблуждение относительно того что по умолчанию могут, а чего нет современные компиляторы.

Элементарные вещи типа get_size() в большинстве библиотек инлайнятся. Соответственно, компилятор все раскрутит и вынесет.
Запретное обсуждение модерирования RSDN:
http://rsdn-user.livejournal.com/652.html
Re[3]: Выносить вычисление длины выше цикла уже не нужно?
От: jazzer Россия Skype: enerjazzer
Дата: 05.07.11 05:14
Оценка: -1
Здравствуйте, minorlogic, Вы писали:

M>Возможно автор подразумевал шаблонную функцию, доступ к реализации которой у компилятора есть.


Не поможет.
доступ должен быть ко всему — и к size, и к телу цикла целиком (со всеми вложенными вызовами), иначе кешировать нельзя.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: Выносить вычисление длины выше цикла уже не нужно?
От: Erop Россия  
Дата: 05.07.11 10:11
Оценка: :)
Здравствуйте, IROV.., Вы писали:

J>>>Если не волнует скорость — конечно. Пусть всё по 100500 раз надежно позовет.

E>>Всё-таки это надо какой-то мегабыстрый цикл написать, чтобы от того, вынесут .end из цикла или нет что-то зависело
IRO>Очень легко, можно получить ускорение в 2-3 раза, но ты этого никогда не найдешь в профайлере, потомучто у тебя везде будет одинаково-тормозить.
Не затруднит привести какой-нибудь реальный пример такого цикла?
На всяк. случай напомню, что там не должно подставляться тело, чтобы оптимизатор не мог оптимизить...

IRO>Не все на столько грамотные программисты что бы понимать — будет ли оптимизация тут или нет.

IMHO, в большинстве НОРМАЛЬНЫХ циклов это вообще и не надо понимать.
Впрочем жду от тебя контрпримеров.

IRO>Я видел много проектов, где клали на — передачу по ссылке, цыклы с енд, кеширование обращения к синглетонам и тд.

IRO>и после моей оптимизации пиковых "багов", осталась толстая прослойка "равномерных" багов, и все сказали следущие — "профайлер не врет!"
Ну, так и не врёт же. Или ты смог сделать какой-то ЗАМЕР, который бы подтверждал твою правоту? Ну, например, переписал кусок программы в "оптимольном стиле" и кусок стал в 3 раза быстрее?

IRO>Я пожелал удачи

Надеюсь, что ты сделал это доброжелательно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Выносить вычисление длины выше цикла уже не нужно?
От: Tilir Россия http://tilir.livejournal.com
Дата: 05.07.11 16:12
Оценка: +1
Здравствуйте, Erop, Вы писали:

E>Согласен, с небольшой оговоркой. Если тебе таки надо проитерировать контейнер, то делай это прямо, так, как это принято делать с такими контейнерами.


Да, кстати, верное замечание. Контейнер всегда лучше пробегать его стандартными средствами, чем голым циклом поверх. STL например, в большинстве реализаций, просто хранит специальную затычку на месте end(), которая будет проинлайнена и там будет всё хорошо если написать от begin() до end(). В случае же size() могут быть нюансы. Например в std::list при реализации предпочли splice за O(1), за что у них size вычисляется за O(N). Что при длинных списках и проверке в теле цикла может сказываться убийственно.
Re[14]: не выпендривайся и не найдёшь много новых граблей
От: IROV..  
Дата: 05.07.11 20:37
Оценка: -1
Здравствуйте, Erop, Вы писали:

IRO>>Сможешь проанализировать сам? и выдать сколько же это ПРОЦЕНТИКОВ тут.

E>Э-э-э, тут маловато статистики -- большой шум. Но даже тут < v.end() проигрывает < i_end как 11 против 9. И это на совсем уже пустом цикле, замечу я в скобках...
E>При этом, опять же, тут видно, что замороки с size однозначно хуже.
E>Но это просто ПУСТОЙ цикл. Если цикл делает ЧТО-ТО ЕЩЁ, кроме как организации своих итераций, то разница совсем мизерная будет.
E>Кстати, в опыте, где нивелировали вклад кэша и шум, результаты отличались совсем немного. Но даже и тут никаких "двух-трёх раз" я пока не наблюдаю.
E>Два-три раза было бы, если бы против 9000 было 22000, например...
Я не понимаю, ты сам придумал 2-3 раза, если тебе это не надо, не делай, это твои личные проблемы.

IRO>>Меня устраивают бесплатные проценты от производительности, а тебя?

E>А меня устраивает комплексный подход.
E>Есть таки затраты на поддержку, на разработку, на перенос.
E>Так что проценты ни разу не бесплатные...
На какую такую поддержку разработку, и перенос, примеры — или голословность.

IRO>>Но когда использовался ID как std::string можно было бы обойтись и копированием только в другие холдеры, вместо того что бы на каждую проверку гонять его туда сюда.

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

E>И я смотрю, как бы подешевле разогнать.

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

IRO>>Запроса?

E>Ну какой-то осмысленной операции, которую делает твоя программа.
И что? A+B > B, тебе это стоит доказывать?

IRO>>А так это просто срать в свой код.

E>Да нет, это просто делать как все. Суть тут в том, что если что-то делать необычно, то имеешь шанс найти необычные грабли. А это лишнее, особенно, если за это ты никакого СУЩЕСТВЕННОГО выигрыша не получаешь...
Это обычный коментарий нуба, который не знает как делать, и боиться это использовать.
Просто есть хорошее выступление одного человека, Андрея Плахова, Дзен помоему называеться.
Так там были хорошие слова — Если тебе чтото мешает, сделай так что бы не мешало.
Переведу для тебя, выучи — и ты не найдешь грабли.
я не волшебник, я только учусь!
Выносить вычисление длины выше цикла уже не нужно?
От: sanx  
Дата: 04.07.11 00:58
Оценка:
Правильно ли я понимаю что все современные компиляторы без проблем оптимизируют код типа:

for(int i = 0; i < s.size; ++i) {

и писать типа

int size = s.size();
for(int i = 0; i < size; ++i) {

уже не нужно? или в зависимости от того чем является s (переменная в примерах выше) — могут быть какие-то проблемы?
Ну и понятное дело, я говорю о ситуации когда длина не меняется в теле for
А есть ли отличия для while?

Звучит вопрос глупо, но вдруг есть какие-то интересные, но не очевидные для меня нюансы.
Re: Выносить вычисление длины выше цикла уже не нужно?
От: Centaur Россия  
Дата: 04.07.11 06:33
Оценка:
Здравствуйте, sanx, Вы писали:

S>Правильно ли я понимаю что все современные компиляторы без проблем оптимизируют код типа:


S>for(int i = 0; i < s.size(); ++i) {


S>и писать типа


S>int size = s.size();

S>for(int i = 0; i < size; ++i) {

S>уже не нужно? или в зависимости от того чем является s (переменная в примерах выше) — могут быть какие-то проблемы?


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

Во-вторых, отсутствие выигрыша достигается не тем, что компилятор автоматически выдёргивает вызов size() из цикла, а тем, что функция size(), как правило, инлайновая и очень простая (доступ к полю объекта, или доступ к двум полям и вычитание указателей).
Re[3]: Выносить вычисление длины выше цикла уже не нужно?
От: IROV..  
Дата: 04.07.11 16:00
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Возможно автор подразумевал шаблонную функцию, доступ к реализации которой у компилятора есть.

Обязан ли компилятор пересчитывать _End — _Begin?
Допустим может, что произойдет если я из другого потока буду менять этот _End и _Begin?

я не волшебник, я только учусь!
Re[4]: Выносить вычисление длины выше цикла уже не нужно?
От: Centaur Россия  
Дата: 05.07.11 04:00
Оценка:
Здравствуйте, IROV.., Вы писали:

M>>Возможно автор подразумевал шаблонную функцию, доступ к реализации которой у компилятора есть.

IRO>Обязан ли компилятор пересчитывать _End — _Begin?

Если _End или _Begin отмечены как volatile — обязан прочитать новые значения при очередном вызове size() и, соответственно, вернуть актуальный размер. Иначе — имеет право не пересчитывать, по крайней мере до С++11.
Re: Выносить вычисление длины выше цикла уже не нужно?
От: igna Россия  
Дата: 05.07.11 04:18
Оценка:
Здравствуйте, sanx, Вы писали:

S>for(int i = 0; i < s.size; ++i) {


S>int size = s.size();

S>for(int i = 0; i < size; ++i) {

В первом случае у тебя s.size, во втором — s.size().
Re[2]: Выносить вычисление длины выше цикла уже не нужно?
От: jazzer Россия Skype: enerjazzer
Дата: 05.07.11 05:13
Оценка:
Здравствуйте, Tilir, Вы писали:

T>Сейчас я вам коротко объясню почему это так происходит и, я так полагаю, всегда будет время от времени при определённых условиях происходить на любом оптимизирующем компиляторе. В общем случае -- мы не знаем что делает функция get_size. Она где-то в другой единице линковки и мы не представляем что этой единице линковки происходит. Чёрт, она может быть вообще скомпилирована отдельно! Да, компилятор может иногда смухлевать. Есть межпроцедурные оптимизации. Есть инлайнинг. Например в gcc опция combine вообще заставляет трактовать все входные файлы как один. Но в самом общем случае, компилятор *не понимает*, что семантически get_size вычисляет и возращает каждый раз один и тот же размер. Он не может это доказать и поэтому ведёт себя максимально консервативно, а именно -- даже на высоких уровнях оптимизации делает ровно то, что вы ему сказали.


+1.

Более того, даже если у компилятора есть доступ к реализации get_size() и он может ее заинлайнить, у него может не быть доступа к реализации call_smth(), а даже если он есть, то может не быть доступа к реализации любой из маленьких функций, которые из call_smth() зовутся.
А это значит, что размер контейнера внутри этой неизвестной маленькой функции может измениться и кешировать его нельзя.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Выносить вычисление длины выше цикла уже не нужно?
От: minorlogic Украина  
Дата: 05.07.11 06:52
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Не поможет.

J>доступ должен быть ко всему — и к size, и к телу цикла целиком (со всеми вложенными вызовами), иначе кешировать нельзя.

Да , я про такую ситуацию.
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[3]: Выносить вычисление длины выше цикла уже не нужно?
От: Erop Россия  
Дата: 05.07.11 06:53
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Более того, даже если у компилятора есть доступ к реализации get_size() и он может ее заинлайнить, у него может не быть доступа к реализации call_smth(), а даже если он есть, то может не быть доступа к реализации любой из маленьких функций, которые из call_smth() зовутся.

J>А это значит, что размер контейнера внутри этой неизвестной маленькой функции может измениться и кешировать его нельзя.

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

В любом случае, обычно компилятор формальные проверки делает лучше, чем человек. Так что писать for( int i = 0; i < c.size(); i++) { body(); } НАДЁЖНЕЕ!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Выносить вычисление длины выше цикла уже не нужно?
От: Erop Россия  
Дата: 05.07.11 06:54
Оценка:
Здравствуйте, Centaur, Вы писали:


C>Если _End или _Begin отмечены как volatile — обязан прочитать новые значения при очередном вызове size()


Если они так помечены не без оснований, то лучше и не мешать компилятору пересчитывать size() на каждой итерации
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Выносить вычисление длины выше цикла уже не нужно?
От: jazzer Россия Skype: enerjazzer
Дата: 05.07.11 08:38
Оценка:
Здравствуйте, Erop, Вы писали:

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


Если ты о strict aliasing, то это немного не о том. Там опция компиляции говорит только, что на одну и ту же память нет ссылок _разных_ типов. А у тебя замечательно может быть один и тот же тип и все обломится (в сымсле, ничего оптимизироваться не будет).

E>В любом случае, обычно компилятор формальные проверки делает лучше, чем человек. Так что писать for( int i = 0; i < c.size(); i++) { body(); } НАДЁЖНЕЕ!

Если не волнует скорость — конечно. Пусть всё по 100500 раз надежно позовет.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: Выносить вычисление длины выше цикла уже не нужно?
От: jazzer Россия Skype: enerjazzer
Дата: 05.07.11 08:39
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Здравствуйте, jazzer, Вы писали:


J>>Не поможет.

J>>доступ должен быть ко всему — и к size, и к телу цикла целиком (со всеми вложенными вызовами), иначе кешировать нельзя.

M>Да , я про такую ситуацию.


Ок. Ну и поскольку гарантировать доступность всего дерева крайне трудно, проще и надежнее закешировать самостоятельно.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: Выносить вычисление длины выше цикла уже не нужно?
От: Erop Россия  
Дата: 05.07.11 09:34
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Если ты о strict aliasing, то это немного не о том. Там опция компиляции говорит только, что на одну и ту же память нет ссылок _разных_ типов. А у тебя замечательно может быть один и тот же тип и все обломится (в сымсле, ничего оптимизироваться не будет).


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

J>Если не волнует скорость — конечно. Пусть всё по 100500 раз надежно позовет.


Всё-таки это надо какой-то мегабыстрый цикл написать, чтобы от того, вынесут .end из цикла или нет что-то зависело
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Выносить вычисление длины выше цикла уже не нужно?
От: IROV..  
Дата: 05.07.11 09:44
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Если _End или _Begin отмечены как volatile — обязан прочитать новые значения при очередном вызове size() и, соответственно, вернуть актуальный размер. Иначе — имеет право не пересчитывать, по крайней мере до С++11.

volatile тут может помочь с решением многопоточности.
И даже если мы обьявим без нее, он все равно будет "вызывать" size — делать отнимание двух поинторов, и производить деление.
Тоесть вычислять актуальный размер, ведь мы можешь изменить его внутри цыкла
я не волшебник, я только учусь!
Re[6]: Выносить вычисление длины выше цикла уже не нужно?
От: IROV..  
Дата: 05.07.11 09:56
Оценка:
Здравствуйте, Erop, Вы писали:

J>>Если не волнует скорость — конечно. Пусть всё по 100500 раз надежно позовет.

E>Всё-таки это надо какой-то мегабыстрый цикл написать, чтобы от того, вынесут .end из цикла или нет что-то зависело
Очень легко, можно получить ускорение в 2-3 раза, но ты этого никогда не найдешь в профайлере, потомучто у тебя везде будет одинаково-тормозить.
Не все на столько грамотные программисты что бы понимать — будет ли оптимизация тут или нет.
Я видел много проектов, где клали на — передачу по ссылке, цыклы с енд, кеширование обращения к синглетонам и тд.
и после моей оптимизации пиковых "багов", осталась толстая прослойка "равномерных" багов, и все сказали следущие — "профайлер не врет!"
Я пожелал удачи )
я не волшебник, я только учусь!
Re[8]: Выносить вычисление длины выше цикла уже не нужно?
От: IROV..  
Дата: 05.07.11 10:42
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, IROV.., Вы писали:


E>Не затруднит привести какой-нибудь реальный пример такого цикла?

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

пример, а почему зразу подставляться тело?
тоесть если подставляеться то надо выносить, а если нет то не надо?


{
  for (int i = 0; i  !=  this->v.size(); ++i)
  {    
    this->v[i] %= 10;
  }
}



чем плох пример?


IRO>>Не все на столько грамотные программисты что бы понимать — будет ли оптимизация тут или нет.

E>IMHO, в большинстве НОРМАЛЬНЫХ циклов это вообще и не надо понимать.
E>Впрочем жду от тебя контрпримеров.
Я с тобой соглашусь, вообще можно много чего не понимать
так делают многие, ты не одинок

IRO>>Я видел много проектов, где клали на — передачу по ссылке, цыклы с енд, кеширование обращения к синглетонам и тд.

IRO>>и после моей оптимизации пиковых "багов", осталась толстая прослойка "равномерных" багов, и все сказали следущие — "профайлер не врет!"
E>Ну, так и не врёт же. Или ты смог сделать какой-то ЗАМЕР, который бы подтверждал твою правоту? Ну, например, переписал кусок программы в "оптимольном стиле" и кусок стал в 3 раза быстрее?
Тебе нужно делать замер что бы понять что передавать стринг по значению это зло?
Если учесть что у них было 100 потоков, и большинство из них более мение активные, и везде юзалось new, меня всегда мучал вопрос сколько времени сьедаеться в синхронизации обращение к этому new

IRO>>Я пожелал удачи

E>Надеюсь, что ты сделал это доброжелательно...
Я когда то был доброжелателен? или это был сарказм )))
я не волшебник, я только учусь!
Re[9]: Выносить вычисление длины выше цикла уже не нужно?
От: Erop Россия  
Дата: 05.07.11 10:56
Оценка:
Здравствуйте, IROV.., Вы писали:

IRO>Кстати, еще — сайз в нутри и снаружи это разная семантика.

Мы вроде как о случаях, когда одинаковая? То есть, когда выносить .end ТАКИ МОЖНО...

IRO>пример, а почему зразу подставляться тело?

IRO>тоесть если подставляеться то надо выносить, а если нет то не надо?

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


IRO>
IRO>{
IRO>  for (int i = 0; i  !=  this->v.size(); ++i)
IRO>  {    
    this->>v[i] %= 10;
IRO>  }
IRO>}
IRO>



IRO>чем плох пример?

1) Не понятно, что есть this->v
2) Если это таки std::vector<интегральный тип>, то принятым способом итерации будет таки или через итератор или через стандартный алгоритм какой...
3) На каком компиляторе/опциях оптимизации достигается заявленный разрвы в 2-3 раза?


E>>Впрочем жду от тебя контрпримеров.

IRO>Я с тобой соглашусь, вообще можно много чего не понимать
IRO>так делают многие, ты не одинок
Это всё флуд. Примеры кода будут?

E>>Ну, так и не врёт же. Или ты смог сделать какой-то ЗАМЕР, который бы подтверждал твою правоту? Ну, например, переписал кусок программы в "оптимольном стиле" и кусок стал в 3 раза быстрее?

IRO>Тебе нужно делать замер что бы понять что передавать стринг по значению это зло?
Зависит от значения слова "зло", если под злом понимается, "потеря производительности системы более, чем на 1%", то во многих случаях нужен замер.
Скажем, если программа открывает один файл, считывает из него бинарно три гектара чисел, как-то их слкдывает/вычитает и потом сливает это всё в другой файл, тоже бинарно, то передача там по значению строки с именами этих файлов, скорее всего некритична.

В общем, я хорошо понимаю такой вот аргумент: "Эти мероприятия похволили поднять производительность системы на 25%", а "я вам зуб даю, что там всё медленно" я не понимаю совсем.

IRO>Если учесть что у них было 100 потоков, и большинство из них более мение активные, и везде юзалось new, меня всегда мучал вопрос сколько времени сьедаеться в синхронизации обращение к этому new

1) Это можно легко довольно измерить, вообще-то... Например, какой процент времени работы программы занимало new в целом?
2) Если у людей в программе всё время уходит на синхронизацию new, то вынос/не вынос .end() в/из цикла не должно было ни на что влиять...
3) Если ты правда думаешь, что описанные тобой проблемы являются реальными, перепиши тот продукт на C# и порви тех ребят по производительности


IRO>Я когда-то был доброжелателен? или это был сарказм )))

Это была надежда...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Выносить вычисление длины выше цикла уже не нужно?
От: IROV..  
Дата: 05.07.11 11:36
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, IROV.., Вы писали:


IRO>>Кстати, еще — сайз в нутри и снаружи это разная семантика.

E>Мы вроде как о случаях, когда одинаковая? То есть, когда выносить .end ТАКИ МОЖНО...
Вроде? я вот уточнил, а ты?


E>Если тело полностью подставилось, то у оптимизатора есть все силы и средства для анализа зависимостей. Так что лажать он имеет право только если что-то в теле подставить не удалось...

правильно, в этом коде это запись в память.


IRO>>
IRO>>{
IRO>>  for (int i = 0; i  !=  this->v.size(); ++i)
IRO>>  {    
    this->>>v[i] %= 10;
IRO>>  }
IRO>>}
IRO>>



IRO>>чем плох пример?

E>1) Не понятно, что есть this->v
std::vector

E>2) Если это таки std::vector<интегральный тип>, то принятым способом итерации будет таки или через итератор или через стандартный алгоритм какой...

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

E>3) На каком компиляторе/опциях оптимизации достигается заявленный разрвы в 2-3 раза?

http://virtul.livejournal.com/8714.html

E>>>Впрочем жду от тебя контрпримеров.

IRO>>Я с тобой соглашусь, вообще можно много чего не понимать
IRO>>так делают многие, ты не одинок
E>Это всё флуд. Примеры кода будут?
http://virtul.livejournal.com/8714.html

E>>>Ну, так и не врёт же. Или ты смог сделать какой-то ЗАМЕР, который бы подтверждал твою правоту? Ну, например, переписал кусок программы в "оптимольном стиле" и кусок стал в 3 раза быстрее?

IRO>>Тебе нужно делать замер что бы понять что передавать стринг по значению это зло?
E>Зависит от значения слова "зло", если под злом понимается, "потеря производительности системы более, чем на 1%", то во многих случаях нужен замер.
E>Скажем, если программа открывает один файл, считывает из него бинарно три гектара чисел, как-то их слкдывает/вычитает и потом сливает это всё в другой файл, тоже бинарно, то передача там по значению строки с именами этих файлов, скорее всего некритична.
Ищем крайности?
Они использовали ID -> std::string

E>В общем, я хорошо понимаю такой вот аргумент: "Эти мероприятия похволили поднять производительность системы на 25%", а "я вам зуб даю, что там всё медленно" я не понимаю совсем.

Не понимай.

IRO>>Если учесть что у них было 100 потоков, и большинство из них более мение активные, и везде юзалось new, меня всегда мучал вопрос сколько времени сьедаеться в синхронизации обращение к этому new

E>1) Это можно легко довольно измерить, вообще-то... Например, какой процент времени работы программы занимало new в целом?
Можно, они бы могли это проверить но они же такие как ты... "я вам зуб даю, что там всё медленно", а я не их мама, и за их кодом особо как по злорадствовать не лез.
У меня был свой код.

E>2) Если у людей в программе всё время уходит на синхронизацию new, то вынос/не вынос .end() в/из цикла не должно было ни на что влиять...

Трололо +1

E>3) Если ты правда думаешь, что описанные тобой проблемы являются реальными, перепиши тот продукт на C# и порви тех ребят по производительности

Трололо +2

IRO>>Я когда-то был доброжелателен? или это был сарказм )))

E>Это была надежда...
я не волшебник, я только учусь!
Re[12]: не выпендривайся и не найдёшь много новых граблей
От: IROV..  
Дата: 05.07.11 13:14
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, IROV.., Вы писали:


IRO>>>>Кстати, еще — сайз в нутри и снаружи это разная семантика.

E>>>Мы вроде как о случаях, когда одинаковая? То есть, когда выносить .end ТАКИ МОЖНО...
IRO>>Вроде? я вот уточнил, а ты?

E>Я не очень понимаю предмет обсуждения.

E>Если семантика разная, то только одни из двух вариантов верный. То есть речь идёт не об оптимизации, а о РАЗНЫХ алгоритмах. При чём тут вообще этот топик?

IRO>>правильно, в этом коде это запись в память.

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


IRO>>std::vector

E>Это хорошо бы показать явно. Если цель в читабельном примере, конечно.
Это имеет большое значение?

E>>>3) На каком компиляторе/опциях оптимизации достигается заявленный разрвы в 2-3 раза?

IRO>>http://virtul.livejournal.com/8714.html
E>Э-э-э? Где?
E>Там, собственно получили, в конце концов, что если в цикле практически ничего, кроме итерации не делать, то вариант
for(iterator it = v.begin(), it_end = v.end(); it != it_end; ++it) {
E>    *it = ...
E>}
является практически лучшим. Вторым по лучшести, уступая всего лишь ПРОЦЕНТЫ является классический для STL way
for( iterator i = v.begin(); i != v.end(); ++i ) {
E>    *i = ...;
E>}

18900.4 — i < v.size();
16353.5 — j < theSize;
11133.4 — i < v.end();
8985.34 — i < i_end;
8772.73 — i < i_end; плюс вынесли запись по глобальном адресном пространстве.

Сможешь проанализировать сам? и выдать сколько же это ПРОЦЕНТИКОВ тут.
Дабы не вводить в заблуждение людей.

IRO>>http://virtul.livejournal.com/8714.html

E>Это ни разу не пример РЕАЛЬНОГО кода.
E>И, тем не менее, даже если рассмотреть вариант, что нам надо вот так заполнить вектор зачем-то, то единственным существенным ускорением этого кода было переписывание функции rand...
E>Всё остальное -- проценты от производительности.
Меня устраивают бесплатные проценты от производительности, а тебя?

IRO>>Они использовали ID -> std::string

E>Ну это ОЧЕНЬ зависит от того, что программа делает.
E>Если она работает со строками, то вообще std::string лучше не использовать, если речь идёт о выжимании перфоманса. Это довольно тормозной шаблон, вообще-то. Его достоинства -- якобы удобство и якобы надёжность, но не скорость...
Поэтому я в свое время сделал свою реализацию ConstString
http://rsdn.ru/forum/cpp/3853558.1.aspx
Автор: IROV..
Дата: 23.06.10

вот код. https://menge-engine.svn.sourceforge.net/svnroot/menge-engine/branches/ConstString3/src/Utils/Core/ConstString.h

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

E>А если это просто в лог/отчёт чего-то пишут, то просто пофиг как оно там передаётся.
E>Ergo: обычно std::string передавать по значению можно. Так как, если надо быстро, то нельзя сам std::string...
Но когда использовался ID как std::string можно было бы обойтись и копированием только в другие холдеры, вместо того что бы на каждую проверку гонять его туда сюда.

IRO>>У меня был свой код.

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

IRO>>Трололо +1

IRO>>Трололо +2
E>О! У тебя проснудась самокритика.
Нет Трололо детектед проснулся.

E>Так что там с примером РЕАЛЬНОГО цикла, который делает что-то нужное, и который ускоряется в 2-3 раза при переносе .end?

Мне и 10-15% хватит с головой.

E>Про ускорение ВСЕГО ЗАПРОСА я даже и не говорю. ХОтя бы ускорение цикла в разы посмотреть бы...

Запроса?

E>Моё утверждение состоит в том, что такой пример привести не удастся. Вернее удастся, но это будет какой-то редкий, эксклюзивный цикл, нужный в каких-то зитрых условиях и без того вылизываемый до крайности.

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

я не волшебник, я только учусь!
Re[3]: А вот и фиг!
От: Tilir Россия http://tilir.livejournal.com
Дата: 05.07.11 16:18
Оценка:
Здравствуйте, Wissenschaftler, Вы писали:

W>Элементарные вещи типа get_size() в большинстве библиотек инлайнятся. Соответственно, компилятор все раскрутит и вынесет.


Не стоит на это уповать. Есть много случаев -- деревья, списки и прочие динамические структуры данных где инлайнить вычисление размера нерационально (см. std::list). Новичку как правило сложно отличить места где магия сработает от мест, где не сработает. Поэтому лучше на неё не надеяться.

Кстати, написанный с явной переменной для размера код будет проще и отлаживать -- есть на что ставить watchpoint, есть где посмотреть что у нас размер оказывается -1 и всё такое.
Re[4]: А вот и фиг!
От: IROV..  
Дата: 05.07.11 17:46
Оценка:
Здравствуйте, Tilir, Вы писали:

T>Не стоит на это уповать. Есть много случаев -- деревья, списки и прочие динамические структуры данных где инлайнить вычисление размера нерационально (см. std::list). Новичку как правило сложно отличить места где магия сработает от мест, где не сработает. Поэтому лучше на неё не надеяться.

В std::vector::size() (MSVC) тоже вычесляеться нерационально, вычитание + деление
я не волшебник, я только учусь!
Re[13]: не выпендривайся и не найдёшь много новых граблей
От: Erop Россия  
Дата: 05.07.11 19:59
Оценка:
Здравствуйте, IROV.., Вы писали:

IRO>После 2005 студии, по моему такую оптимизацию отключили, из за проблем.

IRO>Попробую щас поискать где про это писалось, короче это игра с огоньком. Вот тут то и не стоит оптимизировать ради стабильности алгоритма.

Она по умолчанию выключена.
Это очень зависит от стиля кодирования. Конкретно у MS с их провайдером STL есть какие-то проблемы с std::list.
Если std::list не использовать, а ещё лучше, не использовать вообще STL, то не всё так плохо

E>>>>3) На каком компиляторе/опциях оптимизации достигается заявленный разрвы в 2-3 раза?

IRO>>>http://virtul.livejournal.com/8714.html
E>>Э-э-э? Где?
E>>Там, собственно получили, в конце концов, что если в цикле практически ничего, кроме итерации не делать, то вариант
for(iterator it = v.begin(), it_end = v.end(); it != it_end; ++it) {
E>>    *it = ...
E>>}
является практически лучшим. Вторым по лучшести, уступая всего лишь ПРОЦЕНТЫ является классический для STL way
for( iterator i = v.begin(); i != v.end(); ++i ) {
E>>    *i = ...;
E>>}

IRO>18900.4 — i < v.size();
IRO>16353.5 — j < theSize;
IRO>11133.4 — i < v.end();
IRO>8985.34 — i < i_end;
IRO>8772.73 — i < i_end; плюс вынесли запись по глобальном адресном пространстве.

IRO>Сможешь проанализировать сам? и выдать сколько же это ПРОЦЕНТИКОВ тут.

Э-э-э, тут маловато статистики -- большой шум. Но даже тут < v.end() проигрывает < i_end как 11 против 9. И это на совсем уже пустом цикле, замечу я в скобках...
При этом, опять же, тут видно, что замороки с size однозначно хуже.
Но это просто ПУСТОЙ цикл. Если цикл делает ЧТО-ТО ЕЩЁ, кроме как организации своих итераций, то разница совсем мизерная будет.
Кстати, в опыте, где нивелировали вклад кэша и шум, результаты отличались совсем немного. Но даже и тут никаких "двух-трёх раз" я пока не наблюдаю.
Два-три раза было бы, если бы против 9000 было 22000, например...

IRO>Меня устраивают бесплатные проценты от производительности, а тебя?

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

IRO>Но когда использовался ID как std::string можно было бы обойтись и копированием только в другие холдеры, вместо того что бы на каждую проверку гонять его туда сюда.

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

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


IRO>Запроса?

Ну какой-то осмысленной операции, которую делает твоя программа.

IRO>А так это просто срать в свой код.

Да нет, это просто делать как все. Суть тут в том, что если что-то делать необычно, то имеешь шанс найти необычные грабли. А это лишнее, особенно, если за это ты никакого СУЩЕСТВЕННОГО выигрыша не получаешь...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[15]: Перешёл на личности -- значит слил.
От: Erop Россия  
Дата: 05.07.11 23:38
Оценка:
Здравствуйте, IROV.., Вы писали:

IRO>Я не понимаю, ты сам придумал 2-3 раза,

Э-э-э, дядя, за слова-то свои
Автор: IROV..
Дата: 05.07.11
отвечаешь?

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



Давай, приводи пример, где можно очень легко получить ускорение в 2-3 раза, добавив кэширование .end в циклы...

IRO>Я же тебе не однократно говорил — ты торгаш, и отсюда все твои "особености" мышления.

Перешёл на личности -- значит слил.
Кроме того, я не хочу тебя расстраивать, но программирование давно уже индустрия, и это вовсе не от слова "индус"

IRO>Читай про преждевременую писимизацию.

Пример, или не бывает.

IRO>Это обычный коментарий нуба, который не знает как делать, и боиться это использовать.

Ещё раз перешёл => ещё раз слил.

IRO>Просто есть хорошее выступление одного человека, Андрея Плахова, Дзен помоему называеться.

IRO>Так там были хорошие слова — Если тебе чтото мешает, сделай так что бы не мешало.
IRO>Переведу для тебя, выучи — и ты не найдешь грабли.
IRO>

Ты стих Хаяма забыл процитировать.
Я на твоего Андрея Плахова не молюсь, и он для меня в программировании не авторитет.
Кстати, я верно понял, что ты программированию у кинокритика учишься? Или я тебя опять как-то не так понял?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[12]: не выпендривайся и не найдёшь много новых граблей
От: jazzer Россия Skype: enerjazzer
Дата: 06.07.11 00:38
Оценка:
Здравствуйте, Erop, Вы писали:


IRO>>правильно, в этом коде это запись в память.

E>И что с того? Поставь опцию оптимизации, ограничивающую предположения о разных указателях на один и тот же объект и будет тебе счастье.
Почитай уже про эту опцию, Егор, ну в конце-то концов... (и будет тебе счастье)
Она вообще не о том:

-fstrict-aliasing
For C (and C++), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an "unsigned int" can alias an "int", but not a "void*" or a "double". A character type may alias any other type.

если у тебя есть два int*, то они могут замечательно ссылаться на один и тот же объект и эта опция соответствующий код никогда не будет трактовать как то, что они _не_ могут ссылаться на один и тот же объект. Потому что, например, невозможно станет надежно итерироваться указателями по связным спискам.
Каждый раз, когда ты передаешь указатель по значению, у тебя получаются несколько указателей (исходный и копия) на один и тот же объект — по-твоему, все программы должны просто рухнуть после включения опции, занимающеся такими предположениями, которые ты озвучиваешь
А эта опция лишь предполагает, что если у тебя есть int* и double*, то они не будут указывать на один и тот же адрес.

И какое отношение это имеет в size/end? Там везде один и тот же тип.

E>>>2) Если это таки std::vector<интегральный тип>, то принятым способом итерации будет таки или через итератор или через стандартный алгоритм какой...

При чем тут интегральный тип? С double или CString это не так, что ли?

E>Там, собственно получили, в конце концов, что если в цикле практически ничего, кроме итерации не делать, то вариант
for(iterator it = v.begin(), it_end = v.end(); it != it_end; ++it) {
E>    *it = ...
E>}
является практически лучшим.

А если что-то делать, то он становится худшим, что ли?

E>Вторым по лучшести, уступая всего лишь ПРОЦЕНТЫ является классический для STL way
for( iterator i = v.begin(); i != v.end(); ++i ) {
E>    *i = ...;
E>}

Не очень понятно, почему ты именно второй код называешь классическим, в то время std::for_each и другие стандартные алгоритмы — это первый вариант
Посмотри на сигнатуры в Стандарте — итераторы на конец-начало вычисляются один раз и передаются по значению.
Никто нигде не перевычисляет end().
Так что классический как раз первый.

Ну и "ПРОЦЕНТЫ" — это тоже немало, вообще-то. На моих задачах, по крайней мере.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: А вот и фиг!
От: MasterZiv СССР  
Дата: 06.07.11 06:41
Оценка:
On 05.07.2011 20:18, Tilir wrote:

> Не стоит на это уповать. Есть много случаев -- деревья, списки и прочие

> динамические структуры данных где инлайнить вычисление размера нерационально
> (см. std::list).

size_type size() const
{
return (_Size);
}

Объясни, что тут нерационально инлайнить.
Posted via RSDN NNTP Server 2.1 beta
Re[16]: Перешёл на личности -- значит слил.
От: IROV..  
Дата: 06.07.11 10:17
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, IROV.., Вы писали:


E>Давай, приводи пример, где можно очень легко получить ускорение в 2-3 раза, добавив кэширование .end в циклы...

Я скорее всего отвечал вот на этот закидон.

В любом случае, обычно компилятор формальные проверки делает лучше, чем человек. Так что писать for( int i = 0; i < c.size(); i++) { body(); } НАДЁЖНЕЕ!


18900.4 — i < v.size();
8985.34 — i < i_end;

~2 раза

IRO>>Я же тебе не однократно говорил — ты торгаш, и отсюда все твои "особености" мышления.

E>Перешёл на личности -- значит слил.
Ты стесняешься своей личности? facepalm

E>Кроме того, я не хочу тебя расстраивать, но программирование давно уже индустрия, и это вовсе не от слова "индус"

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

IRO>>Читай про преждевременую писимизацию.

E>Пример, или не бывает.
Пример как читать? www.google.com

IRO>>Просто есть хорошее выступление одного человека, Андрея Плахова, Дзен помоему называеться.

IRO>>Так там были хорошие слова — Если тебе чтото мешает, сделай так что бы не мешало.
IRO>>Переведу для тебя, выучи — и ты не найдешь грабли.
IRO>>
E>Ты стих Хаяма забыл процитировать.
E>Я на твоего Андрея Плахова не молюсь, и он для меня в программировании не авторитет.
Он для меня тоже не авторитет, но я его уважаю, и у него есть много правильных и не правильных идей.

E>Кстати, я верно понял, что ты программированию у кинокритика учишься? Или я тебя опять как-то не так понял?

Да да, именно у кинокритика другого от тебя и не мог ожидать.
я не волшебник, я только учусь!
Re[17]: Перешёл на личности -- значит слил.
От: Erop Россия  
Дата: 06.07.11 11:16
Оценка:
Здравствуйте, IROV.., Вы писали:

IRO>Я скорее всего отвечал вот на этот закидон.

Выбирай выражения.

IRO>

IRO>В любом случае, обычно компилятор формальные проверки делает лучше, чем человек. Так что писать for( int i = 0; i < c.size(); i++) { body(); } НАДЁЖНЕЕ!


С чего ты взял, что c -- это std::vector, и вообще, что он из stl?

IRO>18900.4 — i < v.size();

IRO>8985.34 — i < i_end;

IRO>~2 раза

Так я за то самое и ратую, что надо с stl-контейнерами работать через итераторы, а не через индексы...

IRO>Ты стесняешься своей личности? facepalm

1) Слово "тограш" эмоционально окрашено, и вообще тут не уместно.
2) Моя личность -- офтопик в форуме по С++

IRO>Есть индустрия — купи-продай, а есть производство, вот ты самый низкий пласт — торгаш.

Ну тебе уже пора извиниться.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[19]: Перешёл на личности -- значит слил.
От: Erop Россия  
Дата: 06.07.11 11:30
Оценка:
Здравствуйте, IROV.., Вы писали:

IRO>Даже если у тебя size(){ return this->m_size;} то этот сайз будет всегда читаться из памяти, со всеми вытикающими бедами.

Примеры, пожалуйста. А то с .end бед что-то нет особых...

E>>2) Моя личность -- офтопик в форуме по С++

IRO>Мой моск это не понял.
Сочувствую.

IRO>>>Есть индустрия — купи-продай, а есть производство, вот ты самый низкий пласт — торгаш.

E>>Ну тебе уже пора извиниться.
IRO>Ты уже пожаловался модераторам? а то пацан сказал пацан не сделал, как то не помужски
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: А вот и фиг!
От: IROV..  
Дата: 06.07.11 13:10
Оценка:
Здравствуйте, IROV.., Вы писали:

И за что минус?

разве не извесный факт что есть как минимум две реализации

в одной size() — O(N)
в другой splice() — O(N)

одновремено O(C) для size и splice алгоритмов нет.

Для листа есть операция splice, потому что её можно выполнить очень эффективно — поменять значения десятка указателей, И ВСЁ, вне зависимости от количества элементов которые переносятся из одного контейнера в другой. Для вектора реализовать splice более эффективно чем в коде приведенном выше НЕЛЬЗЯ, поэтому splice для вектора не определяется. Кстати c list::splice не всё так чисто — либо list::length либо list::splice имеют сложность O(1), но не обе сразу.

Вот даже чьята цытата из гугла
я не волшебник, я только учусь!
Re[4]: Выносить вычисление длины выше цикла уже не нужно?
От: Dmi3S Россия http://dmi3s.blogspot.com/
Дата: 16.07.11 02:33
Оценка:
Здравствуйте, Tilir, Вы писали:

T>В случае же size() могут быть нюансы. Например в std::list при реализации предпочли splice за O(1), за что у них size вычисляется за O(N). Что при длинных списках и проверке в теле цикла может сказываться убийственно.


Сам был удивлен, но в C++0x std::list<>::size() должна выполняться за O(1).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.