]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libstdc++-v3/contrib/libstdc++-v3-4.7/doc/xml/manual/profile_mode.xml
update
[l4.git] / l4 / pkg / libstdc++-v3 / contrib / libstdc++-v3-4.7 / doc / xml / manual / profile_mode.xml
1 <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" 
2          xml:id="manual.ext.profile_mode" xreflabel="Profile Mode">
3 <?dbhtml filename="profile_mode.html"?>
4
5 <info><title>Profile Mode</title>
6   <keywordset>
7     <keyword>
8       C++
9     </keyword>
10     <keyword>
11       library
12     </keyword>
13     <keyword>
14       profile
15     </keyword>
16   </keywordset>
17 </info>
18
19
20
21
22 <section xml:id="manual.ext.profile_mode.intro" xreflabel="Intro"><info><title>Intro</title></info>
23   
24   <para>
25   <emphasis>Goal: </emphasis>Give performance improvement advice based on
26   recognition of suboptimal usage patterns of the standard library.
27   </para>
28
29   <para>
30   <emphasis>Method: </emphasis>Wrap the standard library code.  Insert
31   calls to an instrumentation library to record the internal state of
32   various components at interesting entry/exit points to/from the standard
33   library.  Process trace, recognize suboptimal patterns, give advice.
34   For details, see
35   <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://dx.doi.org/10.1109/CGO.2009.36">paper presented at
36    CGO 2009</link>.
37   </para>
38   <para>
39   <emphasis>Strengths: </emphasis>
40 <itemizedlist>
41   <listitem><para>
42   Unintrusive solution.  The application code does not require any
43   modification.
44   </para></listitem>
45   <listitem><para> The advice is call context sensitive, thus capable of
46   identifying precisely interesting dynamic performance behavior.
47   </para></listitem>
48   <listitem><para>
49   The overhead model is pay-per-view.  When you turn off a diagnostic class
50   at compile time, its overhead disappears.
51   </para></listitem>
52 </itemizedlist>
53   </para>
54   <para>
55   <emphasis>Drawbacks: </emphasis>
56 <itemizedlist>
57   <listitem><para>
58   You must recompile the application code with custom options.
59   </para></listitem>
60   <listitem><para>You must run the application on representative input.
61   The advice is input dependent.
62   </para></listitem>
63   <listitem><para>
64   The execution time will increase, in some cases by factors.
65   </para></listitem>
66 </itemizedlist>
67   </para>
68
69
70 <section xml:id="manual.ext.profile_mode.using" xreflabel="Using"><info><title>Using the Profile Mode</title></info>
71   
72
73   <para>
74   This is the anticipated common workflow for program <code>foo.cc</code>:
75 <programlisting>
76 $ cat foo.cc
77 #include &lt;vector&gt;
78 int main() {
79   vector&lt;int&gt; v;
80   for (int k = 0; k &lt; 1024; ++k) v.insert(v.begin(), k);
81 }
82
83 $ g++ -D_GLIBCXX_PROFILE foo.cc
84 $ ./a.out
85 $ cat libstdcxx-profile.txt
86 vector-to-list: improvement = 5: call stack = 0x804842c ...
87     : advice = change std::vector to std::list
88 vector-size: improvement = 3: call stack = 0x804842c ...
89     : advice = change initial container size from 0 to 1024
90 </programlisting>
91   </para>
92
93   <para>
94   Anatomy of a warning:
95   <itemizedlist>
96   <listitem>
97   <para>
98   Warning id.  This is a short descriptive string for the class
99   that this warning belongs to.  E.g., "vector-to-list".
100   </para>
101   </listitem>
102   <listitem>
103   <para>
104   Estimated improvement.  This is an approximation of the benefit expected
105   from implementing the change suggested by the warning.  It is given on
106   a log10 scale.  Negative values mean that the alternative would actually
107   do worse than the current choice.
108   In the example above, 5 comes from the fact that the overhead of
109   inserting at the beginning of a vector vs. a list is around 1024 * 1024 / 2,
110   which is around 10e5.  The improvement from setting the initial size to
111   1024 is in the range of 10e3, since the overhead of dynamic resizing is
112   linear in this case.
113   </para>
114   </listitem>
115   <listitem>
116   <para>
117   Call stack.  Currently, the addresses are printed without
118   symbol name or code location attribution.
119   Users are expected to postprocess the output using, for instance, addr2line.
120   </para>
121   </listitem>
122   <listitem>
123   <para>
124   The warning message.  For some warnings, this is static text, e.g.,
125   "change vector to list".  For other warnings, such as the one above,
126   the message contains numeric advice, e.g., the suggested initial size
127   of the vector.
128   </para>
129   </listitem>
130   </itemizedlist>
131   </para>
132
133   <para>Three files are generated.  <code>libstdcxx-profile.txt</code>
134    contains human readable advice.  <code>libstdcxx-profile.raw</code>
135    contains implementation specific data about each diagnostic.
136    Their format is not documented.  They are sufficient to generate
137    all the advice given in <code>libstdcxx-profile.txt</code>.  The advantage
138    of keeping this raw format is that traces from multiple executions can
139    be aggregated simply by concatenating the raw traces.  We intend to
140    offer an external utility program that can issue advice from a trace.
141    <code>libstdcxx-profile.conf.out</code> lists the actual diagnostic
142    parameters used.  To alter parameters, edit this file and rename it to
143    <code>libstdcxx-profile.conf</code>.
144   </para>
145
146   <para>Advice is given regardless whether the transformation is valid.
147   For instance, we advise changing a map to an unordered_map even if the
148   application semantics require that data be ordered.
149   We believe such warnings can help users understand the performance
150   behavior of their application better, which can lead to changes
151   at a higher abstraction level.
152   </para>
153
154 </section>
155
156 <section xml:id="manual.ext.profile_mode.tuning" xreflabel="Tuning"><info><title>Tuning the Profile Mode</title></info>
157   
158
159   <para>Compile time switches and environment variables (see also file
160    profiler.h).  Unless specified otherwise, they can be set at compile time
161    using -D_&lt;name&gt; or by setting variable &lt;name&gt;
162    in the environment where the program is run, before starting execution.
163   <itemizedlist>
164   <listitem><para>
165    <code>_GLIBCXX_PROFILE_NO_&lt;diagnostic&gt;</code>:
166    disable specific diagnostics.
167    See section Diagnostics for possible values.
168    (Environment variables not supported.)
169    </para></listitem>
170   <listitem><para>
171    <code>_GLIBCXX_PROFILE_TRACE_PATH_ROOT</code>: set an alternative root
172    path for the output files.
173    </para></listitem>
174   <listitem><para>_GLIBCXX_PROFILE_MAX_WARN_COUNT: set it to the maximum
175    number of warnings desired.  The default value is 10.</para></listitem>
176   <listitem><para>
177    <code>_GLIBCXX_PROFILE_MAX_STACK_DEPTH</code>: if set to 0,
178    the advice will
179    be collected and reported for the program as a whole, and not for each
180    call context.
181    This could also be used in continuous regression tests, where you
182    just need to know whether there is a regression or not.
183    The default value is 32.
184    </para></listitem>
185   <listitem><para>
186    <code>_GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC</code>:
187    set a limit on how much memory to use for the accounting tables for each
188    diagnostic type.  When this limit is reached, new events are ignored
189    until the memory usage decreases under the limit.  Generally, this means
190    that newly created containers will not be instrumented until some
191    live containers are deleted.  The default is 128 MB.
192    </para></listitem>
193   <listitem><para>
194    <code>_GLIBCXX_PROFILE_NO_THREADS</code>:
195    Make the library not use threads.  If thread local storage (TLS) is not
196    available, you will get a preprocessor error asking you to set
197    -D_GLIBCXX_PROFILE_NO_THREADS if your program is single-threaded.
198    Multithreaded execution without TLS is not supported.
199    (Environment variable not supported.)
200    </para></listitem>
201   <listitem><para>
202    <code>_GLIBCXX_HAVE_EXECINFO_H</code>:
203    This name should be defined automatically at library configuration time.
204    If your library was configured without <code>execinfo.h</code>, but
205    you have it in your include path, you can define it explicitly.  Without
206    it, advice is collected for the program as a whole, and not for each
207    call context.
208    (Environment variable not supported.)
209    </para></listitem>
210   </itemizedlist>
211   </para>
212
213 </section>
214
215 </section>
216
217
218 <section xml:id="manual.ext.profile_mode.design" xreflabel="Design"><info><title>Design</title></info>
219   
220
221 <para>
222 </para>
223 <table frame="all">
224 <title>Profile Code Location</title>
225
226 <tgroup cols="2" align="left" colsep="1" rowsep="1">
227 <colspec colname="c1"/>
228 <colspec colname="c2"/>
229
230 <thead>
231   <row>
232     <entry>Code Location</entry>
233     <entry>Use</entry>
234   </row>
235 </thead>
236 <tbody>
237   <row>
238     <entry><code>libstdc++-v3/include/std/*</code></entry>
239     <entry>Preprocessor code to redirect to profile extension headers.</entry>
240   </row>
241   <row>
242     <entry><code>libstdc++-v3/include/profile/*</code></entry>
243     <entry>Profile extension public headers (map, vector, ...).</entry>
244   </row>
245   <row>
246     <entry><code>libstdc++-v3/include/profile/impl/*</code></entry>
247     <entry>Profile extension internals.  Implementation files are
248      only included from <code>impl/profiler.h</code>, which is the only
249      file included from the public headers.</entry>
250   </row>
251 </tbody>
252 </tgroup>
253 </table>
254
255 <para>
256 </para>
257
258 <section xml:id="manual.ext.profile_mode.design.wrapper" xreflabel="Wrapper"><info><title>Wrapper Model</title></info>
259
260   <para>
261   In order to get our instrumented library version included instead of the
262   release one,
263   we use the same wrapper model as the debug mode.
264   We subclass entities from the release version.  Wherever
265   <code>_GLIBCXX_PROFILE</code> is defined, the release namespace is
266   <code>std::__norm</code>, whereas the profile namespace is
267   <code>std::__profile</code>.  Using plain <code>std</code> translates
268   into <code>std::__profile</code>.
269   </para>
270   <para>
271   Whenever possible, we try to wrap at the public interface level, e.g.,
272   in <code>unordered_set</code> rather than in <code>hashtable</code>,
273   in order not to depend on implementation.
274   </para>
275   <para>
276   Mixing object files built with and without the profile mode must
277   not affect the program execution.  However, there are no guarantees to
278   the accuracy of diagnostics when using even a single object not built with
279   <code>-D_GLIBCXX_PROFILE</code>.
280   Currently, mixing the profile mode with debug and parallel extensions is
281   not allowed.  Mixing them at compile time will result in preprocessor errors.
282   Mixing them at link time is undefined.
283   </para>
284 </section>
285
286
287 <section xml:id="manual.ext.profile_mode.design.instrumentation" xreflabel="Instrumentation"><info><title>Instrumentation</title></info>
288
289   <para>
290   Instead of instrumenting every public entry and exit point,
291   we chose to add instrumentation on demand, as needed
292   by individual diagnostics.
293   The main reason is that some diagnostics require us to extract bits of
294   internal state that are particular only to that diagnostic.
295   We plan to formalize this later, after we learn more about the requirements
296   of several diagnostics.
297   </para>
298   <para>
299   All the instrumentation points can be switched on and off using
300   <code>-D[_NO]_GLIBCXX_PROFILE_&lt;diagnostic&gt;</code> options.
301   With all the instrumentation calls off, there should be negligible
302   overhead over the release version.  This property is needed to support
303   diagnostics based on timing of internal operations.  For such diagnostics,
304   we anticipate turning most of the instrumentation off in order to prevent
305   profiling overhead from polluting time measurements, and thus diagnostics.
306   </para>
307   <para>
308   All the instrumentation on/off compile time switches live in
309   <code>include/profile/profiler.h</code>.
310   </para>
311 </section>
312
313
314 <section xml:id="manual.ext.profile_mode.design.rtlib" xreflabel="Run Time Behavior"><info><title>Run Time Behavior</title></info>
315
316   <para>
317   For practical reasons, the instrumentation library processes the trace
318   partially
319   rather than dumping it to disk in raw form.  Each event is processed when
320   it occurs.  It is usually attached a cost and it is aggregated into
321   the database of a specific diagnostic class.  The cost model
322   is based largely on the standard performance guarantees, but in some
323   cases we use knowledge about GCC's standard library implementation.
324   </para>
325   <para>
326   Information is indexed by (1) call stack and (2) instance id or address
327   to be able to understand and summarize precise creation-use-destruction
328   dynamic chains.  Although the analysis is sensitive to dynamic instances,
329   the reports are only sensitive to call context.  Whenever a dynamic instance
330   is destroyed, we accumulate its effect to the corresponding entry for the
331   call stack of its constructor location.
332   </para>
333
334   <para>
335   For details, see
336    <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://dx.doi.org/10.1109/CGO.2009.36">paper presented at
337    CGO 2009</link>.
338   </para>
339 </section>
340
341
342 <section xml:id="manual.ext.profile_mode.design.analysis" xreflabel="Analysis and Diagnostics"><info><title>Analysis and Diagnostics</title></info>
343
344   <para>
345   Final analysis takes place offline, and it is based entirely on the
346   generated trace and debugging info in the application binary.
347   See section Diagnostics for a list of analysis types that we plan to support.
348   </para>
349   <para>
350   The input to the analysis is a table indexed by profile type and call stack.
351   The data type for each entry depends on the profile type.
352   </para>
353 </section>
354
355
356 <section xml:id="manual.ext.profile_mode.design.cost-model" xreflabel="Cost Model"><info><title>Cost Model</title></info>
357
358   <para>
359   While it is likely that cost models become complex as we get into
360   more sophisticated analysis, we will try to follow a simple set of rules
361   at the beginning.
362   </para>
363 <itemizedlist>
364   <listitem><para><emphasis>Relative benefit estimation:</emphasis>
365   The idea is to estimate or measure the cost of all operations
366   in the original scenario versus the scenario we advise to switch to.
367   For instance, when advising to change a vector to a list, an occurrence
368   of the <code>insert</code> method will generally count as a benefit.
369   Its magnitude depends on (1) the number of elements that get shifted
370   and (2) whether it triggers a reallocation.
371   </para></listitem>
372   <listitem><para><emphasis>Synthetic measurements:</emphasis>
373   We will measure the relative difference between similar operations on
374   different containers.  We plan to write a battery of small tests that
375   compare the times of the executions of similar methods on different
376   containers.  The idea is to run these tests on the target machine.
377   If this training phase is very quick, we may decide to perform it at
378   library initialization time.  The results can be cached on disk and reused
379   across runs.
380   </para></listitem>
381   <listitem><para><emphasis>Timers:</emphasis>
382   We plan to use timers for operations of larger granularity, such as sort.
383   For instance, we can switch between different sort methods on the fly
384   and report the one that performs best for each call context.
385   </para></listitem>
386   <listitem><para><emphasis>Show stoppers:</emphasis>
387   We may decide that the presence of an operation nullifies the advice.
388   For instance, when considering switching from <code>set</code> to
389   <code>unordered_set</code>, if we detect use of operator <code>++</code>,
390   we will simply not issue the advice, since this could signal that the use
391   care require a sorted container.</para></listitem>
392 </itemizedlist>
393
394 </section>
395
396
397 <section xml:id="manual.ext.profile_mode.design.reports" xreflabel="Reports"><info><title>Reports</title></info>
398
399   <para>
400 There are two types of reports.  First, if we recognize a pattern for which
401 we have a substitute that is likely to give better performance, we print
402 the advice and estimated performance gain.  The advice is usually associated
403 to a code position and possibly a call stack.
404   </para>
405   <para>
406 Second, we report performance characteristics for which we do not have
407 a clear solution for improvement.  For instance, we can point to the user
408 the top 10 <code>multimap</code> locations
409 which have the worst data locality in actual traversals.
410 Although this does not offer a solution,
411 it helps the user focus on the key problems and ignore the uninteresting ones.
412   </para>
413 </section>
414
415
416 <section xml:id="manual.ext.profile_mode.design.testing" xreflabel="Testing"><info><title>Testing</title></info>
417
418   <para>
419   First, we want to make sure we preserve the behavior of the release mode.
420   You can just type <code>"make check-profile"</code>, which
421   builds and runs the whole test suite in profile mode.
422   </para>
423   <para>
424   Second, we want to test the correctness of each diagnostic.
425   We created a <code>profile</code> directory in the test suite.
426   Each diagnostic must come with at least two tests, one for false positives
427   and one for false negatives.
428   </para>
429 </section>
430
431 </section>
432
433 <section xml:id="manual.ext.profile_mode.api" xreflabel="API"><info><title>Extensions for Custom Containers</title></info>
434
435
436   <para>
437   Many large projects use their own data structures instead of the ones in the
438   standard library.  If these data structures are similar in functionality
439   to the standard library, they can be instrumented with the same hooks
440   that are used to instrument the standard library.
441   The instrumentation API is exposed in file
442   <code>profiler.h</code> (look for "Instrumentation hooks").
443   </para>
444
445 </section>
446
447
448 <section xml:id="manual.ext.profile_mode.cost_model" xreflabel="Cost Model"><info><title>Empirical Cost Model</title></info>
449
450
451   <para>
452   Currently, the cost model uses formulas with predefined relative weights
453   for alternative containers or container implementations.  For instance,
454   iterating through a vector is X times faster than iterating through a list.
455   </para>
456   <para>
457   (Under development.)
458   We are working on customizing this to a particular machine by providing
459   an automated way to compute the actual relative weights for operations
460   on the given machine.
461   </para>
462   <para>
463   (Under development.)
464   We plan to provide a performance parameter database format that can be
465   filled in either by hand or by an automated training mechanism.
466   The analysis module will then use this database instead of the built in.
467   generic parameters.
468   </para>
469
470 </section>
471
472
473 <section xml:id="manual.ext.profile_mode.implementation" xreflabel="Implementation"><info><title>Implementation Issues</title></info>
474
475
476
477 <section xml:id="manual.ext.profile_mode.implementation.stack" xreflabel="Stack Traces"><info><title>Stack Traces</title></info>
478
479   <para>
480   Accurate stack traces are needed during profiling since we group events by
481   call context and dynamic instance.  Without accurate traces, diagnostics
482   may be hard to interpret.  For instance, when giving advice to the user
483   it is imperative to reference application code, not library code.
484   </para>
485   <para>
486   Currently we are using the libc <code>backtrace</code> routine to get
487   stack traces.
488   <code>_GLIBCXX_PROFILE_STACK_DEPTH</code> can be set
489   to 0 if you are willing to give up call context information, or to a small
490   positive value to reduce run time overhead.
491   </para>
492 </section>
493
494
495 <section xml:id="manual.ext.profile_mode.implementation.symbols" xreflabel="Symbolization"><info><title>Symbolization of Instruction Addresses</title></info>
496
497   <para>
498   The profiling and analysis phases use only instruction addresses.
499   An external utility such as addr2line is needed to postprocess the result.
500   We do not plan to add symbolization support in the profile extension.
501   This would require access to symbol tables, debug information tables,
502   external programs or libraries and other system dependent information.
503   </para>
504 </section>
505
506
507 <section xml:id="manual.ext.profile_mode.implementation.concurrency" xreflabel="Concurrency"><info><title>Concurrency</title></info>
508
509   <para>
510   Our current model is simplistic, but precise.
511   We cannot afford to approximate because some of our diagnostics require
512   precise matching of operations to container instance and call context.
513   During profiling, we keep a single information table per diagnostic.
514   There is a single lock per information table.
515   </para>
516 </section>
517
518
519 <section xml:id="manual.ext.profile_mode.implementation.stdlib-in-proflib" xreflabel="Using the Standard Library in the Runtime Library"><info><title>Using the Standard Library in the Instrumentation Implementation</title></info>
520
521   <para>
522   As much as we would like to avoid uses of libstdc++ within our
523   instrumentation library, containers such as unordered_map are very
524   appealing.  We plan to use them as long as they are named properly
525   to avoid ambiguity.
526   </para>
527 </section>
528
529
530 <section xml:id="manual.ext.profile_mode.implementation.malloc-hooks" xreflabel="Malloc Hooks"><info><title>Malloc Hooks</title></info>
531
532   <para>
533   User applications/libraries can provide malloc hooks.
534   When the implementation of the malloc hooks uses stdlibc++, there can
535   be an infinite cycle between the profile mode instrumentation and the
536   malloc hook code.
537   </para>
538   <para>
539   We protect against reentrance to the profile mode instrumentation code,
540   which should avoid this problem in most cases.
541   The protection mechanism is thread safe and exception safe.
542   This mechanism does not prevent reentrance to the malloc hook itself,
543   which could still result in deadlock, if, for instance, the malloc hook
544   uses non-recursive locks.
545   XXX: A definitive solution to this problem would be for the profile extension
546   to use a custom allocator internally, and perhaps not to use libstdc++.
547   </para>
548 </section>
549
550
551 <section xml:id="manual.ext.profile_mode.implementation.construction-destruction" xreflabel="Construction and Destruction of Global Objects"><info><title>Construction and Destruction of Global Objects</title></info>
552
553   <para>
554   The profiling library state is initialized at the first call to a profiling
555   method.  This allows us to record the construction of all global objects.
556   However, we cannot do the same at destruction time.  The trace is written
557   by a function registered by <code>atexit</code>, thus invoked by
558   <code>exit</code>.
559   </para>
560 </section>
561
562 </section>
563
564
565 <section xml:id="manual.ext.profile_mode.developer" xreflabel="Developer Information"><info><title>Developer Information</title></info>
566
567
568 <section xml:id="manual.ext.profile_mode.developer.bigpic" xreflabel="Big Picture"><info><title>Big Picture</title></info>
569
570
571   <para>The profile mode headers are included with
572    <code>-D_GLIBCXX_PROFILE</code> through preprocessor directives in
573    <code>include/std/*</code>.
574   </para>
575
576   <para>Instrumented implementations are provided in
577    <code>include/profile/*</code>.  All instrumentation hooks are macros
578    defined in <code>include/profile/profiler.h</code>.
579   </para>
580
581   <para>All the implementation of the instrumentation hooks is in
582    <code>include/profile/impl/*</code>.  Although all the code gets included,
583    thus is publicly visible, only a small number of functions are called from
584    outside this directory.  All calls to hook implementations must be
585    done through macros defined in <code>profiler.h</code>.  The macro
586    must ensure (1) that the call is guarded against reentrance and
587    (2) that the call can be turned off at compile time using a
588    <code>-D_GLIBCXX_PROFILE_...</code> compiler option.
589   </para>
590
591 </section>
592
593 <section xml:id="manual.ext.profile_mode.developer.howto" xreflabel="How To Add A Diagnostic"><info><title>How To Add A Diagnostic</title></info>
594
595
596   <para>Let's say the diagnostic name is "magic".
597   </para>
598
599   <para>If you need to instrument a header not already under
600    <code>include/profile/*</code>, first edit the corresponding header
601    under <code>include/std/</code> and add a preprocessor directive such
602    as the one in <code>include/std/vector</code>:
603 <programlisting>
604 #ifdef _GLIBCXX_PROFILE
605 # include &lt;profile/vector&gt;
606 #endif
607 </programlisting>
608   </para>
609
610   <para>If the file you need to instrument is not yet under
611    <code>include/profile/</code>, make a copy of the one in
612    <code>include/debug</code>, or the main implementation.
613    You'll need to include the main implementation and inherit the classes
614    you want to instrument.  Then define the methods you want to instrument,
615    define the instrumentation hooks and add calls to them.
616    Look at <code>include/profile/vector</code> for an example.
617   </para>
618
619   <para>Add macros for the instrumentation hooks in
620    <code>include/profile/impl/profiler.h</code>.
621    Hook names must start with <code>__profcxx_</code>.
622    Make sure they transform
623    in no code with <code>-D_NO_GLBICXX_PROFILE_MAGIC</code>.
624    Make sure all calls to any method in namespace <code>__gnu_profile</code>
625    is protected against reentrance using macro
626    <code>_GLIBCXX_PROFILE_REENTRANCE_GUARD</code>.
627    All names of methods in namespace <code>__gnu_profile</code> called from
628    <code>profiler.h</code> must start with <code>__trace_magic_</code>.
629   </para>
630
631   <para>Add the implementation of the diagnostic.
632    <itemizedlist>
633      <listitem><para>
634       Create new file <code>include/profile/impl/profiler_magic.h</code>.
635      </para></listitem>
636      <listitem><para>
637       Define class <code>__magic_info: public __object_info_base</code>.
638       This is the representation of a line in the object table.
639       The <code>__merge</code> method is used to aggregate information
640       across all dynamic instances created at the same call context.
641       The <code>__magnitude</code> must return the estimation of the benefit
642       as a number of small operations, e.g., number of words copied.
643       The <code>__write</code> method is used to produce the raw trace.
644       The <code>__advice</code> method is used to produce the advice string.
645      </para></listitem>
646      <listitem><para>
647       Define class <code>__magic_stack_info: public __magic_info</code>.
648       This defines the content of a line in the stack table.
649      </para></listitem>
650      <listitem><para>
651       Define class <code>__trace_magic: public __trace_base&lt;__magic_info,
652       __magic_stack_info&gt;</code>.
653       It defines the content of the trace associated with this diagnostic.
654      </para></listitem>
655     </itemizedlist>
656   </para>
657
658   <para>Add initialization and reporting calls in
659    <code>include/profile/impl/profiler_trace.h</code>.  Use
660    <code>__trace_vector_to_list</code> as an example.
661   </para>
662
663   <para>Add documentation in file <code>doc/xml/manual/profile_mode.xml</code>.
664   </para>
665 </section>
666 </section>
667
668 <section xml:id="manual.ext.profile_mode.diagnostics"><info><title>Diagnostics</title></info>
669
670
671   <para>
672   The table below presents all the diagnostics we intend to implement.
673   Each diagnostic has a corresponding compile time switch
674   <code>-D_GLIBCXX_PROFILE_&lt;diagnostic&gt;</code>.
675   Groups of related diagnostics can be turned on with a single switch.
676   For instance, <code>-D_GLIBCXX_PROFILE_LOCALITY</code> is equivalent to
677   <code>-D_GLIBCXX_PROFILE_SOFTWARE_PREFETCH
678   -D_GLIBCXX_PROFILE_RBTREE_LOCALITY</code>.
679   </para>
680
681   <para>
682   The benefit, cost, expected frequency and accuracy of each diagnostic
683   was given a grade from 1 to 10, where 10 is highest.
684   A high benefit means that, if the diagnostic is accurate, the expected
685   performance improvement is high.
686   A high cost means that turning this diagnostic on leads to high slowdown.
687   A high frequency means that we expect this to occur relatively often.
688   A high accuracy means that the diagnostic is unlikely to be wrong.
689   These grades are not perfect.  They are just meant to guide users with
690   specific needs or time budgets.
691   </para>
692
693 <table frame="all">
694 <title>Profile Diagnostics</title>
695
696 <tgroup cols="7" align="left" colsep="1" rowsep="1">
697 <colspec colname="c1"/>
698 <colspec colname="c2"/>
699 <colspec colname="c3"/>
700 <colspec colname="c4"/>
701 <colspec colname="c5"/>
702 <colspec colname="c6"/>
703 <colspec colname="c7"/>
704
705 <thead>
706   <row>
707     <entry>Group</entry>
708     <entry>Flag</entry>
709     <entry>Benefit</entry>
710     <entry>Cost</entry>
711     <entry>Freq.</entry>
712     <entry>Implemented</entry>
713   </row>
714 </thead>
715 <tbody>
716   <row>
717     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.containers">
718     CONTAINERS</link></entry>
719     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.hashtable_too_small">
720     HASHTABLE_TOO_SMALL</link></entry>
721     <entry>10</entry>
722     <entry>1</entry>
723     <entry/>
724     <entry>10</entry>
725     <entry>yes</entry>
726   </row>
727   <row>
728     <entry/>
729     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.hashtable_too_large">
730     HASHTABLE_TOO_LARGE</link></entry>
731     <entry>5</entry>
732     <entry>1</entry>
733     <entry/>
734     <entry>10</entry>
735     <entry>yes</entry>
736   </row>
737   <row>
738     <entry/>
739     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.inefficient_hash">
740     INEFFICIENT_HASH</link></entry>
741     <entry>7</entry>
742     <entry>3</entry>
743     <entry/>
744     <entry>10</entry>
745     <entry>yes</entry>
746   </row>
747   <row>
748     <entry/>
749     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.vector_too_small">
750     VECTOR_TOO_SMALL</link></entry>
751     <entry>8</entry>
752     <entry>1</entry>
753     <entry/>
754     <entry>10</entry>
755     <entry>yes</entry>
756   </row>
757   <row>
758     <entry/>
759     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.vector_too_large">
760     VECTOR_TOO_LARGE</link></entry>
761     <entry>5</entry>
762     <entry>1</entry>
763     <entry/>
764     <entry>10</entry>
765     <entry>yes</entry>
766   </row>
767   <row>
768     <entry/>
769     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.vector_to_hashtable">
770     VECTOR_TO_HASHTABLE</link></entry>
771     <entry>7</entry>
772     <entry>7</entry>
773     <entry/>
774     <entry>10</entry>
775     <entry>no</entry>
776   </row>
777   <row>
778     <entry/>
779     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.hashtable_to_vector">
780     HASHTABLE_TO_VECTOR</link></entry>
781     <entry>7</entry>
782     <entry>7</entry>
783     <entry/>
784     <entry>10</entry>
785     <entry>no</entry>
786   </row>
787   <row>
788     <entry/>
789     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.vector_to_list">
790     VECTOR_TO_LIST</link></entry>
791     <entry>8</entry>
792     <entry>5</entry>
793     <entry/>
794     <entry>10</entry>
795     <entry>yes</entry>
796   </row>
797   <row>
798     <entry/>
799     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.list_to_vector">
800     LIST_TO_VECTOR</link></entry>
801     <entry>10</entry>
802     <entry>5</entry>
803     <entry/>
804     <entry>10</entry>
805     <entry>no</entry>
806   </row>
807   <row>
808     <entry/>
809     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.assoc_ord_to_unord">
810     ORDERED_TO_UNORDERED</link></entry>
811     <entry>10</entry>
812     <entry>5</entry>
813     <entry/>
814     <entry>10</entry>
815     <entry>only map/unordered_map</entry>
816   </row>
817   <row>
818     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.algorithms">
819     ALGORITHMS</link></entry>
820     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.algorithms.sort">
821     SORT</link></entry>
822     <entry>7</entry>
823     <entry>8</entry>
824     <entry/>
825     <entry>7</entry>
826     <entry>no</entry>
827   </row>
828   <row>
829     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.locality">
830     LOCALITY</link></entry>
831     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.locality.sw_prefetch">
832     SOFTWARE_PREFETCH</link></entry>
833     <entry>8</entry>
834     <entry>8</entry>
835     <entry/>
836     <entry>5</entry>
837     <entry>no</entry>
838   </row>
839   <row>
840     <entry/>
841     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.locality.linked">
842     RBTREE_LOCALITY</link></entry>
843     <entry>4</entry>
844     <entry>8</entry>
845     <entry/>
846     <entry>5</entry>
847     <entry>no</entry>
848   </row>
849   <row>
850     <entry/>
851     <entry><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#manual.ext.profile_mode.analysis.mthread.false_share">
852     FALSE_SHARING</link></entry>
853     <entry>8</entry>
854     <entry>10</entry>
855     <entry/>
856     <entry>10</entry>
857     <entry>no</entry>
858   </row>
859 </tbody>
860 </tgroup>
861 </table>
862
863 <section xml:id="manual.ext.profile_mode.analysis.template" xreflabel="Template"><info><title>Diagnostic Template</title></info>
864
865 <itemizedlist>
866   <listitem><para><emphasis>Switch:</emphasis>
867   <code>_GLIBCXX_PROFILE_&lt;diagnostic&gt;</code>.
868   </para></listitem>
869   <listitem><para><emphasis>Goal:</emphasis>  What problem will it diagnose?
870   </para></listitem>
871   <listitem><para><emphasis>Fundamentals:</emphasis>.
872   What is the fundamental reason why this is a problem</para></listitem>
873   <listitem><para><emphasis>Sample runtime reduction:</emphasis>
874   Percentage reduction in execution time.  When reduction is more than
875   a constant factor, describe the reduction rate formula.
876   </para></listitem>
877   <listitem><para><emphasis>Recommendation:</emphasis>
878   What would the advise look like?</para></listitem>
879   <listitem><para><emphasis>To instrument:</emphasis>
880   What stdlibc++ components need to be instrumented?</para></listitem>
881   <listitem><para><emphasis>Analysis:</emphasis>
882   How do we decide when to issue the advice?</para></listitem>
883   <listitem><para><emphasis>Cost model:</emphasis>
884   How do we measure benefits?  Math goes here.</para></listitem>
885   <listitem><para><emphasis>Example:</emphasis>
886 <programlisting>
887 program code
888 ...
889 advice sample
890 </programlisting>
891 </para></listitem>
892 </itemizedlist>
893 </section>
894
895
896 <section xml:id="manual.ext.profile_mode.analysis.containers" xreflabel="Containers"><info><title>Containers</title></info>
897
898
899 <para>
900 <emphasis>Switch:</emphasis>
901   <code>_GLIBCXX_PROFILE_CONTAINERS</code>.
902 </para>
903
904 <section xml:id="manual.ext.profile_mode.analysis.hashtable_too_small" xreflabel="Hashtable Too Small"><info><title>Hashtable Too Small</title></info>
905
906 <itemizedlist>
907   <listitem><para><emphasis>Switch:</emphasis>
908   <code>_GLIBCXX_PROFILE_HASHTABLE_TOO_SMALL</code>.
909   </para></listitem>
910   <listitem><para><emphasis>Goal:</emphasis> Detect hashtables with many
911   rehash operations, small construction size and large destruction size.
912   </para></listitem>
913   <listitem><para><emphasis>Fundamentals:</emphasis> Rehash is very expensive.
914   Read content, follow chains within bucket, evaluate hash function, place at
915   new location in different order.</para></listitem>
916   <listitem><para><emphasis>Sample runtime reduction:</emphasis> 36%.
917   Code similar to example below.
918   </para></listitem>
919   <listitem><para><emphasis>Recommendation:</emphasis>
920   Set initial size to N at construction site S.
921   </para></listitem>
922   <listitem><para><emphasis>To instrument:</emphasis>
923   <code>unordered_set, unordered_map</code> constructor, destructor, rehash.
924   </para></listitem>
925   <listitem><para><emphasis>Analysis:</emphasis>
926   For each dynamic instance of <code>unordered_[multi]set|map</code>,
927   record initial size and call context of the constructor.
928   Record size increase, if any, after each relevant operation such as insert.
929   Record the estimated rehash cost.</para></listitem>
930   <listitem><para><emphasis>Cost model:</emphasis>
931   Number of individual rehash operations * cost per rehash.</para></listitem>
932   <listitem><para><emphasis>Example:</emphasis>
933 <programlisting>
934 1 unordered_set&lt;int&gt; us;
935 2 for (int k = 0; k &lt; 1000000; ++k) {
936 3   us.insert(k);
937 4 }
938
939 foo.cc:1: advice: Changing initial unordered_set size from 10 to 1000000 saves 1025530 rehash operations.
940 </programlisting>
941 </para></listitem>
942 </itemizedlist>
943 </section>
944
945
946 <section xml:id="manual.ext.profile_mode.analysis.hashtable_too_large" xreflabel="Hashtable Too Large"><info><title>Hashtable Too Large</title></info>
947
948 <itemizedlist>
949   <listitem><para><emphasis>Switch:</emphasis>
950   <code>_GLIBCXX_PROFILE_HASHTABLE_TOO_LARGE</code>.
951   </para></listitem>
952   <listitem><para><emphasis>Goal:</emphasis> Detect hashtables which are
953   never filled up because fewer elements than reserved are ever
954   inserted.
955   </para></listitem>
956   <listitem><para><emphasis>Fundamentals:</emphasis> Save memory, which
957   is good in itself and may also improve memory reference performance through
958   fewer cache and TLB misses.</para></listitem>
959   <listitem><para><emphasis>Sample runtime reduction:</emphasis> unknown.
960   </para></listitem>
961   <listitem><para><emphasis>Recommendation:</emphasis>
962   Set initial size to N at construction site S.
963   </para></listitem>
964   <listitem><para><emphasis>To instrument:</emphasis>
965   <code>unordered_set, unordered_map</code> constructor, destructor, rehash.
966   </para></listitem>
967   <listitem><para><emphasis>Analysis:</emphasis>
968   For each dynamic instance of <code>unordered_[multi]set|map</code>,
969   record initial size and call context of the constructor, and correlate it
970   with its size at destruction time.
971   </para></listitem>
972   <listitem><para><emphasis>Cost model:</emphasis>
973   Number of iteration operations + memory saved.</para></listitem>
974   <listitem><para><emphasis>Example:</emphasis>
975 <programlisting>
976 1 vector&lt;unordered_set&lt;int&gt;&gt; v(100000, unordered_set&lt;int&gt;(100)) ;
977 2 for (int k = 0; k &lt; 100000; ++k) {
978 3   for (int j = 0; j &lt; 10; ++j) {
979 4     v[k].insert(k + j);
980 5  }
981 6 }
982
983 foo.cc:1: advice: Changing initial unordered_set size from 100 to 10 saves N
984 bytes of memory and M iteration steps.
985 </programlisting>
986 </para></listitem>
987 </itemizedlist>
988 </section>
989
990 <section xml:id="manual.ext.profile_mode.analysis.inefficient_hash" xreflabel="Inefficient Hash"><info><title>Inefficient Hash</title></info>
991
992 <itemizedlist>
993   <listitem><para><emphasis>Switch:</emphasis>
994   <code>_GLIBCXX_PROFILE_INEFFICIENT_HASH</code>.
995   </para></listitem>
996   <listitem><para><emphasis>Goal:</emphasis> Detect hashtables with polarized
997   distribution.
998   </para></listitem>
999   <listitem><para><emphasis>Fundamentals:</emphasis> A non-uniform
1000   distribution may lead to long chains, thus possibly increasing complexity
1001   by a factor up to the number of elements.
1002   </para></listitem>
1003   <listitem><para><emphasis>Sample runtime reduction:</emphasis> factor up
1004    to container size.
1005   </para></listitem>
1006   <listitem><para><emphasis>Recommendation:</emphasis> Change hash function
1007   for container built at site S.  Distribution score = N.  Access score = S.
1008   Longest chain = C, in bucket B.
1009   </para></listitem>
1010   <listitem><para><emphasis>To instrument:</emphasis>
1011   <code>unordered_set, unordered_map</code> constructor, destructor, [],
1012   insert, iterator.
1013   </para></listitem>
1014   <listitem><para><emphasis>Analysis:</emphasis>
1015   Count the exact number of link traversals.
1016   </para></listitem>
1017   <listitem><para><emphasis>Cost model:</emphasis>
1018   Total number of links traversed.</para></listitem>
1019   <listitem><para><emphasis>Example:</emphasis>
1020 <programlisting>
1021 class dumb_hash {
1022  public:
1023   size_t operator() (int i) const { return 0; }
1024 };
1025 ...
1026   unordered_set&lt;int, dumb_hash&gt; hs;
1027   ...
1028   for (int i = 0; i &lt; COUNT; ++i) {
1029     hs.find(i);
1030   }
1031 </programlisting>
1032 </para></listitem>
1033 </itemizedlist>
1034 </section>
1035
1036 <section xml:id="manual.ext.profile_mode.analysis.vector_too_small" xreflabel="Vector Too Small"><info><title>Vector Too Small</title></info>
1037
1038 <itemizedlist>
1039   <listitem><para><emphasis>Switch:</emphasis>
1040   <code>_GLIBCXX_PROFILE_VECTOR_TOO_SMALL</code>.
1041   </para></listitem>
1042   <listitem><para><emphasis>Goal:</emphasis>Detect vectors with many
1043   resize operations, small construction size and large destruction size..
1044   </para></listitem>
1045   <listitem><para><emphasis>Fundamentals:</emphasis>Resizing can be expensive.
1046   Copying large amounts of data takes time.  Resizing many small vectors may
1047   have allocation overhead and affect locality.</para></listitem>
1048   <listitem><para><emphasis>Sample runtime reduction:</emphasis>%.
1049   </para></listitem>
1050   <listitem><para><emphasis>Recommendation:</emphasis>
1051   Set initial size to N at construction site S.</para></listitem>
1052   <listitem><para><emphasis>To instrument:</emphasis><code>vector</code>.
1053   </para></listitem>
1054   <listitem><para><emphasis>Analysis:</emphasis>
1055   For each dynamic instance of <code>vector</code>,
1056   record initial size and call context of the constructor.
1057   Record size increase, if any, after each relevant operation such as
1058   <code>push_back</code>.  Record the estimated resize cost.
1059   </para></listitem>
1060   <listitem><para><emphasis>Cost model:</emphasis>
1061   Total number of words copied * time to copy a word.</para></listitem>
1062   <listitem><para><emphasis>Example:</emphasis>
1063 <programlisting>
1064 1 vector&lt;int&gt; v;
1065 2 for (int k = 0; k &lt; 1000000; ++k) {
1066 3   v.push_back(k);
1067 4 }
1068
1069 foo.cc:1: advice: Changing initial vector size from 10 to 1000000 saves
1070 copying 4000000 bytes and 20 memory allocations and deallocations.
1071 </programlisting>
1072 </para></listitem>
1073 </itemizedlist>
1074 </section>
1075
1076 <section xml:id="manual.ext.profile_mode.analysis.vector_too_large" xreflabel="Vector Too Large"><info><title>Vector Too Large</title></info>
1077
1078 <itemizedlist>
1079   <listitem><para><emphasis>Switch:</emphasis>
1080   <code>_GLIBCXX_PROFILE_VECTOR_TOO_LARGE</code>
1081   </para></listitem>
1082   <listitem><para><emphasis>Goal:</emphasis>Detect vectors which are
1083   never filled up because fewer elements than reserved are ever
1084   inserted.
1085   </para></listitem>
1086   <listitem><para><emphasis>Fundamentals:</emphasis>Save memory, which
1087   is good in itself and may also improve memory reference performance through
1088   fewer cache and TLB misses.</para></listitem>
1089   <listitem><para><emphasis>Sample runtime reduction:</emphasis>%.
1090   </para></listitem>
1091   <listitem><para><emphasis>Recommendation:</emphasis>
1092   Set initial size to N at construction site S.</para></listitem>
1093   <listitem><para><emphasis>To instrument:</emphasis><code>vector</code>.
1094   </para></listitem>
1095   <listitem><para><emphasis>Analysis:</emphasis>
1096   For each dynamic instance of <code>vector</code>,
1097   record initial size and call context of the constructor, and correlate it
1098   with its size at destruction time.</para></listitem>
1099   <listitem><para><emphasis>Cost model:</emphasis>
1100   Total amount of memory saved.</para></listitem>
1101   <listitem><para><emphasis>Example:</emphasis>
1102 <programlisting>
1103 1 vector&lt;vector&lt;int&gt;&gt; v(100000, vector&lt;int&gt;(100)) ;
1104 2 for (int k = 0; k &lt; 100000; ++k) {
1105 3   for (int j = 0; j &lt; 10; ++j) {
1106 4     v[k].insert(k + j);
1107 5  }
1108 6 }
1109
1110 foo.cc:1: advice: Changing initial vector size from 100 to 10 saves N
1111 bytes of memory and may reduce the number of cache and TLB misses.
1112 </programlisting>
1113 </para></listitem>
1114 </itemizedlist>
1115 </section>
1116
1117 <section xml:id="manual.ext.profile_mode.analysis.vector_to_hashtable" xreflabel="Vector to Hashtable"><info><title>Vector to Hashtable</title></info>
1118
1119 <itemizedlist>
1120   <listitem><para><emphasis>Switch:</emphasis>
1121   <code>_GLIBCXX_PROFILE_VECTOR_TO_HASHTABLE</code>.
1122   </para></listitem>
1123   <listitem><para><emphasis>Goal:</emphasis> Detect uses of
1124   <code>vector</code> that can be substituted with <code>unordered_set</code>
1125   to reduce execution time.
1126   </para></listitem>
1127   <listitem><para><emphasis>Fundamentals:</emphasis>
1128   Linear search in a vector is very expensive, whereas searching in a hashtable
1129   is very quick.</para></listitem>
1130   <listitem><para><emphasis>Sample runtime reduction:</emphasis>factor up
1131    to container size.
1132   </para></listitem>
1133   <listitem><para><emphasis>Recommendation:</emphasis>Replace
1134   <code>vector</code> with <code>unordered_set</code> at site S.
1135   </para></listitem>
1136   <listitem><para><emphasis>To instrument:</emphasis><code>vector</code>
1137   operations and access methods.</para></listitem>
1138   <listitem><para><emphasis>Analysis:</emphasis>
1139   For each dynamic instance of <code>vector</code>,
1140   record call context of the constructor.  Issue the advice only if the
1141   only methods called on this <code>vector</code> are <code>push_back</code>,
1142   <code>insert</code> and <code>find</code>.
1143   </para></listitem>
1144   <listitem><para><emphasis>Cost model:</emphasis>
1145   Cost(vector::push_back) + cost(vector::insert) + cost(find, vector) -
1146   cost(unordered_set::insert) + cost(unordered_set::find).
1147   </para></listitem>
1148   <listitem><para><emphasis>Example:</emphasis>
1149 <programlisting>
1150 1  vector&lt;int&gt; v;
1151 ...
1152 2  for (int i = 0; i &lt; 1000; ++i) {
1153 3    find(v.begin(), v.end(), i);
1154 4  }
1155
1156 foo.cc:1: advice: Changing "vector" to "unordered_set" will save about 500,000
1157 comparisons.
1158 </programlisting>
1159 </para></listitem>
1160 </itemizedlist>
1161 </section>
1162
1163 <section xml:id="manual.ext.profile_mode.analysis.hashtable_to_vector" xreflabel="Hashtable to Vector"><info><title>Hashtable to Vector</title></info>
1164
1165 <itemizedlist>
1166   <listitem><para><emphasis>Switch:</emphasis>
1167   <code>_GLIBCXX_PROFILE_HASHTABLE_TO_VECTOR</code>.
1168   </para></listitem>
1169   <listitem><para><emphasis>Goal:</emphasis> Detect uses of
1170   <code>unordered_set</code> that can be substituted with <code>vector</code>
1171   to reduce execution time.
1172   </para></listitem>
1173   <listitem><para><emphasis>Fundamentals:</emphasis>
1174   Hashtable iterator is slower than vector iterator.</para></listitem>
1175   <listitem><para><emphasis>Sample runtime reduction:</emphasis>95%.
1176   </para></listitem>
1177   <listitem><para><emphasis>Recommendation:</emphasis>Replace
1178   <code>unordered_set</code> with <code>vector</code> at site S.
1179   </para></listitem>
1180   <listitem><para><emphasis>To instrument:</emphasis><code>unordered_set</code>
1181   operations and access methods.</para></listitem>
1182   <listitem><para><emphasis>Analysis:</emphasis>
1183   For each dynamic instance of <code>unordered_set</code>,
1184   record call context of the constructor.  Issue the advice only if the
1185   number of <code>find</code>, <code>insert</code> and <code>[]</code>
1186   operations on this <code>unordered_set</code> are small relative to the
1187   number of elements, and methods <code>begin</code> or <code>end</code>
1188   are invoked (suggesting iteration).</para></listitem>
1189   <listitem><para><emphasis>Cost model:</emphasis>
1190   Number of .</para></listitem>
1191   <listitem><para><emphasis>Example:</emphasis>
1192 <programlisting>
1193 1  unordered_set&lt;int&gt; us;
1194 ...
1195 2  int s = 0;
1196 3  for (unordered_set&lt;int&gt;::iterator it = us.begin(); it != us.end(); ++it) {
1197 4    s += *it;
1198 5  }
1199
1200 foo.cc:1: advice: Changing "unordered_set" to "vector" will save about N
1201 indirections and may achieve better data locality.
1202 </programlisting>
1203 </para></listitem>
1204 </itemizedlist>
1205 </section>
1206
1207 <section xml:id="manual.ext.profile_mode.analysis.vector_to_list" xreflabel="Vector to List"><info><title>Vector to List</title></info>
1208
1209 <itemizedlist>
1210   <listitem><para><emphasis>Switch:</emphasis>
1211   <code>_GLIBCXX_PROFILE_VECTOR_TO_LIST</code>.
1212   </para></listitem>
1213   <listitem><para><emphasis>Goal:</emphasis> Detect cases where
1214   <code>vector</code> could be substituted with <code>list</code> for
1215   better performance.
1216   </para></listitem>
1217   <listitem><para><emphasis>Fundamentals:</emphasis>
1218   Inserting in the middle of a vector is expensive compared to inserting in a
1219   list.
1220   </para></listitem>
1221   <listitem><para><emphasis>Sample runtime reduction:</emphasis>factor up to
1222    container size.
1223   </para></listitem>
1224   <listitem><para><emphasis>Recommendation:</emphasis>Replace vector with list
1225   at site S.</para></listitem>
1226   <listitem><para><emphasis>To instrument:</emphasis><code>vector</code>
1227   operations and access methods.</para></listitem>
1228   <listitem><para><emphasis>Analysis:</emphasis>
1229   For each dynamic instance of <code>vector</code>,
1230   record the call context of the constructor.  Record the overhead of each
1231   <code>insert</code> operation based on current size and insert position.
1232   Report instance with high insertion overhead.
1233   </para></listitem>
1234   <listitem><para><emphasis>Cost model:</emphasis>
1235   (Sum(cost(vector::method)) - Sum(cost(list::method)), for
1236   method in [push_back, insert, erase])
1237   + (Cost(iterate vector) - Cost(iterate list))</para></listitem>
1238   <listitem><para><emphasis>Example:</emphasis>
1239 <programlisting>
1240 1  vector&lt;int&gt; v;
1241 2  for (int i = 0; i &lt; 10000; ++i) {
1242 3    v.insert(v.begin(), i);
1243 4  }
1244
1245 foo.cc:1: advice: Changing "vector" to "list" will save about 5,000,000
1246 operations.
1247 </programlisting>
1248 </para></listitem>
1249 </itemizedlist>
1250 </section>
1251
1252 <section xml:id="manual.ext.profile_mode.analysis.list_to_vector" xreflabel="List to Vector"><info><title>List to Vector</title></info>
1253
1254 <itemizedlist>
1255   <listitem><para><emphasis>Switch:</emphasis>
1256   <code>_GLIBCXX_PROFILE_LIST_TO_VECTOR</code>.
1257   </para></listitem>
1258   <listitem><para><emphasis>Goal:</emphasis> Detect cases where
1259   <code>list</code> could be substituted with <code>vector</code> for
1260   better performance.
1261   </para></listitem>
1262   <listitem><para><emphasis>Fundamentals:</emphasis>
1263   Iterating through a vector is faster than through a list.
1264   </para></listitem>
1265   <listitem><para><emphasis>Sample runtime reduction:</emphasis>64%.
1266   </para></listitem>
1267   <listitem><para><emphasis>Recommendation:</emphasis>Replace list with vector
1268   at site S.</para></listitem>
1269   <listitem><para><emphasis>To instrument:</emphasis><code>vector</code>
1270   operations and access methods.</para></listitem>
1271   <listitem><para><emphasis>Analysis:</emphasis>
1272   Issue the advice if there are no <code>insert</code> operations.
1273   </para></listitem>
1274   <listitem><para><emphasis>Cost model:</emphasis>
1275     (Sum(cost(vector::method)) - Sum(cost(list::method)), for
1276   method in [push_back, insert, erase])
1277   + (Cost(iterate vector) - Cost(iterate list))</para></listitem>
1278   <listitem><para><emphasis>Example:</emphasis>
1279 <programlisting>
1280 1  list&lt;int&gt; l;
1281 ...
1282 2  int sum = 0;
1283 3  for (list&lt;int&gt;::iterator it = l.begin(); it != l.end(); ++it) {
1284 4    sum += *it;
1285 5  }
1286
1287 foo.cc:1: advice: Changing "list" to "vector" will save about 1000000 indirect
1288 memory references.
1289 </programlisting>
1290 </para></listitem>
1291 </itemizedlist>
1292 </section>
1293
1294 <section xml:id="manual.ext.profile_mode.analysis.list_to_slist" xreflabel="List to Forward List"><info><title>List to Forward List (Slist)</title></info>
1295
1296 <itemizedlist>
1297   <listitem><para><emphasis>Switch:</emphasis>
1298   <code>_GLIBCXX_PROFILE_LIST_TO_SLIST</code>.
1299   </para></listitem>
1300   <listitem><para><emphasis>Goal:</emphasis> Detect cases where
1301   <code>list</code> could be substituted with <code>forward_list</code> for
1302   better performance.
1303   </para></listitem>
1304   <listitem><para><emphasis>Fundamentals:</emphasis>
1305   The memory footprint of a forward_list is smaller than that of a list.
1306   This has beneficial effects on memory subsystem, e.g., fewer cache misses.
1307   </para></listitem>
1308   <listitem><para><emphasis>Sample runtime reduction:</emphasis>40%.
1309   Note that the reduction is only noticeable if the size of the forward_list
1310   node is in fact larger than that of the list node.  For memory allocators
1311   with size classes, you will only notice an effect when the two node sizes
1312   belong to different allocator size classes.
1313   </para></listitem>
1314   <listitem><para><emphasis>Recommendation:</emphasis>Replace list with
1315   forward_list at site S.</para></listitem>
1316   <listitem><para><emphasis>To instrument:</emphasis><code>list</code>
1317   operations and iteration methods.</para></listitem>
1318   <listitem><para><emphasis>Analysis:</emphasis>
1319   Issue the advice if there are no <code>backwards</code> traversals
1320   or insertion before a given node.
1321   </para></listitem>
1322   <listitem><para><emphasis>Cost model:</emphasis>
1323   Always true.</para></listitem>
1324   <listitem><para><emphasis>Example:</emphasis>
1325 <programlisting>
1326 1  list&lt;int&gt; l;
1327 ...
1328 2  int sum = 0;
1329 3  for (list&lt;int&gt;::iterator it = l.begin(); it != l.end(); ++it) {
1330 4    sum += *it;
1331 5  }
1332
1333 foo.cc:1: advice: Change "list" to "forward_list".
1334 </programlisting>
1335 </para></listitem>
1336 </itemizedlist>
1337 </section>
1338
1339 <section xml:id="manual.ext.profile_mode.analysis.assoc_ord_to_unord" xreflabel="Ordered to Unordered Associative Container"><info><title>Ordered to Unordered Associative Container</title></info>
1340
1341 <itemizedlist>
1342   <listitem><para><emphasis>Switch:</emphasis>
1343   <code>_GLIBCXX_PROFILE_ORDERED_TO_UNORDERED</code>.
1344   </para></listitem>
1345   <listitem><para><emphasis>Goal:</emphasis>  Detect cases where ordered
1346   associative containers can be replaced with unordered ones.
1347   </para></listitem>
1348   <listitem><para><emphasis>Fundamentals:</emphasis>
1349   Insert and search are quicker in a hashtable than in
1350   a red-black tree.</para></listitem>
1351   <listitem><para><emphasis>Sample runtime reduction:</emphasis>52%.
1352   </para></listitem>
1353   <listitem><para><emphasis>Recommendation:</emphasis>
1354   Replace set with unordered_set at site S.</para></listitem>
1355   <listitem><para><emphasis>To instrument:</emphasis>
1356   <code>set</code>, <code>multiset</code>, <code>map</code>,
1357   <code>multimap</code> methods.</para></listitem>
1358   <listitem><para><emphasis>Analysis:</emphasis>
1359   Issue the advice only if we are not using operator <code>++</code> on any
1360   iterator on a particular <code>[multi]set|map</code>.
1361   </para></listitem>
1362   <listitem><para><emphasis>Cost model:</emphasis>
1363   (Sum(cost(hashtable::method)) - Sum(cost(rbtree::method)), for
1364   method in [insert, erase, find])
1365   + (Cost(iterate hashtable) - Cost(iterate rbtree))</para></listitem>
1366   <listitem><para><emphasis>Example:</emphasis>
1367 <programlisting>
1368 1  set&lt;int&gt; s;
1369 2  for (int i = 0; i &lt; 100000; ++i) {
1370 3    s.insert(i);
1371 4  }
1372 5  int sum = 0;
1373 6  for (int i = 0; i &lt; 100000; ++i) {
1374 7    sum += *s.find(i);
1375 8  }
1376 </programlisting>
1377 </para></listitem>
1378 </itemizedlist>
1379 </section>
1380
1381 </section>
1382
1383
1384
1385 <section xml:id="manual.ext.profile_mode.analysis.algorithms" xreflabel="Algorithms"><info><title>Algorithms</title></info>
1386
1387
1388   <para><emphasis>Switch:</emphasis>
1389   <code>_GLIBCXX_PROFILE_ALGORITHMS</code>.
1390   </para>
1391
1392 <section xml:id="manual.ext.profile_mode.analysis.algorithms.sort" xreflabel="Sorting"><info><title>Sort Algorithm Performance</title></info>
1393
1394 <itemizedlist>
1395   <listitem><para><emphasis>Switch:</emphasis>
1396   <code>_GLIBCXX_PROFILE_SORT</code>.
1397   </para></listitem>
1398   <listitem><para><emphasis>Goal:</emphasis> Give measure of sort algorithm
1399   performance based on actual input.  For instance, advise Radix Sort over
1400   Quick Sort for a particular call context.
1401   </para></listitem>
1402   <listitem><para><emphasis>Fundamentals:</emphasis>
1403   See papers:
1404   <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://portal.acm.org/citation.cfm?doid=1065944.1065981">
1405   A framework for adaptive algorithm selection in STAPL</link> and
1406   <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://ieeexplore.ieee.org/search/wrapper.jsp?arnumber=4228227">
1407   Optimizing Sorting with Machine Learning Algorithms</link>.
1408   </para></listitem>
1409   <listitem><para><emphasis>Sample runtime reduction:</emphasis>60%.
1410   </para></listitem>
1411   <listitem><para><emphasis>Recommendation:</emphasis> Change sort algorithm
1412   at site S from X Sort to Y Sort.</para></listitem>
1413   <listitem><para><emphasis>To instrument:</emphasis> <code>sort</code>
1414   algorithm.</para></listitem>
1415   <listitem><para><emphasis>Analysis:</emphasis>
1416   Issue the advice if the cost model tells us that another sort algorithm
1417   would do better on this input.  Requires us to know what algorithm we
1418   are using in our sort implementation in release mode.</para></listitem>
1419   <listitem><para><emphasis>Cost model:</emphasis>
1420   Runtime(algo) for algo in [radix, quick, merge, ...]</para></listitem>
1421   <listitem><para><emphasis>Example:</emphasis>
1422 <programlisting>
1423 </programlisting>
1424 </para></listitem>
1425 </itemizedlist>
1426 </section>
1427
1428 </section>
1429
1430
1431 <section xml:id="manual.ext.profile_mode.analysis.locality" xreflabel="Data Locality"><info><title>Data Locality</title></info>
1432
1433
1434   <para><emphasis>Switch:</emphasis>
1435   <code>_GLIBCXX_PROFILE_LOCALITY</code>.
1436   </para>
1437
1438 <section xml:id="manual.ext.profile_mode.analysis.locality.sw_prefetch" xreflabel="Need Software Prefetch"><info><title>Need Software Prefetch</title></info>
1439
1440 <itemizedlist>
1441   <listitem><para><emphasis>Switch:</emphasis>
1442   <code>_GLIBCXX_PROFILE_SOFTWARE_PREFETCH</code>.
1443   </para></listitem>
1444   <listitem><para><emphasis>Goal:</emphasis> Discover sequences of indirect
1445   memory accesses that are not regular, thus cannot be predicted by
1446   hardware prefetchers.
1447   </para></listitem>
1448   <listitem><para><emphasis>Fundamentals:</emphasis>
1449   Indirect references are hard to predict and are very expensive when they
1450   miss in caches.</para></listitem>
1451   <listitem><para><emphasis>Sample runtime reduction:</emphasis>25%.
1452   </para></listitem>
1453   <listitem><para><emphasis>Recommendation:</emphasis> Insert prefetch
1454   instruction.</para></listitem>
1455   <listitem><para><emphasis>To instrument:</emphasis> Vector iterator and
1456   access operator [].
1457   </para></listitem>
1458   <listitem><para><emphasis>Analysis:</emphasis>
1459   First, get cache line size and page size from system.
1460   Then record iterator dereference sequences for which the value is a pointer.
1461   For each sequence within a container, issue a warning if successive pointer
1462   addresses are not within cache lines and do not form a linear pattern
1463   (otherwise they may be prefetched by hardware).
1464   If they also step across page boundaries, make the warning stronger.
1465   </para>
1466   <para>The same analysis applies to containers other than vector.
1467   However, we cannot give the same advice for linked structures, such as list,
1468   as there is no random access to the n-th element.  The user may still be
1469   able to benefit from this information, for instance by employing frays (user
1470   level light weight threads) to hide the latency of chasing pointers.
1471   </para>
1472   <para>
1473   This analysis is a little oversimplified.  A better cost model could be
1474   created by understanding the capability of the hardware prefetcher.
1475   This model could be trained automatically by running a set of synthetic
1476   cases.
1477   </para>
1478   </listitem>
1479   <listitem><para><emphasis>Cost model:</emphasis>
1480   Total distance between pointer values of successive elements in vectors
1481   of pointers.</para></listitem>
1482   <listitem><para><emphasis>Example:</emphasis>
1483 <programlisting>
1484 1 int zero = 0;
1485 2 vector&lt;int*&gt; v(10000000, &amp;zero);
1486 3 for (int k = 0; k &lt; 10000000; ++k) {
1487 4   v[random() % 10000000] = new int(k);
1488 5 }
1489 6 for (int j = 0; j &lt; 10000000; ++j) {
1490 7   count += (*v[j] == 0 ? 0 : 1);
1491 8 }
1492
1493 foo.cc:7: advice: Insert prefetch instruction.
1494 </programlisting>
1495 </para></listitem>
1496 </itemizedlist>
1497 </section>
1498
1499 <section xml:id="manual.ext.profile_mode.analysis.locality.linked" xreflabel="Linked Structure Locality"><info><title>Linked Structure Locality</title></info>
1500
1501 <itemizedlist>
1502   <listitem><para><emphasis>Switch:</emphasis>
1503   <code>_GLIBCXX_PROFILE_RBTREE_LOCALITY</code>.
1504   </para></listitem>
1505   <listitem><para><emphasis>Goal:</emphasis> Give measure of locality of
1506   objects stored in linked structures (lists, red-black trees and hashtables)
1507   with respect to their actual traversal patterns.
1508   </para></listitem>
1509   <listitem><para><emphasis>Fundamentals:</emphasis>Allocation can be tuned
1510   to a specific traversal pattern, to result in better data locality.
1511   See paper:
1512   <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.springerlink.com/content/8085744l00x72662/">
1513   Custom Memory Allocation for Free</link>.
1514   </para></listitem>
1515   <listitem><para><emphasis>Sample runtime reduction:</emphasis>30%.
1516   </para></listitem>
1517   <listitem><para><emphasis>Recommendation:</emphasis>
1518   High scatter score N for container built at site S.
1519   Consider changing allocation sequence or choosing a structure conscious
1520   allocator.</para></listitem>
1521   <listitem><para><emphasis>To instrument:</emphasis> Methods of all
1522   containers using linked structures.</para></listitem>
1523   <listitem><para><emphasis>Analysis:</emphasis>
1524   First, get cache line size and page size from system.
1525   Then record the number of successive elements that are on different line
1526   or page, for each traversal method such as <code>find</code>.  Give advice
1527   only if the ratio between this number and the number of total node hops
1528   is above a threshold.</para></listitem>
1529   <listitem><para><emphasis>Cost model:</emphasis>
1530   Sum(same_cache_line(this,previous))</para></listitem>
1531   <listitem><para><emphasis>Example:</emphasis>
1532 <programlisting>
1533  1  set&lt;int&gt; s;
1534  2  for (int i = 0; i &lt; 10000000; ++i) {
1535  3    s.insert(i);
1536  4  }
1537  5  set&lt;int&gt; s1, s2;
1538  6  for (int i = 0; i &lt; 10000000; ++i) {
1539  7    s1.insert(i);
1540  8    s2.insert(i);
1541  9  }
1542 ...
1543       // Fast, better locality.
1544 10    for (set&lt;int&gt;::iterator it = s.begin(); it != s.end(); ++it) {
1545 11      sum += *it;
1546 12    }
1547       // Slow, elements are further apart.
1548 13    for (set&lt;int&gt;::iterator it = s1.begin(); it != s1.end(); ++it) {
1549 14      sum += *it;
1550 15    }
1551
1552 foo.cc:5: advice: High scatter score NNN for set built here.  Consider changing
1553 the allocation sequence or switching to a structure conscious allocator.
1554 </programlisting>
1555 </para></listitem>
1556 </itemizedlist>
1557 </section>
1558
1559 </section>
1560
1561
1562 <section xml:id="manual.ext.profile_mode.analysis.mthread" xreflabel="Multithreaded Data Access"><info><title>Multithreaded Data Access</title></info>
1563
1564
1565   <para>
1566   The diagnostics in this group are not meant to be implemented short term.
1567   They require compiler support to know when container elements are written
1568   to.  Instrumentation can only tell us when elements are referenced.
1569   </para>
1570
1571   <para><emphasis>Switch:</emphasis>
1572   <code>_GLIBCXX_PROFILE_MULTITHREADED</code>.
1573   </para>
1574
1575 <section xml:id="manual.ext.profile_mode.analysis.mthread.ddtest" xreflabel="Dependence Violations at Container Level"><info><title>Data Dependence Violations at Container Level</title></info>
1576
1577 <itemizedlist>
1578   <listitem><para><emphasis>Switch:</emphasis>
1579   <code>_GLIBCXX_PROFILE_DDTEST</code>.
1580   </para></listitem>
1581   <listitem><para><emphasis>Goal:</emphasis> Detect container elements
1582   that are referenced from multiple threads in the parallel region or
1583   across parallel regions.
1584   </para></listitem>
1585   <listitem><para><emphasis>Fundamentals:</emphasis>
1586   Sharing data between threads requires communication and perhaps locking,
1587   which may be expensive.
1588   </para></listitem>
1589   <listitem><para><emphasis>Sample runtime reduction:</emphasis>?%.
1590   </para></listitem>
1591   <listitem><para><emphasis>Recommendation:</emphasis> Change data
1592   distribution or parallel algorithm.</para></listitem>
1593   <listitem><para><emphasis>To instrument:</emphasis> Container access methods
1594   and iterators.
1595   </para></listitem>
1596   <listitem><para><emphasis>Analysis:</emphasis>
1597   Keep a shadow for each container.  Record iterator dereferences and
1598   container member accesses.  Issue advice for elements referenced by
1599   multiple threads.
1600   See paper: <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://portal.acm.org/citation.cfm?id=207110.207148">
1601   The LRPD test: speculative run-time parallelization of loops with
1602   privatization and reduction parallelization</link>.
1603   </para></listitem>
1604   <listitem><para><emphasis>Cost model:</emphasis>
1605   Number of accesses to elements referenced from multiple threads
1606   </para></listitem>
1607   <listitem><para><emphasis>Example:</emphasis>
1608 <programlisting>
1609 </programlisting>
1610 </para></listitem>
1611 </itemizedlist>
1612 </section>
1613
1614 <section xml:id="manual.ext.profile_mode.analysis.mthread.false_share" xreflabel="False Sharing"><info><title>False Sharing</title></info>
1615
1616 <itemizedlist>
1617   <listitem><para><emphasis>Switch:</emphasis>
1618   <code>_GLIBCXX_PROFILE_FALSE_SHARING</code>.
1619   </para></listitem>
1620   <listitem><para><emphasis>Goal:</emphasis> Detect elements in the
1621   same container which share a cache line, are written by at least one
1622   thread, and accessed by different threads.
1623   </para></listitem>
1624   <listitem><para><emphasis>Fundamentals:</emphasis> Under these assumptions,
1625   cache protocols require
1626   communication to invalidate lines, which may be expensive.
1627   </para></listitem>
1628   <listitem><para><emphasis>Sample runtime reduction:</emphasis>68%.
1629   </para></listitem>
1630   <listitem><para><emphasis>Recommendation:</emphasis> Reorganize container
1631   or use padding to avoid false sharing.</para></listitem>
1632   <listitem><para><emphasis>To instrument:</emphasis> Container access methods
1633   and iterators.
1634   </para></listitem>
1635   <listitem><para><emphasis>Analysis:</emphasis>
1636   First, get the cache line size.
1637   For each shared container, record all the associated iterator dereferences
1638   and member access methods with the thread id.  Compare the address lists
1639   across threads to detect references in two different threads to the same
1640   cache line.  Issue a warning only if the ratio to total references is
1641   significant.  Do the same for iterator dereference values if they are
1642   pointers.</para></listitem>
1643   <listitem><para><emphasis>Cost model:</emphasis>
1644   Number of accesses to same cache line from different threads.
1645   </para></listitem>
1646   <listitem><para><emphasis>Example:</emphasis>
1647 <programlisting>
1648 1     vector&lt;int&gt; v(2, 0);
1649 2 #pragma omp parallel for shared(v, SIZE) schedule(static, 1)
1650 3     for (i = 0; i &lt; SIZE; ++i) {
1651 4       v[i % 2] += i;
1652 5     }
1653
1654 OMP_NUM_THREADS=2 ./a.out
1655 foo.cc:1: advice: Change container structure or padding to avoid false
1656 sharing in multithreaded access at foo.cc:4.  Detected N shared cache lines.
1657 </programlisting>
1658 </para></listitem>
1659 </itemizedlist>
1660 </section>
1661
1662 </section>
1663
1664
1665 <section xml:id="manual.ext.profile_mode.analysis.statistics" xreflabel="Statistics"><info><title>Statistics</title></info>
1666
1667
1668 <para>
1669 <emphasis>Switch:</emphasis>
1670   <code>_GLIBCXX_PROFILE_STATISTICS</code>.
1671 </para>
1672
1673 <para>
1674   In some cases the cost model may not tell us anything because the costs
1675   appear to offset the benefits.  Consider the choice between a vector and
1676   a list.  When there are both inserts and iteration, an automatic advice
1677   may not be issued.  However, the programmer may still be able to make use
1678   of this information in a different way.
1679 </para>
1680 <para>
1681   This diagnostic will not issue any advice, but it will print statistics for
1682   each container construction site.  The statistics will contain the cost
1683   of each operation actually performed on the container.
1684 </para>
1685
1686 </section>
1687
1688
1689 </section>
1690
1691
1692 <bibliography xml:id="profile_mode.biblio"><info><title>Bibliography</title></info>
1693
1694
1695   <biblioentry>
1696     <citetitle>
1697       Perflint: A Context Sensitive Performance Advisor for C++ Programs
1698     </citetitle>
1699
1700     <author><personname><firstname>Lixia</firstname><surname>Liu</surname></personname></author>
1701     <author><personname><firstname>Silvius</firstname><surname>Rus</surname></personname></author>
1702
1703     <copyright>
1704       <year>2009</year>
1705       <holder/>
1706     </copyright>
1707
1708     <publisher>
1709       <publishername>
1710         Proceedings of the 2009 International Symposium on Code Generation
1711         and Optimization
1712       </publishername>
1713     </publisher>
1714   </biblioentry>
1715 </bibliography>
1716
1717
1718 </chapter>