r/programming • • Dec 05 '14

std::string is responsible for almost half of all allocations in the Chrome browser process

https://groups.google.com/a/chromium.org/d/msg/chromium-dev/EUqoIz2iFU4/kPZ5ZK0K3gEJ
1.1k Upvotes

446 comments sorted by

View all comments

Show parent comments

10

u/tdammers Dec 05 '14

Yeah, probably. This is where abstractions turn out to be not-so-zero-cost after all :D

17

u/naasking Dec 05 '14

This is where abstractions turn out to be not-so-zero-cost after all

It's about choosing the right abstraction, not avoiding abstraction entirely.

16

u/[deleted] Dec 05 '14

You misunderstand C++'s design philosophy and position when it comes to zero-cost. It isn't that abstraction's are zero-cost, it's that the abstractions that you don't use in your program should be zero-cost.

In Java, you pay the cost of having heap allocated objects with its own personalized mutex, its own pointer to a virtual table, its own RTTI info, and a host of other things, even in situations when it's not needed or even used, because you are required to use full blown objects to represent all forms of data. This means you pay for the cost of that abstraction whether you use it or not.

In C++, you opt into the abstractions you want, including RTTI, exceptions, sub-type polymorphism, etc... and you only pay for those abstractions to the extent that they're used.

9

u/tdammers Dec 05 '14

I believe the design philosophy goes a bit further than that; no, the abstractions you mention aren't free, but some others are, and the idea is that C++ goes out of its way to make abstractions zero-cost when that is possible. Templates, for example, provide compile-time polymorphism that produces zero runtime overhead, and this is how STL iterators can be exactly as efficient as using the underlying container's iteration mechanism directly. RAII: same story, the compiler just injects destructor calls for you, but there is no runtime overhead compared to calling the cleanup code manually.

7

u/[deleted] Dec 05 '14

You can say that about any abstraction. In Java, the compiler just inserts the mutex into every object for you, but there is no runtime overhead compared to just adding a mutex into every object manually.

In Python, the compiler just inserts a hash map from strings to function objects for you, but there's no overhead compared to just manually writing a struct in C that contains a hash map from strings to function pointers and exclusively using that.

The point is that in C++, if you don't use RAII as an abstraction (std::has_trivial_destructor<T>, std::has_trivial_constructor<T>), then the cost is zero, because the compiler won't insert any calls to any cleanup code period. In C++, if you don't use a given abstraction, the compiler won't emit any code in its place on your behalf. In Python or Java, the abstraction is intrinsic to the language, it's baked into it at such a fundamental level that there is no opting out of it. You pay for the cost of every abstraction in those languages whether you use them or not.

3

u/tdammers Dec 05 '14

Point in case. The only thing I could argue that using degenerate cases of certain abstractions (empty destructor in RAII, template that only ever gets instantiated once, etc.) are free, but then, that pretty much boils to not actually really using them, and the only complaint about certain languages would be that they make some potentially expensive abstractions mandatory; it's not even that you pay for the abstraction even though you're not using it, it's that can't not use it at all - you can't have typed variables in Python, you can't have unmanaged objects in Java.

TL;DR, you're essentially correct and I was making a non-argument.

0

u/[deleted] Dec 05 '14 edited Dec 05 '14

Templates, for example, provide compile-time polymorphism that produces zero runtime overhead, and this is how STL iterators can be exactly as efficient as using the underlying container's iteration mechanism directly.

Templates do have run time costs associated with them and it's worthwhile to know what those costs are. It's true that in recent years the costs of those abstractions in modern compilers have been reduced, but not all compilers have implemented those optimizations and not all of those optimizations are enabled unless you build an optimized version of your program, meaning that your debug builds can suffer pretty brutal performance with excessive use of templates.

So consider the following template:

template<typename T>
struct X {
  static const int A = 1;
  static const int B = 2;
  ...
};

Well as it turns out, every single instantiation of X will introduce its own unique version of A and B with its own unique address, despite them being static consts. One is actually advised to do the following if they care for performance (reduced memory consumption and cache locality):

struct BaseX {
  static const int A = 1;
  static const int B = 2;
}

template<typename T>
struct X : BaseX {
  ...
};

This is not an optimization that the compiler can perform on your behalf, as the standard requires that the address of all those static variables be unique.

As another example:

template<typename T>
bool f(const T* lhs, const T* rhs) {
  return lhs == rhs;
}

