Skip to content

Commit

Permalink
(cont)
Browse files Browse the repository at this point in the history
  • Loading branch information
ygoldfeld committed Feb 4, 2025
1 parent 7298d17 commit 1d0869d
Show file tree
Hide file tree
Showing 3 changed files with 309 additions and 23 deletions.
79 changes: 66 additions & 13 deletions src/flow/log/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,65 @@
#include <typeinfo>
#include <utility>

// Macros.

#ifdef FLOW_DOXYGEN_ONLY // Compiler ignores; Doxygen sees.
/**
* Macro (preprocessor symbol) to optionally set (when building Flow and translation units that use flow::log::Config)
* to override a certain flow::log::Config internal behavior that can affect flow::log::Logger::should_log() perf.
* Typically there is no need to set this, especially if when calling
* flow::log::Config::init_component_to_union_idx_mapping() one always provides arg value
* `component_payload_type_info_ptr_is_uniq = false` (safe default). (Note: It is recommended to in fact set it
* to `true`.) So, if relevant, and if your benchmarks show `should_log()` is using significant
* processor cycles, it can make sense to experiment by setting this to other values; namely:
* - `::flow::log::Component_payload_type_dict_by_ptr_via_tree_map`
* - `::flow::log::Component_payload_type_dict_by_ptr_via_s_hash_map`
* - `::flow::log::Component_payload_type_dict_by_ptr_via_b_hash_map`
* - `::flow::log::Component_payload_type_dict_by_ptr_via_array`
* - `::flow::log::Component_payload_type_dict_by_ptr_via_sorted_array`
* Adventurous types can also implement their own such a template, as long as it implements the semantics of
* `flow::log::Component_payload_type_dict_by_ptr_via_tree_map`.
*
* @internal
* Regarding the default value: Briefly (this requires understanding of Component_payload_type_dict):
* All choices are pretty good, as all rely on pointers and not long type names, but reassuringly
* `std::unordered_map` (with `boost::unordered_map` very close) is the best, though with only 2 types
* linear-search array can be marginally better.
*/
# define FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_PTR value_for_exposition
/**
* Cousin of #FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_PTR, similarly affecting a related behavior.
* Again typically there is no need to set this, especially if when calling
* flow::log::Config::init_component_to_union_idx_mapping() one always provides arg value
* `component_payload_type_info_ptr_is_uniq = true`. Otherwise, and if your benchmarks show `should_log()` is
* using significant processor cycles, it can make sense to experiment by setting this to other values; namely:
* - `::flow::log::Component_payload_type_dict_by_val_via_tree_map`
* - `::flow::log::Component_payload_type_dict_by_val_via_s_hash_map`
* - `::flow::log::Component_payload_type_dict_by_val_via_b_hash_map`
* - `::flow::log::Component_payload_type_dict_by_val_via_array`
* - `::flow::log::Component_payload_type_dict_by_val_via_sorted_array`
* Adventurous types can also implement their own such a template, as long as it implements the semantics of
* `flow::log::Component_payload_type_dict_by_val_via_tree_map`.
*
* @internal
* Regarding the default value: This is the slower lookup type, and may be irrelevant, but within this category we can
* still do better or worse. As noted in flow::log::Config::Component_payload_type_to_cfg_map doc header
* by far the worst are the hash-maps; so not that.
* As of this writing that leaves sorted-map-based; linear-search array; and binary-search array.
* Empirically (presumably due to the <= ~10 # of types in map) the linear-search array is best, though
* when closer to 10 types for some hardware binary-search array works best. They are close, though.
*/
# define FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_PTR value_for_exposition
#else // if !defined(FLOW_DOXYGEN_ONLY)

# ifndef FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_PTR
# define FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_PTR Component_payload_type_dict_by_ptr_via_s_hash_map
# endif
# ifndef FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_VAL
# define FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_VAL Component_payload_type_dict_by_val_via_sorted_array
# endif
#endif // if !defined(FLOW_DOXYGEN_ONLY)

namespace flow::log
{

Expand Down Expand Up @@ -397,6 +456,8 @@ class Config
* -- very much including those that will *not* pass the should-log filter and hence will not log). This can have
* a *significant* impact on your overall performance.
*
* @see #FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_PTR and #FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_VAL.
*
* @internal
* ### Rationale for `enum_sparse_length` ###
* A design is possible (and indeed was used for a very brief period of time) that avoids the need for this arg.
Expand Down Expand Up @@ -731,21 +792,13 @@ class Config
* So what one needs to decide here is how to configure Component_payload_type_dict via its two template args
* just below. The current choices were obtained empirically with benchmarking (which can be found elsewhere
* in unit-test-land; a unit test will fail if those benchmarks start giving unexpected results, e.g. due
* to differing hardware or who knows what). Briefly (this requires understanding of Component_payload_type_dict):
*
* - Arg 1 (for "fast" pointer-based `type_info` lookup):
* All choices are pretty good, as all rely on pointers and not long type names, but reassuringly
* `std::unordered_map` (with `boost::unordered_map` very close) is the best.
* - Arg 2 (for "slow" name-based `type_info` lookup):
* As discussed -- when required -- this is the slower lookup type, but within this category we can
* still do better or worse. As noted above by far the worst are the hash-maps; so not that.
* As of this writing that leaves sorted-map-based; linear-search array; and binary-search array.
* Empirically (presumably due to the <= ~10 # of types in map) the linear-search array is best
* (the other 2 are pretty close).
* to differing hardware or who knows what). (See #FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_PTR and
* #FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_VAL `internal` section for discussion. They also allow
* user to override our decision.)
*/
using Component_payload_type_to_cfg_map
= Component_payload_type_dict<Component_payload_type_dict_by_ptr_via_s_hash_map<Component_config>,
Component_payload_type_dict_by_val_via_array<Component_config>>;
= Component_payload_type_dict<FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_PTR<Component_config>,
FLOW_LOG_CONFIG_COMPONENT_PAYLOAD_TYPE_DICT_BY_VAL<Component_config>>;

