KEMBAR78
Debugging and Profiling C++ Template Metaprograms | PDF
Debugging and Profiling
C++ Template Metaprograms
Zoltán Porkoláb
gsd@elte.hu
Ericsson Hungary
Eötvös Loránd University, Budapest
2015.02.27. C++ Russia 2015 2
● C++ Template Metaprogramming
● Possible debugging and profiling techiques
● Templight back-end tool
● Front-end tools
●
3rd
party applications – please, contribute!
● Vision
Agenda
2015.02.27. C++ Russia 2015 3
C++ Template Metaprograms
● Expression templates (since 1995!)
● Active libraries, compile-time adaption
● Static interface checking
● Simulating language extensions
● DSL embedding
● Many other areas ...
2015.02.27. C++ Russia 2015 4
Motivation – a personal view
template <class T, class S>
? max( T a, S b) // How to define the return value?
{
if ( a > b )
return a;
else
return b;
}
int main()
{
short is = 3; long il = 2; double d = 3.14;
cout << max( il, is);
cout << max( is, d);
}
2015.02.27. C++ Russia 2015 5
Compile-time vs. Run-time
Compile-time Run-timeCompile-time
2015.02.27. C++ Russia 2015 6
Compile-time vs. Run-time
Compile-time Run-timeCompile-time
3 < 3.14
2015.02.27. C++ Russia 2015 7
Compile-time vs. Run-time
Compile-time Run-timeCompile-time
3 > 2L
3 < 3.14
-1.0 < 0
2015.02.27. C++ Russia 2015 8
Compile-time vs. Run-time
Compile-time Run-timeCompile-time
3 > 2L
3 < 3.14
-1.0 < 0
int
std::string
double
long
2015.02.27. C++ Russia 2015 9
Motivation
template <class T, class S>
? max( T a, S b) // How to define the return value?
{
if ( a > b )
return a;
else
return b;
}
int main()
{
short is = 3; long il = 2; double d = 3.14;
cout << max( il, is); // long is ''better'' than short
cout << max( is, d); // double is ''better'' than short
}
2015.02.27. C++ Russia 2015 10
Compile-time vs. Run-time
Run-time
3 > 2L
3 < 3.14
-1.0 < 0
int
std::string
double
long
Template
design time
Compile-time
Template Instantiation
2015.02.27. C++ Russia 2015 11
Compile-time vs. Run-time
Run-timeCompile-time
Template Instantiation
3 > 2L
3 < 3.14
-1.0 < 0
int
std::string
double
long
T
S
Template
design time
2015.02.27. C++ Russia 2015 12
Compile-time vs. Run-time
Run-time
3 > 2L
3 < 3.14
-1.0 < 0
int
std::string
double
long
T
S
sizeof(T) < sizeof(S)
Template
design time
Compile-time
Template Instantiation
2015.02.27. C++ Russia 2015 13
Compile-time vs. Run-time
Run-time
3 > 2L
3 < 3.14
-1.0 < 0
int
std::string
double
long
T
S
sizeof(T) < sizeof(S)
Template
design time
Compile-time
Template Instantiation
2015.02.27. C++ Russia 2015 14
Motivation
template <class T, class S>
? max( T a, S b) // How to define the return value?
{
if ( a > b )
return a;
else
return b;
}
int main()
{
short is = 3; long il = 2; double d = 3.14;
cout << max( il, is); // long is ''better'' than short
cout << max( is, d); // double is ''better'' than short
}
2015.02.27. C++ Russia 2015 15
(de)Motivation
template <class T, class S>
auto max( T a, S b) -> decltype(a+b) // C++11
{
if ( a > b )
return a;
else
return b;
}
int main()
{
short is = 3; long il = 2; double d = 3.14;
cout << max( il, is); // -> long
cout << max( is, d); // -> double
}
2015.02.27. C++ Russia 2015 16
(de)Motivation
template <class T, class S>
typename std::common_type<T,S>::value max( T a, S b) // C++11
{
if ( a > b )
return a;
else
return b;
}
int main()
{
short is = 3; long il = 2; double d = 3.14;
cout << max( il, is); // -> long
cout << max( is, d); // -> double
}
2015.02.27. C++ Russia 2015 17
● Run-time ● Compile-time
2015.02.27. C++ Russia 2015 18
● Functions
● Values, literals
● Data structures
● If/else
● Loop
● Assignment
● May depend on input
● Run-time ● Compile-time
2015.02.27. C++ Russia 2015 19
● Functions
● Values, literals
● Data structures
● If/else
● Loop
● Assignment
● May depend on input
● Metafunctions (type)
● Const, enum,constexpr
● Typelist (type)
● Pattern matching
● Recursion
● Ref. Transparency
● Deterministic
● Run-time ● Compile-time
2015.02.27. C++ Russia 2015 20
● Imperative
● Object-oriented
● Generative
● (some) Functional
● Run-time ● Compile-time
2015.02.27. C++ Russia 2015 21
● Imperative
● Object-oriented
● Generative
● (some) Functional
● Pure Functional
● Run-time ● Compile-time
2015.02.27. C++ Russia 2015 22
The usual factorial program ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
int main()
{
const int fact5 = Factorial<5>::value;
}
2015.02.27. C++ Russia 2015 23
Bugs!!! ...
2015.02.27. C++ Russia 2015 24
The java programmer ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
} //;
int main()
{
const int fact5 = Factorial<5>::value;
}
2015.02.27. C++ Russia 2015 25
The java programmer ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
} //;
int main()
{
const int fact5 = Factorial<5>::value;
}
$ clang++ fact.cpp
fact.cpp:14:2: error: expected ';' after class
}
^
;
1 error generated.
2015.02.27. C++ Russia 2015 26
The vim user ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { ivalue = 1 };
};
int main()
{
const int fact5 = Factorial<5>::value;
}
2015.02.27. C++ Russia 2015 27
The vim user ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { ivalue = 1 };
};
int main()
{
const int fact5 = Factorial<5>::value;
}
$ clang++ fact.cpp
fact.cpp:5:34: error: no member named 'value' in 'Factorial<0>'
enum { value = Factorial<N-1>::value * N };
~~~~~~~~~~~~~~~~^
fact.cpp:5:18: note: in instantiation of template class 'Factorial<1>'
requested here
enum { value = Factorial<N-1>::value * N };
^
fact.cpp:5:18: note: in instantiation of template class 'Factorial<2>'
requested here
enum { value = Factorial<N-1>::value * N };
^
fact.cpp:5:18: note: in instantiation of template class 'Factorial<3>'
requested here
enum { value = Factorial<N-1>::value * N };
^
fact.cpp:5:18: note: in instantiation of template class 'Factorial<4>'
requested here
enum { value = Factorial<N-1>::value * N };
^
fact.cpp:16:21: note: in instantiation of template class 'Factorial<5>'
requested here
const int fact5 = Factorial<5>::value;
^
1 error generated.
2015.02.27. C++ Russia 2015 28
The negative approach ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
int main()
{
const int fact5 = Factorial<-5>::value;
}
2015.02.27. C++ Russia 2015 29
The negative approach ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
int main()
{
const int fact5 = Factorial<-5>::value;
}
$ clang++ fact4.cpp
fact4.cpp:6:18: fatal error: recursive template instantiation exceeded
maximum
depth of 512
enum { value = Factorial<N-1>::value * N };
^
fact4.cpp:6:18: note: in instantiation of template class 'Factorial<-517>'
requested here
enum { value = Factorial<N-1>::value * N };
Fact4.cpp:6:18: note: (skipping 503 contexts in backtrace; use
-ftemplate-backtrace-limit=0 to see all)
fact4.cpp:18:21: note: in instantiation of template class 'Factorial<-5>'
requested here
const int fact5 = Factorial<-5>::value;
^
fact4.cpp:6:18: note: use -ftemplate-depth=N to increase recursive
template
instantiation depth
enum { value = Factorial<N-1>::value * N };
^
1 error generated.
2015.02.27. C++ Russia 2015 30
The greedy ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
int main()
{
const int fact5 = Factorial<-5>::value;
}
$ clang++ -ftemplate-depth=10000 fact4.cpp
2015.02.27. C++ Russia 2015 31
The greedy ...
template <int N>
struct Factorial
{
enum { value = Factorial<N-1>::value * N };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
int main()
{
const int fact5 = Factorial<-5>::value;
}
$ clang++ -ftemplate-depth=10000 fact4.cpp$ clang++ -ftemplate-depth=10000 fact4.cpp
clang: error: unable to execute command: Segmentation fault
clang: error: clang frontend command failed due to signal (use -v to
see invocation)
clang version 3.2 (branches/release_32 180710)
Target: x86_64-unknown-linux-gnu
Thread model: posix
clang: note: diagnostic msg: PLEASE submit a bug report to
http://llvm.org/bugs/ and include the crash backtrace, preprocessed
source, and associated run script.
clang: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/fact4-iy6zKp.cpp
clang: note: diagnostic msg: /tmp/fact4-iy6zKp.sh
clang: note: diagnostic msg:
********************
2015.02.27. C++ Russia 2015 32
We need tools
● C++ syntax is not designed for metaprogramming
● Compilers are not optimised for detecting and
reporting template metaprogram errors
● Compilers are not optimised for template
metaprogram execution
● Compiler internals are black box for most
programmers
● Programmers have less experience with template
metaprograms
2015.02.27. C++ Russia 2015 33
Tool support
● Pretty good support for run-time C++
2015.02.27. C++ Russia 2015 34
Tool support
● Pretty good support for run-time C++
● Static analyzers, lint-like tools
● Debuggers
● Profilers
● Code comprehension tools
● Style checkers
2015.02.27. C++ Russia 2015 35
Tool support
● Pretty good support for run-time C++
● Static analyzers, lint-like tools
● Debuggers
● Profilers
● Code comprehension tools
● Style checkers
● Tools for template metaprogramming
2015.02.27. C++ Russia 2015 36
Tool support
● Pretty good support for run-time C++
● Static analyzers, lint-like tools
● Debuggers
● Profilers
● Code comprehension tools
● Style checkers
● Tools for template metaprogramming
● ?
2015.02.27. C++ Russia 2015 37
Tool support
Run-time Compile-time
2015.02.27. C++ Russia 2015 38
Tool support
Run-time Compile-time
2015.02.27. C++ Russia 2015 39
Tool support
Run-time Compile-time
2015.02.27. C++ Russia 2015 40
Tool support
Run-time Compile-time
2015.02.27. C++ Russia 2015 41
Tool support
Run-time Compile-time
2015.02.27. C++ Russia 2015 42
Related work
● Debugging
● Static assert/Concept check (Siek-Lumsdaine,
McNamara-Smaragdakis, Alexandrescu, others...)
● Warning generation (many attempt)
● Instrumentation
● Profiling
● Measuring full compilation (Gurtovoy-Abrahams)
● Measuring warning apperance (Watanabe)
● Visualize
● Source execution
● Instantiation graph
2015.02.27. C++ Russia 2015 43
Preprocessor
Instrumentator
Compiler
Warning parser
Positioner
#line mapping
Trace file
Position correct trace
Instrumented source
Preprocessed source
template<int i>
struct Factorial
{
/* ---------------- begin inserted ----------- */
struct _TEMPLIGHT_0s { int a; };
enum { _TEMPLIGHT_0 =
Templight::ReportTemplateBegin<_TEMPLIGHT_0s,
&_TEMPLIGHT_0s::a>::Value
};
/* ----------------- end inserted ------------ */
enum { value = Factorial<i-1>::value };
/* ---------------- begin inserted ----------- */
struct _TEMPLIGHT_1s { int a; };
enum { _TEMPLIGHT_1 =
Templight::ReportTemplateEnd<_TEMPLIGHT_1s,
&_TEMPLIGHT_1s::a>::Value
};
/* ----------------- end inserted ------------ */
};
template<>
struct Factorial<1>
{
/* ---------------- begin inserted ----------- */
struct _TEMPLIGHT_2s { int a; };
enum { _TEMPLIGHT_2 =
Templight::ReportTemplateBegin<_TEMPLIGHT_2s,
&_TEMPLIGHT_2s::a>::Value
};
/* ----------------- end inserted ------------ */
enum { value = 1 };
/* ---------------- begin inserted ----------- */
struct _TEMPLIGHT_3s { int a; };
enum { _TEMPLIGHT_3 =
Templight::ReportTemplateEnd<
_TEMPLIGHT_3s, &_TEMPLIGHT_3s::a>::Value
};
/* ----------------- end inserted ------------ */
};
GPCE 2006: Porkoláb, Mihalicza, Sipos:
Debugging C++ template metaprograms
2015.02.27. C++ Russia 2015 44
Instrumentation
● Advantages
● Light-way approach (compared to compiler hack)
● Grammar support (we used wave)
● Easier to port: just change the warning generator
2015.02.27. C++ Russia 2015 45
Instrumentation
● Advantages
● Light-way approach (compared to compiler hack)
● Grammar support (we used wave)
● Easier to port: just change the warning generator
● Disadvantages
● Complex constructs are hard (e.g. inheritance)
● Serious distortion in profiling information
● Memoization not detected
2015.02.27. C++ Russia 2015 46
Templight 2.0
● Based on LLVM/Clang compiler infrastructure
● Patch to
● Detect/measure instantiation
● Detect memoization
● Put timestamp on events
● Measure memory consumption (optional)
● Emit trace in various formats (txt, YAML, XML)
● Front-end tools
● Visual debugger
● Profiler data viewer
2015.02.27. C++ Russia 2015 47
Templight 2.0
Trace
C++
C++
C++
Templight patch
3rd party tools
Clang source
Interactive
debugger/
visualizer
Instantiation time
and memory
profiler
2015.02.27. C++ Russia 2015 48
Installation
● Visit http://plc.inf.elte.hu/templight
● Download templight-<timestamp>.tar.gz
● Contains clang patch and the two frontends
● Download Clang source
● Patch and build clang
● Build front-end tools (optional)
● >=Qt 4.6 and >=Graphviz 2.28.0 required
● $ qmake; make
2015.02.27. C++ Russia 2015 49
How to use
template<int N>
struct Fib
{
static const int value = Fib<N-2>::value + Fib<N-1>::value;
};
template<>
struct Fib<0>
{
static const int value = 0;
};
template<>
struct Fib<1>
{
static const int value = 1;
};
int main()
{
static const int fib5 = Fib<5>::value;
}
2015.02.27. C++ Russia 2015 50
How to use
$ clang++ -templight fib.cpp
$ ls
fib.cpp.trace.xml
$ wc fib.cpp.trace.xml
123 275 3838 fib.cpp.trace.xml
$ head fib.cpp.trace.xml
<?xml version="1.0" standalone="yes"?>
<Trace>
<TemplateBegin>
<Kind>TemplateInstantiation</Kind>
<Context context = "Fib&lt;5&gt;"/>
<PointOfInstantiation>fib.cpp|22|
14</PointOfInstantiation>
<TimeStamp time = "421998401.188854"/>
<MemoryUsage bytes = "0"/>
</TemplateBegin>
<TemplateBegin>
2015.02.27. C++ Russia 2015 51
2015.02.27. C++ Russia 2015 52
2015.02.27. C++ Russia 2015 53
2015.02.27. C++ Russia 2015 54
2015.02.27. C++ Russia 2015 55
2015.02.27. C++ Russia 2015 56
2015.02.27. C++ Russia 2015 57
2015.02.27. C++ Russia 2015 58
2015.02.27. C++ Russia 2015 59
2015.02.27. C++ Russia 2015 60
2015.02.27. C++ Russia 2015 61
2015.02.27. C++ Russia 2015 62
2015.02.27. C++ Russia 2015 63
2015.02.27. C++ Russia 2015 64
Filters
#include <iostream>
template<int N>
struct Fib
{
static const int value = Fib<N-2>::value + Fib<N-1>::value;
};
template<>
struct Fib<0>
{
static const int value = 0;
};
template<>
struct Fib<1>
{
static const int value = 1;
};
int main()
{
std::cout << Fib<5>::value << std::endl;
return 0;
}
2015.02.27. C++ Russia 2015 65
Filters
$ clang++ -templight fib.cpp
$ ls
fib.cpp.trace.xml
$ wc fib.cpp.trace.xml
18291 41765 738233 fib.cpp.trace.xml
$ head fib.cpp.trace.xml
<?xml version="1.0" standalone="yes"?>
<Trace>
<TemplateBegin>
<Kind>DefaultTemplateArgumentInstantiation</Kind>
<Context context = "std::basic_string"/>
<PointOfInstantiation>/usr/lib64/gcc/x86_64-suse-
linux/4.7/../../../../include/c++/4.7/bits/stringfwd.h|64|
11</PointOfInstantiation>
<TimeStamp time = "421999330.595354"/>
2015.02.27. C++ Russia 2015 66
2015.02.27. C++ Russia 2015 67
2015.02.27. C++ Russia 2015 68
2015.02.27. C++ Russia 2015 69
2015.02.27. C++ Russia 2015 70
2015.02.27. C++ Russia 2015 71
2015.02.27. C++ Russia 2015 72
2015.02.27. C++ Russia 2015 73
2015.02.27. C++ Russia 2015 74
2015.02.27. C++ Russia 2015 75
Memory usage
$ clang++ -templight-memory fib.cpp
$ ls
fib.cpp.memory.trace.xml
$ wc fib.cpp.memory.trace.xml
18291 41765 756365 fib5.cpp.memory.trace.xml
0$ head fib.cpp.trace.xml
<?xml version="1.0" standalone="yes"?>
<Trace>
<TemplateBegin>
<Kind>TemplateInstantiation</Kind>
<Context context = "Fib&lt;5&gt;"/>
<PointOfInstantiation>fib.cpp|22|
14</PointOfInstantiation>
<TimeStamp time = "421998401.188854"/>
<MemoryUsage bytes = "647664"/>
</TemplateBegin>
<TemplateBegin>
2015.02.27. C++ Russia 2015 76
Distortion
● Safe-mode is installed
● Invalid profiling info
● Flush messages even the compiler crashes
● Internal buffer collects events
● Heap allocated, not growing, size = 500.000
● Flush at end of compilation
● Distorsion < 3%
● clang++ -templight -trace-capacity=1000000
2015.02.27. C++ Russia 2015 77
Forks, Applications
● Martin Schulze modified client tools
http://github.com/schulmar/Templar
● Malte Skarupke's blog: comparing instantiation
time of unique_ptr, boost::flat_map, etc.
http://probablydance.com/2014/04/05/reinventing
-the-wheel-for-better-compile-time/
● Ábel Sinkovics: comparing lazy and greedy
metaprograms
2015.02.27. C++ Russia 2015 78
Evaluation of lazyness
● Ábel Sinkovics
2015.02.27. C++ Russia 2015 79
Metashell – interactive TMP REPL
● Ábel Sinkovics and András Kucsma
● Metashell https://github.com/sabel83/metashell
● Online demo: http://abel.web.elte.hu/shell
2015.02.27. C++ Russia 2015 80
Mikael Persson's Templight fork
● https://github.com/mikael-s-persson/templight
● https://github.com/mikael-s-persson/templight-tools
● Refactored and greatly
improved Templight
● Patch is under review
● Tools: KCacheGrind format
2015.02.27. C++ Russia 2015 81
Our vision
Trace
3rd party tools
Debugger/
visualizer
Other tools
2015.02.27. C++ Russia 2015 82
Summary
● Tool support for C++ metaprogramming
● Debugger/profiler requires compiler support
● Templight 2.0 based on clang
● Mikael's patch for clang is under review
● Please use it, give us feadback
● Compiler vendors, will you support Templight?
2015.02.27. C++ Russia 2015 83
Debugging and Profiling C++ Template Metaprograms
http://plc.inf.elte.hu/templight
gsd@elte.hu
Thank you!

Debugging and Profiling C++ Template Metaprograms