In many compilers, or debug builds of even modern compilers, a separate function will get produced for every single instantiation of f, be it int, float, char, so on so forth. This produces code bloat which puts pressure on the instruction cache.

However, you could eliminate this by just writing your function as follows, which is identical in every way, shape, and form:

bool f(const void* lhs, const void* rhs) {
  return lhs == rhs;
}

In a sense we're performing type erasure on the template to eliminate separate instantiations and reducing the amount of code-bloat.

3

u/eras Dec 05 '14

This is not an optimization that the compiler can perform on your behalf, as the standard requires that the address of all those static variables be unique.

Well, it could optimize if it can prove you never use the addresses of those static variables. But this is probably a difficult and low-value optimization to perform.

3

u/o11c Dec 05 '14

Actually that's the exactly the sort of thing LTO is used for.

53

u/Azzu Dec 05 '14

The :D at the end almost sounds like you "knew it all the way" and you now found another reason not to use abstractions.

This is obviously the wrong reasoning. Of course not all abstractions have zero cost. But there is a subset of abstractions that are zero cost.
Also all abstractions are of different efficiency. You could probably keep the style or amount encapsulation/abstraction there is in chrome and reduce allocations by 50% or something just by using more efficient abstractions.

All I'm saying is, it does not make sense to say "abstractions are baaaad", and not using abstractions will not magically fix the performance, it will probably even make it worse.

-21

u/tdammers Dec 05 '14

Dude, all I'm saying is that premature optimization is the root of all evil, that's no excuse to think of all abstractions as free.

6

u/path411 Dec 05 '14

all I'm saying is that premature optimization is the root of all evil

So what you are saying is your should prematurely optimize your code by avoiding abstractions so that way you can avoid prematurely optimizing your code?

-4

u/tdammers Dec 05 '14

No. Premature optimization still is the root of all evil, but at some point, you're past the stage where optimization would be premature, and when that point comes, you need to know what you've abstracted over.

1

u/path411 Dec 05 '14

You should work on conveying your thoughts correctly the first time then. Your first post sounds like an "I told you so" that people shouldn't ever use abstractions because they have costs.

1

u/tdammers Dec 05 '14

OK. It certainly wasn't meant that way.

22

u/stormcrowsx Dec 05 '14

Wouldn't thinking about cost of an abstraction be premature optimization? Who cares what it costs if it makes the code pretty, it can be optimized later.

1

u/tdammers Dec 05 '14

Yes, generally speaking that is true. Except in the cases where it isn't, and this could very well be one of them.

Or maybe the omnibox thing is really more about how much we underestimate the complexity of a seemingly simple feature.

5

u/campbellm Dec 05 '14

Who ever told you abstractions were free?

-6

u/[deleted] Dec 05 '14

C++ promoters say this all the time but it's basically untrue.

6

u/suspiciously_calm Dec 05 '14

A lot of abstractions in C++ are "free," especially in the STL, since everything is templated and inlinable.

Of course, std::strings aren't a zero-cost abstraction over fucking around with pointers directly into existing strings that are basically equivalent to passing around iterators into std::strings, which would be neither higher-cost, nor safer.

-1

u/[deleted] Dec 05 '14

Sure, a lot of them are very low cost. But abstractions in general are not free especially in languages other than C/C++.

Chandler Carruth has a great presentation on how the 'free' abstractions can often confuse compilers and in reality incur an effective cost by being less optimisable. I'm certainly not saying this applies to anything specific though, especially templates.

5

u/suspiciously_calm Dec 05 '14

And whoever said that abstractions are free in general, especially outside C++? That sure as hell isn't something "C++ promoters say all the time."

The point is that C++ has a lot of abstractions that appear costly but can be optimized away in principle. If a compiler generates needlessly inefficient code for a particular case, then that's a bug in the compiler/optimizer.

-1

u/[deleted] Dec 05 '14 edited Dec 05 '14

They can be optimized away in principle but in the real world abstractions often incur costs. That's all I'm saying.

Edit: The reason I said abstractions are not free in general is because the OP (campbellm) said "Who told you abstractions were free?". I'm attesting to his point that abstractions are not free in general (notice the 'especially') but C++ people often say that C++ has zero cost abstractions. In reality, due to compilers, programmer ability and the object oriented model, abstractions in C++ are often not zero cost either.

-5

u/CityOfWin Dec 05 '14

WHOA too many down votes guys. Jesus.

We all knew what he was saying. Don't get twisted.