вектор‹логический› доступ

Я профилировал свой код, используя gprof, и из отчета большинство, если не все из 20 лучших или около того, относятся к вектору.

Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
 14.71      0.05     0.05  3870399     0.00     0.00  std::vector<bool, std::allocator<bool> >::size() const
 11.76      0.09     0.04 10552897     0.00     0.00  std::_Bit_reference::_Bit_reference(unsigned long*, unsigned long)
 11.76      0.13     0.04  7890323     0.00     0.00  std::_Bit_const_iterator::_Bit_const_iterator(std::_Bit_iterator const&)
  5.88      0.15     0.02 10089215     0.00     0.00  std::_Bit_iterator::operator*() const
  5.88      0.17     0.02  6083600     0.00     0.00  std::vector<bool, std::allocator<bool> >::operator[](unsigned int)
  5.88      0.19     0.02  3912611     0.00     0.00  std::vector<bool, std::allocator<bool> >::end() const
  5.88      0.21     0.02                             std::istreambuf_iterator<char, std::char_traits<char> > std::num_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::_M_extract_int<unsigned long long>(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, std::_Ios_Iostate&, unsigned long long&) const
  2.94      0.22     0.01  6523499     0.00     0.00  std::_Bit_reference::operator bool() const
  2.94      0.23     0.01  3940406     0.00     0.00  std::vector<bool, std::allocator<bool> >::begin() const
  2.94      0.24     0.01  2807828     0.00     0.00  std::_Bit_iterator::operator++()
  2.94      0.25     0.01   146917     0.00     0.00  std::_Bit_iterator_base::_M_incr(int)
  2.94      0.26     0.01   121706     0.00     0.00  std::__miter_base<unsigned long*, false>::__b(unsigned long*)
  2.94      0.27     0.01    46008     0.00     0.00  std::_Bvector_base<std::allocator<bool> >::~_Bvector_base()
  2.94      0.28     0.01    22596     0.00     0.00  std::_Bit_iterator std::__copy_move<false, false, std::random_access_iterator_tag>::__copy_m<std::_Bit_iterator, std::_Bit_iterator>(std::_Bit_iterator, std::_Bit_iterator, std::_Bit_iterator)
  2.94      0.29     0.01     4525     0.00     0.05  integer::operator+(integer)
  2.94      0.30     0.01     1382     0.01     0.01  void std::_Destroy<unsigned int*, unsigned int>(unsigned int*, unsigned int*, std::allocator<unsigned int>&)
  2.94      0.31     0.01                             std::string::size() const
  2.94      0.32     0.01                             std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()
  2.94      0.33     0.01                             std::locale::locale()
  2.94      0.34     0.01                             __dynamic_cast

это хороший знак, так как это означает, что остальные мои функции довольно эффективны, или что доступ к значениям из вектора ‹ bool > действительно медленный?

я компилирую с помощью gcc -std=c++0x


person calccrypto    schedule 23.06.2011    source источник
comment
Как насчет добавления заголовков столбцов, чтобы нам не приходилось угадывать, что мы читаем? Затем сообщите нам параметры компилятора, которые вы используете.   -  person Ed S.    schedule 24.06.2011
comment
Что-то странное здесь. Почему вызов vector‹bool›::size() занимает так много времени?   -  person Zaur Nasibov    schedule 24.06.2011
comment
обязательное изменение: g++ --std=c++0x -g -O3 (это две опечатки и флаг оптимизации, перепрофилируйте!); Классы шаблонов активно используют встраивание, а это, в свою очередь, позволяет реализовать множество других оптимизаций. Порядок ускорения легко 10-кратный   -  person sehe    schedule 24.06.2011
comment
я не терминальный человек. я использую кодовые блоки. простите   -  person calccrypto    schedule 24.06.2011
comment
@calccrypto: что ты говоришь? Вы включили или не включили оптимизацию?   -  person sehe    schedule 24.06.2011
comment
да. я включил их в графическом интерфейсе кодовых блоков, а не набрав их сам. я на самом деле не знаю синтаксис   -  person calccrypto    schedule 24.06.2011
comment
возможный дубликат Почему vector‹bool›::reference не возвращает ссылку на bool ?   -  person BЈовић    schedule 12.02.2013


Ответы (5)


vector<bool> не хранит bools. Это в основном битовое поле. Вы платите за манипуляции, необходимые для изменения одного значения.

Если вас беспокоит производительность во время выполнения, рассмотрите вместо этого vector<char> или deque<bool>.

