1 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.0.1 Transitional//EN">
5 <meta http-equiv=
"Content-Type" content=
"text/html; charset=ISO-8859-1">
6 <title>Boost.MultiIndex Documentation - Performance
</title>
7 <link rel=
"stylesheet" href=
"style.css" type=
"text/css">
8 <link rel=
"start" href=
"index.html">
9 <link rel=
"prev" href=
"compiler_specifics.html">
10 <link rel=
"up" href=
"index.html">
11 <link rel=
"next" href=
"examples.html">
15 <h1><img src=
"../../../boost.png" alt=
"boost.png (6897 bytes)" align=
16 "middle" width=
"277" height=
"86">Boost.MultiIndex Performance
</h1>
18 <div class=
"prev_link"><a href=
"compiler_specifics.html"><img src=
"prev.gif" alt=
"compiler specifics" border=
"0"><br>
21 <div class=
"up_link"><a href=
"index.html"><img src=
"up.gif" alt=
"index" border=
"0"><br>
24 <div class=
"next_link"><a href=
"examples.html"><img src=
"next.gif" alt=
"examples" border=
"0"><br>
26 </a></div><br clear=
"all" style=
"clear: all;">
33 <li><a href=
"#intro">Introduction
</a></li>
34 <li><a href=
"#simulation">Manual simulation of a
<code>multi_index_container
</code></a></li>
35 <li><a href=
"#spatial_efficiency">Spatial efficiency
</a></li>
36 <li><a href=
"#time_efficiency">Time efficiency
</a></li>
37 <li><a href=
"#tests">Performance tests
</a>
39 <li><a href=
"#test_1r">Results for
1 ordered index
</a>
41 <li><a href=
"#memory_1r">Memory consumption
</a></li>
42 <li><a href=
"#time_1r">Execution time
</a></li>
45 <li><a href=
"#test_1s">Results for
1 sequenced index
</a>
47 <li><a href=
"#memory_1s">Memory consumption
</a></li>
48 <li><a href=
"#time_1s">Execution time
</a></li>
51 <li><a href=
"#test_2r">Results for
2 ordered indices
</a>
53 <li><a href=
"#memory_2r">Memory consumption
</a></li>
54 <li><a href=
"#time_2r">Execution time
</a></li>
57 <li><a href=
"#test_1r1s">Results for
1 ordered index +
1 sequenced index
</a>
59 <li><a href=
"#memory_1r1s">Memory consumption
</a></li>
60 <li><a href=
"#time_1r1s">Execution time
</a></li>
63 <li><a href=
"#test_3r">Results for
3 ordered indices
</a>
65 <li><a href=
"#memory_3r">Memory consumption
</a></li>
66 <li><a href=
"#time_3r">Execution time
</a></li>
69 <li><a href=
"#test_2r1s">Results for
2 ordered indices +
1 sequenced index
</a>
71 <li><a href=
"#memory_2r1s">Memory consumption
</a></li>
72 <li><a href=
"#time_2r1s">Execution time
</a></li>
77 <li><a href=
"#conclusions">Conclusions
</a></li>
80 <h2><a name=
"intro">Introduction
</a></h2>
83 Boost.MultiIndex helps the programmer to avoid the manual construction of cumbersome
84 compositions of containers when multi-indexing capabilities are needed. Furthermore,
85 it does so in an efficient manner, both in terms of space and time consumption. The
86 space savings stem from the compact representation of the underlying data structures,
87 requiring a single node per element. As for time efficiency, Boost.MultiIndex
88 intensively uses metaprogramming techniques producing very tight implementations
89 of member functions which take care of the elementary operations for each index:
90 for
<code>multi_index_container
</code>s with two or more indices, the running time
91 can be reduced to half as long as with manual simulations involving several
95 <h2><a name=
"simulation">Manual simulation of a
<code>multi_index_container
</code></a></h2>
98 The section on
<a href=
"tutorial/techniques.html#emulate_std_containers">emulation
99 of standard containers with
<code>multi_index_container
</code></a> shows the equivalence
100 between single-index
<code>multi_index_container
</code>s and some STL containers. Let us now
101 concentrate on the problem of simulating a
<code>multi_index_container
</code> with two
102 or more indices with a suitable combination of standard containers.
106 Consider the following instantiation of
<code>multi_index_container
</code>:
110 <span class=keyword
>typedef
</span> <span class=identifier
>multi_index_container
</span><span class=special
><</span>
111 <span class=keyword
>int
</span><span class=special
>,
</span>
112 <span class=identifier
>indexed_by
</span><span class=special
><</span>
113 <span class=identifier
>ordered_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>>,
</span>
114 <span class=identifier
>ordered_non_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>>,
</span> <span class=identifier
>std
</span><span class=special
>::
</span><span class=identifier
>greater
</span> <span class=special
>>,
</span>
115 <span class=special
>></span>
116 <span class=special
>></span> <span class=identifier
>indexed_t
</span><span class=special
>;
</span>
120 <code>indexed_t
</code> maintains two internal indices on elements of type
121 <code>int
</code>. In order to simulate this data structure resorting only to
122 standard STL containers, one can use on a first approach the following types:
126 <span class=comment
>// dereferencing compare predicate
</span>
127 <span class=keyword
>template
</span><span class=special
><</span><span class=keyword
>typename
</span> <span class=identifier
>Iterator
</span><span class=special
>,
</span><span class=keyword
>typename
</span> <span class=identifier
>Compare
</span><span class=special
>></span>
128 <span class=keyword
>struct
</span> <span class=identifier
>it_compare
</span>
129 <span class=special
>{
</span>
130 <span class=keyword
>bool
</span> <span class=keyword
>operator
</span><span class=special
>()(
</span><span class=keyword
>const
</span> <span class=identifier
>Iterator
</span><span class=special
>&</span> <span class=identifier
>x
</span><span class=special
>,
</span><span class=keyword
>const
</span> <span class=identifier
>Iterator
</span><span class=special
>&</span> <span class=identifier
>y
</span><span class=special
>)
</span><span class=keyword
>const
</span>
131 <span class=special
>{
</span>
132 <span class=keyword
>return
</span> <span class=identifier
>comp
</span><span class=special
>(*
</span><span class=identifier
>x
</span><span class=special
>,*
</span><span class=identifier
>y
</span><span class=special
>);
</span>
133 <span class=special
>}
</span>
135 <span class=keyword
>private
</span><span class=special
>:
</span>
136 <span class=identifier
>Compare
</span> <span class=identifier
>comp
</span><span class=special
>;
</span>
137 <span class=special
>};
</span>
139 <span class=keyword
>typedef
</span> <span class=identifier
>std
</span><span class=special
>::
</span><span class=identifier
>set
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=identifier
>manual_t1
</span><span class=special
>;
</span> <span class=comment
>// equivalent to indexed_t's index #
0</span>
140 <span class=keyword
>typedef
</span> <span class=identifier
>std
</span><span class=special
>::
</span><span class=identifier
>multiset
</span><span class=special
><</span>
141 <span class=keyword
>const
</span> <span class=keyword
>int
</span><span class=special
>*,
</span>
142 <span class=identifier
>it_compare
</span><span class=special
><</span>
143 <span class=keyword
>const
</span> <span class=keyword
>int
</span><span class=special
>*,
</span>
144 <span class=identifier
>std
</span><span class=special
>::
</span><span class=identifier
>greater
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span>
145 <span class=special
>></span>
146 <span class=special
>></span> <span class=identifier
>manual_t2
</span><span class=special
>;
</span> <span class=comment
>// equivalent to indexed_t's index #
1</span>
150 where
<code>manual_t1
</code> is the
"base" container that holds
151 the actual elements, and
<code>manual_t2
</code> stores pointers to
152 elements of
<code>manual_t1
</code>. This scheme turns out to be quite
153 inefficient, though: while insertion into the data structure is simple enough:
157 <span class=identifier
>manual_t1
</span> <span class=identifier
>c1
</span><span class=special
>;
</span>
158 <span class=identifier
>manual_t2
</span> <span class=identifier
>c2
</span><span class=special
>;
</span>
160 <span class=comment
>// insert the element
5</span>
161 <span class=identifier
>manual_t1
</span><span class=special
>::
</span><span class=identifier
>iterator
</span> <span class=identifier
>it1
</span><span class=special
>=
</span><span class=identifier
>c1
</span><span class=special
>.
</span><span class=identifier
>insert
</span><span class=special
>(
</span><span class=number
>5</span><span class=special
>).
</span><span class=identifier
>first
</span><span class=special
>;
</span>
162 <span class=identifier
>c2
</span><span class=special
>.
</span><span class=identifier
>insert
</span><span class=special
>(
&*
</span><span class=identifier
>it1
</span><span class=special
>);
</span>
165 deletion, on the other hand, necessitates a logarithmic search, whereas
166 <code>indexed_t
</code> deletes in constant time:
169 <span class=comment
>// remove the element pointed to by it2
</span>
170 <span class=identifier
>manual_t2
</span><span class=special
>::
</span><span class=identifier
>iterator
</span> <span class=identifier
>it2
</span><span class=special
>=...;
</span>
171 <span class=identifier
>c1
</span><span class=special
>.
</span><span class=identifier
>erase
</span><span class=special
>(**
</span><span class=identifier
>it2
</span><span class=special
>);
</span> <span class=comment
>// watch out! performs in logarithmic time
</span>
172 <span class=identifier
>c2
</span><span class=special
>.
</span><span class=identifier
>erase
</span><span class=special
>(
</span><span class=identifier
>it2
</span><span class=special
>);
</span>
176 The right approach consists of feeding the second container not with
177 raw pointers, but with elements of type
<code>manual_t1::iterator
</code>:
181 <span class=keyword
>typedef
</span> <span class=identifier
>std
</span><span class=special
>::
</span><span class=identifier
>set
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=identifier
>manual_t1
</span><span class=special
>;
</span> <span class=comment
>// equivalent to indexed_t's index #
0</span>
182 <span class=keyword
>typedef
</span> <span class=identifier
>std
</span><span class=special
>::
</span><span class=identifier
>multiset
</span><span class=special
><</span>
183 <span class=identifier
>manual_t1
</span><span class=special
>::
</span><span class=identifier
>iterator
</span><span class=special
>,
</span>
184 <span class=identifier
>it_compare
</span><span class=special
><</span>
185 <span class=identifier
>manual_t1
</span><span class=special
>::
</span><span class=identifier
>iterator
</span><span class=special
>,
</span>
186 <span class=identifier
>std
</span><span class=special
>::
</span><span class=identifier
>greater
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span>
187 <span class=special
>></span>
188 <span class=special
>></span> <span class=identifier
>manual_t2
</span><span class=special
>;
</span> <span class=comment
>// equivalent to indexed_t's index #
1</span>
192 Now, insertion and deletion can be performed with complexity bounds
193 equivalent to those of
<code>indexed_t
</code>:
197 <span class=identifier
>manual_t1
</span> <span class=identifier
>c1
</span><span class=special
>;
</span>
198 <span class=identifier
>manual_t2
</span> <span class=identifier
>c2
</span><span class=special
>;
</span>
200 <span class=comment
>// insert the element
5</span>
201 <span class=identifier
>manual_t1
</span><span class=special
>::
</span><span class=identifier
>iterator
</span> <span class=identifier
>it1
</span><span class=special
>=
</span><span class=identifier
>c1
</span><span class=special
>.
</span><span class=identifier
>insert
</span><span class=special
>(
</span><span class=number
>5</span><span class=special
>).
</span><span class=identifier
>first
</span><span class=special
>;
</span>
202 <span class=identifier
>c2
</span><span class=special
>.
</span><span class=identifier
>insert
</span><span class=special
>(
</span><span class=identifier
>it1
</span><span class=special
>);
</span>
204 <span class=comment
>// remove the element pointed to by it2
</span>
205 <span class=identifier
>manual_t2
</span><span class=special
>::
</span><span class=identifier
>iterator
</span> <span class=identifier
>it2
</span><span class=special
>=...;
</span>
206 <span class=identifier
>c1
</span><span class=special
>.
</span><span class=identifier
>erase
</span><span class=special
>(*
</span><span class=identifier
>it2
</span><span class=special
>);
</span> <span class=comment
>// OK: constant time
</span>
207 <span class=identifier
>c2
</span><span class=special
>.
</span><span class=identifier
>erase
</span><span class=special
>(
</span><span class=identifier
>it2
</span><span class=special
>);
</span>
211 The construction can be extended in a straightforward manner to
212 handle more than two indices. In what follows, we will compare
213 instantiations of
<code>multi_index_container
</code> against this sort of
217 <h2><a name=
"spatial_efficiency">Spatial efficiency
</a></h2>
220 The gain in space consumption of
<code>multi_index_container
</code> with
221 respect to its manual simulations is amenable to a very simple
222 theoretical analysis. For simplicity, we will ignore alignment
223 issues (which in general play in favor of
<code>multi_index_container
</code>.)
227 Nodes of a
<code>multi_index_container
</code> with
<i>N
</i> indices hold the value
228 of the element plus
<i>N
</i> headers containing linking information for
229 each index. Thus the node size is
233 <i>S
<sub>I
</sub></i> =
<i>e
</i> +
<i>h
</i><sub>0</sub> + ··· +
234 <i>h
</i><sub><i>N
</i>-
1</sub>, where
<br>
235 <i>e
</i> = size of the element,
<br>
236 <i>h
</i><sub><i>i
</i></sub> = size of the
<i>i
</i>-th header.
240 On the other hand, the manual simulation allocates
<i>N
</i> nodes per
241 element, the first holding the elements themselves and the rest
242 storing iterators to the
"base" container. In practice, an iterator
243 merely holds a raw pointer to the node it is associated to, so its size
244 is independent of the type of the elements. Summing all contributions,
245 the space allocated per element in a manual simulation is
249 <i>S
<sub>M
</sub></i> = (
<i>e
</i> +
<i>h
</i><sub>0</sub>) +
250 (
<i>p
</i> +
<i>h
</i><sub>1</sub>) + ··· +
251 (
<i>p
</i> +
<i>h
</i><sub><i>N
</i>-
1</sub>) =
252 <i>S
<sub>I
</sub></i> + (
<i>N
</i>-
1)
<i>p
</i>, where
<br>
253 <i>p
</i> = size of a pointer.
<br>
257 The relative amount of memory taken up by
<code>multi_index_container
</code>
258 with respect to its manual simulation is just
259 <i>S
<sub>I
</sub></i> /
<i>S
<sub>M
</sub></i>, which can be expressed
264 <i>S
<sub>I
</sub></i> /
<i>S
<sub>M
</sub></i> =
265 <i>S
<sub>I
</sub></i> /
(
<i>S
<sub>I
</sub></i> + (
<i>N
</i>-
1)
<i>p
</i>).
269 The formula shows that
<code>multi_index_container
</code> is more efficient
270 with regard to memory consumption as the number of indices grow. An implicit
271 assumption has been made that headers of
<code>multi_index_container
</code>
272 index nodes are the same size that their analogues in STL containers; but there
273 is a particular case in which this is often not the case: ordered indices use a
274 <a href=
"tutorial/indices.html#ordered_node_compression">spatial optimization
275 technique
</a> which is not present in many implementations of
276 <code>std::set
</code>, giving an additional advantage to
277 <code>multi_index_container
</code>s of one system word per ordered index.
278 Taking this fact into account, the former formula can be adjusted to:
282 <i>S
<sub>I
</sub></i> /
<i>S
<sub>M
</sub></i> =
283 <i>S
<sub>I
</sub></i> /
(
<i>S
<sub>I
</sub></i> + (
<i>N
</i>-
1)
<i>p
</i> +
<i>Ow
</i>),
287 where
<i>O
</i> is the number of ordered indices of the container, and
<i>w
</i>
288 is the system word size (typically
4 bytes on
32-bit architectures.)
292 These considerations have overlooked an aspect of the greatest practical
293 importance: the fact that
<code>multi_index_container
</code> allocates a single
294 node per element, compared to the many nodes of different sizes
295 built by manual simulations, diminishes memory fragmentation, which
296 can show up in more usable memory available and better performance.
299 <h2><a name=
"time_efficiency">Time efficiency
</a></h2>
302 From the point of view of computational complexity (i.e. big-O
303 characterization),
<code>multi_index_container
</code> and its corresponding manual
304 simulations are equivalent: inserting an element into
305 a
<code>multi_index_container
</code> reduces to a simple combination of
306 elementary insertion operations on each of the indices, and
307 similarly for deletion. Hence, the most we can expect is a reduction
308 (or increase) of execution time by a roughly constant factor. As we
309 will see later, the reduction can be very significative for
310 <code>multi_index_container
</code>s with two or more indices.
313 <p>In the special case of
<code>multi_index_container
</code>s with only one index,
314 resulting performance will roughly match that of the STL equivalent containers:
315 tests show that there is at most a negligible degradation with respect to STL,
316 and even in some cases a small improvement.
319 <h2><a name=
"tests">Performance tests
</a></h2>
322 See
<a href=
"../perf/test_perf.cpp">source code
</a> used for measurements.
324 In order to assess the efficiency of
<code>multi_index_container
</code>, the following
329 <span class=identifier
>multi_index_container
</span><span class=special
><...
></span> <span class=identifier
>c
</span><span class=special
>;
</span>
330 <span class=keyword
>for
</span><span class=special
>(
</span><span class=keyword
>int
</span> <span class=identifier
>i
</span><span class=special
>=
</span><span class=number
>0</span><span class=special
>;
</span><span class=identifier
>i
</span><span class=special
><</span><span class=identifier
>n
</span><span class=special
>;++
</span><span class=identifier
>i
</span><span class=special
>)
</span><span class=identifier
>c
</span><span class=special
>.
</span><span class=identifier
>insert
</span><span class=special
>(
</span><span class=identifier
>i
</span><span class=special
>);
</span>
331 <span class=keyword
>for
</span><span class=special
>(
</span><span class=identifier
>iterator
</span> <span class=identifier
>it
</span><span class=special
>=
</span><span class=identifier
>c
</span><span class=special
>.
</span><span class=identifier
>begin
</span><span class=special
>();
</span><span class=identifier
>it
</span><span class=special
>!=
</span><span class=identifier
>c
</span><span class=special
>.
</span><span class=identifier
>end
</span><span class=special
>();)
</span><span class=identifier
>c
</span><span class=special
>.
</span><span class=identifier
>erase
</span><span class=special
>(
</span><span class=identifier
>it
</span><span class=special
>++);
</span>
335 has been measured for different instantiations of
<code>multi_index_container
</code>
336 at values of
<i>n
</i> 1,
000,
10,
000 and
100,
000,
337 and its execution time compared with that of the equivalent algorithm
338 for the corresponding manual simulation of the data structure based on
339 STL containers. The table below describes the test environments used.
343 <table cellspacing=
"0" cellpadding=
"5">
344 <caption><b>Tests environments.
</b></caption>
351 <td>GCC
3.4.5 (mingw special)
</td>
352 <td><code>-O3
</code></td>
353 <td>Windows
2000 Pro on P4
1.5 GHz,
256 MB RAM
</td>
356 <td>Intel C++
7.1</td>
357 <td>default release settings
</td>
358 <td>Windows
2000 Pro on P4
1.5 GHz,
256 MB RAM
</td>
361 <td>Microsoft Visual C++
8.0</td>
362 <td>default release settings,
<code>_SECURE_SCL=
0</code></td>
363 <td>Windows XP on P4 Xeon
3.2 GHz,
1 GB RAM
</td>
369 The relative memory consumption (i.e. the amount of memory allocated
370 by a
<code>multi_index_container
</code> with respect to its manual simulation)
371 is determined by dividing the size of a
<code>multi_index_container
</code> node
372 by the sum of node sizes of all the containers integrating the
373 simulating data structure.
376 <h3><a name=
"test_1r">Results for
1 ordered index
</a></h3>
379 The following instantiation of
<code>multi_index_container
</code> was tested:
383 <span class=identifier
>multi_index_container
</span><span class=special
><</span>
384 <span class=keyword
>int
</span><span class=special
>,
</span>
385 <span class=identifier
>indexed_by
</span><span class=special
><</span>
386 <span class=identifier
>ordered_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>></span>
387 <span class=special
>></span>
388 <span class=special
>></span>
392 which is functionally equivalent to
<code>std::set
<int
></code>.
395 <h4><a name=
"memory_1r">Memory consumption
</a></h4>
398 <table cellspacing=
"0">
400 <th width=
"33%">GCC
3.4.5</th>
401 <th width=
"33%">ICC
7.1</th>
402 <th width=
"33%">MSVC
8.0</th>
405 <td align=
"center">80%
</td>
406 <td align=
"center">80%
</td>
407 <td align=
"center">80%
</td>
410 <b>Table
1: Relative memory consumption of
<code>multi_index_container
</code> with
1
415 The reduction in memory usage is accounted for by the optimization technique implemented
416 in Boost.MultiIndex ordered indices, as
<a href=
"#spatial_efficiency">explained above
</a>.
419 <h4><a name=
"time_1r">Execution time
</a></h4>
422 <img src=
"perf_1o.png" alt=
"performance of multi_index_container with 1 ordered index"
423 width=
"556" height=
"372"><br>
424 <b>Fig.
1: Performance of
<code>multi_index_container
</code> with
1 ordered index.
</b>
428 Somewhat surprisingly,
<code>multi_index_container
</code> performs slightly
429 better than
<code>std::set
</code>. A very likely explanation for this behavior
430 is that the lower memory consumption of
<code>multi_index_container
</code>
431 results in a higher processor cache hit rate.
432 The improvement is smallest for GCC, presumably because the worse quality of
433 this compiler's optimizer masks the cache-related benefits.
436 <h3><a name=
"test_1s">Results for
1 sequenced index
</a></h3>
439 The following instantiation of
<code>multi_index_container
</code> was tested:
443 <span class=identifier
>multi_index_container
</span><span class=special
><</span>
444 <span class=keyword
>int
</span><span class=special
>,
</span>
445 <span class=identifier
>indexed_by
</span><span class=special
><</span>
446 <span class=identifier
>sequenced
</span><span class=special
><></span>
447 <span class=special
>></span>
448 <span class=special
>></span>
452 which is functionally equivalent to
<code>std::list
<int
></code>.
455 <h4><a name=
"memory_1s">Memory consumption
</a></h4>
458 <table cellspacing=
"0">
460 <th width=
"33%">GCC
3.4.5</th>
461 <th width=
"33%">ICC
7.1</th>
462 <th width=
"33%">MSVC
8.0</th>
465 <td align=
"center">100%
</td>
466 <td align=
"center">100%
</td>
467 <td align=
"center">100%
</td>
470 <b>Table
2: Relative memory consumption of
<code>multi_index_container
</code> with
1
475 The figures confirm that in this case
<code>multi_index_container
</code> nodes are the
476 same size than those of its
<code>std::list
</code> counterpart.
479 <h4><a name=
"time_1s">Execution time
</a></h4>
482 <img src=
"perf_1s.png" alt=
"performance of multi_index_container with 1 sequenced index"
483 width=
"556" height=
"372"><br>
484 <b>Fig.
2: Performance of
<code>multi_index_container
</code> with
1 sequenced index.
</b>
488 <code>multi_index_container
</code> does not attain the performance
489 of its STL counterpart, although the figures are close. Again, the worst results
490 are those of GCC, with a degradation of up to
7%, while ICC and MSVC do not
494 <h3><a name=
"test_2r">Results for
2 ordered indices
</a></h3>
497 The following instantiation of
<code>multi_index_container
</code> was tested:
501 <span class=identifier
>multi_index_container
</span><span class=special
><</span>
502 <span class=keyword
>int
</span><span class=special
>,
</span>
503 <span class=identifier
>indexed_by
</span><span class=special
><</span>
504 <span class=identifier
>ordered_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>>,
</span>
505 <span class=identifier
>ordered_non_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>></span>
506 <span class=special
>></span>
507 <span class=special
>></span>
510 <h4><a name=
"memory_2r">Memory consumption
</a></h4>
513 <table cellspacing=
"0">
515 <th width=
"33%">GCC
3.4.5</th>
516 <th width=
"33%">ICC
7.1</th>
517 <th width=
"33%">MSVC
8.0</th>
520 <td align=
"center">70%
</td>
521 <td align=
"center">70%
</td>
522 <td align=
"center">70%
</td>
525 <b>Table
3: Relative memory consumption of
<code>multi_index_container
</code> with
2
530 These results coincide with the theoretical formula for
531 <i>S
<sub>I
</sub></i> =
28,
<i>N
</i> =
<i>O
</i> =
2 and
<i>p
</i> =
<i>w
</i> =
4.
534 <h4><a name=
"time_2r">Execution time
</a></h4>
537 <img src=
"perf_2o.png" alt=
"performance of multi_index_container with 2 ordered indices"
538 width=
"556" height=
"372"><br>
539 <b>Fig.
3: Performance of
<code>multi_index_container
</code> with
2 ordered indices.
</b>
543 The experimental results confirm our hypothesis that
<code>multi_index_container
</code>
544 provides an improvement on execution time by an approximately constant factor,
545 which in this case lies around
60%. There is no obvious explanation for the
546 increased advantage of
<code>multi_index_container
</code> in MSVC for
547 <i>n
</i>=
10<sup>5</sup>.
550 <h3><a name=
"test_1r1s">Results for
1 ordered index +
1 sequenced index
</a></h3>
553 The following instantiation of
<code>multi_index_container
</code> was tested:
557 <span class=identifier
>multi_index_container
</span><span class=special
><</span>
558 <span class=keyword
>int
</span><span class=special
>,
</span>
559 <span class=identifier
>indexed_by
</span><span class=special
><</span>
560 <span class=identifier
>ordered_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>>,
</span>
561 <span class=identifier
>sequenced
</span><span class=special
><></span>
562 <span class=special
>></span>
563 <span class=special
>></span>
566 <h4><a name=
"memory_1r1s">Memory consumption
</a></h4>
569 <table cellspacing=
"0">
571 <th width=
"33%">GCC
3.4.5</th>
572 <th width=
"33%">ICC
7.1</th>
573 <th width=
"33%">MSVC
8.0</th>
576 <td align=
"center">75%
</td>
577 <td align=
"center">75%
</td>
578 <td align=
"center">75%
</td>
581 <b>Table
4: Relative memory consumption of
<code>multi_index_container
</code> with
1
582 ordered index +
1 sequenced index.
</b>
586 These results coincide with the theoretical formula for
587 <i>S
<sub>I
</sub></i> =
24,
<i>N
</i> =
2,
<i>O
</i> =
1 and
<i>p
</i> =
<i>w
</i> =
4.
590 <h4><a name=
"time_1r1s">Execution time
</a></h4>
593 <img src=
"perf_1o1s.png"
594 alt=
"performance of multi_index_container with 1 ordered index + 1 sequenced index"
595 width=
"556" height=
"372"><br>
596 <b>Fig.
4: Performance of
<code>multi_index_container
</code> with
1 ordered index
597 +
1 sequenced index.
</b>
601 For
<i>n
</i>=
10<sup>3</sup> and
<i>n
</i>=
10<sup>4</sup>, the results
602 are in agreement with our theoretical analysis, showing a constant factor
603 improvement of
50-
65% with respect to the STL-based manual simulation.
604 Curiously enough, this speedup gets even higher when
605 <i>n
</i>=
10<sup>5</sup> for two of the compilers, namely GCC and ICC.
606 In order to rule out spurious results, the tests
607 have been run many times, yielding similar outcomes. Both test environments
608 are deployed on the same machine, which points to some OS-related reason for
612 <h3><a name=
"test_3r">Results for
3 ordered indices
</a></h3>
615 The following instantiation of
<code>multi_index_container
</code> was tested:
619 <span class=identifier
>multi_index_container
</span><span class=special
><</span>
620 <span class=keyword
>int
</span><span class=special
>,
</span>
621 <span class=identifier
>indexed_by
</span><span class=special
><</span>
622 <span class=identifier
>ordered_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>>,
</span>
623 <span class=identifier
>ordered_non_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>>,
</span>
624 <span class=identifier
>ordered_non_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>></span>
625 <span class=special
>></span>
626 <span class=special
>></span>
629 <h4><a name=
"memory_3r">Memory consumption
</a></h4>
632 <table cellspacing=
"0">
634 <th width=
"33%">GCC
3.4.5</th>
635 <th width=
"33%">ICC
7.1</th>
636 <th width=
"33%">MSVC
8.0</th>
639 <td align=
"center">66.7%
</td>
640 <td align=
"center">66.7%
</td>
641 <td align=
"center">66.7%
</td>
644 <b>Table
5: Relative memory consumption of
<code>multi_index_container
</code> with
3
649 These results coincide with the theoretical formula for
650 <i>S
<sub>I
</sub></i> =
40,
<i>N
</i> =
<i>O
</i> =
3 and
<i>p
</i> =
<i>w
</i> =
4.
653 <h4><a name=
"time_3r">Execution time
</a></h4>
656 <img src=
"perf_3o.png" alt=
"performance of multi_index_container with 3 ordered indices"
657 width=
"556" height=
"372"><br>
658 <b>Fig.
5: Performance of
<code>multi_index_container
</code> with
3 ordered indices.
</b>
662 Execution time for this case is between
45% and
55% lower than achieved with
663 an STL-based manual simulation of the same data structure.
666 <h3><a name=
"test_2r1s">Results for
2 ordered indices +
1 sequenced index
</a></h3>
669 The following instantiation of
<code>multi_index_container
</code> was tested:
673 <span class=identifier
>multi_index_container
</span><span class=special
><</span>
674 <span class=keyword
>int
</span><span class=special
>,
</span>
675 <span class=identifier
>indexed_by
</span><span class=special
><</span>
676 <span class=identifier
>ordered_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>>,
</span>
677 <span class=identifier
>ordered_non_unique
</span><span class=special
><</span><span class=identifier
>identity
</span><span class=special
><</span><span class=keyword
>int
</span><span class=special
>></span> <span class=special
>>,
</span>
678 <span class=identifier
>sequenced
</span><span class=special
><></span>
679 <span class=special
>></span>
680 <span class=special
>></span>
683 <h4><a name=
"memory_2r1s">Memory consumption
</a></h4>
686 <table cellspacing=
"0">
688 <th width=
"33%">GCC
3.4.5</th>
689 <th width=
"33%">ICC
7.1</th>
690 <th width=
"33%">MSVC
8.0</th>
693 <td align=
"center">69.2%
</td>
694 <td align=
"center">69.2%
</td>
695 <td align=
"center">69.2%
</td>
698 <b>Table
6: Relative memory consumption of
<code>multi_index_container
</code> with
2
699 ordered indices +
1 sequenced index.
</b>
703 These results coincide with the theoretical formula for
704 <i>S
<sub>I
</sub></i> =
36,
<i>N
</i> =
3,
<i>O
</i> =
2 and
<i>p
</i> =
<i>w
</i> =
4.
707 <h4><a name=
"time_2r1s">Execution time
</a></h4>
710 <img src=
"perf_2o1s.png"
711 alt=
"performance of multi_index_container with 2 ordered indices + 1 sequenced index"
712 width=
"556" height=
"372"><br>
713 <b>Fig.
6: Performance of
<code>multi_index_container
</code> with
2 ordered indices
714 +
1 sequenced index.
</b>
718 In accordance to the expectations, execution time is improved by a fairly constant
719 factor, which ranges from
45% to
55%.
722 <h2><a name=
"conclusions">Conclusions
</a></h2>
725 We have shown that
<code>multi_index_container
</code> outperforms, both in space and
726 time efficiency, equivalent data structures obtained from the manual
727 combination of STL containers. This improvement gets larger when the number
732 In the special case of replacing standard containers with single-indexed
733 <code>multi_index_container
</code>s, the performance of Boost.MultiIndex
734 is comparable with that of the tested STL implementations, and can even yield
735 some improvements both in space consumption and execution time.
740 <div class=
"prev_link"><a href=
"compiler_specifics.html"><img src=
"prev.gif" alt=
"compiler specifics" border=
"0"><br>
743 <div class=
"up_link"><a href=
"index.html"><img src=
"up.gif" alt=
"index" border=
"0"><br>
746 <div class=
"next_link"><a href=
"examples.html"><img src=
"next.gif" alt=
"examples" border=
"0"><br>
748 </a></div><br clear=
"all" style=
"clear: all;">
752 <p>Revised November
24th
2015</p>
754 <p>© Copyright
2003-
2015 Joaqu
ín M L
ópez Mu
ñoz.
755 Distributed under the Boost Software
756 License, Version
1.0. (See accompanying file
<a href=
"../../../LICENSE_1_0.txt">
757 LICENSE_1_0.txt
</a> or copy at
<a href=
"http://www.boost.org/LICENSE_1_0.txt">
758 http://www.boost.org/LICENSE_1_0.txt
</a>)