Forward: Discussion about custom memory allocators for STL

Hi,

There is a discussion thread on llvm-commits list about a possibility of using custom memory allocators for STL to improve the performance and reduce the memory pressure of STL containers, e.g. std::set.
I thought that this discussion may be interesting for a wider audience and therefore I re-post the messages on llvm-dev as well.

It would be interesting to hear what others think about
- custom allocators,
- reasons for current inefficiency of many STL containers on Evan's/Chris configs and
- possibility of using 3rd party libs like Boost (or their parts) in LLVM

Thanks,
- Roman

----- Forwarded Mail ----

Unless you have very strong evidence that a specific change will provide
considerable benefits without introducing problems anywhere else, I would
strongly suggest forgetting about custom STL allocators and focussing on
something more productive (i.e. features rather than optimizations). If you
do go ahead with it, make sure it can be removed easily and keep checking
that it remains worthwhile as the project develops.

One of the last things I did before I ditched C++ completely was to waste a
lot of time Greenspunning garbage collectors in the form of custom STL
allocators in a last desperate attempt to get adequate performance out of
C++. My efforts were completely fruitless.

"Normal" memory allocators are a serious pessimization for typical
compiler usage patterns and will waste a fair amount of time and a
non-trivial percentage of space pointlessly keeping track of and freeing
tiny lumps of memory.

Compilers tend to (1) incrementally allocate largeish chunks of
temporary storage for the duration of a deep, probably recursive, call
tree, and want to free it all in one go at the end (with this pattern
being itself recursive), and (2) allocate memory with affinity for a
particular compilation unit, assuming they are doing as much as possible
(parsing, compiling, assembling, linking, etc.) in memory for
efficiency, such that it can in turn be freed en-masse when that
compilation unit is finally through.

Pattern (1) wants a stack-like allocator, with an API resembling
{ void *Allocate(size_t); size_t Mark(); void Reset(size_t mark); void
Free(); }.

Pattern (2) wants something more simple: { void *Allocate(int heapID,
size_t); void Free(int heapID); } (assuming a non-OO API; eliminate
heapID if the thing is an object).

Pattern (2) can be implemented in terms of a generalized pattern (1).

-- Barry

Roman Levenstein wrote:

Hi,

There is a discussion thread on llvm-commits list about a possibility of using custom memory allocators for STL to improve the performance and reduce the memory pressure of STL containers, e.g. std::set.
I thought that this discussion may be interesting for a wider audience and therefore I re-post the messages on llvm-dev as well.

It would be interesting to hear what others think about - custom allocators,
  

Only as a build option, and must include performance comparisons against the default allocator in automated testing.

- reasons for current inefficiency of many STL containers on Evan's/Chris configs and - possibility of using 3rd party libs like Boost (or their parts) in LLVM
  

I'd consider forking from Boost at least:
* static asserts in conjunction with the type traits library and std::numeric_limits
* concept_check
* the enable_if library allowing conditional definition of templates, again in conjunction with the type traits library and std:::numeric_limits.

I believe GCC uses a forked version of Boost for the first two points, in its STL. (At least, the comments suggest this.)

Kenneth Boyd

Roman Levenstein wrote:

- possibility of using 3rd party libs like Boost (or their parts) in LLVM
  

There is a thread elsewhere on this mailing list illustrating how important it is for the maintainers of LLVM to keep LLVM usable in a commercial environment. As such, I would strongly recommend avoiding Boost as it has a bad name in some quarters, regardless of its license, for including work that is not safe for commercial users to take on. Ie, there are so many contributors, and their contribution tracking has been poor in the past, that business affairs departments in commercial companies, and their associated patent lawyers, are unable to determine how much of Boost is truly the authors' own work, and how much is borrowed.

Given the delicate relationship between the commercial sector and open source, adding Boost usage to LLVM will harm the commercial sectors view of this product.

Dominic

Dominic Hamon <dom.hamon@gmail.com> writes:

[snip]

Boost as it has a bad name in some quarters, regardless of its license,
for including work that is not safe for commercial users to take on. Ie,
there are so many contributors, and their contribution tracking has been
poor in the past, that business affairs departments in commercial
companies, and their associated patent lawyers, are unable to determine
how much of Boost is truly the authors' own work, and how much is borrowed.

Isn't this applicable to LLVM itself?

Just asking.

[snip]

Yes. I don't really buy that argument against using boost. There are other valid arguments against using specific boost libraries, but contribution tracking seems fairly minor.

-Chris

Do you have a source for that opinion? I've never heard that view of Boost.

I would also like to see some data on that. I have heard it once or
twice before on mailing lists, though never any evidence to back it
up, and never from within an actual business.

There is a discussion thread on llvm-commits list about a possibility of using custom memory allocators for STL to improve the performance and reduce the memory pressure of STL containers, e.g. std::set.
I thought that this discussion may be interesting for a wider audience and therefore I re-post the messages on llvm-dev as well.

