Chapter 19. Profile Mode

Table of Contents

Intro
Using the Profile Mode
Tuning the Profile Mode
Design
Wrapper Model
Instrumentation
Run Time Behavior
Analysis and Diagnostics
Cost Model
Reports
Testing
Extensions for Custom Containers
Empirical Cost Model
Implementation Issues
Stack Traces
Symbolization of Instruction Addresses
Concurrency
Using the Standard Library in the Instrumentation Implementation
Malloc Hooks
Construction and Destruction of Global Objects
Developer Information
Big Picture
How To Add A Diagnostic
Diagnostics
Diagnostic Template
Containers
Hashtable Too Small
Hashtable Too Large
Inefficient Hash
Vector Too Small
Vector Too Large
Vector to Hashtable
Hashtable to Vector
Vector to List
List to Vector
List to Forward List (Slist)
Ordered to Unordered Associative Container
Algorithms
Sort Algorithm Performance
Data Locality
Need Software Prefetch
Linked Structure Locality
Multithreaded Data Access
Data Dependence Violations at Container Level
False Sharing
Statistics
Bibliography

Goal: Give performance improvement advice based on recognition of suboptimal usage patterns of the standard library.

Method: Wrap the standard library code. Insert calls to an instrumentation library to record the internal state of various components at interesting entry/exit points to/from the standard library. Process trace, recognize suboptimal patterns, give advice. For details, see paper presented at CGO 2009.

Strengths:

  • Unintrusive solution. The application code does not require any modification.

  • The advice is call context sensitive, thus capable of identifying precisely interesting dynamic performance behavior.

  • The overhead model is pay-per-view. When you turn off a diagnostic class at compile time, its overhead disappears.

Drawbacks:

  • You must recompile the application code with custom options.

  • You must run the application on representative input. The advice is input dependent.

  • The execution time will increase, in some cases by factors.

This is the anticipated common workflow for program foo.cc:

$ cat foo.cc
#include <vector>
int main() {
  vector<int> v;
  for (int k = 0; k < 1024; ++k) v.insert(v.begin(), k);
}

$ g++ -D_GLIBCXX_PROFILE foo.cc
$ ./a.out
$ cat libstdcxx-profile.txt
vector-to-list: improvement = 5: call stack = 0x804842c ...
    : advice = change std::vector to std::list
vector-size: improvement = 3: call stack = 0x804842c ...
    : advice = change initial container size from 0 to 1024

Anatomy of a warning:

Three files are generated. libstdcxx-profile.txt contains human readable advice. libstdcxx-profile.raw contains implementation specific data about each diagnostic. Their format is not documented. They are sufficient to generate all the advice given in libstdcxx-profile.txt. The advantage of keeping this raw format is that traces from multiple executions can be aggregated simply by concatenating the raw traces. We intend to offer an external utility program that can issue advice from a trace. libstdcxx-profile.conf.out lists the actual diagnostic parameters used. To alter parameters, edit this file and rename it to libstdcxx-profile.conf.

Advice is given regardless whether the transformation is valid. For instance, we advise changing a map to an unordered_map even if the application semantics require that data be ordered. We believe such warnings can help users understand the performance behavior of their application better, which can lead to changes at a higher abstraction level.

Compile time switches and environment variables (see also file profiler.h). Unless specified otherwise, they can be set at compile time using -D_<name> or by setting variable <name> in the environment where the program is run, before starting execution.