C++ Utilities

Scope

A scope configuration handles how the component instances within a bundle get inserted into the call-graph. The default behavior is scope::tree. This can be combined with scope::timeline to form a hierarchical call-graph where each entry is unique (lots of data): scope::config cfg = scope::tree{} + scope::timeline{}. When the scope::flat is used, all component instances become a child of the root node (i.e. the depth in call-stack is always zero). Similar to scope::tree, scope::flat can be combined with scope::timeline.

using bundle_t  = tim::component_tuple<wall_clock>;
namespace scope = tim::scope;

void foo()
{
    // always tree-scoped
    auto a = bundle_t("foo", scope::tree{});
    // always flat-scoped
    auto b = bundle_t("foo", scope::flat{});
    // always timeline-scoped
    auto c = bundle_t("foo", scope::timeline{});
    // subject to global settings for flat and timeline
    auto c = bundle_t("foo", scope::config{});
}
struct config : public std::bitset<scope_count>

this data type encodes the options of storage scope. The default is hierarchical (tree) scope. Specification of flat scope overrides the hierarchy scope, e.g. you cannot have a hierarchical flat scope. The timeline scope is meaningless should a specification of tree or flat, thus the valid combinations are: tree, flat, tree + timeline, flat + timeline.

struct tree : public std::integral_constant<int, 2>

Dummy struct to designates tree (hierarchical) storage. This scope (default) maintains nesting in the call-graph storage. In this scoping mode, the results will be separated from each other based on the identifier AND the current number of component instances in a “start” region. E.g. for two components with the same identifiers where the first calls start, then the second calls start then the second will be at a depth of +1 relative to the first (i.e. a child of the first).

Subclassed by tim::quirk::tree_scope

struct flat : public std::integral_constant<int, 0>

Dummy struct to designates flat (no hierarchy) storage. When flat scoping is globally enabled, all entries to the call-graph storage at entered at a depth of zero. Thus, if you want a report of all the function calls and their total values for each identifier, flat scoping should be globally enabled. This can be combined with timeline scoping to produce results where every measurement is its own call-graph entry at a depth of zero (produces a large amount of data). Flat-scoping can be enabled at the component bundler level also, there are two ways to do this: (1) to enable flat-scoping for all instances of the bundle, add tim::quirk::flat_scope to the template parameters of the bundler; (2) to enable flat-scoping for specific bundler instances, pass.

tim::quirk::config<tim::quirk::flat_scope, ...>{} 
as the second argument to the constructor of the bundle.

Subclassed by tim::quirk::flat_scope

struct timeline : public std::integral_constant<int, 1>

Dummy struct to designates timeline (hierarchical, non-duplicated) storage. It is meaningless by itself and should be combined with tim::scope::tree or tim::scope::flat. A tree timeline has all the hierarchy properties of the tree scope but entries at the same depth with the same identifiers are separated entries in the resuls. Timeline-scoping can be enabled at the component bundler level also, there are two ways to do this: (1) to enable timeline-scoping for all instances of the bundle, add tim::quirk::timeline_scope to the template parameters of the bundler; (2) to enable timeline-scoping for specific bundler instances, pass.

tim::quirk::config<tim::quirk::timeline_scope, ...>{} 
as the second argument to the constructor of the bundle.

Subclassed by tim::quirk::timeline_scope

Quirks

Quirks are used to slightly tweak the default behavior of component bundlers. Quirks can be included as template parameters and the property of the quirk will be applied to all instances of that component bundle, e.g. component_tuple<wall_clock, quirk::flat_scope> will cause all instances of that bundler to propagate the flat-storage specification to the wall-clock component regardless of the global setting. Quirks can also be applied per-component bundle instance within a tim::quirk::config<...> specification, e.g. an auto_list traditionally invokes start() on a component_list in the constructor and thus, any attempts to activate the components in the list after construction are ignored. Thus, if a special initialization case is desired for a particular instance of auto_list, the quirk::explicit_start can be added to suppress this behavior so that initialization can be performed before manually invoking start().

namespace quirk = tim::quirk;

using bundle_t = tim::auto_list<wall_clock, cpu_clock>;
using quirk_t  = quirk::config<quirk::explicit_start>;

