Commit a514eff0 authored by Max Lyon's avatar Max Lyon

Merge from ReForm

parents 8362710d 09fd3eb7
......@@ -3,24 +3,29 @@
#ifndef BASE_DEBOUT_HH_INCLUDED
#define BASE_DEBOUT_HH_INCLUDED
#ifdef PROGRESS_ON
#include "Base/Progress/ProgressNode.hh"
#else//PROGRESS_ON
#define PROGRESS_TICK
#endif//PROGRESS_ON
// DEB_ON is defined, or not, in CMakeLists.txt for primary project
#ifndef DEB_ON
#define DEB_module(SS)
#define DEB_enter_func
#define DEB_enter_func PROGRESS_TICK;
#define DEB_only(CC)
#define DEB_exec(LL, AA) {}
#define DEB_exec_if(CC, LL, AA) {}
#define DEB_out(LL, AA) {}
#define DEB_out_if(CC, LL, AA) {}
#define DEB_line(LL, AA) {}
#define DEB_line_if(CC, LL, AA) {}
#define DEB_exec(LL, AA) { PROGRESS_TICK; }
#define DEB_exec_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_out(LL, AA) { PROGRESS_TICK; }
#define DEB_out_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_line(LL, AA) { PROGRESS_TICK; }
#define DEB_line_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_warning(LL, AA) {}
#define DEB_warning_if(CC, LL, AA) {}
#define DEB_mesh_if(CC, LL, FF, MM) {}
#define DEB_error(AA) {}
#define DEB_error_if(CC, AA) {}
#define DEB_error(AA) {}
#define DEB_error_if(CC, AA) {}
#else // DEB_ON
......@@ -130,27 +135,30 @@ std::string to_string(const T& _t)
#define DEB_module(MODULE)
//TODO: This should use an atomic thread-safe static int(s)
#define DEB_enter_func static int deb_nmbr = 0; \
#define DEB_enter_func \
PROGRESS_TICK; \
static int deb_nmbr = 0; \
static int deb_lvl = Debug::INVALID_LEVEL; \
::Debug::Enter deb(__FILE__, __FUNCTION__, deb_nmbr, deb_lvl);
#define DEB_only(CC) CC
#define DEB_exec(LL, AA) DEB_exec_if(true, LL, AA)
#define DEB_exec_if(CC, LL, AA) { if (deb.pass(LL) && (CC)) { AA; } }
#define DEB_exec_if(CC, LL, AA) { PROGRESS_TICK; \
{ if (deb.pass(LL) && (CC)) { AA; } } }
#define DEB_out(LL, AA) DEB_out_if(true, LL, AA)
#define DEB_out_if(CC, LL, AA) { if (deb.pass(LL) && (CC)) \
{ deb.stream() << AA << ::Base::Command::END; } }
#define DEB_out_if(CC, LL, AA) { PROGRESS_TICK; \
{ if (deb.pass(LL) && (CC)) { deb.stream() << AA << ::Base::Command::END; } } }
#define DEB_line(LL, AA) DEB_line_if(true, LL, AA)
#define DEB_line_if(CC, LL, AA) { if (deb.pass(LL) && (CC)) \
{ deb.stream() << AA << ::Base::LF; } }
#define DEB_line_if(CC, LL, AA) { PROGRESS_TICK; \
{ if (deb.pass(LL) && (CC)) { deb.stream() << AA << ::Base::LF; } } }
#define DEB_warning(LL, AA) DEB_warning_if(true, LL, AA)
#define DEB_warning_if(CC, LL, AA) { if (deb.pass(LL) && (CC)) \
{ ::Base::OStringStream strm; strm << AA; \
::Debug::warning(strm.str, BASE_CODELINK); } }
#define DEB_warning_if(CC, LL, AA) \
{ if (deb.pass(LL) && (CC)) { ::Base::OStringStream strm; strm << AA; \
::Debug::warning(strm.str, BASE_CODELINK); } }
#define DEB_error(AA) { ::Base::OStringStream strm; strm << AA; \
::Debug::error(strm.str, BASE_CODELINK); }
......@@ -164,5 +172,4 @@ std::string to_string(const T& _t)
#define DEB_os_str(AA) Debug::to_string(AA)
#endif // DEB_ON
#endif // BASE_DEBOUT_HH_INCLUDED
......@@ -20,7 +20,7 @@ public:
sw_.start();
}
~StopWatchSession()
~StopWatchSession() noexcept(false)
{
// TODO: implement "prettier" DEB out if seconds turn into minutes/hours/etc
DEB_line(deb_lvl_, sssn_name_ << " took " << sw_.stop()/1000.0 << " s.");
......
// (C) Copyright 2017 by Autodesk, Inc.
#include "Base/Security/Mandatory.hh"
#include "Base/Code/Quality.hh"
#include "ProgressNode.hh"
#include "Base/Utils/BaseError.hh"
#include <exception>
#ifdef PROGRESS_ON
namespace Progress {
/// Context implementation
Context::Context()
: abrt_stte_(AST_NONE), abrt_alwd_(false), phny_root_("phony"),
root_node_(&phny_root_), actv_node_(&phny_root_)
{}
void Context::abort()
{
// Don't throw if abort is not permitted or
// if there is stack unwinding currently in progress in this thread.
// Note that stack unwinding can be active, and it could be still possible to
// throw safely, see here:
// https://akrzemi1.wordpress.com/2011/09/21/destructors-that-throw/
// But we rather just wait until the current exception is handled.
if (!abrt_alwd_ || std::uncaught_exception())
return;
abrt_stte_ = AST_PROCESSING;
BASE_THROW_ERROR(PROGRESS_ABORTED);
}
void Context::resume_abort()
{
if (abrt_stte_ == AST_PROCESSING)
BASE_THROW_ERROR(PROGRESS_ABORTED);
}
void Context::end_abort()
{
abrt_stte_ = AST_NONE;
}
void Context::enter_node(Node* _node)
{ // NOTE: this function is written carefully to allow asynchronous inspection
// of the node graph from a tracking thread. It assumes the tracking thread
// does not use the node parent.
_node->tick_nmbr_ = 0;
if (phony())
root_node_ = _node;
else
_node->prnt_ = actv_node_;
actv_node_ = _node;
}
void Context::exit_node()
{ // NOTE: this function is written carefully to allow asynchronous inspection
// of the node graph from a tracking thread. It assumes the tracking thread
// does not use the node parent.
if (phony())
return; // TODO: this condition is a bug, so we need a DEB_error() here?
auto* const prnt = actv_node_->prnt_;
actv_node_->prnt_ = nullptr;
actv_node_ = prnt == nullptr ? &phny_root_ : prnt;
}
BASE_THREAD_LOCAL Context cntx;
/// Node implementation
Node::~Node()
{}
TickNumber Node::tick_number_max() const
{
return tick_nmbr_;
}
} //namespace Progress
#endif//PROGRESS_ON
// (C) Copyright 2017 by Autodesk, Inc.
#ifndef BASE_PROGRESS_NODE_HH_INCLUDED
#define BASE_PROGRESS_NODE_HH_INCLUDED
#ifdef PROGRESS_ON
#include <Base/Utils/Thread.hh>
namespace Progress {
//! Progress tick counter type
typedef unsigned long long TickNumber;
//! Represent an operational node in the progress graph
class Node
{
public:
typedef Node* (*MakeNodeFunction)(Node* _next);
static inline Node* make_child_list() { return nullptr; }
template <typename... ArgT>
static inline Node* make_child_list(MakeNodeFunction _make_node_fnct,
const ArgT&... _args)
{
return (*_make_node_fnct)(make_child_list(_args...));
}
public:
const char* const name;
Node(const char* const _name,
Node* _next = nullptr, Node* _chld = nullptr)
: name(_name), next_(_next), chld_(_chld), prnt_(nullptr), tick_nmbr_(0)
{}
virtual ~Node();
const Node* next() const { return next_; };
const Node* child() const { return chld_; };
TickNumber tick_number() const { return tick_nmbr_; }
virtual TickNumber tick_number_max() const;
void tick() { ++tick_nmbr_; }
protected:
Node* next_; //!< next node on the same level, last if nullptr
Node* chld_; //!< first child node, leaf if nullptr
Node* prnt_; //!< parent node, set temporarily
TickNumber tick_nmbr_; // number of ticks in the node
friend class Context;
};
class Context
{
public:
//! Default constructor
Context();
/*!
Get if the progress is "faking" tracking, i.e., using a phony root node.
Phony tracking is faster than checking if a root has been set.
*/
bool phony() const { return actv_node_ == &phny_root_; }
/*!
Get the currently active node, only makes sense to use that if not phony().
*/
const Node* active_node() const { return actv_node_; }
/*!
Get the root node, only makes sense to use that if not phony().
*/
const Node* root_node() const { return root_node_; }
/*!
Request progress abort, intended to be called asynchronously from a "tracking"
thread.
The abort will be triggered on the next \ref tick() in the context thread.
*/
void request_abort() { abrt_stte_ = AST_REQUEST; }
/*!
Resume an interrupted abort if the exception could be eaten unintentionally,
e.g., by a 3P library. This throws only if the progress is being aborted and
does nothing otherwise.
*/
void resume_abort();
/*!
Call this to finish the abort process and indicate that the thrown exception
has been handled.
*/
void end_abort();
void tick(const char* const /*_fnct*/)
{
actv_node_->tick();
if (abrt_stte_ == AST_REQUEST)
abort();
}
void enter_node(Node* _node);
void exit_node();
void set_abort_allowed(bool _abrt_alwd) { abrt_alwd_ = _abrt_alwd; }
bool abort_allowed() const { return abrt_alwd_; }
private:
enum AbortStateType
{
AST_NONE,
AST_REQUEST,
AST_PROCESSING
};
private:
AbortStateType abrt_stte_; //!< Abort state
bool abrt_alwd_; //!< Abort allowed flag, ignores AST_REQUEST if false
Node phny_root_; //!< "phony" root
Node* root_node_; //!< Root node
Node* actv_node_; //!< Active node
private:
//! Throws PROGRESS_ABORTED to abort the current operation.
void abort();
};
//! the current thread Progress context
extern BASE_THREAD_LOCAL Context cntx;
/*!
Enable (or disable) the Context::abort() processing, use to enable abort()
processing which is disabled by default.
Use this to set up a scope in which the progress can be aborted. Such scope
should be exception-handled, unless exiting the application on abort is desired.
*/
class AbortAllowedSession
{
public:
AbortAllowedSession(const bool _abrt_alwd)
: abrt_alwd_bckp_(cntx.abort_allowed())
{
cntx.set_abort_allowed(_abrt_alwd);
}
~AbortAllowedSession()
{
cntx.set_abort_allowed(abrt_alwd_bckp_);
}
private:
bool abrt_alwd_bckp_;
};
} //namespace Progress
#define PROGRESS_NODE_NAME(OPRT) OPRT##_node
#define PROGRESS_MAKE_NODE_NAME(OPRT) make_##OPRT##_node
#define PROGRESS_DECLARE_NODE(OPRT) \
namespace Progress { \
extern BASE_THREAD_LOCAL Node* PROGRESS_NODE_NAME(OPRT); \
Node* PROGRESS_MAKE_NODE_NAME(OPRT)(Node* _next = nullptr); \
} //namespace Progress {
#define PROGRESS_DEFINE_NODE_CUSTOM(TYPE, OPRT, ...) \
BASE_THREAD_LOCAL Progress::Node* Progress::PROGRESS_NODE_NAME(OPRT) = nullptr; \
Progress::Node* Progress::PROGRESS_MAKE_NODE_NAME(OPRT) \
(Progress::Node* _next) \
{ \
static BASE_THREAD_LOCAL TYPE node(#OPRT, _next, \
Node::make_child_list( __VA_ARGS__ ));\
return OPRT##_node = &node; \
}
#define PROGRESS_DEFINE_NODE(OPRT, ...) \
PROGRESS_DEFINE_NODE_CUSTOM(Node, OPRT, ##__VA_ARGS__)
#if defined(_MSC_VER)
#define __PROGRESS_FUNCTION__ __FUNCTION__ // works in VC well
#else
#define __PROGRESS_FUNCTION__ __PRETTY_FUNCTION__ // needed for gcc & xcode
#endif// _MSC_VER
#define PROGRESS_TICK { Progress::cntx.tick(__PROGRESS_FUNCTION__); }
#define PROGRESS_RESUME_ABORT { Progress::cntx.resume_abort(); }
#define PROGRESS_END_ABORT { Progress::cntx.end_abort(); }
#define PROGRESS_ALLOW_ABORT Progress::AbortAllowedSession abrt_alwd_sssn(true)
#else
#define PROGRESS_DECLARE_NODE(OPRT)
#define PROGRESS_DEFINE_NODE_CUSTOM(TYPE, OPRT, ...)
#define PROGRESS_DEFINE_NODE(OPRT, ...)
#define PROGRESS_TICK
#define PROGRESS_RESUME_ABORT
#define PROGRESS_END_ABORT
#define PROGRESS_ALLOW_ABORT
#endif// PROGRESS_ON
#endif//BASE_PROGRESS_NODE_HH_INCLUDED
......@@ -10,7 +10,7 @@
namespace Test {
namespace Checksum {
extern Level run_lvl = L_NONE;
Level run_lvl = L_NONE;
namespace {
......@@ -31,7 +31,7 @@ const Registry& registry()
// class Checksum implementation
Object::Object(const char* const _name, const Level _lvl)
: name_(_name), lvl_(_lvl)
: lvl_(_lvl), name_(_name)
{
auto pos = registry_modify().emplace(name_, this);
if (!pos.second)
......@@ -73,22 +73,66 @@ Difference Object::compare(
#define DIFFERENCE(TYPE) data_diff += Difference(Difference::TYPE)
switch (old_rslt_type)
{
case Result::OK :
case Result::OK:
switch (new_rslt_type)
{
return new_rslt_type == Result::WARNING ?
DIFFERENCE(SUSPICIOUS) : DIFFERENCE(REGRESSED);
}
case Result::WARNING: DIFFERENCE(SUSPICIOUS); break;
case Result::ERROR: DIFFERENCE(REGRESSED); break;
default: DIFFERENCE(FAILED); break; // FAILURE, CRASH, HANG
};
break;
case Result::WARNING :
switch (new_rslt_type)
{
return new_rslt_type == Result::OK ?
DIFFERENCE(IMPROVED) : DIFFERENCE(REGRESSED);
}
default : // ERROR, CRASH, HANG, etc
case Result::OK: DIFFERENCE(IMPROVED); break;
case Result::ERROR: DIFFERENCE(REGRESSED); break;
default: DIFFERENCE(FAILED); break; // FAILURE, CRASH, HANG
};
break;
case Result::ERROR :
switch (new_rslt_type)
{
return new_rslt_type == Result::OK || new_rslt_type == Result::WARNING ?
DIFFERENCE(IMPROVED) : DIFFERENCE(UNKNOWN);
}
case Result::OK:
case Result::WARNING: DIFFERENCE(IMPROVED); break;
default: DIFFERENCE(FAILED); break; // FAILURE, CRASH, HANG
};
break;
case Result::FAILURE:
switch (new_rslt_type)
{
// worked with or w/o issues, now fails
case Result::OK:
case Result::WARNING:
case Result::ERROR: DIFFERENCE(WORKED); break;
// gracious failure replaced by HANG or CRASH?!
default: DIFFERENCE(FAILED); break; // CRASH, HANG
};
break;
case Result::CRASH:
switch (new_rslt_type)
{
case Result::OK:
case Result::WARNING:
case Result::ERROR: DIFFERENCE(WORKED); break;
// CRASH replaced by gracious failure!
case Result::FAILURE: DIFFERENCE(IMPROVED); break;
default: DIFFERENCE(FAILED); break; // CRASH replaced by HANG?!
};
break;
case Result::HANG:
switch (new_rslt_type)
{
case Result::OK:
case Result::WARNING:
case Result::ERROR: DIFFERENCE(WORKED); break;
// HANG replaced by gracious failure!
case Result::FAILURE: DIFFERENCE(IMPROVED); break;
case Result::CRASH: DIFFERENCE(SUSPICIOUS); break; // HANG is now CRASH!
default: ; // disable warnings
};
break;
}
return data_diff;
}
void Object::add(const Result& _rslt, const String& _data)
......
......@@ -18,9 +18,9 @@ namespace Test {
namespace Checksum {
//! Enumerate the checksum levels
enum Level { L_NONE, L_PRIME, L_ALL };
enum Level { L_NONE, L_STABLE, L_PRIME, L_ALL };
extern Level run_lvl; //<! The checksum run level
const char* const LEVEL_TEXT[3] = { "NONE", "PRIME", "ALL" };
const char* const LEVEL_TEXT[4] = { "NONE", "STABLE", "PRIME", "ALL" };
//! typedef String, this is used a lot in this namespace
typedef std::string String;
......@@ -41,12 +41,14 @@ class Difference
public:
enum Type
{
EQUAL,
UNKNOWN,
IMPROVED,
NEGLEGIBLE,
SUSPICIOUS,
REGRESSED
EQUAL, // result is bitwise identical
UNKNOWN, // non-negligible difference, but of unknown quality
IMPROVED, // result is better
NEGLEGIBLE, // result is negligibly different
SUSPICIOUS, // result is different, and the new result might be worse
REGRESSED, // result is worse
WORKED, // result works now, but used to fail
FAILED // result fails now, but used to work
};
static const char* const type_text(const Type _type)
......@@ -58,7 +60,9 @@ public:
"IMPROVED",
"NEGLEGIBLE",
"SUSPICIOUS",
"REGRESSED"
"REGRESSED",
"WORKED",
"FAILED"
};
return dscr[_type];
}
......@@ -107,6 +111,8 @@ public:
return _os << _diff.type_text() << " " << _diff.dscr_;
}
bool operator<(const Difference& _othr) const { return type_ < _othr.type_; }
private:
Type type_;
String dscr_;
......
......@@ -21,7 +21,7 @@ namespace Checksum {
class Condition : public Object
{
public:
Condition() : Object("Condition", L_PRIME), nmbr_(0), fail_nmbr_(0) {}
Condition() : Object("Condition", L_STABLE), nmbr_(0), fail_nmbr_(0) {}
virtual void record(const char* const _cndt, const Base::CodeLink& _lnk,
const bool _rslt);
......
......@@ -9,3 +9,4 @@
// and it is not an error code.
DEFINE_ERROR(SUCCESS, "Success")
DEFINE_ERROR(TODO, "TODO: Undefined error message")
DEFINE_ERROR(PROGRESS_ABORTED, "Progress aborted")
......@@ -207,11 +207,25 @@ public:
print(bffr_, _bffr_size, _frmt, _vrbl);
}
#if __cplusplus >= 201103L || _MSC_VER >= 1900 //C++11 support
// Variadic template constructor
template <typename... ArgT>
FormatT(const char* const _frmt, const ArgT&... _args)
{
print(bffr_, _bffr_size, _frmt, _args...);
}
#endif//C++11 support
friend IOutputStream& operator<<(IOutputStream& _os, const Self& _frmt)
{
return _os << _frmt.bffr_;
}
const char* buffer() const { return bffr_; }
private:
char bffr_[_bffr_size];
};
......
// (C) Copyright 2017 by Autodesk, Inc.
#ifndef BASE_THREAD_HH_INCLUDED
#define BASE_THREAD_HH_INCLUDED
// System specific thread support
#if defined(__apple_build_version__)
// work around the lack of thread_local support in XCode 7
#if !__has_feature(cxx_thread_local)
#define BASE_THREAD_LOCAL_BROKEN
#endif//!__has_feature(cxx_thread_local)
#endif//defined(__apple_build_version__)
// TODO: move these macros to a more suitable location
#define GCC_VERSION(MAJOR, MINOR, PATCH) \
(MAJOR * 10000 + MINOR * 100 + PATCH)
#define GCC_VERSION_CURRENT\
GCC_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#if defined(__GNUC__) && GCC_VERSION_CURRENT < GCC_VERSION(4, 8, 3)
// there is a thread_local linker bug prior to gcc-4.8.3
// see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55800
#define BASE_THREAD_LOCAL_BROKEN
#endif//__GNUC__
#ifdef BASE_THREAD_LOCAL_BROKEN // if broken do not use thread_local
#define BASE_THREAD_LOCAL
#else// BASE_THREAD_LOCAL_BROKEN
#define BASE_THREAD_LOCAL thread_local
#endif// BASE_THREAD_LOCAL_BROKEN
#endif//BASE_THREAD_HH_INCLUDED
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment