make expensive checks in asserts optional (#125)
This adds an Internal/EnableExpensiveChecks setting for enabling some or all expensive run-time checks to avoid a massive slowdown when assertions are enabled at compile-time. Currently these cover only the writer and reader-history cache checking. Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
parent
a39701fc2e
commit
7540ac8229
4 changed files with 93 additions and 29 deletions
|
@ -2625,6 +2625,9 @@ int dds_rhc_takecdr
|
|||
#define CHECK_MAX_CONDS 64
|
||||
static int rhc_check_counts_locked (struct rhc *rhc, bool check_conds, bool check_qcmask)
|
||||
{
|
||||
if (!(config.enabled_xchecks & DDS_XCHECK_RHC))
|
||||
return 1;
|
||||
|
||||
const uint32_t ncheck = rhc->nconds < CHECK_MAX_CONDS ? rhc->nconds : CHECK_MAX_CONDS;
|
||||
unsigned n_instances = 0, n_nonempty_instances = 0;
|
||||
unsigned n_not_alive_disposed = 0, n_not_alive_no_writers = 0, n_new = 0;
|
||||
|
|
|
@ -258,6 +258,7 @@ static void check_whc (const struct whc_impl *whc)
|
|||
assert (whc->maxseq_node == whc_findmax_procedurally (whc));
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
if (config.enabled_xchecks & DDS_XCHECK_WHC)
|
||||
{
|
||||
struct whc_intvnode *firstintv;
|
||||
struct whc_node *cur;
|
||||
|
|
|
@ -218,10 +218,15 @@ struct ssl_min_version {
|
|||
};
|
||||
#endif
|
||||
|
||||
/* Expensive checks (compiled in when NDEBUG not defined, enabled only if flag set in xchecks) */
|
||||
#define DDS_XCHECK_WHC 1u
|
||||
#define DDS_XCHECK_RHC 2u
|
||||
|
||||
struct config
|
||||
{
|
||||
int valid;
|
||||
uint32_t enabled_logcats;
|
||||
uint32_t enabled_xchecks;
|
||||
char *servicename;
|
||||
char *pcap_file;
|
||||
|
||||
|
|
|
@ -105,6 +105,14 @@ static const uint32_t logcat_codes[] = {
|
|||
DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING, DDS_LC_INFO, DDS_LC_CONFIG, DDS_LC_DISCOVERY, DDS_LC_DATA, DDS_LC_RADMIN, DDS_LC_TIMING, DDS_LC_TRAFFIC, DDS_LC_TOPIC, DDS_LC_TCP, DDS_LC_PLIST, DDS_LC_WHC, DDS_LC_THROTTLE, DDS_LC_RHC, DDS_LC_ALL
|
||||
};
|
||||
|
||||
/* "trace" is special: it enables (nearly) everything */
|
||||
static const char *xcheck_names[] = {
|
||||
"whc", "rhc", "all", NULL
|
||||
};
|
||||
static const uint32_t xcheck_codes[] = {
|
||||
DDS_XCHECK_WHC, DDS_XCHECK_RHC, ~(uint32_t)0
|
||||
};
|
||||
|
||||
/* We want the tracing/verbosity settings to be fixed while parsing
|
||||
the configuration, so we update this variable instead. */
|
||||
static unsigned enabled_logcats;
|
||||
|
@ -131,6 +139,7 @@ DUPF(string);
|
|||
DU(tracingOutputFileName);
|
||||
DU(verbosity);
|
||||
DUPF(logcat);
|
||||
DUPF(xcheck);
|
||||
DUPF(float);
|
||||
DUPF(int);
|
||||
DUPF(uint);
|
||||
|
@ -632,6 +641,12 @@ static const struct cfgelem unsupp_cfgelems[] = {
|
|||
"<p>Testing options.</p>" },
|
||||
{ GROUP("Watermarks", unsupp_watermarks_cfgelems),
|
||||
"<p>Watermarks for flow-control.</p>" },
|
||||
{ LEAF("EnableExpensiveChecks"), 1, "", ABSOFF(enabled_xchecks), 0, uf_xcheck, 0, pf_xcheck,
|
||||
"<p>This element enables expensive checks in builds with assertions enabled and is ignored otherwise. Recognised categories are:</p>\n\
|
||||
<ul><li><i>whc</i>: writer history cache checking</li>\n\
|
||||
<li><i>rhc</i>: reader history cache checking</li>\n\
|
||||
<p>In addition, there is the keyword <i>all</i> that enables all checks.</p>" },
|
||||
|
||||
END_MARKER
|
||||
};
|
||||
|
||||
|
@ -1348,24 +1363,33 @@ static void pf_boolean_default (struct cfgst *cfgst, void *parent, struct cfgele
|
|||
}
|
||||
#endif
|
||||
|
||||
static int uf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value)
|
||||
static int do_uint32_bitset(struct cfgst *cfgst, uint32_t *cats, const char **names, const uint32_t *codes, const char *value)
|
||||
{
|
||||
static const char **vs = logcat_names;
|
||||
static const uint32_t *lc = logcat_codes;
|
||||
char *copy = ddsrt_strdup(value), *cursor = copy, *tok;
|
||||
while ( (tok = ddsrt_strsep(&cursor, ",")) != NULL ) {
|
||||
int idx = list_index(vs, tok);
|
||||
int idx = list_index(names, tok);
|
||||
if ( idx < 0 ) {
|
||||
int ret = cfg_error(cfgst, "'%s' in '%s' undefined", tok, value);
|
||||
ddsrt_free(copy);
|
||||
return ret;
|
||||
}
|
||||
enabled_logcats |= lc[idx];
|
||||
*cats |= codes[idx];
|
||||
}
|
||||
ddsrt_free(copy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int uf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value)
|
||||
{
|
||||
return do_uint32_bitset (cfgst, &enabled_logcats, logcat_names, logcat_codes, value);
|
||||
}
|
||||
|
||||
static int uf_xcheck(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value)
|
||||
{
|
||||
uint32_t *elem = cfg_address(cfgst, parent, cfgelem);
|
||||
return do_uint32_bitset (cfgst, elem, xcheck_names, xcheck_codes, value);
|
||||
}
|
||||
|
||||
static int uf_verbosity(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value)
|
||||
{
|
||||
static const char *vs[] = {
|
||||
|
@ -2333,45 +2357,76 @@ static void pf_standards_conformance(struct cfgst *cfgst, void *parent, struct c
|
|||
cfg_log(cfgst, "%s%s", str, is_default ? " [def]" : "");
|
||||
}
|
||||
|
||||
static void pf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int is_default))
|
||||
static unsigned uint32_popcnt (uint32_t x)
|
||||
{
|
||||
unsigned n = 0;
|
||||
while (x != 0)
|
||||
{
|
||||
n += ((x & 1u) != 0);
|
||||
x >>= 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void do_print_uint32_bitset (struct cfgst *cfgst, uint32_t mask, size_t ncodes, const char **names, const uint32_t *codes, const char *suffix)
|
||||
{
|
||||
uint32_t remaining = config.enabled_logcats;
|
||||
char res[256] = "", *resp = res;
|
||||
const char *prefix = "";
|
||||
size_t i;
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
size_t max;
|
||||
for ( i = 0, max = 0; i < sizeof(logcat_codes) / sizeof(*logcat_codes); i++ )
|
||||
max += 1 + strlen(logcat_names[i]);
|
||||
size_t max = 0;
|
||||
for (size_t i = 0; i < ncodes; i++ )
|
||||
max += 1 + strlen(names[i]);
|
||||
max += 11; /* ,0x%x */
|
||||
max += 1; /* \0 */
|
||||
assert(max <= sizeof(res));
|
||||
}
|
||||
#endif
|
||||
/* TRACE enables ALLCATS, all the others just one */
|
||||
if ( (remaining & DDS_LC_ALL) == DDS_LC_ALL ) {
|
||||
resp += snprintf(resp, 256, "%strace", prefix);
|
||||
remaining &= ~DDS_LC_ALL;
|
||||
prefix = ",";
|
||||
}
|
||||
for ( i = 0; i < sizeof(logcat_codes) / sizeof(*logcat_codes); i++ ) {
|
||||
if ( remaining & logcat_codes[i] ) {
|
||||
resp += snprintf(resp, 256, "%s%s", prefix, logcat_names[i]);
|
||||
remaining &= ~logcat_codes[i];
|
||||
while (mask) {
|
||||
size_t i_best = 0;
|
||||
unsigned pc_best = 0;
|
||||
for (size_t i = 0; i < ncodes; i++) {
|
||||
uint32_t m = mask & codes[i];
|
||||
if (m == codes[i]) {
|
||||
unsigned pc = uint32_popcnt (m);
|
||||
if (pc > pc_best) {
|
||||
i_best = i;
|
||||
pc_best = pc;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pc_best != 0) {
|
||||
resp += snprintf(resp, 256, "%s%s", prefix, names[i_best]);
|
||||
mask &= ~codes[i_best];
|
||||
prefix = ",";
|
||||
} else {
|
||||
resp += snprintf (resp, 256, "%s0x%x", prefix, (unsigned) mask);
|
||||
mask = 0;
|
||||
}
|
||||
}
|
||||
if ( remaining ) {
|
||||
resp += snprintf(resp, 256, "%s0x%x", prefix, (unsigned) remaining);
|
||||
}
|
||||
assert(resp <= res + sizeof(res));
|
||||
/* can't do default indicator: user may have specified Verbosity, in
|
||||
which case EnableCategory is at default, but for these two
|
||||
settings, I don't mind. */
|
||||
cfg_log(cfgst, "%s", res);
|
||||
assert (resp <= res + sizeof(res));
|
||||
cfg_log (cfgst, "%s%s", res, suffix);
|
||||
}
|
||||
|
||||
static void pf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int is_default))
|
||||
{
|
||||
/* can't do default indicator: user may have specified Verbosity, in
|
||||
which case EnableCategory is at default, but for these two
|
||||
settings, I don't mind. */
|
||||
do_print_uint32_bitset (cfgst, config.enabled_logcats, sizeof(logcat_codes) / sizeof(*logcat_codes), logcat_names, logcat_codes, "");
|
||||
}
|
||||
|
||||
static void pf_xcheck(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default)
|
||||
{
|
||||
const uint32_t *p = cfg_address(cfgst, parent, cfgelem);
|
||||
#ifndef NDEBUG
|
||||
const char *suffix = is_default ? " [def]" : "";
|
||||
#else
|
||||
const char *suffix = " [ignored]";
|
||||
(void)is_default;
|
||||
#endif
|
||||
do_print_uint32_bitset (cfgst, *p, sizeof(xcheck_codes) / sizeof(*xcheck_codes), xcheck_names, xcheck_codes, suffix);
|
||||
}
|
||||
|
||||
static void print_configitems(struct cfgst *cfgst, void *parent, int isattr, struct cfgelem const * const cfgelem, int unchecked)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue