Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Boost.MultiIndex Documentation - Performance

Boost , , Boost.MultiIndex Documentation - Index

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Boost.MultiIndex Performance



Contents

Introduction

Повышаю. MultiIndex помогает программисту избежать ручной сборки громоздких композиций контейнеров при необходимости многоиндексации. Кроме того, он делает это эффективно, как с точки зрения пространства, так и с точки зрения потребления времени. Экономия пространства обусловлена компактным представлением базовых структур данных, требующих единого узла на элемент. Что касается эффективности времени, то рост. MultiIndex интенсивно использует методы метапрограммирования, которые производят очень жесткие реализации функций-членов, которые заботятся об элементарных операциях для каждого индекса: для<multi_index_container>s с двумя или более индексами время работы может быть уменьшено до половины, как с ручным моделированием с участием нескольких контейнеров STL.

Manual simulation of a multi_index_container

В разделеэмуляции стандартных контейнеров с<multi_index_container>показана эквивалентность между одноиндексными<multi_index_container>и некоторыми контейнерами STL. Теперь остановимся на проблеме моделирования<multi_index_container>с двумя или более индексами с подходящей комбинацией стандартных контейнеров.

Рассмотрим следующую инстанцию<multi_index_container>:

typedef multi_index_container<
  int,
  indexed_by<
    ordered_unique<identity<int> >,
    ordered_non_unique<identity<int>, std::greater >,
  >
> indexed_t;

<indexed_t>поддерживает два внутренних индекса на элементах типа<int>. Чтобы смоделировать эту структуру данных, прибегая только к стандартным контейнерам STL, можно использовать при первом подходе следующие типы:

// dereferencing compare predicate
template<typename Iterator,typename Compare>
struct it_compare
{
  bool operator()(const Iterator& x,const Iterator& y)const
  {
    return comp(*x,*y);
  }
private:
  Compare comp;
};
typedef std::set<int>  manual_t1; // equivalent to indexed_t's index #0
typedef std::multiset<
  const int*,
  it_compare<
    const int*,
    std::greater<int>
  >
>                      manual_t2; // equivalent to indexed_t's index #1

где<manual_t1>— «базовый» контейнер, который содержит фактические элементы, и<manual_t2>хранит указатели на элементы<manual_t1>. Эта схема оказывается довольно неэффективной, правда: при этом вставка в структуру данных достаточно проста:

manual_t1 c1;
manual_t2 c2;
// insert the element 5
manual_t1::iterator it1=c1.insert(5).first;
c2.insert(&*it1);
deletion, on the other hand, necessitates a logarithmic search, whereas indexed_t deletes in constant time:
// remove the element pointed to by it2
manual_t2::iterator it2=...;
c1.erase(**it2); // watch out! performs in logarithmic time
c2.erase(it2); 

Правильный подход заключается в подаче второго контейнера не сырыми указателями, а элементами типа<manual_t1::iterator>:

typedef std::set<int>    manual_t1; // equivalent to indexed_t's index #0
typedef std::multiset<
  manual_t1::iterator,
  it_compare<
    manual_t1::iterator,
    std::greater<int>
  >
>                        manual_t2; // equivalent to indexed_t's index #1

Теперь вставка и удаление могут быть выполнены с ограничениями сложности, эквивалентными<indexed_t>:

manual_t1 c1;
manual_t2 c2;
// insert the element 5
manual_t1::iterator it1=c1.insert(5).first;
c2.insert(it1);
// remove the element pointed to by it2
manual_t2::iterator it2=...;
c1.erase(*it2); // OK: constant time
c2.erase(it2); 

Конструкция может быть расширена простым способом для обработки более двух индексов. Далее мы сравним инстанциации<multi_index_container>с подобными ручными симуляциями.

Spatial efficiency

Прирост в потреблении пространства<multi_index_container>по отношению к его ручному моделированию поддается очень простому теоретическому анализу. Для простоты мы будем игнорировать вопросы выравнивания (которые в целом играют в пользу<multi_index_container>).

Узлы<multi_index_container>с индексамиNсодержат значение элемента плюс заголовкиN, содержащие информацию о ссылках для каждого индекса. Таким образом, размер узла

SI = e + h0 + ··· + hN-1, where
e = size of the element,
hi = size of the i-th header.

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

SM = (e + h0) + (p + h1) + ··· + (p + hN-1) = SI + (N-1)p, where
p = size of a pointer.

Относительный объем памяти, занимаемый<multi_index_container>в отношении его ручного моделирования, составляет всегоSI / SM, который может быть выражен следующим образом:

SI / SM = SI / (SI + (N-1)p).

Формула показывает, что<multi_index_container>более эффективно в отношении потребления памяти по мере роста числа индексов. Было сделано неявное предположение, что заголовки<multi_index_container>индексных узлов имеют тот же размер, что и их аналоги в STL-контейнерах; но есть конкретный случай, в котором это часто не так: упорядоченные индексы используют методпространственной оптимизации, который не присутствует во многих реализациях<std::set>, давая дополнительное преимущество<multi_index_container>s одного системного слова на упорядоченный индекс. С учетом этого факта прежнюю формулу можно скорректировать следующим образом:

SI / SM = SI / (SI + (N-1)p + Ow),

гдеO— число упорядоченных индексов контейнера, аw— размер системного слова (обычно 4 байта на 32-битных архитектурах).

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

Time efficiency

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

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

Performance tests

См.исходный код, используемый для измерений.

Для того, чтобы оценить эффективность<multi_index_container>, следующий базовый алгоритм:

multi_index_container<...> c;
for(int i=0;i<n;++i)c.insert(i);
for(iterator it=c.begin();it!=c.end();)c.erase(it++);

Измеряется для различных инстанциаций<multi_index_container>при значенияхn1000, 10 000 и 100 000, и время его выполнения по сравнению с эквивалентным алгоритмом для соответствующего ручного моделирования структуры данных на основе контейнеров STL. В приведенной ниже таблице описаны используемые среды испытаний.

Tests environments.
Compiler Settings OS and CPU
GCC 3.4.5 (mingw special) <-O3> Windows 2000 Pro на P4 1,5 ГГц, 256 МБ ОЗУ
Intel C++ 7.1 Параметры выпуска по умолчанию Windows 2000 Pro на P4 1,5 ГГц, 256 МБ ОЗУ
Microsoft Visual C++ 8.0 По умолчанию,<_SECURE_SCL=0> Windows XP на P4 Xeon 3,2 ГГц, 1 ГБ ОЗУ

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

Results for 1 ordered index

Было проверено следующее<multi_index_container>:

multi_index_container<
  int,
  indexed_by<
    ordered_unique<identity<int> >
  >
>

Это эквивалентно<std::set<int>>.

Memory consumption

GCC 3.4.5 ICC 7.1 MSVC 8.0
80% 80% 80%
Table 1: Relative memory consumption of multi_index_container with 1 ordered index.

Снижение использования памяти объясняется методом оптимизации, реализованным в Boost. МультиИндекс заказал индексы, какобъяснил выше.

Execution time

performance of multi_index_container with 1 ordered index
Fig. 1: Performance of multi_index_container with 1 ordered index.

Что удивительно,<multi_index_container>работает немного лучше, чем<std::set>. Очень вероятное объяснение такого поведения заключается в том, что более низкое потребление памяти<multi_index_container>приводит к более высокой скорости попадания кэша процессора. Улучшение является наименьшим для GCC, по-видимому, потому, что худшее качество оптимизатора этого компилятора маскирует преимущества, связанные с кэшем.

Results for 1 sequenced index

Было проверено следующее<multi_index_container>:

multi_index_container<
  int,
  indexed_by<
    sequenced<>
  >
>

То же самое можно сказать и о<std::list<int>>.

Memory consumption

GCC 3.4.5 ICC 7.1 MSVC 8.0
100% 100% 100%
Table 2: Relative memory consumption of multi_index_container with 1 sequenced index.

Эти цифры подтверждают, что в этом случае<multi_index_container>узлов имеют тот же размер, что и его<std::list>аналог.

Execution time

performance of multi_index_container with 1 sequenced index
Fig. 2: Performance of multi_index_container with 1 sequenced index.

<multi_index_container>не достигает производительности своего аналога STL, хотя цифры близки. Опять же, худшие результаты - это GCC с деградацией до 7%, в то время как ICC и MSVC не превышают всего 5%.

Results for 2 ordered indices

Было проверено следующее<multi_index_container>:

multi_index_container<
  int,
  indexed_by<
    ordered_unique<identity<int> >,
    ordered_non_unique<identity<int> >
  >
>

Memory consumption

GCC 3.4.5 ICC 7.1 MSVC 8.0
70% 70% 70%
Table 3: Relative memory consumption of multi_index_container with 2 ordered indices.

