common.h 7.7 KB
Newer Older
1 2 3 4
/**
 * \file src/core/include/megbrain/common.h
 * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
 *
5
 * Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
6 7 8 9 10 11 12 13 14
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 */

#pragma once

#include "megbrain_build_config.h"
15
#include "megdnn/basic_types.h"
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

#include <memory>
#include <string>
#include <mutex>
#include <exception>

#include <cstdint>
#include <cstddef>
#include <cstdarg>
#include <cstdlib>

namespace mgb {

/* ================ compiler related ================  */

//! comma to be used in macros for template arguments
#define MGB_COMMA   ,

//! branch prediction hint: likely to take
#define mgb_likely(v)   __builtin_expect(static_cast<bool>(v), 1)

//! branch prediction hint: unlikely to take
#define mgb_unlikely(v)   __builtin_expect(static_cast<bool>(v), 0)

//! mark a var to be used
#define MGB_MARK_USED_VAR(var) static_cast<void>(var)

//! remove padding in a struct
#define MGB_PACKED  __attribute__((packed))

//! ask the compiler to not inline a function
#define MGB_NOINLINE  __attribute__((noinline))

//! warn if result of a function is not used
#define MGB_WARN_UNUSED_RESULT __attribute__((warn_unused_result))

52 53 54 55 56 57 58
#if __cplusplus >= 201703L || __clang_major__ >= 4
#define MGB_FALLTHRU [[fallthrough]];
#elif __GNUC__ >= 7
#define MGB_FALLTHRU __attribute__((fallthrough));
#else
#define MGB_FALLTHRU
#endif
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

/* ================ exception and assertion ================  */

#ifndef mgb_trap
#define mgb_trap() __builtin_trap()
#endif

#if MGB_ENABLE_EXCEPTION

//! throw raw exception object
#define mgb_throw_raw(_exc...) throw _exc
//! try block
#define MGB_TRY try
//! catch block
#define MGB_CATCH(_decl, _stmt) \
    catch(_decl) _stmt

#else

#if MGB_ENABLE_LOGGING
#define mgb_throw_raw(_exc...) ::mgb::__on_exception_throw__(_exc)
void __on_exception_throw__(const std::exception &exc)
    __attribute__((noreturn));
#else
#define mgb_throw_raw(_exc...) mgb_trap()
#endif
#define MGB_TRY
#define MGB_CATCH(_decl, _stmt)

#endif // MGB_ENABLE_EXCEPTION

//! used after try-catch block, like try-finally construct in python
#define MGB_FINALLY(_stmt) \
    MGB_CATCH(..., {_stmt; throw; }) \
    _stmt

95 96 97 98
#if MGB_ENABLE_LOGGING
//! throw exception with given message
#define mgb_throw(_exc, _msg...) mgb_throw_raw(_exc(::mgb::ssprintf(_msg)))
#else
99
//! throw exception with given message
100 101
#define mgb_throw(_exc, _msg...) mgb_throw_raw(_exc(""))
#endif
102 103 104 105 106 107 108 109 110

//! throw exception with given message if condition is true
#define mgb_throw_if(_cond, _exc, _msg...) \
    do { \
        if (mgb_unlikely((_cond))) \
            mgb_throw(_exc, _msg); \
    } while(0)

// assert
111 112 113
void __assert_fail__(const char* file, int line, const char* func,
                     const char* expr, const char* msg_fmt = 0, ...)
        __attribute__((format(printf, 5, 6), noreturn));
114 115 116 117 118 119
#if MGB_ASSERT_LOC
/*!
 * \brief extended assert
 * extra diagnostics message (in printf format) could be printed when assertion
 * fails; the asserted expression is guaranteed to be evaluated
 */
120 121 122 123 124 125
#define mgb_assert(expr, msg...)                                            \
    do {                                                                    \
        if (mgb_unlikely(!(expr)))                                          \
            ::mgb::__assert_fail__(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
                                   #expr, ##msg);                           \
    } while (0)
126
#else
127 128 129 130 131 132 133 134
#define mgb_assert(expr, msg...)                                              \
    do {                                                                      \
        if (mgb_unlikely(!(expr)))                                            \
            ::mgb::__assert_fail__(                                           \
                    "about location info, please build with debug", __LINE__, \
                    NULL, #expr, ##msg);                                      \
    } while (0)
#endif  // MGB_ASSERT_LOC
135 136

/* ================ logging ================  */
137
#if MGB_ASSERT_LOC
138 139 140 141 142 143 144 145 146
#define mgb_log_debug(fmt...) \
    _mgb_do_log(::mgb::LogLevel::DEBUG, __FILE__, __func__, __LINE__, fmt)
#define mgb_log(fmt...) \
    _mgb_do_log(::mgb::LogLevel::INFO, __FILE__, __func__, __LINE__, fmt)
#define mgb_log_warn(fmt...) \
    _mgb_do_log(::mgb::LogLevel::WARN, __FILE__, __func__, __LINE__, fmt)
#define mgb_log_error(fmt...) \
    _mgb_do_log(::mgb::LogLevel::ERROR, __FILE__, __func__, __LINE__, fmt)
#else
M
Megvii Engine Team 已提交
147
#define LOC "about location info, please build with debug"
148
#define mgb_log_debug(fmt...) \
M
Megvii Engine Team 已提交
149
    _mgb_do_log(::mgb::LogLevel::DEBUG, "", "", __LINE__, fmt)
150
#define mgb_log(fmt...) \
M
Megvii Engine Team 已提交
151
    _mgb_do_log(::mgb::LogLevel::INFO, "", "", __LINE__, fmt)
152
#define mgb_log_warn(fmt...) \
M
Megvii Engine Team 已提交
153
    _mgb_do_log(::mgb::LogLevel::WARN, "", "", __LINE__, fmt)
154
#define mgb_log_error(fmt...) \
M
Megvii Engine Team 已提交
155
    _mgb_do_log(::mgb::LogLevel::ERROR, LOC, "", __LINE__, fmt)
156
#endif
M
Megvii Engine Team 已提交
157
enum class LogLevel { DEBUG, INFO, WARN, ERROR, NO_LOG };
158 159 160 161 162 163 164 165 166 167 168 169 170

typedef void(*LogHandler)(LogLevel level,
        const char *file, const char *func, int line, const char *fmt,
        va_list ap);

/*!
 * \brief set logging level
 * messages lower than given level would not be sent to log handler
 *
 * \return previous log level
 */
LogLevel set_log_level(LogLevel level);

M
Megvii Engine Team 已提交
171 172 173 174 175 176 177
/*!
 * \brief get logging level
 *
 * \return current log level
 */
LogLevel get_log_level();

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
/*!
 * \brief set callback for receiving log requests
 * \return previous log handler
 */
LogHandler set_log_handler(LogHandler handler);

#if MGB_ENABLE_LOGGING
void __log__(LogLevel level, const char *file, const char *func, int line,
        const char *fmt, ...)
    __attribute__((format(printf, 5, 6)));

#define _mgb_do_log ::mgb::__log__
//! make a string used for log
#define mgb_ssprintf_log ::mgb::ssprintf
//! v if log is enabled, and "" if not
#define mgb_cstr_log(v) v
#else
#define _mgb_do_log(...) do{} while(0)
#define mgb_ssprintf_log(...) ::std::string{}
#define mgb_cstr_log(v) ""
#endif // MGB_ENABLE_LOGGING

/* ================ misc ================  */

#if MGB_ENABLE_GETENV
#define MGB_GETENV  ::std::getenv
#else
#define MGB_GETENV(_name)  static_cast<char*>(nullptr)
#endif

208 209 210 211 212
#ifdef WIN32
#define unsetenv(_name) _putenv_s(_name, "");
#define setenv(name,value,overwrite) _putenv_s(name,value)
#endif

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
// use some macro tricks to get lock guard with unique variable name
#define MGB_TOKENPASTE(x, y) x ## y
#define MGB_TOKENPASTE2(x, y) MGB_TOKENPASTE(x, y)
#define MGB_LOCK_GUARD_CTOR(mtx) MGB_TOKENPASTE2(__lock_guard_, __LINE__)(mtx)

#define MGB_LOCK_GUARD(mtx) \
    std::lock_guard<decltype(mtx)> MGB_LOCK_GUARD_CTOR(mtx)

#define MGB_LOCK_GUARD_UNIQUE(mtx) \
    std::unique_lock<decltype(mtx)> MGB_LOCK_GUARD_CTOR(mtx)

#define MGB_LOCK_GUARD_SHARED(mtx) \
	std::shared_lock<decltype(mtx)> MGB_LOCK_GUARD_CTOR(mtx)

/*!
 * \brief printf-like std::string constructor
 */
std::string ssprintf(const char *fmt, ...)
    __attribute__((format(printf, 1, 2)));

std::string svsprintf(const char *fmt, va_list ap);

#if 0
// used for win32 with vs prior to 2015
const char* convert_fmt_str(const char *fmt);
static inline const char* operator "" _fmt(const char *fmt, std::size_t) {
    return convert_fmt_str(fmt);
}
#else
static inline constexpr const char* convert_fmt_str(const char *fmt) {
    return fmt;
}
static inline constexpr const char* operator "" _fmt(
        const char *fmt, std::size_t) {
    return convert_fmt_str(fmt);
}
inline constexpr std::size_t operator"" _z(unsigned long long n) {
    return n;
}
#endif
253 254 255 256

#define MGB_DEF_ENUM_CLASS_BIT_OPR(cls) \
    MEGDNN_DEF_ENUM_CLASS_BIT_OPR(cls)

257 258 259
}   // namespace mgb

// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}