1 /***************************************************************************** 2 3 Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License, version 2.0, as published by the 7 Free Software Foundation. 8 9 This program is also distributed with certain software (including but not 10 limited to OpenSSL) that is licensed under separate terms, as designated in a 11 particular file or component or in included license documentation. The authors 12 of MySQL hereby grant you an additional permission to link the program and 13 your derivative works with the separately licensed software that they have 14 included with MySQL. 15 16 This program is distributed in the hope that it will be useful, but WITHOUT 17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, 19 for more details. 20 21 You should have received a copy of the GNU General Public License along with 22 this program; if not, write to the Free Software Foundation, Inc., 23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 25 *****************************************************************************/ 26 27 /** @file include/ut0dbg.h 28 Debug utilities for Innobase 29 30 Created 1/30/1994 Heikki Tuuri 31 **********************************************************************/ 32 33 #ifndef ut0dbg_h 34 #define ut0dbg_h 35 36 /* Do not include univ.i because univ.i includes this. */ 37 38 #include <functional> 39 #include "os0thread.h" 40 41 /** Set a callback function to be called before exiting. 42 @param[in] callback user callback function */ 43 void ut_set_assert_callback(std::function<void()> &callback); 44 45 /** Report a failed assertion. */ 46 [[noreturn]] void ut_dbg_assertion_failed( 47 const char *expr, /*!< in: the failed assertion */ 48 const char *file, /*!< in: source file containing the assertion */ 49 ulint line); /*!< in: line number of the assertion */ 50 51 /** Abort execution if EXPR does not evaluate to nonzero. 52 @param EXPR assertion expression that should hold */ 53 #define ut_a(EXPR) \ 54 do { \ 55 if (UNIV_UNLIKELY(!(ulint)(EXPR))) { \ 56 ut_dbg_assertion_failed(#EXPR, __FILE__, (ulint)__LINE__); \ 57 } \ 58 } while (0) 59 60 /** Abort execution. */ 61 #define ut_error ut_dbg_assertion_failed(0, __FILE__, (ulint)__LINE__) 62 63 #ifdef UNIV_DEBUG 64 /** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */ 65 #define ut_ad(EXPR) ut_a(EXPR) 66 /** Debug statement. Does nothing unless UNIV_DEBUG is defined. */ 67 #define ut_d(EXPR) EXPR 68 /** Opposite of ut_d(). Does nothing if UNIV_DEBUG is defined. */ 69 #define ut_o(EXPR) 70 #else 71 /** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */ 72 #define ut_ad(EXPR) 73 /** Debug statement. Does nothing unless UNIV_DEBUG is defined. */ 74 #define ut_d(EXPR) 75 /** Opposite of ut_d(). Does nothing if UNIV_DEBUG is defined. */ 76 #define ut_o(EXPR) EXPR 77 #endif 78 79 /** Debug crash point */ 80 #ifdef UNIV_DEBUG 81 #define DBUG_INJECT_CRASH(prefix, count) \ 82 do { \ 83 char buf[64]; \ 84 snprintf(buf, sizeof buf, prefix "_%u", count); \ 85 DBUG_EXECUTE_IF(buf, DBUG_SUICIDE();); \ 86 } while (0) 87 88 #define DBUG_INJECT_CRASH_WITH_LOG_FLUSH(prefix, count) \ 89 do { \ 90 char buf[64]; \ 91 snprintf(buf, sizeof buf, prefix "_%u", count); \ 92 DBUG_EXECUTE_IF(buf, log_buffer_flush_to_disk(); DBUG_SUICIDE();); \ 93 } while (0) 94 #else 95 #define DBUG_INJECT_CRASH(prefix, count) 96 #define DBUG_INJECT_CRASH_WITH_LOG_FLUSH(prefix, count) 97 #endif 98 99 /** Silence warnings about an unused variable by doing a null assignment. 100 @param A the unused variable */ 101 #define UT_NOT_USED(A) A = A 102 103 #if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H) 104 105 #define HAVE_UT_CHRONO_T 106 107 #include <sys/resource.h> 108 #include <sys/time.h> 109 #include <sys/types.h> 110 111 /** A "chronometer" used to clock snippets of code. 112 Example usage: 113 ut_chrono_t ch("this loop"); 114 for (;;) { ... } 115 ch.show(); 116 would print the timings of the for() loop, prefixed with "this loop:" */ 117 class ut_chrono_t { 118 public: 119 /** Constructor. 120 @param[in] name chrono's name, used when showing the values */ ut_chrono_t(const char * name)121 ut_chrono_t(const char *name) : m_name(name), m_show_from_destructor(true) { 122 reset(); 123 } 124 125 /** Resets the chrono (records the current time in it). */ reset()126 void reset() { 127 gettimeofday(&m_tv, nullptr); 128 129 getrusage(RUSAGE_SELF, &m_ru); 130 } 131 132 /** Shows the time elapsed and usage statistics since the last reset. */ show()133 void show() { 134 struct rusage ru_now; 135 struct timeval tv_now; 136 struct timeval tv_diff; 137 138 getrusage(RUSAGE_SELF, &ru_now); 139 140 gettimeofday(&tv_now, nullptr); 141 142 #ifndef timersub 143 #define timersub(a, b, r) \ 144 do { \ 145 (r)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ 146 (r)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ 147 if ((r)->tv_usec < 0) { \ 148 (r)->tv_sec--; \ 149 (r)->tv_usec += 1000000; \ 150 } \ 151 } while (0) 152 #endif /* timersub */ 153 154 #define CHRONO_PRINT(type, tvp) \ 155 fprintf(stderr, "%s: %s% 5ld.%06ld sec\n", m_name, type, \ 156 static_cast<long>((tvp)->tv_sec), static_cast<long>((tvp)->tv_usec)) 157 158 timersub(&tv_now, &m_tv, &tv_diff); 159 CHRONO_PRINT("real", &tv_diff); 160 161 timersub(&ru_now.ru_utime, &m_ru.ru_utime, &tv_diff); 162 CHRONO_PRINT("user", &tv_diff); 163 164 timersub(&ru_now.ru_stime, &m_ru.ru_stime, &tv_diff); 165 CHRONO_PRINT("sys ", &tv_diff); 166 } 167 168 /** Cause the timings not to be printed from the destructor. */ end()169 void end() { m_show_from_destructor = false; } 170 171 /** Destructor. */ ~ut_chrono_t()172 ~ut_chrono_t() { 173 if (m_show_from_destructor) { 174 show(); 175 } 176 } 177 178 private: 179 /** Name of this chronometer. */ 180 const char *m_name; 181 182 /** True if the current timings should be printed by the destructor. */ 183 bool m_show_from_destructor; 184 185 /** getrusage() result as of the last reset(). */ 186 struct rusage m_ru; 187 188 /** gettimeofday() result as of the last reset(). */ 189 struct timeval m_tv; 190 }; 191 192 #endif /* HAVE_SYS_TIME_H && HAVE_SYS_RESOURCE_H */ 193 194 #endif 195