Frobby
0.9.5
src
DebugAllocator.cpp
Go to the documentation of this file.
1
/* Frobby: Software for monomial ideal computations.
2
Copyright (C) 2007 Bjarke Hammersholt Roune (www.broune.com)
3
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program. If not, see http://www.gnu.org/licenses/.
16
*/
17
#include "
stdinc.h
"
18
#include "
DebugAllocator.h
"
19
20
#include "
main.h
"
21
#include "
error.h
"
22
#include "
Ideal.h
"
23
#include "
test/TestCase.h
"
24
#include "
IOHandler.h
"
25
#include <limits>
26
27
// Must not include code below if not debugging. For one, then Frobby
28
// cannot be built as a library as this code calls main.
29
// The code only applies to debug builds anyway.
30
#ifdef DEBUG
31
#undef new
32
33
static
const
size_t
AllocationLimitsTryFirst
= 500;
34
static
const
size_t
AllocationLimitsTryLast
= 200;
35
static
const
size_t
AllocationLimitsStepRatio
= 1000;
36
37
DebugAllocator
& DebugAllocator::getSingleton() {
38
static
DebugAllocator
singleton
;
39
return
singleton
;
40
}
41
42
void
DebugAllocator::rewindInput() {
43
if
(
_inputFile
!=
""
)
44
if
(!
freopen
(
_inputFile
.c_str(),
"r"
,
stdin
))
45
reportError
(
"Could not open file \""
+
_inputFile
+
"\" for input."
);
46
}
47
55
int
DebugAllocator::runDebugMain(
int
argc
,
const
char
**
argv
) {
56
processDebugOptions
(
argc
,
argv
);
57
58
// Run all the way through once to count the number of allocations
59
// and to produce the correct output. Note that the number of
60
// allocations on subsequent runs can be a bit less due to static
61
// caches.
62
rewindInput
();
63
_allocationCount
= 0;
64
int
exitCode
=
frobbyMain
(
argc
,
argv
);
65
size_t
maxAllocations
=
_allocationCount
;
66
if
(
_actionIsTest
|| !
_debugAllocation
)
67
return
exitCode
;
68
69
fclose
(
stdout
);
// Output has already been produced.
70
71
fputs
(
"DEBUG: Now debugging out-of-memory conditions.\n"
,
stderr
);
72
fprintf
(
stderr
,
"DEBUG: There are %i allocations in total on this input.\n"
,
73
(
int
)
maxAllocations
);
74
75
// If maxAllocations is small then just try every possible limit.
76
if
(
maxAllocations
<
AllocationLimitsTryFirst
+
AllocationLimitsTryLast
) {
77
fputs
(
"DEBUG: This is few, so am now running through "
78
"every possible condition.\n"
,
stderr
);
79
for
(
size_t
limit
= 0;
limit
<
maxAllocations
; ++
limit
)
80
runWithLimit
(
argc
,
argv
,
limit
);
81
return
ExitCodeSuccess
;
82
}
83
84
fprintf
(
stderr
,
"DEBUG: Trying the first %i allocations.\n"
,
85
(
int
)
AllocationLimitsTryFirst
);
86
for
(
size_t
limit
= 0;
limit
<
AllocationLimitsTryFirst
; ++
limit
)
87
runWithLimit
(
argc
,
argv
,
limit
);
88
89
fprintf
(
stderr
,
"DEBUG: Trying the last %i allocations.\n"
,
90
(
int
)
AllocationLimitsTryLast
);
91
for
(
size_t
limit
= 0;
limit
<
AllocationLimitsTryLast
; ++
limit
)
92
runWithLimit
(
argc
,
argv
,
maxAllocations
-
limit
);
93
94
size_t
limitsLeft
=
95
maxAllocations
-
AllocationLimitsTryFirst
-
AllocationLimitsTryLast
;
96
size_t
stepSize
=
limitsLeft
/
AllocationLimitsStepRatio
+ 1;
97
fprintf
(
stderr
,
98
"DEBUG: Going through the %i remaining allocations "
99
"with steps of size %i.\n"
,
100
(
int
)
limitsLeft
, (
int
)
stepSize
);
101
102
for
(
size_t
limit
=
AllocationLimitsTryFirst
;
103
limit
<
maxAllocations
-
AllocationLimitsTryLast
;
limit
+=
stepSize
)
104
runWithLimit
(
argc
,
argv
,
limit
);
105
106
return
ExitCodeSuccess
;
107
}
108
109
void
DebugAllocator::runWithLimit(
int
argc
,
const
char
**
argv
,
size_t
limit
) {
110
if
(
_detailAllocation
)
111
fprintf
(
stderr
,
"DEBUG: Trying allocation limit of %i\n"
, (
int
)
limit
);
112
113
// To make each run more similar.
114
Ideal::clearStaticCache
();
115
116
_limitAllocation
=
true
;
117
_allocationLimit
=
limit
;
118
_allocationCount
= 0;
119
120
// We use this to distinguish genuinely running out of memory from
121
// our artificial limit-induced throwing of bad_alloc.
122
_expectBadAllocException
=
false
;
123
124
rewindInput
();
125
126
try
{
127
frobbyMain
(
argc
,
argv
);
128
}
catch
(
const
bad_alloc
&) {
129
if
(!
_expectBadAllocException
)
130
throw
;
131
}
132
133
_limitAllocation
=
false
;
134
}
135
136
void
DebugAllocator::processDebugOptions(
int
&
argc
,
const
char
**&
argv
) {
137
const
char
*
originalArgvZero
=
argv
[0];
138
139
while
(
true
) {
140
if
(
argc
<= 1 ||
argv
[1][0] !=
'_'
)
141
break
;
142
143
string
option
(
argv
[1] + 1);
144
++
argv
;
145
--
argc
;
146
147
if
(
option
==
"debugAlloc"
)
148
_debugAllocation
=
true
;
149
else
if
(
option
==
"detailAlloc"
)
150
_detailAllocation
=
true
;
151
else
if
(
option
==
"input"
) {
152
if
(
argc
<= 1)
153
reportError
(
"Debug option _input requries an argument."
);
154
155
_inputFile
=
argv
[1];
156
++
argv
;
157
--
argc
;
158
}
else
159
reportError
(
"Unknown debug option \""
+
option
+
"\"."
);
160
}
161
162
if
(
argc
>= 2 &&
string
(
argv
[1]) ==
"test"
)
163
_actionIsTest
=
true
;
164
165
argv
[0] =
originalArgvZero
;
166
}
167
168
void
DebugAllocator::runTest(
TestCase
&
test
,
const
string
&
name
) {
169
test
.run(
name
.c_str(),
true
);
170
171
if
(!
_debugAllocation
)
172
return
;
173
174
_limitAllocation
=
true
;
175
176
for
(
_allocationLimit
= 0;
_allocationLimit < numeric_limits<size_t>::max
();
177
++
_allocationLimit
) {
178
if
(
_detailAllocation
)
179
fprintf
(
stderr
,
"DEBUG: Trying test allocation limit of %i\n"
,
180
(
int
)
_allocationLimit
);
181
182
// To make each run more similar.
183
Ideal::clearStaticCache
();
184
185
_allocationCount
= 0;
186
_expectBadAllocException
=
false
;
187
188
rewindInput
();
189
190
try
{
191
test
.run(
name
.c_str(),
false
);
192
193
// At this point test has completed within allocation limit.
194
break
;
195
}
catch
(
const
bad_alloc
&) {
196
if
(!
_expectBadAllocException
)
197
throw
;
198
// Continue and try next limit.
199
}
200
}
201
202
_limitAllocation
=
false
;
203
}
204
205
void
* DebugAllocator::allocate(
size_t
size) {
206
return
allocate(size, 0, 0);
207
}
208
209
void
* DebugAllocator::allocate(
size_t
size,
210
const
char
* file,
211
size_t
lineNumber
) {
212
if
(
_detailAllocation
) {
213
if
(file != 0)
214
fprintf
(
stderr
,
"DEBUG: Allocating %i bytes at %s:%i.\n"
,
215
(
int
)size, file, (
int
)
lineNumber
);
216
if
(file == 0)
217
fprintf
(
stderr
,
"DEBUG: Allocating %i bytes at an unknown point.\n"
,
218
(
int
)size);
219
}
220
221
if
(
_limitAllocation
&&
_allocationCount
>=
_allocationLimit
) {
222
if
(
_detailAllocation
)
223
fputs
(
"DEBUG: Throwing bad_alloc due to artifically imposed limit.\n"
,
224
stderr
);
225
_expectBadAllocException
=
true
;
226
throw
bad_alloc
();
227
}
228
229
++
_allocationCount
;
230
void
*
p
=
malloc
(size);
231
if
(
p
== 0)
232
throw
bad_alloc
();
233
return
p
;
234
}
235
236
DebugAllocator::DebugAllocator():
237
_debugAllocation
(
false
),
238
_detailAllocation
(
false
),
239
_limitAllocation
(
false
),
240
_expectBadAllocException
(
false
),
241
_actionIsTest
(
false
),
242
_allocationCount
(0),
243
_allocationLimit
(0) {
244
}
245
246
void
*
operator
new
(
size_t
size,
const
char
* file,
size_t
lineNumber
)
247
throw
(
bad_alloc
) {
248
return
DebugAllocator::getSingleton().allocate(size, file,
lineNumber
);
249
}
250
251
void
*
operator
new
[](
size_t
size,
const
char
* file,
size_t
lineNumber
)
252
throw
(
bad_alloc
) {
253
return
DebugAllocator::getSingleton().allocate(size, file,
lineNumber
);
254
}
255
256
void
*
operator
new
(
size_t
size)
throw
(
bad_alloc
) {
257
return
DebugAllocator::getSingleton().allocate(size);
258
}
259
260
void
*
operator
new
[](
size_t
size)
throw
(
bad_alloc
) {
261
return
DebugAllocator::getSingleton().allocate(size);
262
}
263
264
void
operator
delete
(
void
*
buffer
)
throw
() {
265
free
(
buffer
);
266
}
267
268
void
operator
delete
[](
void
*
buffer
)
throw
() {
269
free
(
buffer
);
270
}
271
290
void
operator
delete
(
void
*
buffer
,
const
char
* file,
size_t
line) {
291
free
(
buffer
);
292
}
293
294
void
operator
delete
[](
void
*
buffer
,
const
char
* file,
size_t
line) {
295
free
(
buffer
);
296
}
297
298
#endif
DebugAllocator.h
IOHandler.h
Ideal.h
nameFactoryRegister
void nameFactoryRegister(NameFactory< AbstractProduct > &factory)
Registers the string returned by ConcreteProduct::getStaticName() to a function that default-construc...
Definition
NameFactory.h:142
TestCase.h
Ideal::clearStaticCache
static void clearStaticCache()
Ideal caches memory allocated with new internally and reuses it to avoid calling new all the time.
Definition
Ideal.cpp:810
TestCase
Represents a test case, which is usually created through a macro that defines a subclass.
Definition
TestCase.h:29
reportError
void reportError(const string &errorMsg)
Definition
error.cpp:23
error.h
frobbyMain
int frobbyMain(int argc, const char **argv)
This function runs the Frobby console interface.
Definition
main.cpp:34
main.h
ExitCodeSuccess
static const int ExitCodeSuccess
Definition
main.h:33
stdinc.h
Generated by
1.9.8