You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /**
  2. * \file include/misc.h
  3. * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
  4. *
  5. * Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
  6. *
  7. * Unless required by applicable law or agreed to in writing,
  8. * software distributed under the License is distributed on an
  9. * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or
  10. * implied.
  11. */
  12. #pragma once
  13. #include "lite_build_config.h"
  14. #include <chrono>
  15. #include <exception>
  16. #include <stdexcept>
  17. #include <string>
  18. #include "lite/common_enum_c.h"
  19. #include "lite/global.h"
  20. namespace lite {
  21. #if LITE_ENABLE_EXCEPTION
  22. /*! \brief The error class in lite.
  23. *
  24. * It can be used to represent both an error caused by the invalid
  25. * input of the caller or an invalid runtime condition.
  26. *
  27. * The necessary presumption should be guaranteed by assertions instead of
  28. * exceptions.
  29. */
  30. class Error : public std::exception {
  31. public:
  32. Error(const std::string& msg) : m_msg("Error: " + msg) {}
  33. const char* what() const noexcept override { return m_msg.c_str(); }
  34. private:
  35. std::string m_msg;
  36. };
  37. #endif
  38. LITE_API std::string ssprintf(const char* fmt = 0, ...)
  39. __attribute__((format(printf, 1, 2)));
  40. /*!
  41. * \brief Print a message.
  42. *
  43. * The message is printed only if level is above or equals to the current log
  44. * level.
  45. */
  46. LITE_API void print_log(LiteLogLevel level, const char* format = 0, ...)
  47. __attribute__((format(printf, 2, 3)));
  48. } // namespace lite
  49. #if LITE_ENABLE_LOGGING
  50. #define LITE_LOG_(level, msg...) \
  51. do { \
  52. lite::print_log(LiteLogLevel::level, ##msg); \
  53. } while (0)
  54. #else
  55. #define LITE_LOG_(level, msg...) (void)0
  56. #endif
  57. #define LITE_LOG(fmt...) LITE_LOG_(DEBUG, fmt);
  58. #define LITE_DEBUG(fmt...) LITE_LOG_(DEBUG, fmt);
  59. #define LITE_WARN(fmt...) LITE_LOG_(WARN, fmt);
  60. #define LITE_ERROR(fmt...) LITE_LOG_(ERROR, fmt);
  61. #if LITE_ENABLE_EXCEPTION
  62. #define LITE_THROW(msg) throw lite::Error(msg)
  63. #else
  64. #define LITE_THROW(msg) \
  65. do { \
  66. std::string msg_str(msg); \
  67. LITE_ERROR(msg_str.c_str()); \
  68. __builtin_trap(); \
  69. } while (0)
  70. #endif
  71. #if LITE_ENABLE_EXCEPTION
  72. #define LITE_ERROR_HANDLER_BEGIN try {
  73. #define LITE_ERROR_HANDLER_END \
  74. } \
  75. catch (const ::lite::Error& e) { \
  76. std::string msg = std::string("Lite exception: ") + e.what(); \
  77. LITE_ERROR("%s.", msg.c_str()); \
  78. throw; \
  79. }
  80. #else
  81. #define LITE_ERROR_HANDLER_BEGIN
  82. #define LITE_ERROR_HANDLER_END
  83. #endif
  84. /*! \brief Return an error if the given pointer is null pointer.
  85. *
  86. * The macro is used to ensure the validity of the passing context pointer.
  87. */
  88. #define LITE_CHECK_NON_NULL_POINTER(ptr) \
  89. LITE_ASSERT(ptr != nullptr, "Input ptr is null.")
  90. //! branch prediction hint: likely to take
  91. #define lite_likely(v) __builtin_expect(static_cast<bool>(v), 1)
  92. //! branch prediction hint: unlikely to take
  93. #define lite_unlikely(v) __builtin_expect(static_cast<bool>(v), 0)
  94. #if LITE_ENABLE_LOGGING
  95. #if LITE_ASSERT_LOC
  96. #define LITE_ASSERT(expr, msg...) \
  97. do { \
  98. if (lite_unlikely(!(expr))) { \
  99. auto info = lite::ssprintf(msg); \
  100. LITE_THROW(lite::ssprintf( \
  101. "Assert \' %s \' failed at file : %s \n" \
  102. "line %d : %s,\nextra " \
  103. "message: %s", \
  104. #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__, info.c_str())); \
  105. } \
  106. } while (0)
  107. #else
  108. #define LITE_ASSERT(expr, msg...) \
  109. do { \
  110. if (lite_unlikely(!(expr))) { \
  111. auto info = lite::ssprintf(msg); \
  112. LITE_THROW(lite::ssprintf( \
  113. "Assert \' %s \' failed at file : %s \n" \
  114. "line %d : %s,\nextra " \
  115. "message: %s", \
  116. #expr, "about location info, please build with debug", __LINE__, \
  117. __PRETTY_FUNCTION__, info.c_str())); \
  118. } \
  119. } while (0)
  120. #endif
  121. #else
  122. #define LITE_ASSERT(expr, msg...) \
  123. do { \
  124. if (lite_unlikely(!(expr))) { \
  125. auto msg_string = lite::ssprintf(msg); \
  126. LITE_THROW(msg_string.c_str()); \
  127. } \
  128. } while (0)
  129. #endif
  130. #define LITE_MARK_USED_VAR(var) ((void)var)
  131. namespace lite {
  132. class ScopedTimer {
  133. public:
  134. typedef std::chrono::system_clock Clock;
  135. typedef std::chrono::nanoseconds Nsec;
  136. ScopedTimer(std::string name) : m_name(name) { m_start = Clock::now(); }
  137. ~ScopedTimer() {
  138. m_stop = Clock::now();
  139. std::chrono::duration<double> elapsed = m_stop - m_start;
  140. Nsec u = std::chrono::duration_cast<Nsec>(elapsed);
  141. auto msg = ssprintf(
  142. "%s used time %fms.", m_name.c_str(),
  143. static_cast<double>(u.count()) / 1000000.f);
  144. LITE_LOG("%s", msg.c_str());
  145. }
  146. private:
  147. std::chrono::time_point<std::chrono::system_clock> m_start, m_stop;
  148. const std::string m_name;
  149. };
  150. class Timer {
  151. public:
  152. typedef std::chrono::system_clock Clock;
  153. typedef std::chrono::nanoseconds Nsec;
  154. Timer(std::string name) : m_name(name) { m_start = Clock::now(); }
  155. double get_used_time() {
  156. m_stop = Clock::now();
  157. std::chrono::duration<double> elapsed = m_stop - m_start;
  158. Nsec u = std::chrono::duration_cast<Nsec>(elapsed);
  159. return static_cast<double>(u.count()) / 1000000.0;
  160. }
  161. void print_used_time(int iter) {
  162. m_stop = Clock::now();
  163. std::chrono::duration<double> elapsed = m_stop - m_start;
  164. Nsec u = std::chrono::duration_cast<Nsec>(elapsed);
  165. printf("%s used time %f ms\n", (m_name + std::to_string(iter)).c_str(),
  166. static_cast<double>(u.count()) / 1000000.0);
  167. }
  168. void reset_start() { m_start = Clock::now(); }
  169. private:
  170. std::chrono::time_point<std::chrono::system_clock> m_start, m_stop;
  171. const std::string m_name;
  172. };
  173. inline void mark_used_variable() {}
  174. template <typename T, typename... Arg>
  175. inline void mark_used_variable(T firstArg, Arg... args) {
  176. LITE_MARK_USED_VAR(firstArg);
  177. mark_used_variable(args...);
  178. }
  179. } // namespace lite
  180. #if defined(_WIN32)
  181. #include <io.h>
  182. #include <windows.h>
  183. #undef CONST
  184. #define F_OK 0
  185. #define RTLD_LAZY 0
  186. // On the windows platform we use a lib_filename without a full path so
  187. // the win-api "LoadLibrary" would uses a standard search strategy to
  188. // find the lib module. As we cannot access to the lib_filename without a
  189. // full path, we should not use "access(a, b)" to verify it.
  190. #define access(a, b) false
  191. static inline void* dlopen(const char* file, int) {
  192. return static_cast<void*>(LoadLibrary(file));
  193. }
  194. static inline char* dlerror() {
  195. const char* errmsg = "dlerror not aviable in windows";
  196. return const_cast<char*>(errmsg);
  197. }
  198. static inline void* dlsym(void* handle, const char* name) {
  199. FARPROC symbol = GetProcAddress((HMODULE)handle, name);
  200. return reinterpret_cast<void*>(symbol);
  201. }
  202. #elif __linux__ || __unix__ || __APPLE__
  203. #include <dlfcn.h>
  204. #include <unistd.h>
  205. #endif
  206. #if __DEPLOY_ON_XP_SP2__
  207. //! refer to
  208. //! https://docs.microsoft.com/en-us/cpp/build/configuring-programs-for-windows-xp?view=msvc-160
  209. //! xp sp2 do not support vc runtime fully, casused by KERNEL32.dll do not
  210. //! implement some base apis for c++ std function, for example,
  211. //! std::mutex/std::thread/std::condition_variable as a workround, we will
  212. //! disable some MegEngine feature on xp sp2 env, for exampe, multi-thread etc!
  213. #define LITE_MUTEX size_t
  214. #define LITE_RECURSIVE_MUTEX size_t
  215. #define LITE_LOCK_GUARD(mtx) LITE_MARK_USED_VAR(mtx)
  216. #define LITE_LOCK_GUARD_UNIQUE(mtx) LITE_MARK_USED_VAR(mtx)
  217. #define LITE_LOCK_GUARD_SHARED(mtx) LITE_MARK_USED_VAR(LITE_MARK_USED_VAR)
  218. #else
  219. #define LITE_MUTEX std::mutex
  220. #define LITE_RECURSIVE_MUTEX std::recursive_mutex
  221. #define LITE_LOCK_GUARD(mtx) std::lock_guard<decltype(mtx)> LITE_LOCK_GUARD_CTOR(mtx)
  222. #define LITE_LOCK_GUARD_UNIQUE(mtx) \
  223. std::unique_lock<decltype(mtx)> LITE_LOCK_GUARD_CTOR(mtx)
  224. #define LITE_LOCK_GUARD_SHARED(mtx) \
  225. std::shared_lock<decltype(mtx)> LITE_LOCK_GUARD_CTOR(mtx)
  226. #endif
  227. // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}