person Billy ONeal    schedule 23.06.2011
comment
vector<bool> никогда не должен был входить в стандарт в его нынешнем виде. К сожалению, мы застряли с этим. - person Mark Ransom; 24.06.2011
comment
@Insilico: Ну, они должны соглашаться только в ограниченной степени, поскольку vector<bool> все еще находится в FDIS. ;-] - person ildjarn; 24.06.2011
comment
@ildjarn: статья, на которую ссылается In silico, была опубликована в 2007 году. Комитет прекратил прием статей для C++0x (я думаю) в 2006 году. - person Billy ONeal; 24.06.2011
comment
А, интересно. Что ж, будем надеяться, что это попадет в TR2. - person ildjarn; 24.06.2011

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

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

Поскольку операция std::vector занимает наибольшее количество времени, именно с нее следует начинать, чтобы сделать код еще быстрее.

Обратите внимание, что std::vector<bool> обычно немного медленнее, чем std::vector<int>, потому что он хранит не реальные bool, а скорее набор битовых масок (т.е. в идеале для каждой записи требуется только один бит). Это экономит место, но работает медленнее. Если вам нужно, чтобы это было быстрее, попробуйте вместо этого использовать std::vector<int> (или char, .., в зависимости от ваших потребностей).

Я подозреваю, что std::vector<bool> может сильно пострадать от отладочных сборок, поэтому попробуйте некоторые флаги оптимизации, если вы еще этого не сделали (вы всегда должны это делать для профилирования).

person Alexander Gessler    schedule 23.06.2011
comment
я включил все флаги оптимизации, и это лишь немного лучше - person calccrypto; 24.06.2011

vector<bool> на самом деле является специализацией шаблона, где каждое значение bool хранится как один бит. Однако невозможно напрямую работать с отдельными битами так же, как с int или просто с «обычным» bool. Таким образом, алгоритмы, используемые в vector<bool>, сильно отличаются от «нормального» vector<>, и для того, чтобы максимально сохранить интерфейс vector, он может возвращать прокси-объекты, которые манипулируют битами, когда вы вызываете такие функции, как operator[]. Это может повлиять на результаты в вашем отчете gprof, в зависимости от того, как настроен ваш компилятор и рассматриваемый код.

person In silico    schedule 23.06.2011
comment
так что... вносите свой вклад в замедление моей программы? - person calccrypto; 24.06.2011

Я бы сказал, что это воняет, потому что 14,71% вашего времени тратится на vector<bool>::size()!?! Размер наверное дан.

Попробуйте уменьшить количество вызовов size() или используйте вектор фиксированного размера, если вы заранее знаете размер: bitset

Изменить после прочтения обновления вопроса:

Обязательное изменение: g++ --std=c++0x -g -O3 (это две опечатки и флаг оптимизации, перепрофилировать!); Классы шаблонов активно используют встраивание, а это, в свою очередь, позволяет реализовать множество других оптимизаций. Порядок ускорения легко 10-кратный

person sehe    schedule 23.06.2011
comment
нет. этот код пытается уменьшить размер хранимого вектора‹bool› - person calccrypto; 24.06.2011
comment
@calccrypto: если вы расскажете нам об алгоритме и цели, я уверен, что толпа ТАК оптимизирует его до чертиков :) - person sehe; 24.06.2011
comment
это класс, который хранит целые числа в битовой форме, поэтому ограничений по битам нет. я знаю, что для этого есть большие библиотеки int, но ни одна из них не помещается в один легко включаемый файл - person calccrypto; 24.06.2011
comment
звучит крайне неудачно. Bigints должны быть bigints, а не длинными списками битов. - person sehe; 24.06.2011
comment
наверное. я просто сделал это как некоторую практику с битовыми манипуляциями. мне также нужно было немного посчитать в poly1305aes - person calccrypto; 24.06.2011
comment
я хотел посмотреть, что я должен оптимизировать - person calccrypto; 24.06.2011
comment
Ну, очевидно, вы должны оптимизировать контейнер для хранения резервных копий :) - person sehe; 24.06.2011
comment
@sehe: +1, только за этот комментарий. ;-] - person ildjarn; 24.06.2011

Много ли это говорит о вашей программе? Кроме vector<bool> бизнеса, это практически ничего вам не говорит.

Вы сами видите проблемы с gprof.

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

Единственное, что вы можете с этим сделать, это попытаться вызвать ее less, или попытаться вызвать less процедуру, которая ее вызывает, или попытаться вызвать эту подпрограмму less, и вам остается только пытаться угадать, где то есть.

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

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

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

person Mike Dunlavey    schedule 24.06.2011