void foo(bool condition)
{
    auto f = bundle_t("foo", quirk_t{});
    if(condition)
    {
        f.initialize<wall_clock>();
        f.disable<cpu_clock>();
        f.start();
    }
    // ...
}

void bar()
{
    auto f = bundle_t("bar");
    // ...
}
template<typename ...Types>
struct config

a variadic type which holds zero or more quirks that are passed to the constructor of a component bundler.

namespace quirk = tim::quirk;
using foo_t = tim::component_tuple<wall_clock>;

foo_t f("example", quirk::config<quirk::auto_start, quirk::flat_scope>{});
...
f.stop();

struct auto_start : public tim::concepts::quirk_type

Will cause non-auto bundlers to invoke start() during construction. If included as a template parameter of the bundler, it will have no effect. Usage:

// usage as template parameter
using bundle_t = tim::component_tuple<foo, tim::quirk::auto_start>;

void bar()
{
    using bundle_t = tim::component_tuple<foo>;

    // usage in constructor
    bundle_t obj{ "bar", tim::quirk::config<tim::quirk:auto_start>{} };
}

struct auto_stop : public tim::concepts::quirk_type

This quirk is irrelevant. This is the default behavior for all bundlers. See tim::quirk::explicit_stop to suppress this behavior.

struct explicit_start : public tim::concepts::quirk_type

Will cause auto bundlers to suppress calling start during construction. If included as a template parameter of the non-auto bundler, it will have no effect. Usage:

// usage as template parameter
using bundle_t = tim::auto_tuple<foo, tim::quirk::explicit_start>;

void bar()
{
    using bundle_t = tim::auto_tuple<foo>;

    // usage in constructor
    bundle_t obj{ "bar", tim::quirk::config<tim::quirk:explicit_start>{} };
    obj.start(); // now required
}

struct explicit_stop : public tim::concepts::quirk_type

Will cause bundlers to suppress calling stop during destruction. Usage:

  • bundler template parameter

// usage as template parameter
using foo_bundle_t = tim::auto_tuple<foo, tim::quirk::explicit_stop>;
using baz_bundle_t = tim::component_tuple<foo, tim::quirk::explicit_stop>;

struct explicit_push : public tim::concepts::quirk_type

Will suppress the implicit push() within start() for the bundlers with this characteristic Usage:

// usage as template parameter
using bundle_t = tim::component_tuple<foo, tim::quirk::explicit_push>;

struct explicit_pop : public tim::concepts::quirk_type

Will suppress the implicit pop() within stop() for the bundlers with this characteristic. Combining this with tim::quirk::explicit_push will effectively allow the measurements within the bundler to only be recorded locally and statistics to not be updated during intermediate measurements. Usage:

  • bundler template parameter

// usage as template parameter
using bundle_t = tim::component_tuple<tim::component::wall_clock,
                                      tim::quirk::explicit_push,
                                      tim::quirk::explicit_pop>;

static bundle_t fibonacci_total{ "total" };

long fibonacci(long n)
{
    bundle_t tmp{};
    tmp.start();
    auto result = (n < 2) ? n : (fibonacci(n-1) + fibonacci(n-2));
    fibonacci_total += tmp.stop();
    return result;
}

long foo(long n)
{
    // create new "fibonacci_total" entry in call-graph. Pushing will reset
    // any previous measurements
    bundle_total.push();

    // invoke this function when foo returns
    tim::scope::destructor _dtor{ []() { fibonacci_total.pop(); } };

    return fibonacci(n);
}

struct exit_report : public tim::concepts::quirk_type

Will cause auto-bundlers to write itself to stdout during destruction. Usage:

struct no_init : public tim::concepts::quirk_type

Will cause bundlers to suppress calling any routines related to initializing routines during construction. This is useful to override the default-initializer for a bundler type Usage:

struct no_store : public tim::concepts::quirk_type

Will cause bundlers to suppress any implicit entries into the component storage. This behavior is the default for tim::lightweight_bundle and is meaningless in that context. It is quite similar to adding both tim::quirk::explicit_push and tim::quirk::explicit_pop, however it effectively propagates tim::quirk::explicit_pop when used within the constructor. Usage:

struct tree_scope : public tim::scope::tree, public tim::concepts::quirk_type

Will cause bundlers to ignore the global settings and enforce hierarchical storage in the call-graph. Usage:

struct flat_scope : public tim::scope::flat, public tim::concepts::quirk_type

