From 1bcdf6aafbbfced8252eedfcd4f221f260675467 Mon Sep 17 00:00:00 2001 From: vesis84 Date: Wed, 4 May 2016 12:14:33 +0200 Subject: [PATCH 1/5] base/kaldi_error : the error messages are no longer printed 2x - e.what() contains stackttrace or is empty string - we should also consider changing: 'std::cerr << e.what();' -> 'fprintf(stderr, e.what().c_str());' - fprintf is thread-safe and it is better not to mix 'std::cerr' and 'stderr', and 'stderr' is already used for logging... --- src/base/kaldi-error.cc | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/base/kaldi-error.cc b/src/base/kaldi-error.cc index f5e83ad55..b02d59520 100644 --- a/src/base/kaldi-error.cc +++ b/src/base/kaldi-error.cc @@ -181,22 +181,31 @@ MessageLogger::~MessageLogger() KALDI_NOEXCEPT(false) { std::string str = ss_.str(); while (!str.empty() && str[str.length() - 1] == '\n') str.resize(str.length() - 1); + + // print the mesage (or send to logging handler), SendToLog(envelope_, str.c_str()); - if (envelope_.severity > LogMessageEnvelope::Error) + if (envelope_.severity > LogMessageEnvelope::Error) { + // We are done, it was not 'KALDI_ERR << msg', return; - - // On error, throw an exception with the message, plus traceback info if - // available. - if (!std::uncaught_exception()) { -#ifdef HAVE_EXECINFO_H - throw std::runtime_error(str + "\n\n[stack trace: ]\n" + - KaldiGetStackTrace() + "\n"); -#else - throw std::runtime_error(str); -#endif } else { - abort(); + if (std::uncaught_exception()) { + // We get here, if there was an exception on this thread that has not + // yet arrived to its 'catch' clause... (can happen if an exception + // triggers a destructor and the destructor calls 'KALDI_ERR << msg'). + // Throwing a new exception would be unsafe! + abort(); + } else { + // On error we throw an exception. + // - 'what()' contains stack-trace or is empty. + // - the message was printed in 'SendToLog(...)'. +#ifdef HAVE_EXECINFO_H + throw std::runtime_error("\n[stack trace: ]\n" + + KaldiGetStackTrace() + "\n"); +#else + throw std::runtime_error(""); +#endif + } } } From 24bef8dcb4c501a59324debcafd9dcd426bfde23 Mon Sep 17 00:00:00 2001 From: vesis84 Date: Tue, 10 May 2016 17:41:49 +0200 Subject: [PATCH 2/5] base/kaldi_error : refactoring the logging code - some TODO's are to be decided: - Can we remove the: 'IsKaldiError()'? (It's very 'dirty' function. And it's used only in the table-I/O to suppress printing 'what' messages from KALDI_ERR. IMHO, it may not be a good idea to suppress this.) - With Kirill's log-handler, the log is sent and then there's no abort() for errors/asserts (seems like a bad idea, but it is the way it worked previously). --- src/base/kaldi-error.cc | 311 ++++++++++++++++++++++------------------ src/base/kaldi-error.h | 111 +++++++++----- 2 files changed, 245 insertions(+), 177 deletions(-) diff --git a/src/base/kaldi-error.cc b/src/base/kaldi-error.cc index b02d59520..b76c460b4 100644 --- a/src/base/kaldi-error.cc +++ b/src/base/kaldi-error.cc @@ -1,5 +1,6 @@ // base/kaldi-error.cc +// Copyright 2016 Brno University of Technology (author: Karel Vesely) // Copyright 2009-2011 Microsoft Corporation; Lukas Burget; Ondrej Glembek // See ../../COPYING for clarification regarding multiple authors @@ -18,25 +19,27 @@ // limitations under the License. #ifdef HAVE_EXECINFO_H -#include // To get stack trace in error messages. -// If this #include fails there is an error in the Makefile, it does not -// support your platform well. Make sure HAVE_EXECINFO_H is undefined, and the -// code will compile. -#ifdef HAVE_CXXABI_H -#include // For name demangling. -// Useful to decode the stack trace, but only used if we have execinfo.h -#endif // HAVE_CXXABI_H + #include // To get stack trace in error messages. + // If this #include fails there is an error in the Makefile, it does not + // support your platform well. Make sure HAVE_EXECINFO_H is undefined, + // and the code will compile. + #ifdef HAVE_CXXABI_H + #include // For name demangling. + // Useful to decode the stack trace, but only used if we have execinfo.h + #endif // HAVE_CXXABI_H #endif // HAVE_EXECINFO_H #include "base/kaldi-common.h" #include "base/kaldi-error.h" namespace kaldi { + +/***** GLOBAL VARIABLES FOR LOGGING *****/ + int32 g_kaldi_verbose_level = 0; const char *g_program_name = NULL; static LogHandler g_log_handler = NULL; - // If the program name was set (g_program_name != ""), the function // GetProgramName returns the program name (without the path) followed by a // colon, e.g. "gmm-align:". Otherwise it returns the empty string "". @@ -44,10 +47,83 @@ const char *GetProgramName() { return g_program_name == NULL ? "" : g_program_name; } + +/***** STACKTRACE *****/ + +static std::string Demangle(std::string trace_name) { +#if defined(HAVE_CXXABI_H) && defined(HAVE_EXECINFO_H) + // at input the string looks like: + // ./kaldi-error-test(_ZN5kaldi13UnitTestErrorEv+0xb) [0x804965d] + // We want to extract the name e.g. '_ZN5kaldi13UnitTestErrorEv", + // demangle it and return it. + + // try to locate '(' and '+', take the string in between, + size_t begin(trace_name.find("(")), + end(trace_name.rfind("+")); + if (begin != std::string::npos && end != std::string::npos && begin < end) { + trace_name = trace_name.substr(begin+1,end-(begin+1)); + } + // demangle, + int status; + char *demangled_name = abi::__cxa_demangle(trace_name.c_str(), 0, 0, &status); + std::string ans; + if (status == 0) { + ans = demangled_name; + free(demangled_name); + } else { + ans = trace_name; + } + // return, + return ans; +#else + return trace_name; +#endif +} + + +static std::string KaldiGetStackTrace() { + std::string ans; +#ifdef HAVE_EXECINFO_H + #define KALDI_MAX_TRACE_SIZE 50 + #define KALDI_MAX_TRACE_PRINT 20 // must be even. + // buffer for the trace, + void *trace[KALDI_MAX_TRACE_SIZE]; + // get the trace, + size_t size = backtrace(trace, KALDI_MAX_TRACE_SIZE); + // get the trace symbols, + char **trace_symbol = backtrace_symbols(trace, size); + + // Compose the 'string', + ans += "[ Stack-Trace: ]\n"; + if (size <= KALDI_MAX_TRACE_PRINT) { + for (size_t i = 0; i < size; i++) { + ans += Demangle(trace_symbol[i]) + "\n"; + } + } else { // print out first+last (e.g.) 5. + for (size_t i = 0; i < KALDI_MAX_TRACE_PRINT/2; i++) { + ans += Demangle(trace_symbol[i]) + "\n"; + } + ans += ".\n.\n.\n"; + for (size_t i = size - KALDI_MAX_TRACE_PRINT/2; i < size; i++) { + ans += Demangle(trace_symbol[i]) + "\n"; + } + if (size == KALDI_MAX_TRACE_SIZE) + ans += ".\n.\n.\n"; // stack was too long, probably a bug. + } + + // cleanup, + free(trace_symbol); // it's okay, just the pointers, not the strings. +#endif // HAVE_EXECINFO_H + return ans; +} + + +/***** KALDI LOGIGNG *****/ + // Given a filename like "/a/b/c/d/e/f.cc", GetShortFileName // returns "e/f.cc". Does not currently work if backslash is // the filename separator. -const char *GetShortFileName(const char *filename) { +static const char *GetShortFileName(const char *filename) { const char *last_slash = strrchr(filename, '/'); if (!last_slash) { return filename; @@ -58,115 +134,6 @@ const char *GetShortFileName(const char *filename) { } } -#if defined(HAVE_CXXABI_H) && defined(HAVE_EXECINFO_H) -// The function name looks like a macro: it's a macro if we don't have ccxxabi.h -inline void KALDI_APPEND_POSSIBLY_DEMANGLED_STRING(const char *to_append, - std::string *ans) { - // at input the string "to_append" looks like: - // ./kaldi-error-test(_ZN5kaldi13UnitTestErrorEv+0xb) [0x804965d] - // We want to extract the name e.g. '_ZN5kaldi13UnitTestErrorEv", - // demangle it and return it. - int32 status; - const char *paren = strchr(to_append, '('); - const char *plus = (paren ? strchr(paren, '+') : NULL); - if (!plus) { // did not find the '(' or did not find the '+' - // This is a soft failure in case we did not get what we expected. - ans->append(to_append); - return; - } - std::string stripped(paren+1, plus-(paren+1)); // the bit between ( and +. - - char *demangled_name = abi::__cxa_demangle(stripped.c_str(), 0, 0, &status); - - // if status != 0 it is an error (demangling failure), but not all names seem - // to demangle, so we don't check it. - - if (demangled_name != NULL) { - ans->append(demangled_name); - free(demangled_name); - } else { - ans->append(to_append); // add the original string. - } -} -#else // defined(HAVE_CXXABI_H) && defined(HAVE_EXECINFO_H) -#define KALDI_APPEND_POSSIBLY_DEMANGLED_STRING(to_append, ans) \ - ans->append(to_append) -#endif // defined(HAVE_CXXABI_H) && defined(HAVE_EXECINFO_H) - -#ifdef HAVE_EXECINFO_H -std::string KaldiGetStackTrace() { -#define KALDI_MAX_TRACE_SIZE 50 -#define KALDI_MAX_TRACE_PRINT 20 // must be even. - std::string ans; - void *array[KALDI_MAX_TRACE_SIZE]; - size_t size = backtrace(array, KALDI_MAX_TRACE_SIZE); - char **strings = backtrace_symbols(array, size); - if (size <= KALDI_MAX_TRACE_PRINT) { - for (size_t i = 0; i < size; i++) { - KALDI_APPEND_POSSIBLY_DEMANGLED_STRING(strings[i], &ans); - ans += "\n"; - } - } else { // print out first+last (e.g.) 5. - for (size_t i = 0; i < KALDI_MAX_TRACE_PRINT/2; i++) { - KALDI_APPEND_POSSIBLY_DEMANGLED_STRING(strings[i], &ans); - ans += "\n"; - } - ans += ".\n.\n.\n"; - for (size_t i = size - KALDI_MAX_TRACE_PRINT/2; i < size; i++) { - KALDI_APPEND_POSSIBLY_DEMANGLED_STRING(strings[i], &ans); - ans += "\n"; - } - if (size == KALDI_MAX_TRACE_SIZE) - ans += ".\n.\n.\n"; // stack was too long, probably a bug. - } - free(strings); // it's all in one big malloc()ed block. - - -#ifdef HAVE_CXXABI_H // demangle the name, if possible. -#endif // HAVE_CXXABI_H - return ans; -} -#endif - -void KaldiAssertFailure_(const char *func, const char *file, - int32 line, const char *cond_str) { - MessageLogger ml(LogMessageEnvelope::Error, func, file, line); - ml.stream() << "Assertion failed: " << cond_str; -#ifdef HAVE_EXECINFO_H - ml.stream() << "\nStack trace is:\n" << KaldiGetStackTrace(); -#endif -} - -LogHandler SetLogHandler(LogHandler new_handler) { - LogHandler old_handler = g_log_handler; - g_log_handler = new_handler; - return old_handler; -} - -static void SendToLog(const LogMessageEnvelope &envelope, - const char *message) { - // Send to a logging handler if provided. - if (g_log_handler != NULL) { - g_log_handler(envelope, message); - return; - } - - // Otherwise, use Kaldi default logging. - std::stringstream header; - if (envelope.severity > LogMessageEnvelope::Info) - header << "VLOG[" << envelope.severity << "] ("; - else if (envelope.severity == LogMessageEnvelope::Info) - header << "LOG ("; - else if (envelope.severity == LogMessageEnvelope::Warning) - header << "WARNING ("; - else - header << "ERROR ("; - header << GetProgramName() << envelope.func << "():" - << envelope.file << ':' << envelope.line << ")"; - - std::string header_str = header.str(); - fprintf(stderr, "%s %s\n", header_str.c_str(), message); -} MessageLogger::MessageLogger(LogMessageEnvelope::Severity severity, const char *func, const char *file, int32 line) { @@ -177,36 +144,104 @@ MessageLogger::MessageLogger(LogMessageEnvelope::Severity severity, envelope_.line = line; } + MessageLogger::~MessageLogger() KALDI_NOEXCEPT(false) { + // remove trailing '\n', std::string str = ss_.str(); while (!str.empty() && str[str.length() - 1] == '\n') str.resize(str.length() - 1); // print the mesage (or send to logging handler), - SendToLog(envelope_, str.c_str()); + MessageLogger::SendToLog(envelope_, str.c_str()); +} - if (envelope_.severity > LogMessageEnvelope::Error) { - // We are done, it was not 'KALDI_ERR << msg', + +void MessageLogger::SendToLog(const LogMessageEnvelope &envelope, + const char *message) { + // Send to a logging handler if provided. + if (g_log_handler != NULL) { + g_log_handler(envelope, message); + // TODO: should we abort() at 'assert_failed' or 'error'? return; + } + // Otherwise, we use the default Kaldi logging. + + // Build the log-message 'header', + std::stringstream header; + if (envelope.severity > LogMessageEnvelope::Info) { + header << "VLOG[" << envelope.severity << "] ("; } else { - if (std::uncaught_exception()) { - // We get here, if there was an exception on this thread that has not - // yet arrived to its 'catch' clause... (can happen if an exception - // triggers a destructor and the destructor calls 'KALDI_ERR << msg'). - // Throwing a new exception would be unsafe! - abort(); - } else { - // On error we throw an exception. - // - 'what()' contains stack-trace or is empty. - // - the message was printed in 'SendToLog(...)'. -#ifdef HAVE_EXECINFO_H - throw std::runtime_error("\n[stack trace: ]\n" + - KaldiGetStackTrace() + "\n"); -#else - throw std::runtime_error(""); -#endif + switch (envelope.severity) { + case LogMessageEnvelope::Info : + header << "LOG ("; + break; + case LogMessageEnvelope::Warning : + header << "WARNING ("; + break; + case LogMessageEnvelope::Error : + header << "ERROR ("; + break; + case LogMessageEnvelope::AssertFailed : + header << "ASSERTION_FAILED ("; + break; + default: + abort(); // coding errror (unknown 'severity'), } } + // fill the other info from the envelope, + header << GetProgramName() << envelope.func << "():" + << envelope.file << ':' << envelope.line << ")"; + + // In following lines we decide what to do, + if (envelope.severity >= LogMessageEnvelope::Warning) { + // VLOG, LOG, WARNING: + // print to stderr, + fprintf(stderr, "%s %s\n", header.str().c_str(), message); + } else if (envelope.severity == LogMessageEnvelope::Error) { + // ERROR: + // throw exception with 'what()' message (contains stack-trace), + std::string what_arg = header.str() + " " + + message + "\n\n" + + KaldiGetStackTrace() + "\n"; + if (!std::uncaught_exception()) { + throw std::runtime_error(what_arg); + } else { + // If we got here, this thread has already thrown exception, + // and this exception has not yet arrived to its 'catch' clause... + // Throwing a new exception would be unsafe! + // (can happen during 'stack unwinding', if we have 'KALDI_ERR << msg' + // in a destructor). + fprintf(stderr, "%s", what_arg.c_str()); + abort(); + } + } else if (envelope.severity == LogMessageEnvelope::AssertFailed) { + // ASSERT_FAILED: + // print to stderr (with stack-trace), call abort(), + fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message, + KaldiGetStackTrace().c_str()); + abort(); + } else { + abort(); // coding error (unknown 'severity'), + } } + +/***** KALDI ASSERTS *****/ + +void KaldiAssertFailure_(const char *func, const char *file, + int32 line, const char *cond_str) { + MessageLogger ml(LogMessageEnvelope::AssertFailed, func, file, line); + ml.stream() << ": '" << cond_str << "' "; +} + + +/***** THIRD-PARTY LOG-HANDLER *****/ + +LogHandler SetLogHandler(LogHandler new_handler) { + LogHandler old_handler = g_log_handler; + g_log_handler = new_handler; + return old_handler; +} + + } // end namespace kaldi diff --git a/src/base/kaldi-error.h b/src/base/kaldi-error.h index b76b69cc5..485ac38be 100644 --- a/src/base/kaldi-error.h +++ b/src/base/kaldi-error.h @@ -1,5 +1,6 @@ // base/kaldi-error.h +// Copyright 2016 Brno University of Technology (author: Karel Vesely) // Copyright 2009-2011 Microsoft Corporation; Ondrej Glembek; Lukas Burget; // Saarland University @@ -29,20 +30,22 @@ #include "base/kaldi-types.h" #include "base/kaldi-utils.h" - /* Important that this file does not depend on any other kaldi headers. */ +// By adding 'KALDI_NOEXCEPT(bool)' immediately after function declaration, +// we can tell the compiler that the function must-not produce +// exceptions (true), or may produce exceptions (false): #if _MSC_VER >= 1900 || (!defined(_MSC_VER) && __cplusplus >= 201103L) -#define KALDI_NOEXCEPT(Predicate) noexcept((Predicate)) + #define KALDI_NOEXCEPT(Predicate) noexcept((Predicate)) #elif defined(__GXX_EXPERIMENTAL_CXX0X__) && \ (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6) -#define KALDI_NOEXCEPT(Predicate) noexcept((Predicate)) + #define KALDI_NOEXCEPT(Predicate) noexcept((Predicate)) #else -#define KALDI_NOEXCEPT(Predicate) + #define KALDI_NOEXCEPT(Predicate) #endif #ifdef _MSC_VER -#define __func__ __FUNCTION__ + #define __func__ __FUNCTION__ #endif namespace kaldi { @@ -50,7 +53,9 @@ namespace kaldi { /// \addtogroup error_group /// @{ -/// This is set by util/parse-options.{h, cc} if you set --verbose = ? option. +/***** VERBOSITY LEVEL *****/ + +/// This is set by util/parse-options.{h, cc} if you set --verbose=? option. extern int32 g_kaldi_verbose_level; /// This is set by util/parse-options.{h, cc} (from argv[0]) and used (if set) @@ -66,9 +71,13 @@ inline int32 GetVerboseLevel() { return g_kaldi_verbose_level; } /// automatically from ParseOptions. inline void SetVerboseLevel(int32 i) { g_kaldi_verbose_level = i; } + +/***** KALDI LOGGING *****/ + /// Log message severity and source location info. struct LogMessageEnvelope { enum Severity { + AssertFailed = -3, Error = -2, Warning = -1, Info = 0, @@ -80,36 +89,59 @@ struct LogMessageEnvelope { int32 line; }; -/// Type of user-provided logging function. -typedef void (*LogHandler)(const LogMessageEnvelope &envelope, - const char *message); - -/// Set logging handler. If called with a non-NULL function pointer, the -/// function pointed by it is called to send messages to a caller-provided -/// log. If called with NULL pointer, restores default Kaldi error logging to -/// stderr. SetLogHandler is obviously not thread safe. -LogHandler SetLogHandler(LogHandler); - -// Class MessageLogger is invoked from the KALDI_ERR, KALDI_WARN, KALDI_LOG and +// Class MessageLogger is invoked from the KALDI_ASSERT, KALDI_ERR, KALDI_WARN and // KALDI_LOG macros. It formats the message, then either prints it to stderr or // passes to the log custom handler if provided, then, in case of the error, -// throws an std::runtime_exception. +// throws an std::runtime_exception, in case of failed KALDI_ASSERT calls abort(). // -// Note: we avoid using std::cerr, since it does not guarantee thread safety -// in general, until C++11; even then, in "cerr << a << b", other thread's -// output is allowed to intrude between a and b. fprintf(stderr,...) is -// guaranteed thread-safe, and outputs its formatted string atomically. +// Note: we avoid using std::cerr for thread safety issues. +// fprintf(stderr,...) is guaranteed thread-safe, and outputs +// its formatted string atomically. class MessageLogger { public: - MessageLogger(LogMessageEnvelope::Severity severity, const char *func, - const char *file, int32 line); + /// Constructor stores the info, + MessageLogger(LogMessageEnvelope::Severity severity, + const char *func, + const char *file, + int32 line); + + /// Destructor, calls 'SendToLog' which prints the message, + /// (since C++11 a 'throwing' destructor must be declared 'noexcept(false)') ~MessageLogger() KALDI_NOEXCEPT(false); + + /// The hook for the 'insertion operator', e.g. + /// 'KALDI_LOG << "Message,"', inline std::ostream &stream() { return ss_; } + +private: + /// The logging function, + static void SendToLog(const LogMessageEnvelope &env, const char *msg); + private: LogMessageEnvelope envelope_; std::ostringstream ss_; }; +// The definition of the logging macros, +#define KALDI_ERR \ + ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Error, \ + __func__, __FILE__, __LINE__).stream() +#define KALDI_WARN \ + ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Warning, \ + __func__, __FILE__, __LINE__).stream() +#define KALDI_LOG \ + ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Info, \ + __func__, __FILE__, __LINE__).stream() +#define KALDI_VLOG(v) if ((v) <= ::kaldi::g_kaldi_verbose_level) \ + ::kaldi::MessageLogger((::kaldi::LogMessageEnvelope::Severity)(v), \ + __func__, __FILE__, __LINE__).stream() + + +/***** KALDI ASSERTS *****/ + +void KaldiAssertFailure_(const char *func, const char *file, + int32 line, const char *cond_str); + // Note on KALDI_ASSERT and KALDI_PARANOID_ASSERT // The original (simple) version of the code was this // @@ -138,7 +170,7 @@ private: #else #define KALDI_ASSERT(cond) (void)0 #endif -// also see KALDI_COMPILE_TIME_ASSERT, defined in base/kaldi-utils.h, +// Also see KALDI_COMPILE_TIME_ASSERT, defined in base/kaldi-utils.h, // and KALDI_ASSERT_IS_INTEGER_TYPE and KALDI_ASSERT_IS_FLOATING_TYPE, // also defined there. // some more expensive asserts only checked if this defined @@ -150,25 +182,26 @@ private: #endif -#define KALDI_ERR \ - ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Error, \ - __func__, __FILE__, __LINE__).stream() -#define KALDI_WARN \ - ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Warning, \ - __func__, __FILE__, __LINE__).stream() -#define KALDI_LOG \ - ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Info, \ - __func__, __FILE__, __LINE__).stream() -#define KALDI_VLOG(v) if ((v) <= ::kaldi::g_kaldi_verbose_level) \ - ::kaldi::MessageLogger((::kaldi::LogMessageEnvelope::Severity)(v), \ - __func__, __FILE__, __LINE__).stream() +/***** THIRD-PARTY LOG-HANDLER *****/ +/// Type of third-party logging function, +typedef void (*LogHandler)(const LogMessageEnvelope &envelope, + const char *message); + +/// Set logging handler. If called with a non-NULL function pointer, the +/// function pointed by it is called to send messages to a caller-provided +/// log. If called with NULL pointer, restores default Kaldi error logging to +/// stderr. SetLogHandler is obviously not thread safe. +LogHandler SetLogHandler(LogHandler); + + +/***** DEPRECATED *****/ +/// TODO: Deprecated function, get rid of it if possible! inline bool IsKaldiError(const std::string &str) { + KALDI_WARN << "Deprecated!"; return(!strncmp(str.c_str(), "ERROR ", 6)); } -void KaldiAssertFailure_(const char *func, const char *file, - int32 line, const char *cond_str); /// @} end "addtogroup error_group" From a4fff0d55113cd75600eec75a7d4b9f1990606bc Mon Sep 17 00:00:00 2001 From: vesis84 Date: Tue, 10 May 2016 20:17:26 +0200 Subject: [PATCH 3/5] base/kaldi_error : integrating comments from Dan. --- src/base/kaldi-error.cc | 74 ++++++++++++++++++------------------- src/base/kaldi-error.h | 23 ++++-------- src/feat/wave-reader.h | 12 +++--- src/hmm/posterior.cc | 12 ++---- src/util/kaldi-holder-inl.h | 31 ++++++---------- 5 files changed, 65 insertions(+), 87 deletions(-) diff --git a/src/base/kaldi-error.cc b/src/base/kaldi-error.cc index b76c460b4..bc8a7af09 100644 --- a/src/base/kaldi-error.cc +++ b/src/base/kaldi-error.cc @@ -19,14 +19,14 @@ // limitations under the License. #ifdef HAVE_EXECINFO_H - #include // To get stack trace in error messages. - // If this #include fails there is an error in the Makefile, it does not - // support your platform well. Make sure HAVE_EXECINFO_H is undefined, - // and the code will compile. - #ifdef HAVE_CXXABI_H - #include // For name demangling. - // Useful to decode the stack trace, but only used if we have execinfo.h - #endif // HAVE_CXXABI_H +#include // To get stack trace in error messages. +// If this #include fails there is an error in the Makefile, it does not +// support your platform well. Make sure HAVE_EXECINFO_H is undefined, +// and the code will compile. +#ifdef HAVE_CXXABI_H +#include // For name demangling. +// Useful to decode the stack trace, but only used if we have execinfo.h +#endif // HAVE_CXXABI_H #endif // HAVE_EXECINFO_H #include "base/kaldi-common.h" @@ -48,6 +48,23 @@ const char *GetProgramName() { } +/***** HELPER FUNCTIONS *****/ + +// Given a filename like "/a/b/c/d/e/f.cc", GetShortFileName +// returns "e/f.cc". Does not currently work if backslash is +// the filename separator. +static const char *GetShortFileName(const char *filename) { + const char *last_slash = strrchr(filename, '/'); + if (!last_slash) { + return filename; + } else { + while (last_slash > filename && last_slash[-1] != '/') + last_slash--; + return last_slash; + } +} + + /***** STACKTRACE *****/ static std::string Demangle(std::string trace_name) { @@ -84,8 +101,8 @@ static std::string Demangle(std::string trace_name) { static std::string KaldiGetStackTrace() { std::string ans; #ifdef HAVE_EXECINFO_H - #define KALDI_MAX_TRACE_SIZE 50 - #define KALDI_MAX_TRACE_PRINT 20 // must be even. +#define KALDI_MAX_TRACE_SIZE 50 +#define KALDI_MAX_TRACE_PRINT 20 // must be even. // buffer for the trace, void *trace[KALDI_MAX_TRACE_SIZE]; // get the trace, @@ -120,21 +137,6 @@ static std::string KaldiGetStackTrace() { /***** KALDI LOGIGNG *****/ -// Given a filename like "/a/b/c/d/e/f.cc", GetShortFileName -// returns "e/f.cc". Does not currently work if backslash is -// the filename separator. -static const char *GetShortFileName(const char *filename) { - const char *last_slash = strrchr(filename, '/'); - if (!last_slash) { - return filename; - } else { - while (last_slash > filename && last_slash[-1] != '/') - last_slash--; - return last_slash; - } -} - - MessageLogger::MessageLogger(LogMessageEnvelope::Severity severity, const char *func, const char *file, int32 line) { // Obviously, we assume the strings survive the destruction of this object. @@ -152,12 +154,12 @@ MessageLogger::~MessageLogger() KALDI_NOEXCEPT(false) { str.resize(str.length() - 1); // print the mesage (or send to logging handler), - MessageLogger::SendToLog(envelope_, str.c_str()); + MessageLogger::HandleMessage(envelope_, str.c_str()); } -void MessageLogger::SendToLog(const LogMessageEnvelope &envelope, - const char *message) { +void MessageLogger::HandleMessage(const LogMessageEnvelope &envelope, + const char *message) { // Send to a logging handler if provided. if (g_log_handler != NULL) { g_log_handler(envelope, message); @@ -198,20 +200,19 @@ void MessageLogger::SendToLog(const LogMessageEnvelope &envelope, // print to stderr, fprintf(stderr, "%s %s\n", header.str().c_str(), message); } else if (envelope.severity == LogMessageEnvelope::Error) { - // ERROR: - // throw exception with 'what()' message (contains stack-trace), - std::string what_arg = header.str() + " " + - message + "\n\n" + - KaldiGetStackTrace() + "\n"; + // ERROR: + // print to stderr (with stack-trace), + fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message, + KaldiGetStackTrace().c_str()); if (!std::uncaught_exception()) { - throw std::runtime_error(what_arg); + // throw exception with empty message, + throw std::runtime_error(""); } else { // If we got here, this thread has already thrown exception, // and this exception has not yet arrived to its 'catch' clause... // Throwing a new exception would be unsafe! // (can happen during 'stack unwinding', if we have 'KALDI_ERR << msg' - // in a destructor). - fprintf(stderr, "%s", what_arg.c_str()); + // in a destructor of some local object). abort(); } } else if (envelope.severity == LogMessageEnvelope::AssertFailed) { @@ -243,5 +244,4 @@ LogHandler SetLogHandler(LogHandler new_handler) { return old_handler; } - } // end namespace kaldi diff --git a/src/base/kaldi-error.h b/src/base/kaldi-error.h index 485ac38be..c203a24bf 100644 --- a/src/base/kaldi-error.h +++ b/src/base/kaldi-error.h @@ -36,16 +36,16 @@ // we can tell the compiler that the function must-not produce // exceptions (true), or may produce exceptions (false): #if _MSC_VER >= 1900 || (!defined(_MSC_VER) && __cplusplus >= 201103L) - #define KALDI_NOEXCEPT(Predicate) noexcept((Predicate)) +#define KALDI_NOEXCEPT(Predicate) noexcept((Predicate)) #elif defined(__GXX_EXPERIMENTAL_CXX0X__) && \ - (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6) - #define KALDI_NOEXCEPT(Predicate) noexcept((Predicate)) + (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6) +#define KALDI_NOEXCEPT(Predicate) noexcept((Predicate)) #else - #define KALDI_NOEXCEPT(Predicate) +#define KALDI_NOEXCEPT(Predicate) #endif #ifdef _MSC_VER - #define __func__ __FUNCTION__ +#define __func__ __FUNCTION__ #endif namespace kaldi { @@ -105,7 +105,7 @@ public: const char *file, int32 line); - /// Destructor, calls 'SendToLog' which prints the message, + /// Destructor, calls 'HandleMessage' which prints the message, /// (since C++11 a 'throwing' destructor must be declared 'noexcept(false)') ~MessageLogger() KALDI_NOEXCEPT(false); @@ -115,7 +115,7 @@ public: private: /// The logging function, - static void SendToLog(const LogMessageEnvelope &env, const char *msg); + static void HandleMessage(const LogMessageEnvelope &env, const char *msg); private: LogMessageEnvelope envelope_; @@ -194,15 +194,6 @@ typedef void (*LogHandler)(const LogMessageEnvelope &envelope, /// stderr. SetLogHandler is obviously not thread safe. LogHandler SetLogHandler(LogHandler); - -/***** DEPRECATED *****/ -/// TODO: Deprecated function, get rid of it if possible! -inline bool IsKaldiError(const std::string &str) { - KALDI_WARN << "Deprecated!"; - return(!strncmp(str.c_str(), "ERROR ", 6)); -} - - /// @} end "addtogroup error_group" } // namespace kaldi diff --git a/src/feat/wave-reader.h b/src/feat/wave-reader.h index 963e0e5e0..0749022f7 100644 --- a/src/feat/wave-reader.h +++ b/src/feat/wave-reader.h @@ -135,8 +135,8 @@ class WaveHolder { t.Write(os); // throws exception on failure. return true; } catch (const std::exception &e) { - KALDI_WARN << "Exception caught in WaveHolder object (writing)."; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught in WaveHolder object (writing). " + << e.what(); return false; // write failure. } } @@ -162,8 +162,8 @@ class WaveHolder { t_.Read(is); // throws exception on failure. return true; } catch (const std::exception &e) { - KALDI_WARN << "Exception caught in WaveHolder object (reading)."; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught in WaveHolder object (reading). " + << e.what(); return false; // write failure. } } @@ -213,8 +213,8 @@ class WaveInfoHolder { t_.Read(is, WaveData::kLeaveDataUndefined); // throws exception on failure. return true; } catch (const std::exception &e) { - KALDI_WARN << "Exception caught in WaveHolder object (reading)."; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught in WaveHolder object (reading). " + << e.what(); return false; // write failure. } } diff --git a/src/hmm/posterior.cc b/src/hmm/posterior.cc index 4e5cbd452..66965ad8d 100644 --- a/src/hmm/posterior.cc +++ b/src/hmm/posterior.cc @@ -129,8 +129,7 @@ bool PosteriorHolder::Write(std::ostream &os, bool binary, const T &t) { WritePosterior(os, binary, t); return true; } catch(const std::exception &e) { - KALDI_WARN << "Exception caught writing table of posteriors"; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught writing table of posteriors. " << e.what(); return false; // Write failure. } } @@ -147,8 +146,7 @@ bool PosteriorHolder::Read(std::istream &is) { ReadPosterior(is, is_binary, &t_); return true; } catch (std::exception &e) { - KALDI_WARN << "Exception caught reading table of posteriors"; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught reading table of posteriors. " << e.what(); t_.clear(); return false; } @@ -174,8 +172,7 @@ bool GaussPostHolder::Write(std::ostream &os, bool binary, const T &t) { if(!binary) os << '\n'; return os.good(); } catch (const std::exception &e) { - KALDI_WARN << "Exception caught writing table of posteriors"; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught writing table of posteriors. " << e.what(); return false; // Write failure. } } @@ -210,8 +207,7 @@ bool GaussPostHolder::Read(std::istream &is) { } return true; } catch (std::exception &e) { - KALDI_WARN << "Exception caught reading table of posteriors"; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught reading table of posteriors. " << e.what(); t_.clear(); return false; } diff --git a/src/util/kaldi-holder-inl.h b/src/util/kaldi-holder-inl.h index 2fc89409c..4297af9a2 100644 --- a/src/util/kaldi-holder-inl.h +++ b/src/util/kaldi-holder-inl.h @@ -52,8 +52,7 @@ template class KaldiObjectHolder { t.Write(os, binary); return os.good(); } catch(const std::exception &e) { - KALDI_WARN << "Exception caught writing Table object: " << e.what(); - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught writing Table object. " << e.what(); return false; // Write failure. } } @@ -80,8 +79,7 @@ template class KaldiObjectHolder { t_->Read(is, is_binary); return true; } catch(const std::exception &e) { - KALDI_WARN << "Exception caught reading Table object "; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught reading Table object. " << e.what(); delete t_; t_ = NULL; return false; @@ -137,8 +135,7 @@ template class BasicHolder { // easier to manipulate. return os.good(); } catch(const std::exception &e) { - KALDI_WARN << "Exception caught writing Table object: " << e.what(); - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught writing Table object. " << e.what(); return false; // Write failure. } } @@ -186,8 +183,7 @@ template class BasicHolder { } return true; } catch(const std::exception &e) { - KALDI_WARN << "Exception caught reading Table object"; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught reading Table object. " << e.what(); return false; } } @@ -252,8 +248,8 @@ template class BasicVectorHolder { } return os.good(); } catch(const std::exception &e) { - KALDI_WARN << "Exception caught writing Table object (BasicVector). "; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught writing Table object (BasicVector). " + << e.what(); return false; // Write failure. } } @@ -290,8 +286,7 @@ template class BasicVectorHolder { return true; } catch(const std::exception &e) { KALDI_WARN << "BasicVectorHolder::Read, could not interpret line: " - << line; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + << "'" << line << "'" << "\n" << e.what(); return false; } } else { // binary mode. @@ -390,8 +385,7 @@ template class BasicVectorVectorHolder { } return os.good(); } catch(const std::exception &e) { - KALDI_WARN << "Exception caught writing Table object. "; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught writing Table object. " << e.what(); return false; // Write failure. } } @@ -436,8 +430,7 @@ template class BasicVectorVectorHolder { } } } catch(const std::exception &e) { - KALDI_WARN << "BasicVectorVectorHolder::Read, read error"; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "BasicVectorVectorHolder::Read, read error. " << e.what(); return false; } } else { // binary mode. @@ -532,8 +525,7 @@ template class BasicPairVectorHolder { } return os.good(); } catch(const std::exception &e) { - KALDI_WARN << "Exception caught writing Table object. "; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "Exception caught writing Table object. " << e.what(); return false; // Write failure. } } @@ -589,8 +581,7 @@ template class BasicPairVectorHolder { } } } catch(const std::exception &e) { - KALDI_WARN << "BasicPairVectorHolder::Read, read error"; - if (!IsKaldiError(e.what())) { std::cerr << e.what(); } + KALDI_WARN << "BasicPairVectorHolder::Read, read error. " << e.what(); return false; } } else { // binary mode. From 216f9ec42a47940d6e405956f3abb70a75325bc4 Mon Sep 17 00:00:00 2001 From: vesis84 Date: Tue, 17 May 2016 16:41:32 +0200 Subject: [PATCH 4/5] error_logs: adding 'k' to the enum. --- src/base/kaldi-error.cc | 18 +++++++++--------- src/base/kaldi-error.h | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/base/kaldi-error.cc b/src/base/kaldi-error.cc index bc8a7af09..9fd025e96 100644 --- a/src/base/kaldi-error.cc +++ b/src/base/kaldi-error.cc @@ -170,20 +170,20 @@ void MessageLogger::HandleMessage(const LogMessageEnvelope &envelope, // Build the log-message 'header', std::stringstream header; - if (envelope.severity > LogMessageEnvelope::Info) { + if (envelope.severity > LogMessageEnvelope::kInfo) { header << "VLOG[" << envelope.severity << "] ("; } else { switch (envelope.severity) { - case LogMessageEnvelope::Info : + case LogMessageEnvelope::kInfo : header << "LOG ("; break; - case LogMessageEnvelope::Warning : + case LogMessageEnvelope::kWarning : header << "WARNING ("; break; - case LogMessageEnvelope::Error : + case LogMessageEnvelope::kError : header << "ERROR ("; break; - case LogMessageEnvelope::AssertFailed : + case LogMessageEnvelope::kAssertFailed : header << "ASSERTION_FAILED ("; break; default: @@ -195,11 +195,11 @@ void MessageLogger::HandleMessage(const LogMessageEnvelope &envelope, << envelope.file << ':' << envelope.line << ")"; // In following lines we decide what to do, - if (envelope.severity >= LogMessageEnvelope::Warning) { + if (envelope.severity >= LogMessageEnvelope::kWarning) { // VLOG, LOG, WARNING: // print to stderr, fprintf(stderr, "%s %s\n", header.str().c_str(), message); - } else if (envelope.severity == LogMessageEnvelope::Error) { + } else if (envelope.severity == LogMessageEnvelope::kError) { // ERROR: // print to stderr (with stack-trace), fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message, @@ -215,7 +215,7 @@ void MessageLogger::HandleMessage(const LogMessageEnvelope &envelope, // in a destructor of some local object). abort(); } - } else if (envelope.severity == LogMessageEnvelope::AssertFailed) { + } else if (envelope.severity == LogMessageEnvelope::kAssertFailed) { // ASSERT_FAILED: // print to stderr (with stack-trace), call abort(), fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message, @@ -231,7 +231,7 @@ void MessageLogger::HandleMessage(const LogMessageEnvelope &envelope, void KaldiAssertFailure_(const char *func, const char *file, int32 line, const char *cond_str) { - MessageLogger ml(LogMessageEnvelope::AssertFailed, func, file, line); + MessageLogger ml(LogMessageEnvelope::kAssertFailed, func, file, line); ml.stream() << ": '" << cond_str << "' "; } diff --git a/src/base/kaldi-error.h b/src/base/kaldi-error.h index c203a24bf..2911036d1 100644 --- a/src/base/kaldi-error.h +++ b/src/base/kaldi-error.h @@ -77,10 +77,10 @@ inline void SetVerboseLevel(int32 i) { g_kaldi_verbose_level = i; } /// Log message severity and source location info. struct LogMessageEnvelope { enum Severity { - AssertFailed = -3, - Error = -2, - Warning = -1, - Info = 0, + kAssertFailed = -3, + kError = -2, + kWarning = -1, + kInfo = 0, }; // An 'enum Severity' value, or a positive number indicating verbosity level. int severity; @@ -124,13 +124,13 @@ private: // The definition of the logging macros, #define KALDI_ERR \ - ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Error, \ + ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::kError, \ __func__, __FILE__, __LINE__).stream() #define KALDI_WARN \ - ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Warning, \ + ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::kWarning, \ __func__, __FILE__, __LINE__).stream() #define KALDI_LOG \ - ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::Info, \ + ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::kInfo, \ __func__, __FILE__, __LINE__).stream() #define KALDI_VLOG(v) if ((v) <= ::kaldi::g_kaldi_verbose_level) \ ::kaldi::MessageLogger((::kaldi::LogMessageEnvelope::Severity)(v), \ From 1449a9d021f71824e81fe4437316e51667cf8dbe Mon Sep 17 00:00:00 2001 From: vesis84 Date: Tue, 17 May 2016 20:23:19 +0200 Subject: [PATCH 5/5] error_logs: abort or throw exception even with custom log-handler --- src/base/kaldi-error.cc | 111 +++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 57 deletions(-) diff --git a/src/base/kaldi-error.cc b/src/base/kaldi-error.cc index 9fd025e96..5ca884e99 100644 --- a/src/base/kaldi-error.cc +++ b/src/base/kaldi-error.cc @@ -163,66 +163,63 @@ void MessageLogger::HandleMessage(const LogMessageEnvelope &envelope, // Send to a logging handler if provided. if (g_log_handler != NULL) { g_log_handler(envelope, message); - // TODO: should we abort() at 'assert_failed' or 'error'? - return; - } - // Otherwise, we use the default Kaldi logging. - - // Build the log-message 'header', - std::stringstream header; - if (envelope.severity > LogMessageEnvelope::kInfo) { - header << "VLOG[" << envelope.severity << "] ("; } else { - switch (envelope.severity) { - case LogMessageEnvelope::kInfo : - header << "LOG ("; - break; - case LogMessageEnvelope::kWarning : - header << "WARNING ("; - break; - case LogMessageEnvelope::kError : - header << "ERROR ("; - break; - case LogMessageEnvelope::kAssertFailed : - header << "ASSERTION_FAILED ("; - break; - default: - abort(); // coding errror (unknown 'severity'), - } - } - // fill the other info from the envelope, - header << GetProgramName() << envelope.func << "():" - << envelope.file << ':' << envelope.line << ")"; - - // In following lines we decide what to do, - if (envelope.severity >= LogMessageEnvelope::kWarning) { - // VLOG, LOG, WARNING: - // print to stderr, - fprintf(stderr, "%s %s\n", header.str().c_str(), message); - } else if (envelope.severity == LogMessageEnvelope::kError) { - // ERROR: - // print to stderr (with stack-trace), - fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message, - KaldiGetStackTrace().c_str()); - if (!std::uncaught_exception()) { - // throw exception with empty message, - throw std::runtime_error(""); + // Otherwise, we use the default Kaldi logging. + // Build the log-message 'header', + std::stringstream header; + if (envelope.severity > LogMessageEnvelope::kInfo) { + header << "VLOG[" << envelope.severity << "] ("; } else { - // If we got here, this thread has already thrown exception, - // and this exception has not yet arrived to its 'catch' clause... - // Throwing a new exception would be unsafe! - // (can happen during 'stack unwinding', if we have 'KALDI_ERR << msg' - // in a destructor of some local object). - abort(); + switch (envelope.severity) { + case LogMessageEnvelope::kInfo : + header << "LOG ("; + break; + case LogMessageEnvelope::kWarning : + header << "WARNING ("; + break; + case LogMessageEnvelope::kError : + header << "ERROR ("; + break; + case LogMessageEnvelope::kAssertFailed : + header << "ASSERTION_FAILED ("; + break; + default: + abort(); // coding errror (unknown 'severity'), + } } - } else if (envelope.severity == LogMessageEnvelope::kAssertFailed) { - // ASSERT_FAILED: - // print to stderr (with stack-trace), call abort(), - fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message, - KaldiGetStackTrace().c_str()); - abort(); - } else { - abort(); // coding error (unknown 'severity'), + // fill the other info from the envelope, + header << GetProgramName() << envelope.func << "():" + << envelope.file << ':' << envelope.line << ")"; + + // Printing the message, + if (envelope.severity >= LogMessageEnvelope::kWarning) { + // VLOG, LOG, WARNING: + fprintf(stderr, "%s %s\n", header.str().c_str(), message); + } else { + // ERROR, ASSERT_FAILED (print with stack-trace): + fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message, + KaldiGetStackTrace().c_str()); + } + } + + // Should we throw exception, or abort? + switch (envelope.severity) { + case LogMessageEnvelope::kAssertFailed: + abort(); // ASSERT_FAILED, + break; + case LogMessageEnvelope::kError: + if (!std::uncaught_exception()) { + // throw exception with empty message, + throw std::runtime_error(""); // KALDI_ERR, + } else { + // If we got here, this thread has already thrown exception, + // and this exception has not yet arrived to its 'catch' clause... + // Throwing a new exception would be unsafe! + // (can happen during 'stack unwinding', if we have 'KALDI_ERR << msg' + // in a destructor of some local object). + abort(); + } + break; } }