From eaad036407c9546be0de27f61745fef4b6856e56 Mon Sep 17 00:00:00 2001 From: johannst Date: Mon, 29 May 2023 20:34:16 +0000 Subject: deploy: d2013ee5952bbcf88906a832748783e372f3a939 --- print.html | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 277 insertions(+), 6 deletions(-) (limited to 'print.html') diff --git a/print.html b/print.html index cd55f31..13a45f6 100644 --- a/print.html +++ b/print.html @@ -84,7 +84,7 @@ @@ -2618,6 +2618,7 @@ objdump -D -b binary -m i386:x86-64 test-bin
  • ld.so
  • symbol versioning
  • python
  • +
  • gcov
  • c++filt(1)

    Demangle symbol

    @@ -2628,6 +2629,7 @@ objdump -D -b binary -m i386:x86-64 test-bin
      readelf -W --dyn-syms <elf> | c++filt
     

    c++

    +

    Source files of most examples is available here.

    Type deduction

    Force compile error to see what auto is deduced to.

    auto foo = bar();
    @@ -2673,6 +2675,74 @@ int main() {
         show(1, 1.0, "foo", 'a');
     }
     
    +

    Forwarding reference (fwd ref)

    +

    A forwarding reference is a special references that preserves the value category of a function parameter and therefore allows for perfect +forwarding.

    +

    A forwarding reference is a parameter of a function template, which is declared +as rvalue reference to a non-cv qualified type template parameter.

    +
    template<typename T>
    +void fn(T&& param); // param is a forwarding reference
    +
    +

    Perfect forwarding can be achieved with std::forward. This for +example allows a wrapper function to pass a parameter with the exact same +value category to a down-stream function which is being invoked in the wrapper.

    +
    #include <cstdio>
    +#include <utility>
    +
    +struct M {};
    +
    +// -- CONSUMER -----------------------------------------------------------------
    +
    +void use(M&) {
    +    puts(__PRETTY_FUNCTION__);
    +}
    +
    +void use(M&&) {
    +    puts(__PRETTY_FUNCTION__);
    +}
    +
    +// -- TESTER -------------------------------------------------------------------
    +
    +template<typename T>
    +void wrapper(T&& param) {  // forwarding reference
    +    puts(__PRETTY_FUNCTION__);
    +    // PARAM is an lvalue, therefore this always calls use(M&).
    +    use(param);
    +}
    +
    +template<typename T>
    +void fwd_wrapper(T&& param) {  // forwarding reference
    +    puts(__PRETTY_FUNCTION__);
    +    // PARAM is an lvalue, but std::forward returns PARAM with the same value
    +    // category as the forwarding reference takes.
    +    use(std::forward<T>(param));
    +}
    +
    +// -- MAIN ---------------------------------------------------------------------
    +
    +int main() {
    +    {
    +        std::puts("==> wrapper rvalue reference");
    +        wrapper(M{});
    +        // calls use(M&).
    +
    +        std::puts("==> wrapper lvalue reference");
    +        struct M m;
    +        wrapper(m);
    +        // calls use(M&).
    +    }
    +    {
    +        std::puts("==> fwd_wrapper rvalue reference");
    +        fwd_wrapper(M{});
    +        // calls use(M&&).
    +
    +        std::puts("==> fwd_wrapper lvalue reference");
    +        struct M m;
    +        fwd_wrapper(m);
    +        // calls use(M&).
    +    }
    +}
    +

    Example: any_of template meta function

    #include <type_traits>
     
    @@ -2755,7 +2825,9 @@ void Invoke(const Ctx& C, P... params) {
     // Custom context.
     
     struct Ctx {
    -    void out(const char* s, unsigned v) const { printf("%s%x\n", s, v); }
    +    void out(const char* s, unsigned v) const {
    +        printf("%s%x\n", s, v);
    +    }
     };
     
     // Operations to invoke.
    @@ -2766,7 +2838,9 @@ struct OpA {
         using Return = int;
         static constexpr const char* const Name = "OpA";
     
    -    constexpr Return operator()(int a, int b) const { return a + b; }
    +    constexpr Return operator()(int a, int b) const {
    +        return a + b;
    +    }
     };
     
     template<typename Ctx>
    @@ -2775,7 +2849,9 @@ struct OpB {
         using Return = void;
         static constexpr const char* const Name = "OpB";
     
    -    Return operator()(const Ctx& C, unsigned a) const { C.out("a = ", a); }
    +    Return operator()(const Ctx& C, unsigned a) const {
    +        C.out("a = ", a);
    +    }
     };
     
     int main() {
    @@ -2812,7 +2888,9 @@ struct registry {
             return r.second;
         }
     
    -    R invoke(const std::string& nm, P... p) const { return invoke_impl<R>(nm, p...); }
    +    R invoke(const std::string& nm, P... p) const {
    +        return invoke_impl<R>(nm, p...);
    +    }
     
         void dump() const {
             for (const auto& it : m_fns) {
    @@ -3074,6 +3152,88 @@ int main() {
         // * No specialization matches, take the primary template.
     }
     
    +

    Example: Perfect forwarding

    +
    #include <cassert>
    +#include <cstdio>
    +#include <new>
    +#include <type_traits>
    +#include <utility>
    +
    +struct S {};
    +
    +struct M {
    +    M() {
    +        std::puts("M()");
    +    }
    +    M(const M&) {
    +        std::puts("M(M&)");
    +    }
    +    M(M&&) {
    +        std::puts("M(M&&)");
    +    }
    +    M& operator=(const M&) = delete;
    +    M& operator=(M&&) = delete;
    +
    +    M(S&, int) {
    +        std::puts("M(S&)");
    +    }
    +    M(S&&, int) {
    +        std::puts("M(S&&)");
    +    }
    +    ~M() {
    +        std::puts("~M()");
    +    }
    +};
    +
    +template<typename T>
    +struct option {
    +    static_assert(!std::is_reference_v<T>);
    +
    +    constexpr option() = default;
    +
    +    template<typename... Params>
    +    constexpr option(Params&&... params) : m_has_val(true) {
    +        // BAD: does not perfectly forward!
    +        //      eg, if option(S&&) is invoked, this would invoke M(S&).
    +        // new (&m_val) T(params...);
    +
    +        // GOOD: perfectly forwards params to constructor of T.
    +        new (m_val) T(std::forward<Params>(params)...);
    +    }
    +
    +    ~option() {
    +        reset();
    +    }
    +
    +    constexpr T& value() {
    +        assert(m_has_val);
    +        return *reinterpret_cast<T*>(m_val);
    +    }
    +
    +  private:
    +    constexpr void reset() {
    +        if (!m_has_val) {
    +            return;
    +        }
    +        if constexpr (!std::is_trivially_destructible_v<T>) {
    +            value().~T();
    +        };
    +    }
    +
    +    alignas(T) char m_val[sizeof(T)];
    +    bool m_has_val{false};
    +};
    +
    +int main() {
    +    std::puts("==> case 1");
    +    // invokes M(S&&, int)
    +    option<M> opt1(S{}, 123);
    +
    +    std::puts("==> case 2");
    +    // invokes M() + M(M&&)
    +    option<M> x /* option(M&&) + M(M&&) */ = M{} /* M() */;
    +}
    +

    glibc

    malloc tracer mtrace(3)

    Trace memory allocation and de-allocation to detect memory leaks. @@ -3115,6 +3275,8 @@ LD_PRELOAD=./libmtrace.so <binary>

  • -dM list only #define statements
  • -### dry-run, outputting exact compiler/linker invocations
  • -print-multi-lib print available multilib configurations
  • +
  • --help=<class> print description of cmdline options for given class, eg +warnings, optimizers, target, c, c++
  • Target options

    # List all target options with their description.
    @@ -3123,6 +3285,15 @@ gcc --help=target
     # Configure for current cpu arch and query (-Q) value of options.
     gcc -march=native -Q --help=target
     
    +

    Warnings / optimizations

    +
    # List available warnings with short description.
    +gcc --help=warnings
    +# List available optimizations with short description.
    +gcc --help=optimizers
    +
    +# Prepend --help with `-Q` to print wheter options are enabled or disabled
    +# instead showing their description.
    +

    Builtins

    __builtin_expect(expr, cond)

    Give the compiler a hint which branch is hot, so it can lay out the code @@ -3220,7 +3391,7 @@ aaa: bbb:

    Running above Makefile gives:

    -
    @ = foobar
    +
    @ = foobar
     < = aaa
     ^ = aaa bbb
     + = aaa bbb bbb
    @@ -3237,6 +3408,19 @@ bbb:
     
    • $(CURDIR): Path of current working dir after using make -C path
    +

    Arguments

    +

    Arguments specified on the command line override ordinary variable +assignments in the makefile (overriding variables).

    +
    VAR = abc
    +all:
    +	@echo VAR=$(VAR)
    +
    +
    # make
    +VAR=abc
    +
    +# make VAR=123
    +VAR=123
    +

    Useful functions

    Substitution references

    Substitute strings matching pattern in a list.

    @@ -3673,6 +3857,93 @@ def sum(a: int, b: int) -> int:

    Micro benchmarking.

    python -m timeit '[x.strip() for x in ["a ", " b"]]'
     
    +

    gcov(1)

    +

    Generate code coverage reports in text format.

    +

    Compile the source files of interest and link the final binary with the +following flags:

    +
      +
    • -fprofile-arcs instruments the generated code such that it writes a .gcda +file when being executed with details about which branches are taken
    • +
    • -ftest-coverage writes a .gcno notes file which is used by gcov during +generation of the coverage report
    • +
    +

    Depending on the build environment one may also set -fprofile-abs-path to +generate absolute path names into the .gcno note files, this can ease setups +where compilations are done in different directories to the source directory.

    +
    +

    gcc / clang also support an alias flag --coverage which during +compilation time is equivalent to -fprofile-arcs -ftest-coverage and during +link time -lgcov.

    +
    +

    After running the instrumented binary, the human readable report can then be +generated for a single file for example such as

    +
    gcov <SRC FILE | OBJ FILE>
    +
    +

    Example

    +
    #include <cstdio>
    +
    +void tell_me(int desc) {
    +  if (desc & 1) {
    +    std::puts("this");
    +  } else {
    +    std::puts("that");
    +  }
    +}
    +
    +int main(int argc, char *argv[]) {
    +  tell_me(argc);
    +  tell_me(argc);
    +  return 0;
    +}
    +
    +

    The gcov coverage report can be generated as follows for gcc or clang.

    +
    CXXFLAGS = -fprofile-arcs -ftest-coverage
    +# or the alias
    +#CXXFLAGS = --coverage
    +
    +cov-gcc: clean
    +	g++ $(CXXFLAGS) -c -o cov.o cov.cc
    +	g++ $(CXXFLAGS) -o $@ cov.o
    +	./$@
    +	gcov --demangled-names cov.cc
    +	cat cov.cc.gcov
    +.PHONY: cov-gcc
    +
    +cov-clang: clean
    +	clang++ $(CXXFLAGS) -c -o cov.o cov.cc
    +	clang++ $(CXXFLAGS) -o $@ cov.o
    +	./$@
    +	llvm-cov gcov --demangled-names cov.cc
    +	cat cov.cc.gcov
    +.PHONY: cov-clang
    +
    +clean:
    +	$(RM) *.gcov *.gcno *.gcda *.o cov-*
    +
    +

    The will generate a report similar to the following.

    +
    cat cov.cc.gcov
    +        -:    0:Source:cov.cc
    +        -:    0:Graph:cov.gcno
    +        -:    0:Data:cov.gcda
    +        -:    0:Runs:1
    +        -:    1:// Copyright (C) 2023 johannst
    +        -:    2:
    +        -:    3:#include <cstdio>
    +        -:    4:
    +        2:    5:void tell_me(int desc) {
    +        2:    6:  if (desc & 1) {
    +        2:    7:    std::puts("this");
    +        -:    8:  } else {
    +    #####:    9:    std::puts("that");
    +        -:   10:  }
    +        2:   11:}
    +        -:   12:
    +        1:   13:int main(int argc, char *argv[]) {
    +        1:   14:  tell_me(argc);
    +        1:   15:  tell_me(argc);
    +        1:   16:  return 0;
    +        -:   17:}
    +

    Linux