  • 1.
    Debugging and Profiling C++Template Metaprograms Zoltán Porkoláb gsd@elte.hu Ericsson Hungary Eötvös Loránd University, Budapest
  • 2.
    2015.02.27. C++ Russia2015 2 ● C++ Template Metaprogramming ● Possible debugging and profiling techiques ● Templight back-end tool ● Front-end tools ● 3rd party applications – please, contribute! ● Vision Agenda
  • 3.
    2015.02.27. C++ Russia2015 3 C++ Template Metaprograms ● Expression templates (since 1995!) ● Active libraries, compile-time adaption ● Static interface checking ● Simulating language extensions ● DSL embedding ● Many other areas ...
  • 4.
    2015.02.27. C++ Russia2015 4 Motivation – a personal view template <class T, class S> ? max( T a, S b) // How to define the return value? { if ( a > b ) return a; else return b; } int main() { short is = 3; long il = 2; double d = 3.14; cout << max( il, is); cout << max( is, d); }
  • 5.
    2015.02.27. C++ Russia2015 5 Compile-time vs. Run-time Compile-time Run-timeCompile-time
  • 6.
    2015.02.27. C++ Russia2015 6 Compile-time vs. Run-time Compile-time Run-timeCompile-time 3 < 3.14
  • 7.
    2015.02.27. C++ Russia2015 7 Compile-time vs. Run-time Compile-time Run-timeCompile-time 3 > 2L 3 < 3.14 -1.0 < 0
  • 8.
    2015.02.27. C++ Russia2015 8 Compile-time vs. Run-time Compile-time Run-timeCompile-time 3 > 2L 3 < 3.14 -1.0 < 0 int std::string double long
  • 9.
    2015.02.27. C++ Russia2015 9 Motivation template <class T, class S> ? max( T a, S b) // How to define the return value? { if ( a > b ) return a; else return b; } int main() { short is = 3; long il = 2; double d = 3.14; cout << max( il, is); // long is ''better'' than short cout << max( is, d); // double is ''better'' than short }
  • 10.
    2015.02.27. C++ Russia2015 10 Compile-time vs. Run-time Run-time 3 > 2L 3 < 3.14 -1.0 < 0 int std::string double long Template design time Compile-time Template Instantiation
  • 11.
    2015.02.27. C++ Russia2015 11 Compile-time vs. Run-time Run-timeCompile-time Template Instantiation 3 > 2L 3 < 3.14 -1.0 < 0 int std::string double long T S Template design time
  • 12.
    2015.02.27. C++ Russia2015 12 Compile-time vs. Run-time Run-time 3 > 2L 3 < 3.14 -1.0 < 0 int std::string double long T S sizeof(T) < sizeof(S) Template design time Compile-time Template Instantiation
  • 13.
    2015.02.27. C++ Russia2015 13 Compile-time vs. Run-time Run-time 3 > 2L 3 < 3.14 -1.0 < 0 int std::string double long T S sizeof(T) < sizeof(S) Template design time Compile-time Template Instantiation
  • 14.
    2015.02.27. C++ Russia2015 14 Motivation template <class T, class S> ? max( T a, S b) // How to define the return value? { if ( a > b ) return a; else return b; } int main() { short is = 3; long il = 2; double d = 3.14; cout << max( il, is); // long is ''better'' than short cout << max( is, d); // double is ''better'' than short }
  • 15.
    2015.02.27. C++ Russia2015 15 (de)Motivation template <class T, class S> auto max( T a, S b) -> decltype(a+b) // C++11 { if ( a > b ) return a; else return b; } int main() { short is = 3; long il = 2; double d = 3.14; cout << max( il, is); // -> long cout << max( is, d); // -> double }
  • 16.
    2015.02.27. C++ Russia2015 16 (de)Motivation template <class T, class S> typename std::common_type<T,S>::value max( T a, S b) // C++11 { if ( a > b ) return a; else return b; } int main() { short is = 3; long il = 2; double d = 3.14; cout << max( il, is); // -> long cout << max( is, d); // -> double }
  • 17.
    2015.02.27. C++ Russia2015 17 ● Run-time ● Compile-time
  • 18.
    2015.02.27. C++ Russia2015 18 ● Functions ● Values, literals ● Data structures ● If/else ● Loop ● Assignment ● May depend on input ● Run-time ● Compile-time
  • 19.
    2015.02.27. C++ Russia2015 19 ● Functions ● Values, literals ● Data structures ● If/else ● Loop ● Assignment ● May depend on input ● Metafunctions (type) ● Const, enum,constexpr ● Typelist (type) ● Pattern matching ● Recursion ● Ref. Transparency ● Deterministic ● Run-time ● Compile-time
  • 20.
    2015.02.27. C++ Russia2015 20 ● Imperative ● Object-oriented ● Generative ● (some) Functional ● Run-time ● Compile-time
  • 21.
    2015.02.27. C++ Russia2015 21 ● Imperative ● Object-oriented ● Generative ● (some) Functional ● Pure Functional ● Run-time ● Compile-time
  • 22.
    2015.02.27. C++ Russia2015 22 The usual factorial program ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { value = 1 }; }; int main() { const int fact5 = Factorial<5>::value; }
  • 23.
    2015.02.27. C++ Russia2015 23 Bugs!!! ...
  • 24.
    2015.02.27. C++ Russia2015 24 The java programmer ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { value = 1 }; } //; int main() { const int fact5 = Factorial<5>::value; }
  • 25.
    2015.02.27. C++ Russia2015 25 The java programmer ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { value = 1 }; } //; int main() { const int fact5 = Factorial<5>::value; } $ clang++ fact.cpp fact.cpp:14:2: error: expected ';' after class } ^ ; 1 error generated.
  • 26.
    2015.02.27. C++ Russia2015 26 The vim user ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { ivalue = 1 }; }; int main() { const int fact5 = Factorial<5>::value; }
  • 27.
    2015.02.27. C++ Russia2015 27 The vim user ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { ivalue = 1 }; }; int main() { const int fact5 = Factorial<5>::value; } $ clang++ fact.cpp fact.cpp:5:34: error: no member named 'value' in 'Factorial<0>' enum { value = Factorial<N-1>::value * N }; ~~~~~~~~~~~~~~~~^ fact.cpp:5:18: note: in instantiation of template class 'Factorial<1>' requested here enum { value = Factorial<N-1>::value * N }; ^ fact.cpp:5:18: note: in instantiation of template class 'Factorial<2>' requested here enum { value = Factorial<N-1>::value * N }; ^ fact.cpp:5:18: note: in instantiation of template class 'Factorial<3>' requested here enum { value = Factorial<N-1>::value * N }; ^ fact.cpp:5:18: note: in instantiation of template class 'Factorial<4>' requested here enum { value = Factorial<N-1>::value * N }; ^ fact.cpp:16:21: note: in instantiation of template class 'Factorial<5>' requested here const int fact5 = Factorial<5>::value; ^ 1 error generated.
  • 28.
    2015.02.27. C++ Russia2015 28 The negative approach ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { value = 1 }; }; int main() { const int fact5 = Factorial<-5>::value; }
  • 29.
    2015.02.27. C++ Russia2015 29 The negative approach ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { value = 1 }; }; int main() { const int fact5 = Factorial<-5>::value; } $ clang++ fact4.cpp fact4.cpp:6:18: fatal error: recursive template instantiation exceeded maximum depth of 512 enum { value = Factorial<N-1>::value * N }; ^ fact4.cpp:6:18: note: in instantiation of template class 'Factorial<-517>' requested here enum { value = Factorial<N-1>::value * N }; Fact4.cpp:6:18: note: (skipping 503 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all) fact4.cpp:18:21: note: in instantiation of template class 'Factorial<-5>' requested here const int fact5 = Factorial<-5>::value; ^ fact4.cpp:6:18: note: use -ftemplate-depth=N to increase recursive template instantiation depth enum { value = Factorial<N-1>::value * N }; ^ 1 error generated.
  • 30.
    2015.02.27. C++ Russia2015 30 The greedy ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { value = 1 }; }; int main() { const int fact5 = Factorial<-5>::value; } $ clang++ -ftemplate-depth=10000 fact4.cpp
  • 31.
    2015.02.27. C++ Russia2015 31 The greedy ... template <int N> struct Factorial { enum { value = Factorial<N-1>::value * N }; }; template <> struct Factorial<0> { enum { value = 1 }; }; int main() { const int fact5 = Factorial<-5>::value; } $ clang++ -ftemplate-depth=10000 fact4.cpp$ clang++ -ftemplate-depth=10000 fact4.cpp clang: error: unable to execute command: Segmentation fault clang: error: clang frontend command failed due to signal (use -v to see invocation) clang version 3.2 (branches/release_32 180710) Target: x86_64-unknown-linux-gnu Thread model: posix clang: note: diagnostic msg: PLEASE submit a bug report to http://llvm.org/bugs/ and include the crash backtrace, preprocessed source, and associated run script. clang: note: diagnostic msg: ******************** PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT: Preprocessed source(s) and associated run script(s) are located at: clang: note: diagnostic msg: /tmp/fact4-iy6zKp.cpp clang: note: diagnostic msg: /tmp/fact4-iy6zKp.sh clang: note: diagnostic msg: ********************
  • 32.
    2015.02.27. C++ Russia2015 32 We need tools ● C++ syntax is not designed for metaprogramming ● Compilers are not optimised for detecting and reporting template metaprogram errors ● Compilers are not optimised for template metaprogram execution ● Compiler internals are black box for most programmers ● Programmers have less experience with template metaprograms
  • 33.
    2015.02.27. C++ Russia2015 33 Tool support ● Pretty good support for run-time C++
  • 34.
    2015.02.27. C++ Russia2015 34 Tool support ● Pretty good support for run-time C++ ● Static analyzers, lint-like tools ● Debuggers ● Profilers ● Code comprehension tools ● Style checkers
  • 35.
    2015.02.27. C++ Russia2015 35 Tool support ● Pretty good support for run-time C++ ● Static analyzers, lint-like tools ● Debuggers ● Profilers ● Code comprehension tools ● Style checkers ● Tools for template metaprogramming
  • 36.
    2015.02.27. C++ Russia2015 36 Tool support ● Pretty good support for run-time C++ ● Static analyzers, lint-like tools ● Debuggers ● Profilers ● Code comprehension tools ● Style checkers ● Tools for template metaprogramming ● ?
  • 37.
    2015.02.27. C++ Russia2015 37 Tool support Run-time Compile-time
  • 38.
    2015.02.27. C++ Russia2015 38 Tool support Run-time Compile-time
  • 39.
    2015.02.27. C++ Russia2015 39 Tool support Run-time Compile-time
  • 40.
    2015.02.27. C++ Russia2015 40 Tool support Run-time Compile-time
  • 41.
    2015.02.27. C++ Russia2015 41 Tool support Run-time Compile-time
  • 42.
    2015.02.27. C++ Russia2015 42 Related work ● Debugging ● Static assert/Concept check (Siek-Lumsdaine, McNamara-Smaragdakis, Alexandrescu, others...) ● Warning generation (many attempt) ● Instrumentation ● Profiling ● Measuring full compilation (Gurtovoy-Abrahams) ● Measuring warning apperance (Watanabe) ● Visualize ● Source execution ● Instantiation graph
  • 43.
    2015.02.27. C++ Russia2015 43 Preprocessor Instrumentator Compiler Warning parser Positioner #line mapping Trace file Position correct trace Instrumented source Preprocessed source template<int i> struct Factorial { /* ---------------- begin inserted ----------- */ struct _TEMPLIGHT_0s { int a; }; enum { _TEMPLIGHT_0 = Templight::ReportTemplateBegin<_TEMPLIGHT_0s, &_TEMPLIGHT_0s::a>::Value }; /* ----------------- end inserted ------------ */ enum { value = Factorial<i-1>::value }; /* ---------------- begin inserted ----------- */ struct _TEMPLIGHT_1s { int a; }; enum { _TEMPLIGHT_1 = Templight::ReportTemplateEnd<_TEMPLIGHT_1s, &_TEMPLIGHT_1s::a>::Value }; /* ----------------- end inserted ------------ */ }; template<> struct Factorial<1> { /* ---------------- begin inserted ----------- */ struct _TEMPLIGHT_2s { int a; }; enum { _TEMPLIGHT_2 = Templight::ReportTemplateBegin<_TEMPLIGHT_2s, &_TEMPLIGHT_2s::a>::Value }; /* ----------------- end inserted ------------ */ enum { value = 1 }; /* ---------------- begin inserted ----------- */ struct _TEMPLIGHT_3s { int a; }; enum { _TEMPLIGHT_3 = Templight::ReportTemplateEnd< _TEMPLIGHT_3s, &_TEMPLIGHT_3s::a>::Value }; /* ----------------- end inserted ------------ */ }; GPCE 2006: Porkoláb, Mihalicza, Sipos: Debugging C++ template metaprograms
  • 44.
    2015.02.27. C++ Russia2015 44 Instrumentation ● Advantages ● Light-way approach (compared to compiler hack) ● Grammar support (we used wave) ● Easier to port: just change the warning generator
  • 45.
    2015.02.27. C++ Russia2015 45 Instrumentation ● Advantages ● Light-way approach (compared to compiler hack) ● Grammar support (we used wave) ● Easier to port: just change the warning generator ● Disadvantages ● Complex constructs are hard (e.g. inheritance) ● Serious distortion in profiling information ● Memoization not detected
  • 46.
    2015.02.27. C++ Russia2015 46 Templight 2.0 ● Based on LLVM/Clang compiler infrastructure ● Patch to ● Detect/measure instantiation ● Detect memoization ● Put timestamp on events ● Measure memory consumption (optional) ● Emit trace in various formats (txt, YAML, XML) ● Front-end tools ● Visual debugger ● Profiler data viewer
  • 47.
    2015.02.27. C++ Russia2015 47 Templight 2.0 Trace C++ C++ C++ Templight patch 3rd party tools Clang source Interactive debugger/ visualizer Instantiation time and memory profiler
  • 48.
    2015.02.27. C++ Russia2015 48 Installation ● Visit http://plc.inf.elte.hu/templight ● Download templight-<timestamp>.tar.gz ● Contains clang patch and the two frontends ● Download Clang source ● Patch and build clang ● Build front-end tools (optional) ● >=Qt 4.6 and >=Graphviz 2.28.0 required ● $ qmake; make
  • 49.
    2015.02.27. C++ Russia2015 49 How to use template<int N> struct Fib { static const int value = Fib<N-2>::value + Fib<N-1>::value; }; template<> struct Fib<0> { static const int value = 0; }; template<> struct Fib<1> { static const int value = 1; }; int main() { static const int fib5 = Fib<5>::value; }
  • 50.
    2015.02.27. C++ Russia2015 50 How to use $ clang++ -templight fib.cpp $ ls fib.cpp.trace.xml $ wc fib.cpp.trace.xml 123 275 3838 fib.cpp.trace.xml $ head fib.cpp.trace.xml <?xml version="1.0" standalone="yes"?> <Trace> <TemplateBegin> <Kind>TemplateInstantiation</Kind> <Context context = "Fib&lt;5&gt;"/> <PointOfInstantiation>fib.cpp|22| 14</PointOfInstantiation> <TimeStamp time = "421998401.188854"/> <MemoryUsage bytes = "0"/> </TemplateBegin> <TemplateBegin>
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
    2015.02.27. C++ Russia2015 64 Filters #include <iostream> template<int N> struct Fib { static const int value = Fib<N-2>::value + Fib<N-1>::value; }; template<> struct Fib<0> { static const int value = 0; }; template<> struct Fib<1> { static const int value = 1; }; int main() { std::cout << Fib<5>::value << std::endl; return 0; }
  • 65.
    2015.02.27. C++ Russia2015 65 Filters $ clang++ -templight fib.cpp $ ls fib.cpp.trace.xml $ wc fib.cpp.trace.xml 18291 41765 738233 fib.cpp.trace.xml $ head fib.cpp.trace.xml <?xml version="1.0" standalone="yes"?> <Trace> <TemplateBegin> <Kind>DefaultTemplateArgumentInstantiation</Kind> <Context context = "std::basic_string"/> <PointOfInstantiation>/usr/lib64/gcc/x86_64-suse- linux/4.7/../../../../include/c++/4.7/bits/stringfwd.h|64| 11</PointOfInstantiation> <TimeStamp time = "421999330.595354"/>
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
    2015.02.27. C++ Russia2015 75 Memory usage $ clang++ -templight-memory fib.cpp $ ls fib.cpp.memory.trace.xml $ wc fib.cpp.memory.trace.xml 18291 41765 756365 fib5.cpp.memory.trace.xml 0$ head fib.cpp.trace.xml <?xml version="1.0" standalone="yes"?> <Trace> <TemplateBegin> <Kind>TemplateInstantiation</Kind> <Context context = "Fib&lt;5&gt;"/> <PointOfInstantiation>fib.cpp|22| 14</PointOfInstantiation> <TimeStamp time = "421998401.188854"/> <MemoryUsage bytes = "647664"/> </TemplateBegin> <TemplateBegin>
  • 76.
    2015.02.27. C++ Russia2015 76 Distortion ● Safe-mode is installed ● Invalid profiling info ● Flush messages even the compiler crashes ● Internal buffer collects events ● Heap allocated, not growing, size = 500.000 ● Flush at end of compilation ● Distorsion < 3% ● clang++ -templight -trace-capacity=1000000
  • 77.
    2015.02.27. C++ Russia2015 77 Forks, Applications ● Martin Schulze modified client tools http://github.com/schulmar/Templar ● Malte Skarupke's blog: comparing instantiation time of unique_ptr, boost::flat_map, etc. http://probablydance.com/2014/04/05/reinventing -the-wheel-for-better-compile-time/ ● Ábel Sinkovics: comparing lazy and greedy metaprograms
  • 78.
    2015.02.27. C++ Russia2015 78 Evaluation of lazyness ● Ábel Sinkovics
  • 79.
    2015.02.27. C++ Russia2015 79 Metashell – interactive TMP REPL ● Ábel Sinkovics and András Kucsma ● Metashell https://github.com/sabel83/metashell ● Online demo: http://abel.web.elte.hu/shell
  • 80.
    2015.02.27. C++ Russia2015 80 Mikael Persson's Templight fork ● https://github.com/mikael-s-persson/templight ● https://github.com/mikael-s-persson/templight-tools ● Refactored and greatly improved Templight ● Patch is under review ● Tools: KCacheGrind format
  • 81.
    2015.02.27. C++ Russia2015 81 Our vision Trace 3rd party tools Debugger/ visualizer Other tools
  • 82.
    2015.02.27. C++ Russia2015 82 Summary ● Tool support for C++ metaprogramming ● Debugger/profiler requires compiler support ● Templight 2.0 based on clang ● Mikael's patch for clang is under review ● Please use it, give us feadback ● Compiler vendors, will you support Templight?
  • 83.
    2015.02.27. C++ Russia2015 83 Debugging and Profiling C++ Template Metaprograms http://plc.inf.elte.hu/templight gsd@elte.hu Thank you!