Will cause bundlers to ignore the global settings and enforce flat storage in the call-graph. Usage:

struct timeline_scope : public tim::scope::timeline, public tim::concepts::quirk_type

Will cause bundlers to ignore the global settings and enforce timeline storage. Usage:

Sampling

Typedefs

template<size_t N>
using fixed_size_t = typename fixed_size<N>::type
template<int... Ids>
using fixed_sig_t = typename fixed_sig<Ids...>::type

Enums

enum [anonymous]

\value tim::sampling::dynamic

A bare enumeration value implicitly convertible to zero.

Values:

enumerator dynamic
template<typename CompT, size_t N>
struct is_component<sampling::sampler<CompT, N>> : public true_type
#include “timemory/sampling/sampler.hpp”
namespace tim

Extern template declarations

namespace sampling

Typedefs

template<size_t N>
using fixed_size_t = typename fixed_size<N>::type
template<int... Ids>
using fixed_sig_t = typename fixed_sig<Ids...>::type

Enums

enum [anonymous]

\value tim::sampling::dynamic

A bare enumeration value implicitly convertible to zero.

Values:

enumerator dynamic
template<int... Ids>
struct fixed_sig : public std::true_type
#include “timemory/sampling/sampler.hpp”
template<>
struct fixed_sig<> : public std::false_type
#include “timemory/sampling/sampler.hpp”
template<size_t N>
struct fixed_size : public std::true_type
#include “timemory/sampling/sampler.hpp”
template<>
struct fixed_size<dynamic> : public std::false_type
#include “timemory/sampling/sampler.hpp”
template<template<typename...> class CompT, size_t N, typename ...Types, int... SigIds>
struct sampler<CompT<Types...>, N, SigIds...> : public tim::component::base<sampler<CompT<Types...>, N, SigIds...>, void>, private tim::policy::instance_tracker<sampler<CompT<Types...>, N, SigIds...>, false>
#include “timemory/sampling/sampler.hpp”

Public Types

using this_type = sampler<CompT<Types...>, N, SigIds...>
using base_type = component::base<this_type, void>
using components_t = CompT<Types...>
using signal_set_t = std::set<int>
using pid_cb_t = std::function<bool(pid_t, int, int)>
using array_t = conditional_t<fixed_size_t<N>::value, std::array<components_t, N>, std::vector<components_t>>
using array_type = array_t
using tracker_type = policy::instance_tracker<this_type, false>

Public Functions

template<typename Tp = fixed_size_t<N>, enable_if_t<Tp::value> = 0>
sampler(const std::string &_label, signal_set_t _good, signal_set_t _bad = signal_set_t{})
template<typename Tp = fixed_size_t<N>, enable_if_t<!Tp::value> = 0>
sampler(const std::string &_label, signal_set_t _good, signal_set_t _bad = signal_set_t{})
~sampler()
template<typename Tp = fixed_size_t<N>, enable_if_t<Tp::value> = 0>
void sample()
template<typename Tp = fixed_size_t<N>, enable_if_t<!Tp::value> = 0>
void sample()
template<typename Tp = fixed_sig_t<SigIds...>, enable_if_t<Tp::value> = 0>
void start()
template<typename Tp = fixed_sig_t<SigIds...>, enable_if_t<Tp::value> = 0>
void stop()
template<typename Tp = fixed_sig_t<SigIds...>, enable_if_t<!Tp::value> = 0>
void start()
template<typename Tp = fixed_sig_t<SigIds...>, enable_if_t<!Tp::value> = 0>
void stop()
inline bool is_good(int v) const
inline bool is_bad(int v) const
inline auto good_count() const
inline auto bad_count() const
inline auto count() const
inline auto &get_good()
inline auto &get_bad()
inline const auto &get_good() const
inline const auto &get_bad() const
inline auto backtrace_enabled() const
inline void enable_backtrace(bool val)
inline components_t *&get_last()
inline components_t *get_last() const
inline components_t *&get_latest()
inline components_t *get_latest() const
template<typename Tp = fixed_size_t<N>, enable_if_t<Tp::value> = 0>
components_t &get(size_t idx)
template<typename Tp = fixed_size_t<N>, enable_if_t<!Tp::value> = 0>
components_t &get(size_t idx)
template<typename Tp = fixed_size_t<N>, enable_if_t<Tp::value> = 0>
const components_t &get(size_t idx) const
template<typename Tp = fixed_size_t<N>, enable_if_t<!Tp::value> = 0>
const components_t &get(size_t idx) const
inline array_t &get_data()
inline const array_t &get_data() const
template<typename Tp, enable_if_t<Tp::value>>
sampler<CompT<Types...>, N, SigIds...>::components_t &get(size_t idx)
template<typename Tp, enable_if_t<Tp::value>>
const sampler<CompT<Types...>, N, SigIds...>::components_t &get(size_t idx) const

