the goal and the journey - turning back on one year of c++14 migration

47
Migration of C++ Libraries to C++14 The Goal and the Journey numscale Unlocked software performance Joel Falcou NumScale SAS Meeting C++ 2015 1 of 30

Upload: joel-falcou

Post on 19-Mar-2017

818 views

Category:

Engineering


1 download

TRANSCRIPT

Migration of C++ Libraries to C++14The Goal and the Journey

numscaleUnlocked software performance

Joel Falcou

NumScale SAS

Meeting C++ 2015

1 of 30

The Times, They’are-a-changing

Isn’t it 2015 already ?

� Code base migration to C++ 11/14 is a clear concern now� Time to support in compilers� Time to adopt the new standard

Worried ?

� Isn’t the new C++ even creepier ?� Is <feature X> really worth it ?� Will my coworkers get it ?

2 of 30

Sustainable C++

3 of 30

Sustainable C++

What is Sustainability for C++ ?

� Code intent must be obvious� Code must be clear for you and “future you”� Code must be clear for your coworkers

Are C++ 11 and 14 sustainable ?

� We claim that yes� Complex and simple tasks are easier� This talk is what we learnt

3 of 30

Fear and Loathing in C++

State of the union

What were we working on ?

� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment

Limitations of C++ 03

� Compile time� Complex customization point� Heavy dependency on Boost� Dependances on 3rd parties

5 of 30

State of the union

What were we working on ?

� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment

Limitations of C++ 03

� Compile time

� Complex customization point� Heavy dependency on Boost� Dependances on 3rd parties

5 of 30

State of the union

What were we working on ?

� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment

Limitations of C++ 03

� Compile time� Complex customization point

� Heavy dependency on Boost� Dependances on 3rd parties

5 of 30

State of the union

What were we working on ?

� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment

Limitations of C++ 03

� Compile time� Complex customization point� Heavy dependency on Boost

� Dependances on 3rd parties

5 of 30

State of the union

What were we working on ?

� Boost.Dispatch : tag dispatching abstraction� Boost.SIMD : portable standard SIMD API� NT2 : Matlab done right in C++� BSP++ : parallel application deployment

Limitations of C++ 03

� Compile time� Complex customization point� Heavy dependency on Boost� Dependances on 3rd parties

5 of 30

State of the union

6 of 30

Ocean Eleven

Anticipated features

� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support

Anticipated Benet

� Shorter compile-time� Simpler interaction wit user� Less external dependency� Did I say shorter compile-time ?

7 of 30

Ocean Eleven

Anticipated features

� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support

Anticipated Benet

� Shorter compile-time

� Simpler interaction wit user� Less external dependency� Did I say shorter compile-time ?

7 of 30

Ocean Eleven

Anticipated features

� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support

Anticipated Benet

� Shorter compile-time� Simpler interaction wit user

� Less external dependency� Did I say shorter compile-time ?

7 of 30

Ocean Eleven

Anticipated features

� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support

Anticipated Benet

� Shorter compile-time� Simpler interaction wit user� Less external dependency

� Did I say shorter compile-time ?

7 of 30

Ocean Eleven

Anticipated features

� Type deduction� Variadic templates� Anonymous functions� Tuples� Threading support

Anticipated Benet

� Shorter compile-time� Simpler interaction wit user� Less external dependency� Did I say shorter compile-time ?

7 of 30

Initial migration

What we did rst

� Used auto/decltype here and there� Used variadic templates where it was obvious� Used std::future for threading� Used lambda as short-cut to algorithm customization

Well, well, well ...

� Underwhelming results : compile time still unpleasant� Smelly code to adapt lagging compilers� STL QoI varies wildly between compilers� Customization was still problematic

8 of 30

Initial migration

What we did rst

� Used auto/decltype here and there� Used variadic templates where it was obvious� Used std::future for threading� Used lambda as short-cut to algorithm customization

Well, well, well ...

� Underwhelming results : compile time still unpleasant� Smelly code to adapt lagging compilers� STL QoI varies wildly between compilers� Customization was still problematic

8 of 30

The Million Dollars Man

Lesson #1When migrating to C++ 14, consider rebuilding the

code base in a C++ 14 idiomatic way.

9 of 30

C++ 14 is the new black

auto and decltype

Principles

� auto lets compiler nd the type of a variable� auto is usable as function return� decltype computes types of expressions

Effects

� Shorter, more generic code� Prevent type ‘intuition’ errors� Less symbol for the compiler to determine

11 of 30

auto and decltype

When to use auto ?

� Almost Always Auto (H. Sutter)� Except : non-template public API return type� Except : concrete type is needed for outside reasons� Caveat : auto deduction rules

When to use decltype ?

� Meta-programming tasks� SFINAE context in auto return type

12 of 30

Lesson Learnt

Lesson #2Follow the Almost Always Auto philosophy in a viral

way to ensure compile-time performance

13 of 30

Variadics Templates

Principles

� typename... Ts is a pack of types� Ts... is the pack expansion� Applicable to integral templates parameter� Applicable to lambdas parameters

Effects

� Less macros for variadics functions support� ... pack expansion generates code� ... works on arbitrary expression containing a pack

14 of 30

Variadics Templates examples

template<typename Pred, typename... Ts>struct all;

template<typename Pred, typename T>struct all : Pred::apply<T>::type{};

template<typename Pred, typename H, typename... Ts>struct all : and_ < typename all<Pred,H>::type

, typename all<Pred,Ts...>::type>

{};

15 of 30

Variadics Templates examples

template<bool... Bs> struct bools_ {};

template<typename Pred, typename... Ts>struct all : is_same< bools_<true, typename Pred<Ts>::type...>

, bools_<typename Pred<Ts>::type..., true>>

