Compiler aided optimization of the pimpl-idiom Alexander Richardson - - PowerPoint PPT Presentation

compiler aided optimization of the pimpl idiom
SMART_READER_LITE
LIVE PREVIEW

Compiler aided optimization of the pimpl-idiom Alexander Richardson - - PowerPoint PPT Presentation

Compiler aided optimization of the pimpl-idiom Alexander Richardson (alr48@cam.ac.uk) University of Cambridge Tuesday 14 th April, 2015 Tuesday 14 th April, 2015 Alexander Richardson Compiler aided optimization of the pimpl-idiom 1 / 11


slide-1
SLIDE 1

Compiler aided optimization of the pimpl-idiom

Alexander Richardson (alr48@cam.ac.uk)

University of Cambridge

Tuesday 14th April, 2015

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 1 / 11

slide-2
SLIDE 2

Pimpl-idiom

Used to keep binary compatibility in C++ libraries Heavily used by e.g. Qt and KDE Problem: requires extra memory allocations

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 2 / 11

slide-3
SLIDE 3

Example

//foo.h class Foo { public: Foo(const char∗ s); // ... private: FooPrivate∗ d; }; // foo.cpp class FooPrivate { // data members } Foo::Foo(const char∗ s) : d(new FooPrivate(s)) {}

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 3 / 11

slide-4
SLIDE 4

Pimpl overhead

Foo::d FooPrivate Foo* foo = new Foo() malloc() malloc()

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 4 / 11

slide-5
SLIDE 5

Even more overhead with inheritance

Base::d Derived::d DerivedPrivate BasePrivate Derived* foo = new Derived() malloc() malloc() malloc()

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 5 / 11

slide-6
SLIDE 6

Optimized layout

Base::d Derived::d DerivedPrivate BasePrivate Derived* foo = new Derived()

malloc() caculate_offset() caculate_offset()

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 6 / 11

slide-7
SLIDE 7

Solution

One large malloc() call and then use placement new Must retain binary compatibility Could be done at the library level Error-prone and hard to debug Requires changing every new expression! Better: Let clang do the work for us

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 7 / 11

slide-8
SLIDE 8

Solution

//foo.h class Foo { public: Foo(const char∗ s); // ... private: [[clang::pimpl]] FooPrivate∗ d; // only need to add one attribute }; // foo.cpp class FooPrivate { // data members } Foo::Foo(const char∗ s) : d(new FooPrivate(s)) {}

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 8 / 11

slide-9
SLIDE 9

Solution

Generate three static data members per class sizeof(private class) alignof(private class) Total required allocation size (optimization)

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 9 / 11

slide-10
SLIDE 10

Solution

Generate three static data members per class sizeof(private class) alignof(private class) Total required allocation size (optimization) Generate extra constructor overloads Foo(int x) → Foo(int x, void* dpointer) If dpointer is non-null use placement new Pass adjusted dpointer to base class constructor

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 9 / 11

slide-11
SLIDE 11

Solution

Generate three static data members per class sizeof(private class) alignof(private class) Total required allocation size (optimization) Generate extra constructor overloads Foo(int x) → Foo(int x, void* dpointer) If dpointer is non-null use placement new Pass adjusted dpointer to base class constructor Let original constructor delegate to new one and pass nullptr for the dpointer parameter

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 9 / 11

slide-12
SLIDE 12

Solution

Generate three static data members per class sizeof(private class) alignof(private class) Total required allocation size (optimization) Generate extra constructor overloads Foo(int x) → Foo(int x, void* dpointer) If dpointer is non-null use placement new Pass adjusted dpointer to base class constructor Let original constructor delegate to new one and pass nullptr for the dpointer parameter Add custom operator delete to private class

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 9 / 11

slide-13
SLIDE 13

Solution

Generate three static data members per class sizeof(private class) alignof(private class) Total required allocation size (optimization) Generate extra constructor overloads Foo(int x) → Foo(int x, void* dpointer) If dpointer is non-null use placement new Pass adjusted dpointer to base class constructor Let original constructor delegate to new one and pass nullptr for the dpointer parameter Add custom operator delete to private class Replace every new Foo(args) expression by

void∗ buffer = ::operator new(Foo::totalSize); Foo∗ foo = new (buffer) Foo(args,buffer + sizeof(Foo) + align);

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 9 / 11

slide-14
SLIDE 14

Conclusion

Over 50% speedup in allocation-heavy benchmark Total memory usage reduced by about 3%

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 10 / 11

slide-15
SLIDE 15

Code at https://github.com/a-richardson/clang Questions → alr48@cam.ac.uk

Alexander Richardson Compiler aided optimization of the pimpl-idiom Tuesday 14th April, 2015 11 / 11