Public Static Functions

static void execute(int signum)
static void execute(int signum, siginfo_t*, void*)
static inline auto &get_samplers()
static inline auto get_latest_samples()
static void configure(std::set<int> _signals, int _verbose = 1)

Set up the sampler.

Parameters
  • _signals[in] A set of signals to catch

  • _verb[in] Logging Verbosity

static inline void configure(int _signal = SIGALRM, int _verbose = 1)
static inline void ignore(const std::set<int> &_signals)

Ignore the signals.

Parameters

_signals[in] Set of signals

static inline void clear()

Clear all signals. Recommended to call ignore() prior to clearing all the signals.

static inline void pause()

Pause until a signal is delivered.

template<typename Func = pid_cb_t>
static int wait(pid_t _pid, int _verbose, bool _debug, Func &&_callback = pid_callback())

Wait function with an optional user callback of type:

bool (*)(int a, int b)
where ‘a’ is the status, ‘b’ is the error value, and returns true if waiting should continue

Parameters
  • _pid[in] Process id to wait on

  • _verb[in] Logging verbosity

  • _debug[in] Enable debug logging

  • _cb[in] Callback for checking whether to exit

template<typename Func = pid_cb_t>
static inline int wait(int _verbose = settings::verbose(), bool _debug = settings::debug(), Func &&_callback = pid_callback())
template<typename Func, enable_if_t<std::is_function<Func>::value> = 0>
static inline int wait(pid_t _pid, Func &&_callback, int _verbose = settings::verbose(), bool _debug = settings::debug())
template<typename Func, enable_if_t<std::is_function<Func>::value> = 0>
static inline int wait(Func &&_callback, int _verbose = settings::verbose(), bool _debug = settings::debug())
static inline void set_flags(int _flags)

Set the sigaction flags, e.g. SA_RESTART | SA_SIGINFO.

Parameters

flags[in] – the sigaction flags to use

static void set_delay(double fdelay)

Value, expressed in seconds, that sets the length of time the sampler waits before starting sampling of the relevant measurements.

static void set_frequency(double ffreq)
static inline void set_rate(double frate)

Value, expressed in number of interupts per second, that configures the frequency that the sampler samples the relevant measurements.

static inline int64_t get_delay(int64_t units = units::usec)

Get the delay of the sampler.

static inline int64_t get_frequency(int64_t units = units::usec)

Get the frequency of the sampler.

static int get_itimer(int _signal)

Returns the itimer value associated with the given signal.

static bool check_itimer(int _stat, bool _throw_exception = false)

Checks to see if there was an error setting or getting itimer val.

Protected Attributes

bool m_backtrace = false
size_t m_idx = 0
components_t *m_last = nullptr
signal_set_t m_good = {}
signal_set_t m_bad = {}
array_t m_data = {}

Private Types

using sigaction_t = sigaction
using itimerval_t = itimerval

Private Static Functions

static inline persistent_data &get_persistent_data()
static inline pid_cb_t pid_callback()

Default callback when configuring sampler.

struct persistent_data

Public Members

bool m_active = false
int m_flags = SA_RESTART | SA_SIGINFO
double m_delay = 0.001
double m_freq = 1.0 / 2.0
sigaction_t m_custom_sigaction
itimerval_t m_custom_itimerval = {{1, 0}, {0, 1000}}
sigaction_t m_original_sigaction
itimerval_t m_original_itimerval
std::set<int> m_signals = {}
std::vector<this_type*> m_instances = {}
namespace trait
template<typename CompT, size_t N> sampler< CompT, N > > : public true_type
#include “timemory/sampling/sampler.hpp”

Conditional

Provides structure for conditionally generating a timemory component configuration

namespace tim

Extern template declarations

namespace utility