It would be interesting to hear what others think about
- custom allocators,

I think custom allocators can be a great thing, as long as they are specific to instances of containers, not a general replacement for malloc/free. That way they can be used on demand when profiling shows they are important.

Ideally, I would be able to do something like:

   MyRegion R;
   std:set<x> (R);
   std::map<y,z> (R);

etc, and have the nodes for both containers share the same pool. We already have some things like this that we use in clang, check out llvm/support/allocators.h. It is not the standard STL allocator interface though, we need a simple adaptor.

- reasons for current inefficiency of many STL containers on Evan's/Chris configs and

The reason is pretty obvious when you know what to look for. On the mac, std::allocator<t> just calls malloc/free. On linux and apparently everywhere else, std::allocator<T> is implemented in terms of a strange pool allocator. [IMO, the mac way of doing things is the right way to go, but we can discuss philosophy elsewhere. Here we will focus on the ramifications of this reality]

The end result of this is that std::set/map on the mac ends up calling malloc/free for each node in the red/black tree, and it allocates a metric butt load of nodes (one per each item inserted). Further, each query of the set incurs traversals of the tree. In the case of the mac, because malloc/free is used, the allocations are spread all throughout the heap and traversing a tree touches all sorts of random pages of memory in very cache-unfriendly ways. I think the performance delta of mac vs linux is primarily due to this locality issue, not the raw performance of malloc on the two systems.

On linux (for example) the custom implementation of std::set happens to get lucky, and generally gives better locality than mapping directly to malloc/free, just because only a very small subset of the objects on the heap go through std::allocator (f.e. none of the SDNodes or LLVM IR objects go through std::allocator). This implicit partitioning of the heap leads to accidental improved performance, but the performance is still pretty bad if you do have multiple node-based containers live at once (though that is rare in llvm). I did a whole phd thesis about partitioning memory objects, so I know that partitioning data structures into their own regions can be a big win :). It just happens that std::allocator on linux gets lucky on this for LLVM, since we generally have few STL containers live at once (and when we beat on them, we beat on them heavily).

- possibility of using 3rd party libs like Boost (or their parts) in LLVM

We have already imported pieces of boost. The general rule is that it is ok to use specific pieces, but they have to be converted to the LLVM style and way of doing things. Also, things with huge chains of dependencies sometimes have to be simplified.

-Chris

me22 wrote:

  

There is a thread elsewhere on this mailing list illustrating how
important it is for the maintainers of LLVM to keep LLVM usable in a
commercial environment. As such, I would strongly recommend avoiding
Boost as it has a bad name in some quarters, regardless of its license,
for including work that is not safe for commercial users to take on. Ie,
there are so many contributors, and their contribution tracking has been
poor in the past, that business affairs departments in commercial
companies, and their associated patent lawyers, are unable to determine
how much of Boost is truly the authors' own work, and how much is borrowed.

Given the delicate relationship between the commercial sector and open
source, adding Boost usage to LLVM will harm the commercial sectors view
of this product.

Do you have a source for that opinion? I've never heard that view of Boost.

The company that I work for that had to pull boost out of a project after the patent lawyers couldn't reliably determine the sources for some of the components of boost.

There are other arguments elsewhere on this mailing list against using boost that are far more specific, however this does come from personal experience and I thought it important to share.

It has also been mentioned that it is also true for LLVM itself, and it is. However, the amount of code in LLVM, and the specific nature of its usage and what it is for lends itself to better contribution tracking immediately. Boost is a nebulous piece of software with a wide range of functionality.

Dominic

If I were worrying about patents, though, I'd be much more worried
about LLVM than Boost. Much of Boost is original, and could well be
prior art against patent claims, whereas LLVM could easily use a
patented register allocator or similar without anyone knowing.

Actually it's not patents (where origin of code is irrelevant) but
copyright (where it is).

I'd like to see some more specific statements about what the IP lawyers
at Dominic's company did. If they aren't too familiar with Open Source,
they simply might have looked in the wrong places.

Regards,
Jo

Actually it's not patents (where origin of code is irrelevant) but
copyright (where it is).

I'm aware of that, but he quite specifically said "patent lawyers",
not IP or copyright lawyers.

I'd like to see some more specific statements about what the IP lawyers
at Dominic's company did. If they aren't too familiar with Open Source,
they simply might have looked in the wrong places.

It feels to me like having made a reasonable effort to verify
provenance would be sufficient. For an inconclusive result, just
following the license seems fine. It the unlikely event of a suit,
damages would be small, if any, since you were acting in good faith,
and the code could be clean-room rewritten.

I also know that there are companies that sell software that checks
for open-source-derived code in a codebase -- the company that
currently employs me uses one such product.

Of course, IANAL.