{};

15 of 30

Variadics Templates examples

template<typename F, typename... Ts>F for_each_args(F f, Ts&&...a){return initializer_list<int>{(ref(f)(forward<Ts>(a)),0)...}, f;

}

16 of 30

Variadics Templates

Turtles all the way down

� Don’t recurse variadics unless forced too� Each recursion generate symbols and need mangling� Instead, turn your code into something that can be comma separated

Effects

� Less symbols generated� Slimer executable� Faster compile-time

17 of 30

Lesson Learnt

Lesson #3With variadics templates, it’s variadic all the way down

18 of 30

Lambda functions

Principles

� Anonymous function block� Can be variadic, generic� Generates magical callable object for you

Effects

� Code is more localized� Less work for the compiler� Enable higher-order programming

19 of 30

Anonymous functions

template<typename F, typename G>auto compose( F f, G g ){return [f,g](auto x) { return f(g(x)); }

}

auto sqr_sin = compose( [](float x) { return x*x; }, &::sinf)

auto x = sqr_fin(1.758f);

20 of 30

Anonymous functions

template<typename C, typename T, typename F>typename std::enable_if<C::value,T&&>::type select(T&& t, F&&){return std::forward<T>(t);

}

template<typename C, typename T, typename F>typename std::enable_if<!C::value,F&&>::type select(T&&, F&& f){return std::forward<F>(f);

}

20 of 30

Anonymous functions

// Somewhere in a container constructor

std::for_each ( begin, end, select<std::is_trivial<type>>

( [](auto ) {}, [&a](auto x) { alloc_t::construct(a,&x); })

);

20 of 30

Lesson Learnt

Lesson #4If your issues is solved by a higher order function, use

polymorphic/variadic lambdas functions

21 of 30

But wait, there’s more

Truths ...

� Lambda are just magic functor type� Lambda’s capture are stored as members� All done automagically by the compiler

... and Consequences

� Lambda can be used as throw-away struct� Those structs have function interface� Cheap way to get a tuple !

22 of 30

But wait, there’s more

Truths ...

� Lambda are just magic functor type� Lambda’s capture are stored as members� All done automagically by the compiler

... and Consequences

� Lambda can be used as throw-away struct� Those structs have function interface� Cheap way to get a tuple !

22 of 30

Rule #1 - Don’t speak about expression templates

Expression Templates in 4 bullets

� Way to implement DSL in C++� Operators evaluates a meta-AST� AST is transformed at compile-time� Allow arbitrary code generation for high level API

Known Issues

� Compile Time Hog� Complex code base (e.g Boost.Proto)� Interaction with C++ 11

23 of 30

The lambda tree that hides the type forest

Tree, Tuples, all the same

� Heterogeneous tuples are Trees� A AST is basically a types tree� Implements AST as tuples ...� ... tuple simplemented as lambda

Benets

� Lambda wash away symbol name� Better compile time because of shorter names� Correct behavior with move semantic

24 of 30

One sec, Hold My Beer !

template<typename C0, typename C1> auto as_expr(C0&& c0, C1&& c1){auto erase_type = [&]() {struct node {storage_type_t<C0&&> c0_;storage_type_t<C1&&> c1_;

explicit node(C0&& a, C1&& b): c0_{std::forward<C0>(a)}, c1_{std::forward<C1>(b)}

{}};

return node{std::forward<C0>(c0), std::forward<C1>(c1)};};

25 of 30

One sec, Hold My Beer !

using node = decltype(erase_type());return expr<node> { std::forward<C0>(c0)

, std::forward<C1>(c1)};

}

25 of 30

One sec, Hold My Beer !

template <typename T>auto f(T&& t){return as_expr(std::forward<T>(t), std::forward<T>(t));

}

some_type x;

std::cout << typeid(f(x)).name() << ”\n”;std::cout << typeid(f(f(x))).name() << ”\n”;std::cout << typeid(f(f(f(x)))).name() << ”\n”;std::cout << typeid(f(f(f(f(x))))).name() << ”\n”;

25 of 30

One sec, Hold My Beer !

expr<‘public: <lambda_009ab8f375e07b4c1155929143898761>::operator()(void)const ’::‘2’::node,void>

expr<‘public: <lambda_f2b41fa0275084c9467959ede97530cb>::operator()(void)const ’::‘2’::node,void>

expr<‘public: <lambda_37974d88904c635bc611f74424f19963>::operator()(void)const ’::‘2’::node,void>

expr<‘public: <lambda_ac503c8f3aa72c2953f3b0f0037dfa56>::operator()(void)const ’::‘2’::node,void>

25 of 30

Lesson Learnt

Lesson #5Use lambda as disposable data structures to reduce

symbol size.

26 of 30

It’s a Wrap !

Conclusion

What we learnt

� C++ 14 change the DNA of the language� Code must adapt to C++ 14 deeply� Don’t be afraid to be creative, it *is* rewarding

Hat tipping in the general direction of :

� Louis Dionne : GSoC student extraordinaire, Boost.Hana author� Agustín ”K-ballo” Bergé : Mind-blowing C++ guru� Edouard Alligand : brigand’s co-author� Jonathan Poelen : brigand’s day 1 adopter and contributor

28 of 30

Conclusion

What we learnt

� C++ 14 change the DNA of the language� Code must adapt to C++ 14 deeply� Don’t be afraid to be creative, it *is* rewarding

Hat tipping in the general direction of :

� Louis Dionne : GSoC student extraordinaire, Boost.Hana author� Agustín ”K-ballo” Bergé : Mind-blowing C++ guru� Edouard Alligand : brigand’s co-author� Jonathan Poelen : brigand’s day 1 adopter and contributor

28 of 30

Thanks for your attention