mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
Moving logging from caffe2 to c10. (#12881)
Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/12881 TSIA. This should not change any functionality. Remaining work: - change the build script to deprecate use of CAFFE2_USE_MINIMAL_GOOGLE_GLOG and use a C10 macro instead. - Unify the exception name (EnforceNotMet -> Error) - Unify the logging and warning APIs (like AT_WARNING) Reviewed By: dzhulgakov Differential Revision: D10441597 fbshipit-source-id: 4784dc0cd5af83dacb10c4952a2d1d7236b3f14d
This commit is contained in:
committed by
Facebook Github Bot
parent
d120b9af5a
commit
7dbb38e856
@ -39,6 +39,10 @@ if (${USE_GLOG})
|
||||
target_link_libraries(c10 PUBLIC glog::glog)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
target_link_libraries(c10 PRIVATE log)
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
c10 PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../>
|
||||
|
@ -52,4 +52,11 @@
|
||||
// the c10 namespace but not any nontrivial files.
|
||||
namespace c10 {} // namespace c10
|
||||
|
||||
// C10_NORETURN
|
||||
#if defined(_MSC_VER)
|
||||
#define C10_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define C10_NORETURN __attribute__((noreturn))
|
||||
#endif
|
||||
|
||||
#endif // C10_MACROS_MACROS_H_
|
||||
|
@ -1,9 +1,13 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "caffe2/core/logging.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include "c10/util/Logging.h"
|
||||
|
||||
namespace caffe2 {
|
||||
namespace c10_test {
|
||||
|
||||
using std::set;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
TEST(LoggingTest, TestEnforceTrue) {
|
||||
// This should just work.
|
||||
@ -17,7 +21,7 @@ TEST(LoggingTest, TestEnforceFalse) {
|
||||
CAFFE_ENFORCE(false, "This throws.");
|
||||
// This should never be triggered.
|
||||
ADD_FAILURE();
|
||||
} catch (const EnforceNotMet&) {
|
||||
} catch (const ::c10::Error&) {
|
||||
}
|
||||
std::swap(FLAGS_caffe2_use_fatal_for_enforce, kFalse);
|
||||
}
|
||||
@ -29,7 +33,7 @@ TEST(LoggingTest, TestEnforceEquals) {
|
||||
CAFFE_ENFORCE_THAT(Equals(++x, ++y));
|
||||
// This should never be triggered.
|
||||
ADD_FAILURE();
|
||||
} catch (const EnforceNotMet& err) {
|
||||
} catch (const ::c10::Error& err) {
|
||||
EXPECT_NE(err.msg().find("5 vs 6"), string::npos);
|
||||
}
|
||||
|
||||
@ -45,11 +49,11 @@ TEST(LoggingTest, EnforceShowcase) {
|
||||
int one = 1;
|
||||
int two = 2;
|
||||
int three = 3;
|
||||
#define WRAP_AND_PRINT(exp) \
|
||||
try { \
|
||||
exp; \
|
||||
} catch (const EnforceNotMet&) { \
|
||||
/* EnforceNotMet already does LOG(ERROR) */ \
|
||||
#define WRAP_AND_PRINT(exp) \
|
||||
try { \
|
||||
exp; \
|
||||
} catch (const ::c10::Error&) { \
|
||||
/* ::c10::Error already does LOG(ERROR) */ \
|
||||
}
|
||||
WRAP_AND_PRINT(CAFFE_ENFORCE_EQ(one, two));
|
||||
WRAP_AND_PRINT(CAFFE_ENFORCE_NE(one * 2, two));
|
||||
@ -82,4 +86,4 @@ TEST(LoggingDeathTest, TestEnforceUsingFatal) {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace caffe2
|
||||
} // namespace c10_test
|
@ -1,5 +1,5 @@
|
||||
#include "caffe2/core/logging.h"
|
||||
#include "caffe2/core/flags.h"
|
||||
#include "c10/util/Logging.h"
|
||||
#include "c10/util/Flags.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@ -14,7 +14,7 @@ C10_DEFINE_bool(
|
||||
"If set true, when CAFFE_ENFORCE is not met, abort instead "
|
||||
"of throwing an exception.");
|
||||
|
||||
namespace caffe2 {
|
||||
namespace c10 {
|
||||
namespace enforce_detail {
|
||||
/* implicit */ EnforceFailMessage::EnforceFailMessage(std::string&& msg) {
|
||||
msg_ = new std::string(std::move(msg));
|
||||
@ -45,9 +45,9 @@ void ThrowEnforceNotMet(
|
||||
throw e;
|
||||
}
|
||||
|
||||
} // namespace caffe2
|
||||
} // namespace c10
|
||||
|
||||
#ifdef C10_USE_GFLAGS
|
||||
#if defined(C10_USE_GFLAGS) && defined(C10_USE_GLOG)
|
||||
// When GLOG depends on GFLAGS, these variables are being defined in GLOG
|
||||
// directly via the GFLAGS definition, so we will use DECLARE_* to declare
|
||||
// them, and use them in Caffe2.
|
||||
@ -57,25 +57,28 @@ DECLARE_int32(minloglevel);
|
||||
DECLARE_int32(v);
|
||||
// GLOG's logtostderr value
|
||||
DECLARE_bool(logtostderr);
|
||||
#elif !CAFFE2_MOBILE && !__APPLE__ && !defined(_WIN32)
|
||||
// Declare our own versions of the above flags so we don't error out
|
||||
// when they are passed into Caffe2.
|
||||
C10_DEFINE_int(minloglevel, 0, "Equivalent to glog minloglevel");
|
||||
C10_DEFINE_int(v, 0, "Equivalent to glog verbose");
|
||||
C10_DEFINE_bool(logtostderr, false, "Equivalent to glog logtostderr");
|
||||
#endif // C10_USE_GFLAGS
|
||||
#endif // defined(C10_USE_GFLAGS) && defined(C10_USE_GLOG)
|
||||
|
||||
#ifdef CAFFE2_USE_GOOGLE_GLOG
|
||||
#if !defined(C10_USE_GLOG)
|
||||
// This backward compatibility flags are in order to deal with cases where
|
||||
// Caffe2 are not built with glog, but some init flags still pass in these
|
||||
// flags. They may go away in the future.
|
||||
C10_DEFINE_int32(minloglevel, 0, "Equivalent to glog minloglevel");
|
||||
C10_DEFINE_int32(v, 0, "Equivalent to glog verbose");
|
||||
C10_DEFINE_bool(logtostderr, false, "Equivalent to glog logtostderr");
|
||||
#endif // !defined(c10_USE_GLOG)
|
||||
|
||||
#ifdef C10_USE_GLOG
|
||||
|
||||
// Provide easy access to the above variables, regardless whether GLOG is
|
||||
// dependent on GFLAGS or not. Note that the namespace (fLI, fLB) is actually
|
||||
// consistent between GLOG and GFLAGS, so we can do the below declaration
|
||||
// consistently.
|
||||
namespace caffe2 {
|
||||
namespace c10 {
|
||||
using fLB::FLAGS_logtostderr;
|
||||
using fLI::FLAGS_minloglevel;
|
||||
using fLI::FLAGS_v;
|
||||
using fLB::FLAGS_logtostderr;
|
||||
} // namespace caffe2
|
||||
} // namespace c10
|
||||
|
||||
C10_DEFINE_int(
|
||||
caffe2_log_level,
|
||||
@ -89,13 +92,13 @@ C10_DEFINE_int(
|
||||
namespace google {
|
||||
namespace glog_internal_namespace_ {
|
||||
bool IsGoogleLoggingInitialized();
|
||||
} // namespace glog_internal_namespace_
|
||||
} // namespace google
|
||||
} // namespace glog_internal_namespace_
|
||||
} // namespace google
|
||||
|
||||
|
||||
namespace caffe2 {
|
||||
namespace c10 {
|
||||
bool InitCaffeLogging(int* argc, char** argv) {
|
||||
if (*argc == 0) return true;
|
||||
if (*argc == 0)
|
||||
return true;
|
||||
#if !defined(_MSC_VER)
|
||||
// This trick can only be used on UNIX platforms
|
||||
if (!::google::glog_internal_namespace_::IsGoogleLoggingInitialized())
|
||||
@ -103,7 +106,7 @@ bool InitCaffeLogging(int* argc, char** argv) {
|
||||
{
|
||||
::google::InitGoogleLogging(argv[0]);
|
||||
#if !defined(_MSC_VER)
|
||||
// This is never defined on Windows
|
||||
// This is never defined on Windows
|
||||
::google::InstallFailureSignalHandler();
|
||||
#endif
|
||||
}
|
||||
@ -129,9 +132,9 @@ void ShowLogInfoToStderr() {
|
||||
FLAGS_logtostderr = 1;
|
||||
FLAGS_minloglevel = std::min(FLAGS_minloglevel, google::GLOG_INFO);
|
||||
}
|
||||
} // namespace caffe2
|
||||
} // namespace c10
|
||||
|
||||
#else // !CAFFE2_USE_GOOGLE_GLOG
|
||||
#else // !C10_USE_GLOG
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
@ -142,11 +145,12 @@ C10_DEFINE_int(
|
||||
ERROR,
|
||||
"The minimum log level that caffe2 will output.");
|
||||
|
||||
namespace caffe2 {
|
||||
namespace c10 {
|
||||
bool InitCaffeLogging(int* argc, char** argv) {
|
||||
// When doing InitCaffeLogging, we will assume that caffe's flag paser has
|
||||
// already finished.
|
||||
if (*argc == 0) return true;
|
||||
if (*argc == 0)
|
||||
return true;
|
||||
if (!c10::CommandLineFlagsHasBeenParsed()) {
|
||||
std::cerr << "InitCaffeLogging() has to be called after "
|
||||
"c10::ParseCommandLineFlags. Modify your program to make sure "
|
||||
@ -162,24 +166,23 @@ bool InitCaffeLogging(int* argc, char** argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateLoggingLevelsFromFlags() {
|
||||
}
|
||||
void UpdateLoggingLevelsFromFlags() {}
|
||||
|
||||
void ShowLogInfoToStderr() {
|
||||
FLAGS_caffe2_log_level = INFO;
|
||||
}
|
||||
|
||||
MessageLogger::MessageLogger(const char *file, int line, int severity)
|
||||
: severity_(severity) {
|
||||
MessageLogger::MessageLogger(const char* file, int line, int severity)
|
||||
: severity_(severity) {
|
||||
if (severity_ < FLAGS_caffe2_log_level) {
|
||||
// Nothing needs to be logged.
|
||||
return;
|
||||
}
|
||||
#ifdef ANDROID
|
||||
tag_ = "native";
|
||||
#else // !ANDROID
|
||||
#else // !ANDROID
|
||||
tag_ = "";
|
||||
#endif // ANDROID
|
||||
#endif // ANDROID
|
||||
/*
|
||||
time_t rawtime;
|
||||
struct tm * timeinfo;
|
||||
@ -210,12 +213,12 @@ MessageLogger::~MessageLogger() {
|
||||
stream_ << "\n";
|
||||
#ifdef ANDROID
|
||||
static const int android_log_levels[] = {
|
||||
ANDROID_LOG_FATAL, // LOG_FATAL
|
||||
ANDROID_LOG_ERROR, // LOG_ERROR
|
||||
ANDROID_LOG_WARN, // LOG_WARNING
|
||||
ANDROID_LOG_INFO, // LOG_INFO
|
||||
ANDROID_LOG_DEBUG, // VLOG(1)
|
||||
ANDROID_LOG_VERBOSE, // VLOG(2) .. VLOG(N)
|
||||
ANDROID_LOG_FATAL, // LOG_FATAL
|
||||
ANDROID_LOG_ERROR, // LOG_ERROR
|
||||
ANDROID_LOG_WARN, // LOG_WARNING
|
||||
ANDROID_LOG_INFO, // LOG_INFO
|
||||
ANDROID_LOG_DEBUG, // VLOG(1)
|
||||
ANDROID_LOG_VERBOSE, // VLOG(2) .. VLOG(N)
|
||||
};
|
||||
int android_level_index = FATAL - std::min(FATAL, severity_);
|
||||
int level = android_log_levels[std::min(android_level_index, 5)];
|
||||
@ -225,7 +228,7 @@ MessageLogger::~MessageLogger() {
|
||||
if (severity_ == FATAL) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, tag_, "terminating.\n");
|
||||
}
|
||||
#else // !ANDROID
|
||||
#else // !ANDROID
|
||||
if (severity_ >= FLAGS_caffe2_log_level) {
|
||||
// If not building on Android, log all output to std::cerr.
|
||||
std::cerr << stream_.str();
|
||||
@ -236,12 +239,12 @@ MessageLogger::~MessageLogger() {
|
||||
std::cerr << std::flush;
|
||||
}
|
||||
}
|
||||
#endif // ANDROID
|
||||
#endif // ANDROID
|
||||
if (severity_ == FATAL) {
|
||||
DealWithFatal();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace caffe2
|
||||
} // namespace c10
|
||||
|
||||
#endif // !CAFFE2_USE_GOOGLE_GLOG
|
||||
#endif // !C10_USE_GLOG
|
246
c10/util/Logging.h
Normal file
246
c10/util/Logging.h
Normal file
@ -0,0 +1,246 @@
|
||||
#ifndef C10_UTIL_LOGGING_H_
|
||||
#define C10_UTIL_LOGGING_H_
|
||||
|
||||
#include <climits>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include "c10/macros/Macros.h"
|
||||
#include "c10/util/Exception.h"
|
||||
#include "c10/util/Flags.h"
|
||||
#include "c10/util/StringUtil.h"
|
||||
|
||||
// CAFFE2_LOG_THRESHOLD is a compile time flag that would allow us to turn off
|
||||
// logging at compile time so no logging message below that level is produced
|
||||
// at all. The value should be between INT_MIN and CAFFE_FATAL.
|
||||
#ifndef CAFFE2_LOG_THRESHOLD
|
||||
// If we have not defined the compile time log threshold, we keep all the
|
||||
// log cases.
|
||||
#define CAFFE2_LOG_THRESHOLD INT_MIN
|
||||
#endif // CAFFE2_LOG_THRESHOLD
|
||||
|
||||
// Below are different implementations for glog and non-glog cases.
|
||||
#ifdef C10_USE_GLOG
|
||||
#include "c10/util/logging_is_google_glog.h"
|
||||
#else // !C10_USE_GLOG
|
||||
#include "c10/util/logging_is_not_google_glog.h"
|
||||
#endif // C10_USE_GLOG
|
||||
|
||||
C10_DECLARE_int(caffe2_log_level);
|
||||
C10_DECLARE_bool(caffe2_use_fatal_for_enforce);
|
||||
|
||||
namespace c10 {
|
||||
|
||||
using std::string;
|
||||
|
||||
// Functions that we use for initialization.
|
||||
C10_API bool InitCaffeLogging(int* argc, char** argv);
|
||||
C10_API void UpdateLoggingLevelsFromFlags();
|
||||
|
||||
C10_API C10_NORETURN void ThrowEnforceNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
const std::string& msg,
|
||||
const void* caller = nullptr);
|
||||
|
||||
constexpr bool IsUsingGoogleLogging() {
|
||||
#ifdef C10_USE_GLOG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility to allow one to show log info to stderr after the program starts.
|
||||
*
|
||||
* This is similar to calling GLOG's --logtostderr, or setting caffe2_log_level
|
||||
* to smaller than INFO. You are recommended to only use this in a few sparse
|
||||
* cases, such as when you want to write a tutorial or something. Normally, use
|
||||
* the commandline flags to set the log level.
|
||||
*/
|
||||
C10_API void ShowLogInfoToStderr();
|
||||
|
||||
C10_API void SetStackTraceFetcher(std::function<string(void)> fetcher);
|
||||
|
||||
using EnforceNotMet = ::c10::Error;
|
||||
|
||||
#define CAFFE_ENFORCE(condition, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
::c10::ThrowEnforceNotMet( \
|
||||
__FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__)); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_ENFORCE_WITH_CALLER(condition, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
::c10::ThrowEnforceNotMet( \
|
||||
__FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__), this); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_THROW(...) \
|
||||
::c10::ThrowEnforceNotMet(__FILE__, __LINE__, "", ::c10::str(__VA_ARGS__))
|
||||
|
||||
/**
|
||||
* Rich logging messages
|
||||
*
|
||||
* CAFFE_ENFORCE_THAT can be used with one of the "checker functions" that
|
||||
* capture input argument values and add it to the exception message. E.g.
|
||||
* `CAFFE_ENFORCE_THAT(Equals(foo(x), bar(y)), "Optional additional message")`
|
||||
* would evaluate both foo and bar only once and if the results are not equal -
|
||||
* include them in the exception message.
|
||||
*
|
||||
* Some of the basic checker functions like Equals or Greater are already
|
||||
* defined below. Other header might define customized checkers by adding
|
||||
* functions to caffe2::enforce_detail namespace. For example:
|
||||
*
|
||||
* namespace caffe2 { namespace enforce_detail {
|
||||
* inline EnforceFailMessage IsVector(const vector<int64_t>& shape) {
|
||||
* if (shape.size() == 1) { return EnforceOK(); }
|
||||
* return c10::str("Shape ", shape, " is not a vector");
|
||||
* }
|
||||
* }}
|
||||
*
|
||||
* With further usages like `CAFFE_ENFORCE_THAT(IsVector(Input(0).dims()))`
|
||||
*
|
||||
* Convenient wrappers for binary operations like CAFFE_ENFORCE_EQ are provided
|
||||
* too. Please use them instead of CHECK_EQ and friends for failures in
|
||||
* user-provided input.
|
||||
*/
|
||||
|
||||
namespace enforce_detail {
|
||||
|
||||
struct C10_API EnforceOK {};
|
||||
|
||||
class C10_API EnforceFailMessage {
|
||||
public:
|
||||
#ifdef _MSC_VER
|
||||
// MSVC + NVCC ignores constexpr and will issue a warning if included.
|
||||
/* implicit */ EnforceFailMessage(EnforceOK) : msg_(nullptr) {}
|
||||
#else
|
||||
constexpr /* implicit */ EnforceFailMessage(EnforceOK) : msg_(nullptr) {}
|
||||
#endif
|
||||
EnforceFailMessage(EnforceFailMessage&&) = default;
|
||||
EnforceFailMessage(const EnforceFailMessage&) = delete;
|
||||
EnforceFailMessage& operator=(EnforceFailMessage&&) = delete;
|
||||
EnforceFailMessage& operator=(const EnforceFailMessage&) = delete;
|
||||
|
||||
// Catch all wrong usages like CAFFE_ENFORCE_THAT(x < y)
|
||||
template <class... Args>
|
||||
/* implicit */ EnforceFailMessage(Args...) {
|
||||
static_assert(
|
||||
// This stands for an "impossible" condition. Plain `false` doesn't
|
||||
// trick compiler enough.
|
||||
sizeof...(Args) == std::numeric_limits<std::size_t>::max(),
|
||||
"CAFFE_ENFORCE_THAT has to be used with one of special check functions "
|
||||
"like `Equals`. Use CAFFE_ENFORCE for simple boolean checks.");
|
||||
}
|
||||
|
||||
/* implicit */ EnforceFailMessage(std::string&& msg);
|
||||
|
||||
inline bool bad() const {
|
||||
return msg_ != nullptr;
|
||||
}
|
||||
std::string get_message_and_free(std::string&& extra) const {
|
||||
std::string r;
|
||||
if (extra.empty()) {
|
||||
r = std::move(*msg_);
|
||||
} else {
|
||||
r = ::c10::str(std::move(*msg_), ". ", std::move(extra));
|
||||
}
|
||||
delete msg_;
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string* msg_;
|
||||
};
|
||||
|
||||
#define BINARY_COMP_HELPER(name, op) \
|
||||
template <typename T1, typename T2> \
|
||||
inline EnforceFailMessage name(const T1& x, const T2& y) { \
|
||||
if (x op y) { \
|
||||
return EnforceOK(); \
|
||||
} \
|
||||
return c10::str(x, " vs ", y); \
|
||||
}
|
||||
BINARY_COMP_HELPER(Equals, ==)
|
||||
BINARY_COMP_HELPER(NotEquals, !=)
|
||||
BINARY_COMP_HELPER(Greater, >)
|
||||
BINARY_COMP_HELPER(GreaterEquals, >=)
|
||||
BINARY_COMP_HELPER(Less, <)
|
||||
BINARY_COMP_HELPER(LessEquals, <=)
|
||||
#undef BINARY_COMP_HELPER
|
||||
|
||||
#define CAFFE_ENFORCE_THAT_IMPL(condition, expr, ...) \
|
||||
do { \
|
||||
using namespace ::c10::enforce_detail; \
|
||||
const EnforceFailMessage& CAFFE_ENFORCE_THAT_IMPL_r_ = (condition); \
|
||||
if (CAFFE_ENFORCE_THAT_IMPL_r_.bad()) { \
|
||||
::c10::ThrowEnforceNotMet( \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
expr, \
|
||||
CAFFE_ENFORCE_THAT_IMPL_r_.get_message_and_free( \
|
||||
::c10::str(__VA_ARGS__))); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(condition, expr, ...) \
|
||||
do { \
|
||||
using namespace ::c10::enforce_detail; \
|
||||
const EnforceFailMessage& CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER_r_ = \
|
||||
(condition); \
|
||||
if (CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER_r_.bad()) { \
|
||||
::c10::ThrowEnforceNotMet( \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
expr, \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER_r_.get_message_and_free( \
|
||||
::c10::str(__VA_ARGS__)), \
|
||||
this); \
|
||||
} \
|
||||
} while (false)
|
||||
} // namespace enforce_detail
|
||||
|
||||
#define CAFFE_ENFORCE_THAT(condition, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL((condition), #condition, __VA_ARGS__)
|
||||
|
||||
#define CAFFE_ENFORCE_EQ(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(Equals((x), (y)), #x " == " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_NE(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(NotEquals((x), (y)), #x " != " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LE(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(LessEquals((x), (y)), #x " <= " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LT(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(Less((x), (y)), #x " < " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GE(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(GreaterEquals((x), (y)), #x " >= " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GT(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(Greater((x), (y)), #x " > " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_EQ_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER( \
|
||||
Equals((x), (y)), #x " == " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_NE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER( \
|
||||
NotEquals((x), (y)), #x " != " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER( \
|
||||
LessEquals((x), (y)), #x " <= " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LT_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(Less((x), (y)), #x " < " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER( \
|
||||
GreaterEquals((x), (y)), #x " >= " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GT_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER( \
|
||||
Greater((x), (y)), #x " > " #y, __VA_ARGS__)
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_LOGGING_H_
|
52
c10/util/logging_is_google_glog.h
Normal file
52
c10/util/logging_is_google_glog.h
Normal file
@ -0,0 +1,52 @@
|
||||
#ifndef C10_UTIL_LOGGING_IS_GOOGLE_GLOG_H_
|
||||
#define C10_UTIL_LOGGING_IS_GOOGLE_GLOG_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <iomanip> // because some of the caffe2 code uses e.g. std::setw
|
||||
// Using google glog. For glog 0.3.2 versions, stl_logging.h needs to be before
|
||||
// logging.h to actually use stl_logging. Because template magic.
|
||||
// In addition, we do not do stl logging in .cu files because nvcc does not like
|
||||
// it. Some mobile platforms do not like stl_logging, so we add an
|
||||
// overload in that case as well.
|
||||
|
||||
#ifdef __CUDACC__
|
||||
#include <cuda.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__CUDACC__) && !defined(CAFFE2_USE_MINIMAL_GOOGLE_GLOG)
|
||||
#include <glog/stl_logging.h>
|
||||
|
||||
// Old versions of glog don't declare this using declaration, so help
|
||||
// them out. Fortunately, C++ won't complain if you declare the same
|
||||
// using declaration multiple times.
|
||||
namespace std {
|
||||
using ::operator<<;
|
||||
}
|
||||
|
||||
#else // !defined(__CUDACC__) && !defined(CAFFE2_USE_MINIMAL_GOOGLE_GLOG)
|
||||
|
||||
// In the cudacc compiler scenario, we will simply ignore the container
|
||||
// printout feature. Basically we need to register a fake overload for
|
||||
// vector/string - here, we just ignore the entries in the logs.
|
||||
|
||||
namespace std {
|
||||
#define INSTANTIATE_FOR_CONTAINER(container) \
|
||||
template <class... Types> \
|
||||
ostream& operator<<(ostream& out, const container<Types...>&) { \
|
||||
return out; \
|
||||
}
|
||||
|
||||
INSTANTIATE_FOR_CONTAINER(vector)
|
||||
INSTANTIATE_FOR_CONTAINER(map)
|
||||
INSTANTIATE_FOR_CONTAINER(set)
|
||||
#undef INSTANTIATE_FOR_CONTAINER
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#endif // C10_UTIL_LOGGING_IS_GOOGLE_GLOG_H_
|
@ -1,42 +1,47 @@
|
||||
#ifndef CAFFE2_CORE_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
||||
#define CAFFE2_CORE_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
||||
#ifndef C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
||||
#define C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "caffe2/core/flags.h"
|
||||
#include "c10/util/Flags.h"
|
||||
|
||||
// Log severity level constants.
|
||||
const int FATAL = 3;
|
||||
const int FATAL = 3;
|
||||
#if !defined(_MSC_VER) || !defined(ERROR)
|
||||
// Windows defines the ERROR macro already, and as a result we will
|
||||
// simply use that one. The downside is that one will now mix LOG(INFO)
|
||||
// and LOG(ERROR) because ERROR is defined to be zero. Anyway, the
|
||||
// recommended way is to use glog so fixing this is a low-pri item.
|
||||
const int ERROR = 2;
|
||||
const int ERROR = 2;
|
||||
#endif
|
||||
const int WARNING = 1;
|
||||
const int INFO = 0;
|
||||
const int INFO = 0;
|
||||
const char CAFFE2_SEVERITY_PREFIX[] = "FEWIV";
|
||||
|
||||
namespace caffe2 {
|
||||
class CAFFE2_API MessageLogger {
|
||||
namespace c10 {
|
||||
class C10_API MessageLogger {
|
||||
public:
|
||||
MessageLogger(const char *file, int line, int severity);
|
||||
MessageLogger(const char* file, int line, int severity);
|
||||
~MessageLogger();
|
||||
// Return the stream associated with the logger object.
|
||||
std::stringstream &stream() { return stream_; }
|
||||
std::stringstream& stream() {
|
||||
return stream_;
|
||||
}
|
||||
|
||||
private:
|
||||
// When there is a fatal log, we simply abort.
|
||||
void DealWithFatal() { abort(); }
|
||||
void DealWithFatal() {
|
||||
abort();
|
||||
}
|
||||
|
||||
const char* tag_;
|
||||
std::stringstream stream_;
|
||||
@ -46,24 +51,24 @@ class CAFFE2_API MessageLogger {
|
||||
// This class is used to explicitly ignore values in the conditional
|
||||
// logging macros. This avoids compiler warnings like "value computed
|
||||
// is not used" and "statement has no effect".
|
||||
class CAFFE2_API LoggerVoidify {
|
||||
class C10_API LoggerVoidify {
|
||||
public:
|
||||
LoggerVoidify() { }
|
||||
LoggerVoidify() {}
|
||||
// This has to be an operator with a precedence lower than << but
|
||||
// higher than ?:
|
||||
void operator&(const std::ostream &s) { }
|
||||
void operator&(const std::ostream& s) {}
|
||||
};
|
||||
|
||||
// Log a message and terminate.
|
||||
template<class T>
|
||||
void LogMessageFatal(const char *file, int line, const T &message) {
|
||||
template <class T>
|
||||
void LogMessageFatal(const char* file, int line, const T& message) {
|
||||
MessageLogger(file, line, FATAL).stream() << message;
|
||||
}
|
||||
|
||||
// Helpers for CHECK_NOTNULL(). Two are necessary to support both raw pointers
|
||||
// and smart pointers.
|
||||
template <typename T>
|
||||
T& CheckNotNullCommon(const char *file, int line, const char *names, T& t) {
|
||||
T& CheckNotNullCommon(const char* file, int line, const char* names, T& t) {
|
||||
if (t == nullptr) {
|
||||
LogMessageFatal(file, line, std::string(names));
|
||||
}
|
||||
@ -71,55 +76,56 @@ T& CheckNotNullCommon(const char *file, int line, const char *names, T& t) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* CheckNotNull(const char *file, int line, const char *names, T* t) {
|
||||
T* CheckNotNull(const char* file, int line, const char* names, T* t) {
|
||||
return CheckNotNullCommon(file, line, names, t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& CheckNotNull(const char *file, int line, const char *names, T& t) {
|
||||
T& CheckNotNull(const char* file, int line, const char* names, T& t) {
|
||||
return CheckNotNullCommon(file, line, names, t);
|
||||
}
|
||||
} // namespace caffe2
|
||||
} // namespace c10
|
||||
|
||||
// ---------------------- Logging Macro definitions --------------------------
|
||||
|
||||
|
||||
static_assert(CAFFE2_LOG_THRESHOLD <= FATAL,
|
||||
"CAFFE2_LOG_THRESHOLD should at most be FATAL.");
|
||||
static_assert(
|
||||
CAFFE2_LOG_THRESHOLD <= FATAL,
|
||||
"CAFFE2_LOG_THRESHOLD should at most be FATAL.");
|
||||
// If n is under the compile time caffe log threshold, The _CAFFE_LOG(n)
|
||||
// should not generate anything in optimized code.
|
||||
#define LOG(n) \
|
||||
#define LOG(n) \
|
||||
if (n >= CAFFE2_LOG_THRESHOLD) \
|
||||
::caffe2::MessageLogger((char*)__FILE__, __LINE__, n).stream()
|
||||
::c10::MessageLogger((char*)__FILE__, __LINE__, n).stream()
|
||||
#define VLOG(n) LOG((-n))
|
||||
|
||||
#define LOG_IF(n, condition) \
|
||||
if (n >= CAFFE2_LOG_THRESHOLD && (condition)) \
|
||||
::caffe2::MessageLogger((char*)__FILE__, __LINE__, n).stream()
|
||||
::c10::MessageLogger((char*)__FILE__, __LINE__, n).stream()
|
||||
#define VLOG_IF(n, condition) LOG_IF((-n), (condition))
|
||||
|
||||
#define VLOG_IS_ON(verboselevel) (CAFFE2_LOG_THRESHOLD <= -(verboselevel))
|
||||
|
||||
// Log only if condition is met. Otherwise evaluates to void.
|
||||
#define FATAL_IF(condition) \
|
||||
condition ? (void) 0 : ::caffe2::LoggerVoidify() & \
|
||||
::caffe2::MessageLogger((char*)__FILE__, __LINE__, FATAL).stream()
|
||||
#define FATAL_IF(condition) \
|
||||
condition ? (void)0 \
|
||||
: ::c10::LoggerVoidify() & \
|
||||
::c10::MessageLogger((char*)__FILE__, __LINE__, FATAL).stream()
|
||||
|
||||
// Check for a given boolean condition.
|
||||
#define CHECK(condition) FATAL_IF(condition) \
|
||||
<< "Check failed: " #condition " "
|
||||
#define CHECK(condition) FATAL_IF(condition) << "Check failed: " #condition " "
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Debug only version of CHECK
|
||||
#define DCHECK(condition) FATAL_IF(condition) \
|
||||
<< "Check failed: " #condition " "
|
||||
#define DCHECK(condition) FATAL_IF(condition) << "Check failed: " #condition " "
|
||||
#else
|
||||
// Optimized version - generates no code.
|
||||
#define DCHECK(condition) if(false) CHECK(condition)
|
||||
#endif // NDEBUG
|
||||
#define DCHECK(condition) \
|
||||
if (false) \
|
||||
CHECK(condition)
|
||||
#endif // NDEBUG
|
||||
|
||||
#define CHECK_OP(val1, val2, op) FATAL_IF((val1 op val2)) \
|
||||
<< "Check failed: " #val1 " " #op " " #val2 " "
|
||||
#define CHECK_OP(val1, val2, op) \
|
||||
FATAL_IF((val1 op val2)) << "Check failed: " #val1 " " #op " " #val2 " "
|
||||
|
||||
// Check_op macro definitions
|
||||
#define CHECK_EQ(val1, val2) CHECK_OP(val1, val2, ==)
|
||||
@ -137,30 +143,44 @@ static_assert(CAFFE2_LOG_THRESHOLD <= FATAL,
|
||||
#define DCHECK_LT(val1, val2) CHECK_OP(val1, val2, <)
|
||||
#define DCHECK_GE(val1, val2) CHECK_OP(val1, val2, >=)
|
||||
#define DCHECK_GT(val1, val2) CHECK_OP(val1, val2, >)
|
||||
#else // !NDEBUG
|
||||
#else // !NDEBUG
|
||||
// These versions generate no code in optimized mode.
|
||||
#define DCHECK_EQ(val1, val2) if(false) CHECK_OP(val1, val2, ==)
|
||||
#define DCHECK_NE(val1, val2) if(false) CHECK_OP(val1, val2, !=)
|
||||
#define DCHECK_LE(val1, val2) if(false) CHECK_OP(val1, val2, <=)
|
||||
#define DCHECK_LT(val1, val2) if(false) CHECK_OP(val1, val2, <)
|
||||
#define DCHECK_GE(val1, val2) if(false) CHECK_OP(val1, val2, >=)
|
||||
#define DCHECK_GT(val1, val2) if(false) CHECK_OP(val1, val2, >)
|
||||
#endif // NDEBUG
|
||||
#define DCHECK_EQ(val1, val2) \
|
||||
if (false) \
|
||||
CHECK_OP(val1, val2, ==)
|
||||
#define DCHECK_NE(val1, val2) \
|
||||
if (false) \
|
||||
CHECK_OP(val1, val2, !=)
|
||||
#define DCHECK_LE(val1, val2) \
|
||||
if (false) \
|
||||
CHECK_OP(val1, val2, <=)
|
||||
#define DCHECK_LT(val1, val2) \
|
||||
if (false) \
|
||||
CHECK_OP(val1, val2, <)
|
||||
#define DCHECK_GE(val1, val2) \
|
||||
if (false) \
|
||||
CHECK_OP(val1, val2, >=)
|
||||
#define DCHECK_GT(val1, val2) \
|
||||
if (false) \
|
||||
CHECK_OP(val1, val2, >)
|
||||
#endif // NDEBUG
|
||||
|
||||
// Check that a pointer is not null.
|
||||
#define CHECK_NOTNULL(val) \
|
||||
::caffe2::CheckNotNull( \
|
||||
::c10::CheckNotNull( \
|
||||
__FILE__, __LINE__, "Check failed: '" #val "' Must be non NULL", (val))
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Debug only version of CHECK_NOTNULL
|
||||
#define DCHECK_NOTNULL(val) \
|
||||
::caffe2::CheckNotNull( \
|
||||
::c10::CheckNotNull( \
|
||||
__FILE__, __LINE__, "Check failed: '" #val "' Must be non NULL", (val))
|
||||
#else // !NDEBUG
|
||||
#else // !NDEBUG
|
||||
// Optimized version - generates no code.
|
||||
#define DCHECK_NOTNULL(val) if (false) CHECK_NOTNULL(val)
|
||||
#endif // NDEBUG
|
||||
#define DCHECK_NOTNULL(val) \
|
||||
if (false) \
|
||||
CHECK_NOTNULL(val)
|
||||
#endif // NDEBUG
|
||||
|
||||
// ---------------------- Support for std objects --------------------------
|
||||
// These are adapted from glog to support a limited set of logging capability
|
||||
@ -170,50 +190,51 @@ namespace std {
|
||||
// Forward declare these two, and define them after all the container streams
|
||||
// operators so that we can recurse from pair -> container -> container -> pair
|
||||
// properly.
|
||||
template<class First, class Second>
|
||||
std::ostream& operator<<(
|
||||
std::ostream& out, const std::pair<First, Second>& p);
|
||||
template <class First, class Second>
|
||||
std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
|
||||
} // namespace std
|
||||
|
||||
namespace caffe2 {
|
||||
namespace c10 {
|
||||
template <class Iter>
|
||||
void PrintSequence(std::ostream& ss, Iter begin, Iter end);
|
||||
} // namespace caffe2
|
||||
} // namespace c10
|
||||
|
||||
namespace std {
|
||||
#define INSTANTIATE_FOR_CONTAINER(container) \
|
||||
template <class... Types> \
|
||||
std::ostream& operator<<( \
|
||||
std::ostream& out, const container<Types...>& seq) { \
|
||||
caffe2::PrintSequence(out, seq.begin(), seq.end()); \
|
||||
return out; \
|
||||
}
|
||||
#define INSTANTIATE_FOR_CONTAINER(container) \
|
||||
template <class... Types> \
|
||||
std::ostream& operator<<( \
|
||||
std::ostream& out, const container<Types...>& seq) { \
|
||||
c10::PrintSequence(out, seq.begin(), seq.end()); \
|
||||
return out; \
|
||||
}
|
||||
|
||||
INSTANTIATE_FOR_CONTAINER(std::vector)
|
||||
INSTANTIATE_FOR_CONTAINER(std::map)
|
||||
INSTANTIATE_FOR_CONTAINER(std::set)
|
||||
#undef INSTANTIATE_FOR_CONTAINER
|
||||
|
||||
template<class First, class Second>
|
||||
template <class First, class Second>
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& out, const std::pair<First, Second>& p) {
|
||||
std::ostream& out,
|
||||
const std::pair<First, Second>& p) {
|
||||
out << '(' << p.first << ", " << p.second << ')';
|
||||
return out;
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
namespace caffe2 {
|
||||
namespace c10 {
|
||||
template <class Iter>
|
||||
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
|
||||
// Output at most 100 elements -- appropriate if used for logging.
|
||||
for (int i = 0; begin != end && i < 100; ++i, ++begin) {
|
||||
if (i > 0) out << ' ';
|
||||
if (i > 0)
|
||||
out << ' ';
|
||||
out << *begin;
|
||||
}
|
||||
if (begin != end) {
|
||||
out << " ...";
|
||||
}
|
||||
}
|
||||
} // namespace caffe2
|
||||
} // namespace c10
|
||||
|
||||
#endif // CAFFE2_CORE_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
||||
#endif // C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
@ -1,238 +1,3 @@
|
||||
#ifndef CAFFE2_CORE_LOGGING_H_
|
||||
#define CAFFE2_CORE_LOGGING_H_
|
||||
|
||||
#include <climits>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include <c10/util/Exception.h>
|
||||
#include "c10/util/StringUtil.h"
|
||||
#pragma once
|
||||
#include "c10/util/Logging.h"
|
||||
#include "caffe2/core/common.h"
|
||||
#include "caffe2/core/flags.h"
|
||||
|
||||
// CAFFE2_LOG_THRESHOLD is a compile time flag that would allow us to turn off
|
||||
// logging at compile time so no logging message below that level is produced
|
||||
// at all. The value should be between INT_MIN and CAFFE_FATAL.
|
||||
#ifndef CAFFE2_LOG_THRESHOLD
|
||||
// If we have not defined the compile time log threshold, we keep all the
|
||||
// log cases.
|
||||
#define CAFFE2_LOG_THRESHOLD INT_MIN
|
||||
#endif // CAFFE2_LOG_THRESHOLD
|
||||
|
||||
// Below are different implementations for glog and non-glog cases.
|
||||
#ifdef CAFFE2_USE_GOOGLE_GLOG
|
||||
#include "caffe2/core/logging_is_google_glog.h"
|
||||
#else // !CAFFE2_USE_GOOGLE_GLOG
|
||||
#include "caffe2/core/logging_is_not_google_glog.h"
|
||||
#endif // CAFFE2_USE_GOOGLE_GLOG
|
||||
|
||||
C10_DECLARE_int(caffe2_log_level);
|
||||
C10_DECLARE_bool(caffe2_use_fatal_for_enforce);
|
||||
|
||||
namespace caffe2 {
|
||||
// Functions that we use for initialization.
|
||||
CAFFE2_API bool InitCaffeLogging(int* argc, char** argv);
|
||||
CAFFE2_API void UpdateLoggingLevelsFromFlags();
|
||||
|
||||
CAFFE2_API CAFFE2_NORETURN void ThrowEnforceNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
const std::string& msg,
|
||||
const void* caller = nullptr);
|
||||
|
||||
constexpr bool IsUsingGoogleLogging() {
|
||||
#ifdef CAFFE2_USE_GOOGLE_GLOG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility to allow one to show log info to stderr after the program starts.
|
||||
*
|
||||
* This is similar to calling GLOG's --logtostderr, or setting caffe2_log_level
|
||||
* to smaller than INFO. You are recommended to only use this in a few sparse
|
||||
* cases, such as when you want to write a tutorial or something. Normally, use
|
||||
* the commandline flags to set the log level.
|
||||
*/
|
||||
CAFFE2_API void ShowLogInfoToStderr();
|
||||
|
||||
CAFFE2_API void SetStackTraceFetcher(std::function<string(void)> fetcher);
|
||||
|
||||
using EnforceNotMet = ::c10::Error;
|
||||
|
||||
#define CAFFE_ENFORCE(condition, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
::caffe2::ThrowEnforceNotMet( \
|
||||
__FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__)); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_ENFORCE_WITH_CALLER(condition, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
::caffe2::ThrowEnforceNotMet( \
|
||||
__FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__), this); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_THROW(...) \
|
||||
::caffe2::ThrowEnforceNotMet(__FILE__, __LINE__, "", ::c10::str(__VA_ARGS__))
|
||||
|
||||
/**
|
||||
* Rich logging messages
|
||||
*
|
||||
* CAFFE_ENFORCE_THAT can be used with one of the "checker functions" that
|
||||
* capture input argument values and add it to the exception message. E.g.
|
||||
* `CAFFE_ENFORCE_THAT(Equals(foo(x), bar(y)), "Optional additional message")`
|
||||
* would evaluate both foo and bar only once and if the results are not equal -
|
||||
* include them in the exception message.
|
||||
*
|
||||
* Some of the basic checker functions like Equals or Greater are already
|
||||
* defined below. Other header might define customized checkers by adding
|
||||
* functions to caffe2::enforce_detail namespace. For example:
|
||||
*
|
||||
* namespace caffe2 { namespace enforce_detail {
|
||||
* inline EnforceFailMessage IsVector(const vector<int64_t>& shape) {
|
||||
* if (shape.size() == 1) { return EnforceOK(); }
|
||||
* return c10::str("Shape ", shape, " is not a vector");
|
||||
* }
|
||||
* }}
|
||||
*
|
||||
* With further usages like `CAFFE_ENFORCE_THAT(IsVector(Input(0).dims()))`
|
||||
*
|
||||
* Convenient wrappers for binary operations like CAFFE_ENFORCE_EQ are provided
|
||||
* too. Please use them instead of CHECK_EQ and friends for failures in
|
||||
* user-provided input.
|
||||
*/
|
||||
|
||||
namespace enforce_detail {
|
||||
|
||||
struct CAFFE2_API EnforceOK {};
|
||||
|
||||
class CAFFE2_API EnforceFailMessage {
|
||||
public:
|
||||
#ifdef _MSC_VER
|
||||
// MSVC + NVCC ignores constexpr and will issue a warning if included.
|
||||
/* implicit */ EnforceFailMessage(EnforceOK) : msg_(nullptr) {}
|
||||
#else
|
||||
constexpr /* implicit */ EnforceFailMessage(EnforceOK) : msg_(nullptr) {}
|
||||
#endif
|
||||
EnforceFailMessage(EnforceFailMessage&&) = default;
|
||||
EnforceFailMessage(const EnforceFailMessage&) = delete;
|
||||
EnforceFailMessage& operator=(EnforceFailMessage&&) = delete;
|
||||
EnforceFailMessage& operator=(const EnforceFailMessage&) = delete;
|
||||
|
||||
// Catch all wrong usages like CAFFE_ENFORCE_THAT(x < y)
|
||||
template <class... Args>
|
||||
/* implicit */ EnforceFailMessage(Args...) {
|
||||
static_assert(
|
||||
// This stands for an "impossible" condition. Plain `false` doesn't
|
||||
// trick compiler enough.
|
||||
sizeof...(Args) == std::numeric_limits<std::size_t>::max(),
|
||||
"CAFFE_ENFORCE_THAT has to be used with one of special check functions "
|
||||
"like `Equals`. Use CAFFE_ENFORCE for simple boolean checks.");
|
||||
}
|
||||
|
||||
/* implicit */ EnforceFailMessage(std::string&& msg);
|
||||
|
||||
inline bool bad() const {
|
||||
return msg_ != nullptr;
|
||||
}
|
||||
std::string get_message_and_free(std::string&& extra) const {
|
||||
std::string r;
|
||||
if (extra.empty()) {
|
||||
r = std::move(*msg_);
|
||||
} else {
|
||||
r = ::c10::str(std::move(*msg_), ". ", std::move(extra));
|
||||
}
|
||||
delete msg_;
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string* msg_;
|
||||
};
|
||||
|
||||
#define BINARY_COMP_HELPER(name, op) \
|
||||
template <typename T1, typename T2> \
|
||||
inline EnforceFailMessage name(const T1& x, const T2& y) { \
|
||||
if (x op y) { \
|
||||
return EnforceOK(); \
|
||||
} \
|
||||
return c10::str(x, " vs ", y); \
|
||||
}
|
||||
BINARY_COMP_HELPER(Equals, ==)
|
||||
BINARY_COMP_HELPER(NotEquals, !=)
|
||||
BINARY_COMP_HELPER(Greater, >)
|
||||
BINARY_COMP_HELPER(GreaterEquals, >=)
|
||||
BINARY_COMP_HELPER(Less, <)
|
||||
BINARY_COMP_HELPER(LessEquals, <=)
|
||||
#undef BINARY_COMP_HELPER
|
||||
|
||||
#define CAFFE_ENFORCE_THAT_IMPL(condition, expr, ...) \
|
||||
do { \
|
||||
using namespace ::caffe2::enforce_detail; \
|
||||
const EnforceFailMessage& CAFFE_ENFORCE_THAT_IMPL_r_ = (condition); \
|
||||
if (CAFFE_ENFORCE_THAT_IMPL_r_.bad()) { \
|
||||
::caffe2::ThrowEnforceNotMet( \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
expr, \
|
||||
CAFFE_ENFORCE_THAT_IMPL_r_.get_message_and_free( \
|
||||
::c10::str(__VA_ARGS__))); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(condition, expr, ...) \
|
||||
do { \
|
||||
using namespace ::caffe2::enforce_detail; \
|
||||
const EnforceFailMessage& CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER_r_ = \
|
||||
(condition); \
|
||||
if (CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER_r_.bad()) { \
|
||||
::caffe2::ThrowEnforceNotMet( \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
expr, \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER_r_.get_message_and_free( \
|
||||
::c10::str(__VA_ARGS__)), \
|
||||
this); \
|
||||
} \
|
||||
} while (false)
|
||||
}
|
||||
|
||||
#define CAFFE_ENFORCE_THAT(condition, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL((condition), #condition, __VA_ARGS__)
|
||||
|
||||
#define CAFFE_ENFORCE_EQ(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(Equals((x), (y)), #x " == " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_NE(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(NotEquals((x), (y)), #x " != " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LE(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(LessEquals((x), (y)), #x " <= " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LT(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(Less((x), (y)), #x " < " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GE(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(GreaterEquals((x), (y)), #x " >= " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GT(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(Greater((x), (y)), #x " > " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_EQ_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(Equals((x), (y)), #x " == " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_NE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(NotEquals((x), (y)), #x " != " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(LessEquals((x), (y)), #x " <= " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LT_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(Less((x), (y)), #x " < " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(GreaterEquals((x), (y)), #x " >= " #y, __VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GT_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(Greater((x), (y)), #x " > " #y, __VA_ARGS__)
|
||||
} // namespace caffe2
|
||||
|
||||
#endif // CAFFE2_CORE_LOGGING_H_
|
||||
|
@ -1,49 +0,0 @@
|
||||
#ifndef CAFFE2_CORE_LOGGING_IS_GOOGLE_GLOG_H_
|
||||
#define CAFFE2_CORE_LOGGING_IS_GOOGLE_GLOG_H_
|
||||
|
||||
#include <iomanip> // because some of the caffe2 code uses e.g. std::setw
|
||||
// Using google glog. For glog 0.3.2 versions, stl_logging.h needs to be before
|
||||
// logging.h to actually use stl_logging. Because template magic.
|
||||
// In addition, we do not do stl logging in .cu files because nvcc does not like
|
||||
// it. Some mobile platforms do not like stl_logging, so we add an
|
||||
// overload in that case as well.
|
||||
|
||||
#ifdef __CUDACC__
|
||||
#include <cuda.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__CUDACC__) && !defined(CAFFE2_USE_MINIMAL_GOOGLE_GLOG)
|
||||
#include <glog/stl_logging.h>
|
||||
|
||||
// Old versions of glog don't declare this using declaration, so help
|
||||
// them out. Fortunately, C++ won't complain if you declare the same
|
||||
// using declaration multiple times.
|
||||
namespace std {
|
||||
using ::operator<<;
|
||||
}
|
||||
|
||||
#else // !defined(__CUDACC__) && !defined(CAFFE2_USE_MINIMAL_GOOGLE_GLOG)
|
||||
|
||||
// here, we need to register a fake overload for vector/string - here,
|
||||
// we just ignore the entries in the logs.
|
||||
|
||||
namespace std
|
||||
{
|
||||
#define INSTANTIATE_FOR_CONTAINER(container) \
|
||||
template <class... Types> \
|
||||
ostream& operator<<(ostream& out, const container<Types...>&) { \
|
||||
return out; \
|
||||
}
|
||||
|
||||
INSTANTIATE_FOR_CONTAINER(vector)
|
||||
INSTANTIATE_FOR_CONTAINER(map)
|
||||
INSTANTIATE_FOR_CONTAINER(set)
|
||||
#undef INSTANTIATE_FOR_CONTAINER
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
|
||||
#endif // CAFFE2_CORE_LOGGING_IS_GOOGLE_GLOG_H_
|
Reference in New Issue
Block a user