summaryrefslogtreecommitdiffstats
path: root/storage/innobase/include/ut0dbg.h
blob: 85856660494e8b35c258665810e36e1c0e009b5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
52
53
54
55
56
57
58
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*****************************************************************************

Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2019, MariaDB Corporation.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA

*****************************************************************************/

/*****************************************************************//**
@file include/ut0dbg.h
Debug utilities for Innobase

Created 1/30/1994 Heikki Tuuri
**********************************************************************/

#ifndef ut0dbg_h
#define ut0dbg_h

#ifdef UNIV_INNOCHECKSUM
#define ut_a		assert
#define ut_ad		assert
#define ut_error	assert(0)
#else /* !UNIV_INNOCHECKSUM */

/* Do not include univ.i because univ.i includes this. */

/*************************************************************//**
Report a failed assertion. */
ATTRIBUTE_NORETURN ATTRIBUTE_COLD __attribute__((nonnull(2)))
void
ut_dbg_assertion_failed(
/*====================*/
	const char*	expr,	/*!< in: the failed assertion */
	const char*	file,	/*!< in: source file containing the assertion */
	unsigned	line);	/*!< in: line number of the assertion */

/** Abort execution if EXPR does not evaluate to nonzero.
@param EXPR assertion expression that should hold */
#define ut_a(EXPR) do {						\
	if (UNIV_UNLIKELY(!(ulint) (EXPR))) {			\
		ut_dbg_assertion_failed(#EXPR,			\
				__FILE__, __LINE__);		\
	}							\
} while (0)

/** Abort execution. */
#define ut_error						\
	ut_dbg_assertion_failed(0, __FILE__, __LINE__)

/** Debug assertion */
#define ut_ad	DBUG_SLOW_ASSERT
#if defined(UNIV_DEBUG) || !defined(DBUG_OFF)
/** Debug statement. Does nothing unless UNIV_DEBUG is defined. */
#define ut_d(EXPR)	EXPR
#else
/** Debug statement. Does nothing unless UNIV_DEBUG is defined. */
#define ut_d(EXPR)
#endif

#if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H)

#define HAVE_UT_CHRONO_T

#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>

/** A "chronometer" used to clock snippets of code.
Example usage:
	ut_chrono_t	ch("this loop");
	for (;;) { ... }
	ch.show();
would print the timings of the for() loop, prefixed with "this loop:" */
class ut_chrono_t {
public:
	/** Constructor.
	@param[in]	name	chrono's name, used when showing the values */
	ut_chrono_t(
		const char*	name)
		:
		m_name(name),
		m_show_from_destructor(true)
	{
		reset();
	}

	/** Resets the chrono (records the current time in it). */
	void
	reset()
	{
		gettimeofday(&m_tv, NULL);

		getrusage(RUSAGE_SELF, &m_ru);
	}

	/** Shows the time elapsed and usage statistics since the last reset. */
	void
	show()
	{
		struct rusage	ru_now;
		struct timeval	tv_now;
		struct timeval	tv_diff;

		getrusage(RUSAGE_SELF, &ru_now);

		gettimeofday(&tv_now, NULL);

#ifndef timersub
#define timersub(a, b, r)						\
		do {							\
			(r)->tv_sec = (a)->tv_sec - (b)->tv_sec;	\
			(r)->tv_usec = (a)->tv_usec - (b)->tv_usec;	\
			if ((r)->tv_usec < 0) {				\
				(r)->tv_sec--;				\
				(r)->tv_usec += 1000000;		\
			}						\
		} while (0)
#endif /* timersub */

#define CHRONO_PRINT(type, tvp)						\
		fprintf(stderr, "%s: %s% 5ld.%06ld sec\n",		\
			m_name, type,					\
			static_cast<long>((tvp)->tv_sec),		\
			static_cast<long>((tvp)->tv_usec))

		timersub(&tv_now, &m_tv, &tv_diff);
		CHRONO_PRINT("real", &tv_diff);

		timersub(&ru_now.ru_utime, &m_ru.ru_utime, &tv_diff);
		CHRONO_PRINT("user", &tv_diff);

		timersub(&ru_now.ru_stime, &m_ru.ru_stime, &tv_diff);
		CHRONO_PRINT("sys ", &tv_diff);
	}

	/** Cause the timings not to be printed from the destructor. */
	void end()
	{
		m_show_from_destructor = false;
	}

	/** Destructor. */
	~ut_chrono_t()
	{
		if (m_show_from_destructor) {
			show();
		}
	}

private:
	/** Name of this chronometer. */
	const char*	m_name;

	/** True if the current timings should be printed by the destructor. */
	bool		m_show_from_destructor;

	/** getrusage() result as of the last reset(). */
	struct rusage	m_ru;

	/** gettimeofday() result as of the last reset(). */
	struct timeval	m_tv;
};

#endif /* HAVE_SYS_TIME_H && HAVE_SYS_RESOURCE_H */

#endif /* !UNIV_INNOCHECKSUM */

#endif