Эти результаты совпадают с теоретической формулой дляSI= 28,N=O= 2 иp=w= 4.

Execution time

performance of multi_index_container with 2 ordered indices
Fig. 3: Performance of multi_index_container with 2 ordered indices.

Экспериментальные результаты подтверждают нашу гипотезу о том, что<multi_index_container>обеспечивает улучшение времени выполнения примерно постоянным фактором, который в этом случае составляет около 60%. Нет очевидного объяснения повышенного преимущества<multi_index_container>в MSVC дляn=105.

Results for 1 ordered index + 1 sequenced index

Было проверено следующее<multi_index_container>:

multi_index_container<
  int,
  indexed_by<
    ordered_unique<identity<int> >,
    sequenced<>
  >
>

Memory consumption

GCC 3.4.5 ICC 7.1 MSVC 8.0
75% 75% 75%
Table 4: Relative memory consumption of multi_index_container with 1 ordered index + 1 sequenced index.

Эти результаты совпадают с теоретической формулой дляSI= 24,N= 2,O= 1 иp=w= 4.

Execution time

performance of multi_index_container with 1 ordered index + 1 sequenced index
Fig. 4: Performance of multi_index_container with 1 ordered index + 1 sequenced index.

Дляn=103иn=104результаты согласуются с нашим теоретическим анализом, показывая постоянное улучшение коэффициента 50-65% по отношению к ручному моделированию на основе STL. Любопытно, что это ускорение становится еще выше, когдаn=105для двух компиляторов, а именно GCC и ICC. Чтобы исключить ложные результаты, тесты проводились много раз, приводя к аналогичным результатам. Обе тестовые среды развернуты на одной машине, что указывает на некоторую причину этого явления.

Results for 3 ordered indices

Было проверено следующее<multi_index_container>:

multi_index_container<
  int,
  indexed_by<
    ordered_unique<identity<int> >,
    ordered_non_unique<identity<int> >,
    ordered_non_unique<identity<int> >
  >
>

Memory consumption

GCC 3.4.5 ICC 7.1 MSVC 8.0
66.7% 66.7% 66.7%
Table 5: Relative memory consumption of multi_index_container with 3 ordered indices.

Эти результаты совпадают с теоретической формулой дляSI= 40,N=O= 3 иp=w= 4.

Execution time

performance of multi_index_container with 3 ordered indices
Fig. 5: Performance of multi_index_container with 3 ordered indices.

Время выполнения для этого случая на 45-55% ниже, чем при ручном моделировании той же структуры данных на основе STL.

Results for 2 ordered indices + 1 sequenced index

Было проверено следующее<multi_index_container>:

multi_index_container<
  int,
  indexed_by<
    ordered_unique<identity<int> >,
    ordered_non_unique<identity<int> >,
    sequenced<>
  >
>

Memory consumption

GCC 3.4.5 ICC 7.1 MSVC 8.0
69.2% 69.2% 69.2%
Table 6: Relative memory consumption of multi_index_container with 2 ordered indices + 1 sequenced index.

Эти результаты совпадают с теоретической формулой дляSI= 36,N= 3,O= 2 иp=w= 4.

Execution time

performance of multi_index_container with 2 ordered indices + 1 sequenced index
Fig. 6: Performance of multi_index_container with 2 ordered indices + 1 sequenced index.

В соответствии с ожиданиями время исполнения улучшается достаточно постоянным фактором, который колеблется от 45% до 55%.

Conclusions

Мы показали, что<multi_index_container>превосходит по эффективности как в пространстве, так и во времени эквивалентные структуры данных, полученные из ручной комбинации контейнеров STL. Это улучшение усиливается при увеличении числа индексов.

В особом случае замены стандартных контейнеров одноиндексными<multi_index_container>с производительностью Boost. MultiIndex сопоставим с тестируемыми реализациями STL и может даже привести к некоторым улучшениям как в пространстве, так и во времени выполнения.




Пересмотрено 24 ноября 2015

© Copyright 2003-2015 Joaquín M López Muñoz. Распространяется под лицензией Boost Software License, версия 1.0. (См. сопроводительный файлLICENSE_1_0.txtили копию на) http://www.boost.org/LICENSE_1_0.txt

Статья Boost.MultiIndex Documentation - Performance раздела Boost.MultiIndex Documentation - Index может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: Boost.MultiIndex Documentation - Index ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 09:17:44/0.011604070663452/1