/// How we store a log::Sev (a mere `enum` itself) in a certain data structure.
using raw_sev_t = uint8_t;
Expand Down
36 changes: 33 additions & 3 deletions src/flow/log/detail/component_cfg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,9 @@ class Component_payload_type_dict
* This is (at least) potentially used by log::Config, internally, to map Component::payload_type() values to
* log-config table indices.
*
* Note: The API/semantics documented here are also shared by all `Component_payload_type_dict_by_val_*` types,
* except that the aforementioned `type_info` address uniqueness guarantee cannot be made for those types. Generally
* Note: The API/semantics documented here are also shared by all `Component_payload_type_dict_by_val_*` types
* (modulo member `bool S_BY_PTR_ELSE_VAL`) except that the aforementioned `type_info` address
* uniqueness guarantee cannot be made for those types. Generally
* *our* implementation(s) tend to be faster than their implementation(s), because internally lookup by pointer
* is faster than lookup by `std::type_index` which (due to the possibility of dynamic linking) must involve hashing
* and/or comparison of type name strings.
Expand All @@ -153,6 +154,14 @@ class Component_payload_type_dict_by_ptr_via_map
/// Convenience alias for the mapped-type looked-up by a `*this`.
using Cfg = typename Map_to_cfg::mapped_type;

// Constants.

/**
* For meta-programming convenience: `true` indicates for us `type_info` equality <=> `&type_info` equality;
* meaning we belong to the `Component_payload_type_dict_by_ptr_*` family.
*/
static constexpr bool S_BY_PTR_ELSE_VAL = true;

// Methods.

/**
Expand Down Expand Up @@ -209,6 +218,9 @@ class Component_payload_type_dict_by_ptr_via_array
// Types.
/// See Component_payload_type_dict_by_ptr_via_map.
using Cfg = Cfg_t;
// Constants.
/// See Component_payload_type_dict_by_ptr_via_map.
static constexpr bool S_BY_PTR_ELSE_VAL = true;
// Methods.
/**
* See Component_payload_type_dict_by_ptr_via_map.
Expand Down Expand Up @@ -268,6 +280,9 @@ class Component_payload_type_dict_by_ptr_via_sorted_array
// Types.
/// See Component_payload_type_dict_by_ptr_via_map.
using Cfg = Cfg_t;
// Constants.
/// See Component_payload_type_dict_by_ptr_via_map.
static constexpr bool S_BY_PTR_ELSE_VAL = true;
// Methods.
/**
* See Component_payload_type_dict_by_ptr_via_map.
Expand Down Expand Up @@ -335,6 +350,15 @@ class Component_payload_type_dict_by_val_via_map
using Map_to_cfg = Map_to_cfg_t;
/// See Component_payload_type_dict_by_ptr_via_map.
using Cfg = typename Map_to_cfg::mapped_type;

// Constants.

/**
* For meta-programming convenience: `false` indicates for us `type_info` equality <=> `&type_info` equality
* is *not* guaranteed; meaning we belong to the `Component_payload_type_dict_by_val_*` family.
*/
static constexpr bool S_BY_PTR_ELSE_VAL = false;

// Methods.
/**
* See Component_payload_type_dict_by_ptr_via_map.
Expand Down Expand Up @@ -370,7 +394,7 @@ class Component_payload_type_dict_by_val_via_map
* the string is more or less `type_info::name()`. In practice that usually contains at least the fully qualified
* name of each type being `typeid()`ed. Still... it is potentially not *too* terrible, as the first character
* to differ will end a string-compare, and this should typically come pretty early-on.
*
*
* If it is a hash map, it is amortized constant-time -- but the constant factor is (while technically a black box
* inside `std::type_info::hash_code()`) almost certainly composed of *very slow*
* hashing of the aforementioned `type_info::name()`. The constant time sounds nice, but for low N
Expand All @@ -393,6 +417,9 @@ class Component_payload_type_dict_by_val_via_array
// Types.
/// See Component_payload_type_dict_by_ptr_via_map.
using Cfg = Cfg_t;
// Constants.
/// See Component_payload_type_dict_by_val_via_map.
static constexpr bool S_BY_PTR_ELSE_VAL = false;
// Methods.
/**
* See Component_payload_type_dict_by_ptr_via_map.
Expand Down Expand Up @@ -451,6 +478,9 @@ class Component_payload_type_dict_by_val_via_sorted_array
// Types.
/// See Component_payload_type_dict_by_ptr_via_map.
using Cfg = Cfg_t;
// Constants.
/// See Component_payload_type_dict_by_val_via_map.
static constexpr bool S_BY_PTR_ELSE_VAL = false;
// Methods.
/**
* See Component_payload_type_dict_by_ptr_via_map.
Expand Down
Loading

0 comments on commit 1d0869d

Please sign in to comment.