blob: 491cd057ef87c22ba437e0e802ccda85d8731959 [file] [log] [blame]
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001import contextlib
Victor Stinnered3b0bc2013-11-23 12:27:24 +01002import os
3import sys
4import tracemalloc
5import unittest
6from unittest.mock import patch
Berker Peksagce643912015-05-06 06:33:17 +03007from test.support.script_helper import (assert_python_ok, assert_python_failure,
8 interpreter_requires_environment)
9from test import support
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020010
Victor Stinner10b73e12016-03-22 13:39:05 +010011try:
12 import _testcapi
13except ImportError:
14 _testcapi = None
15
Victor Stinnered3b0bc2013-11-23 12:27:24 +010016
17EMPTY_STRING_SIZE = sys.getsizeof(b'')
Victor Stinner60b04c92018-07-25 19:23:53 +020018INVALID_NFRAME = (-1, 2**30)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010019
Victor Stinner10b73e12016-03-22 13:39:05 +010020
Victor Stinnered3b0bc2013-11-23 12:27:24 +010021def get_frames(nframe, lineno_delta):
22 frames = []
23 frame = sys._getframe(1)
24 for index in range(nframe):
25 code = frame.f_code
26 lineno = frame.f_lineno + lineno_delta
27 frames.append((code.co_filename, lineno))
28 lineno_delta = 0
29 frame = frame.f_back
30 if frame is None:
31 break
32 return tuple(frames)
33
34def allocate_bytes(size):
35 nframe = tracemalloc.get_traceback_limit()
36 bytes_len = (size - EMPTY_STRING_SIZE)
37 frames = get_frames(nframe, 1)
38 data = b'x' * bytes_len
39 return data, tracemalloc.Traceback(frames)
40
41def create_snapshots():
42 traceback_limit = 2
43
Victor Stinnere492ae52016-03-22 12:58:23 +010044 # _tracemalloc._get_traces() returns a list of (domain, size,
45 # traceback_frames) tuples. traceback_frames is a tuple of (filename,
46 # line_number) tuples.
Victor Stinnered3b0bc2013-11-23 12:27:24 +010047 raw_traces = [
Victor Stinnere492ae52016-03-22 12:58:23 +010048 (0, 10, (('a.py', 2), ('b.py', 4))),
49 (0, 10, (('a.py', 2), ('b.py', 4))),
50 (0, 10, (('a.py', 2), ('b.py', 4))),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010051
Victor Stinnere492ae52016-03-22 12:58:23 +010052 (1, 2, (('a.py', 5), ('b.py', 4))),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010053
Victor Stinnere492ae52016-03-22 12:58:23 +010054 (2, 66, (('b.py', 1),)),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010055
Victor Stinnere492ae52016-03-22 12:58:23 +010056 (3, 7, (('<unknown>', 0),)),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010057 ]
58 snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit)
59
60 raw_traces2 = [
Victor Stinnere492ae52016-03-22 12:58:23 +010061 (0, 10, (('a.py', 2), ('b.py', 4))),
62 (0, 10, (('a.py', 2), ('b.py', 4))),
63 (0, 10, (('a.py', 2), ('b.py', 4))),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010064
Victor Stinnere492ae52016-03-22 12:58:23 +010065 (2, 2, (('a.py', 5), ('b.py', 4))),
66 (2, 5000, (('a.py', 5), ('b.py', 4))),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010067
Victor Stinnere492ae52016-03-22 12:58:23 +010068 (4, 400, (('c.py', 578),)),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010069 ]
70 snapshot2 = tracemalloc.Snapshot(raw_traces2, traceback_limit)
71
72 return (snapshot, snapshot2)
73
74def frame(filename, lineno):
75 return tracemalloc._Frame((filename, lineno))
76
77def traceback(*frames):
78 return tracemalloc.Traceback(frames)
79
80def traceback_lineno(filename, lineno):
81 return traceback((filename, lineno))
82
83def traceback_filename(filename):
84 return traceback_lineno(filename, 0)
85
86
87class TestTracemallocEnabled(unittest.TestCase):
88 def setUp(self):
89 if tracemalloc.is_tracing():
90 self.skipTest("tracemalloc must be stopped before the test")
91
Victor Stinner3728d6c2013-11-23 12:37:20 +010092 tracemalloc.start(1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010093
94 def tearDown(self):
95 tracemalloc.stop()
96
97 def test_get_tracemalloc_memory(self):
98 data = [allocate_bytes(123) for count in range(1000)]
99 size = tracemalloc.get_tracemalloc_memory()
100 self.assertGreaterEqual(size, 0)
101
102 tracemalloc.clear_traces()
103 size2 = tracemalloc.get_tracemalloc_memory()
104 self.assertGreaterEqual(size2, 0)
105 self.assertLessEqual(size2, size)
106
107 def test_get_object_traceback(self):
108 tracemalloc.clear_traces()
109 obj_size = 12345
110 obj, obj_traceback = allocate_bytes(obj_size)
111 traceback = tracemalloc.get_object_traceback(obj)
112 self.assertEqual(traceback, obj_traceback)
113
114 def test_set_traceback_limit(self):
115 obj_size = 10
116
Victor Stinner3728d6c2013-11-23 12:37:20 +0100117 tracemalloc.stop()
118 self.assertRaises(ValueError, tracemalloc.start, -1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100119
Victor Stinner3728d6c2013-11-23 12:37:20 +0100120 tracemalloc.stop()
121 tracemalloc.start(10)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100122 obj2, obj2_traceback = allocate_bytes(obj_size)
123 traceback = tracemalloc.get_object_traceback(obj2)
124 self.assertEqual(len(traceback), 10)
125 self.assertEqual(traceback, obj2_traceback)
126
Victor Stinner3728d6c2013-11-23 12:37:20 +0100127 tracemalloc.stop()
128 tracemalloc.start(1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100129 obj, obj_traceback = allocate_bytes(obj_size)
130 traceback = tracemalloc.get_object_traceback(obj)
131 self.assertEqual(len(traceback), 1)
132 self.assertEqual(traceback, obj_traceback)
133
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100134 def find_trace(self, traces, traceback):
135 for trace in traces:
Victor Stinnere492ae52016-03-22 12:58:23 +0100136 if trace[2] == traceback._frames:
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100137 return trace
138
139 self.fail("trace not found")
140
141 def test_get_traces(self):
142 tracemalloc.clear_traces()
143 obj_size = 12345
144 obj, obj_traceback = allocate_bytes(obj_size)
145
146 traces = tracemalloc._get_traces()
147 trace = self.find_trace(traces, obj_traceback)
148
149 self.assertIsInstance(trace, tuple)
Victor Stinnere492ae52016-03-22 12:58:23 +0100150 domain, size, traceback = trace
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100151 self.assertEqual(size, obj_size)
152 self.assertEqual(traceback, obj_traceback._frames)
153
154 tracemalloc.stop()
155 self.assertEqual(tracemalloc._get_traces(), [])
156
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100157 def test_get_traces_intern_traceback(self):
158 # dummy wrappers to get more useful and identical frames in the traceback
159 def allocate_bytes2(size):
160 return allocate_bytes(size)
161 def allocate_bytes3(size):
162 return allocate_bytes2(size)
163 def allocate_bytes4(size):
164 return allocate_bytes3(size)
165
166 # Ensure that two identical tracebacks are not duplicated
Victor Stinner3728d6c2013-11-23 12:37:20 +0100167 tracemalloc.stop()
168 tracemalloc.start(4)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100169 obj_size = 123
170 obj1, obj1_traceback = allocate_bytes4(obj_size)
171 obj2, obj2_traceback = allocate_bytes4(obj_size)
172
173 traces = tracemalloc._get_traces()
174
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100175 obj1_traceback._frames = tuple(reversed(obj1_traceback._frames))
176 obj2_traceback._frames = tuple(reversed(obj2_traceback._frames))
177
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100178 trace1 = self.find_trace(traces, obj1_traceback)
179 trace2 = self.find_trace(traces, obj2_traceback)
Victor Stinnere492ae52016-03-22 12:58:23 +0100180 domain1, size1, traceback1 = trace1
181 domain2, size2, traceback2 = trace2
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100182 self.assertIs(traceback2, traceback1)
183
184 def test_get_traced_memory(self):
185 # Python allocates some internals objects, so the test must tolerate
186 # a small difference between the expected size and the real usage
187 max_error = 2048
188
189 # allocate one object
190 obj_size = 1024 * 1024
191 tracemalloc.clear_traces()
192 obj, obj_traceback = allocate_bytes(obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100193 size, peak_size = tracemalloc.get_traced_memory()
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100194 self.assertGreaterEqual(size, obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100195 self.assertGreaterEqual(peak_size, size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100196
197 self.assertLessEqual(size - obj_size, max_error)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100198 self.assertLessEqual(peak_size - size, max_error)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100199
200 # destroy the object
201 obj = None
Victor Stinner3c0481d2013-11-27 21:39:49 +0100202 size2, peak_size2 = tracemalloc.get_traced_memory()
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100203 self.assertLess(size2, size)
204 self.assertGreaterEqual(size - size2, obj_size - max_error)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100205 self.assertGreaterEqual(peak_size2, peak_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100206
207 # clear_traces() must reset traced memory counters
208 tracemalloc.clear_traces()
209 self.assertEqual(tracemalloc.get_traced_memory(), (0, 0))
210
211 # allocate another object
212 obj, obj_traceback = allocate_bytes(obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100213 size, peak_size = tracemalloc.get_traced_memory()
214 self.assertGreaterEqual(size, obj_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100215
Victor Stinnera89ecc72013-11-25 09:29:45 +0100216 # stop() also resets traced memory counters
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100217 tracemalloc.stop()
218 self.assertEqual(tracemalloc.get_traced_memory(), (0, 0))
219
220 def test_clear_traces(self):
221 obj, obj_traceback = allocate_bytes(123)
222 traceback = tracemalloc.get_object_traceback(obj)
223 self.assertIsNotNone(traceback)
224
225 tracemalloc.clear_traces()
226 traceback2 = tracemalloc.get_object_traceback(obj)
227 self.assertIsNone(traceback2)
228
229 def test_is_tracing(self):
230 tracemalloc.stop()
231 self.assertFalse(tracemalloc.is_tracing())
232
233 tracemalloc.start()
234 self.assertTrue(tracemalloc.is_tracing())
235
236 def test_snapshot(self):
237 obj, source = allocate_bytes(123)
238
239 # take a snapshot
240 snapshot = tracemalloc.take_snapshot()
241
242 # write on disk
243 snapshot.dump(support.TESTFN)
244 self.addCleanup(support.unlink, support.TESTFN)
245
246 # load from disk
247 snapshot2 = tracemalloc.Snapshot.load(support.TESTFN)
248 self.assertEqual(snapshot2.traces, snapshot.traces)
249
250 # tracemalloc must be tracing memory allocations to take a snapshot
251 tracemalloc.stop()
252 with self.assertRaises(RuntimeError) as cm:
253 tracemalloc.take_snapshot()
254 self.assertEqual(str(cm.exception),
255 "the tracemalloc module must be tracing memory "
256 "allocations to take a snapshot")
257
258 def test_snapshot_save_attr(self):
259 # take a snapshot with a new attribute
260 snapshot = tracemalloc.take_snapshot()
261 snapshot.test_attr = "new"
262 snapshot.dump(support.TESTFN)
263 self.addCleanup(support.unlink, support.TESTFN)
264
Martin Panter8f265652016-04-19 04:03:41 +0000265 # load() should recreate the attribute
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100266 snapshot2 = tracemalloc.Snapshot.load(support.TESTFN)
267 self.assertEqual(snapshot2.test_attr, "new")
268
269 def fork_child(self):
270 if not tracemalloc.is_tracing():
271 return 2
272
273 obj_size = 12345
274 obj, obj_traceback = allocate_bytes(obj_size)
275 traceback = tracemalloc.get_object_traceback(obj)
276 if traceback is None:
277 return 3
278
279 # everything is fine
280 return 0
281
282 @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()')
283 def test_fork(self):
284 # check that tracemalloc is still working after fork
285 pid = os.fork()
286 if not pid:
287 # child
288 exitcode = 1
289 try:
290 exitcode = self.fork_child()
291 finally:
292 os._exit(exitcode)
293 else:
294 pid2, status = os.waitpid(pid, 0)
295 self.assertTrue(os.WIFEXITED(status))
296 exitcode = os.WEXITSTATUS(status)
297 self.assertEqual(exitcode, 0)
298
299
300class TestSnapshot(unittest.TestCase):
301 maxDiff = 4000
302
303 def test_create_snapshot(self):
Victor Stinnere492ae52016-03-22 12:58:23 +0100304 raw_traces = [(0, 5, (('a.py', 2),))]
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100305
306 with contextlib.ExitStack() as stack:
307 stack.enter_context(patch.object(tracemalloc, 'is_tracing',
308 return_value=True))
309 stack.enter_context(patch.object(tracemalloc, 'get_traceback_limit',
310 return_value=5))
311 stack.enter_context(patch.object(tracemalloc, '_get_traces',
312 return_value=raw_traces))
313
314 snapshot = tracemalloc.take_snapshot()
315 self.assertEqual(snapshot.traceback_limit, 5)
316 self.assertEqual(len(snapshot.traces), 1)
317 trace = snapshot.traces[0]
318 self.assertEqual(trace.size, 5)
319 self.assertEqual(len(trace.traceback), 1)
320 self.assertEqual(trace.traceback[0].filename, 'a.py')
321 self.assertEqual(trace.traceback[0].lineno, 2)
322
323 def test_filter_traces(self):
324 snapshot, snapshot2 = create_snapshots()
325 filter1 = tracemalloc.Filter(False, "b.py")
326 filter2 = tracemalloc.Filter(True, "a.py", 2)
327 filter3 = tracemalloc.Filter(True, "a.py", 5)
328
329 original_traces = list(snapshot.traces._traces)
330
331 # exclude b.py
332 snapshot3 = snapshot.filter_traces((filter1,))
333 self.assertEqual(snapshot3.traces._traces, [
Victor Stinnere492ae52016-03-22 12:58:23 +0100334 (0, 10, (('a.py', 2), ('b.py', 4))),
335 (0, 10, (('a.py', 2), ('b.py', 4))),
336 (0, 10, (('a.py', 2), ('b.py', 4))),
337 (1, 2, (('a.py', 5), ('b.py', 4))),
338 (3, 7, (('<unknown>', 0),)),
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100339 ])
340
341 # filter_traces() must not touch the original snapshot
342 self.assertEqual(snapshot.traces._traces, original_traces)
343
344 # only include two lines of a.py
345 snapshot4 = snapshot3.filter_traces((filter2, filter3))
346 self.assertEqual(snapshot4.traces._traces, [
Victor Stinnere492ae52016-03-22 12:58:23 +0100347 (0, 10, (('a.py', 2), ('b.py', 4))),
348 (0, 10, (('a.py', 2), ('b.py', 4))),
349 (0, 10, (('a.py', 2), ('b.py', 4))),
350 (1, 2, (('a.py', 5), ('b.py', 4))),
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100351 ])
352
353 # No filter: just duplicate the snapshot
354 snapshot5 = snapshot.filter_traces(())
355 self.assertIsNot(snapshot5, snapshot)
356 self.assertIsNot(snapshot5.traces, snapshot.traces)
357 self.assertEqual(snapshot5.traces, snapshot.traces)
358
Victor Stinner8ce8ff92014-03-10 11:05:07 +0100359 self.assertRaises(TypeError, snapshot.filter_traces, filter1)
360
Victor Stinnere492ae52016-03-22 12:58:23 +0100361 def test_filter_traces_domain(self):
362 snapshot, snapshot2 = create_snapshots()
363 filter1 = tracemalloc.Filter(False, "a.py", domain=1)
364 filter2 = tracemalloc.Filter(True, "a.py", domain=1)
365
366 original_traces = list(snapshot.traces._traces)
367
368 # exclude a.py of domain 1
369 snapshot3 = snapshot.filter_traces((filter1,))
370 self.assertEqual(snapshot3.traces._traces, [
371 (0, 10, (('a.py', 2), ('b.py', 4))),
372 (0, 10, (('a.py', 2), ('b.py', 4))),
373 (0, 10, (('a.py', 2), ('b.py', 4))),
374 (2, 66, (('b.py', 1),)),
375 (3, 7, (('<unknown>', 0),)),
376 ])
377
378 # include domain 1
379 snapshot3 = snapshot.filter_traces((filter1,))
380 self.assertEqual(snapshot3.traces._traces, [
381 (0, 10, (('a.py', 2), ('b.py', 4))),
382 (0, 10, (('a.py', 2), ('b.py', 4))),
383 (0, 10, (('a.py', 2), ('b.py', 4))),
384 (2, 66, (('b.py', 1),)),
385 (3, 7, (('<unknown>', 0),)),
386 ])
387
388 def test_filter_traces_domain_filter(self):
389 snapshot, snapshot2 = create_snapshots()
390 filter1 = tracemalloc.DomainFilter(False, domain=3)
391 filter2 = tracemalloc.DomainFilter(True, domain=3)
392
393 # exclude domain 2
394 snapshot3 = snapshot.filter_traces((filter1,))
395 self.assertEqual(snapshot3.traces._traces, [
396 (0, 10, (('a.py', 2), ('b.py', 4))),
397 (0, 10, (('a.py', 2), ('b.py', 4))),
398 (0, 10, (('a.py', 2), ('b.py', 4))),
399 (1, 2, (('a.py', 5), ('b.py', 4))),
400 (2, 66, (('b.py', 1),)),
401 ])
402
403 # include domain 2
404 snapshot3 = snapshot.filter_traces((filter2,))
405 self.assertEqual(snapshot3.traces._traces, [
406 (3, 7, (('<unknown>', 0),)),
407 ])
408
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100409 def test_snapshot_group_by_line(self):
410 snapshot, snapshot2 = create_snapshots()
411 tb_0 = traceback_lineno('<unknown>', 0)
412 tb_a_2 = traceback_lineno('a.py', 2)
413 tb_a_5 = traceback_lineno('a.py', 5)
414 tb_b_1 = traceback_lineno('b.py', 1)
415 tb_c_578 = traceback_lineno('c.py', 578)
416
417 # stats per file and line
418 stats1 = snapshot.statistics('lineno')
419 self.assertEqual(stats1, [
420 tracemalloc.Statistic(tb_b_1, 66, 1),
421 tracemalloc.Statistic(tb_a_2, 30, 3),
422 tracemalloc.Statistic(tb_0, 7, 1),
423 tracemalloc.Statistic(tb_a_5, 2, 1),
424 ])
425
426 # stats per file and line (2)
427 stats2 = snapshot2.statistics('lineno')
428 self.assertEqual(stats2, [
429 tracemalloc.Statistic(tb_a_5, 5002, 2),
430 tracemalloc.Statistic(tb_c_578, 400, 1),
431 tracemalloc.Statistic(tb_a_2, 30, 3),
432 ])
433
434 # stats diff per file and line
435 statistics = snapshot2.compare_to(snapshot, 'lineno')
436 self.assertEqual(statistics, [
437 tracemalloc.StatisticDiff(tb_a_5, 5002, 5000, 2, 1),
438 tracemalloc.StatisticDiff(tb_c_578, 400, 400, 1, 1),
439 tracemalloc.StatisticDiff(tb_b_1, 0, -66, 0, -1),
440 tracemalloc.StatisticDiff(tb_0, 0, -7, 0, -1),
441 tracemalloc.StatisticDiff(tb_a_2, 30, 0, 3, 0),
442 ])
443
444 def test_snapshot_group_by_file(self):
445 snapshot, snapshot2 = create_snapshots()
446 tb_0 = traceback_filename('<unknown>')
447 tb_a = traceback_filename('a.py')
448 tb_b = traceback_filename('b.py')
449 tb_c = traceback_filename('c.py')
450
451 # stats per file
452 stats1 = snapshot.statistics('filename')
453 self.assertEqual(stats1, [
454 tracemalloc.Statistic(tb_b, 66, 1),
455 tracemalloc.Statistic(tb_a, 32, 4),
456 tracemalloc.Statistic(tb_0, 7, 1),
457 ])
458
459 # stats per file (2)
460 stats2 = snapshot2.statistics('filename')
461 self.assertEqual(stats2, [
462 tracemalloc.Statistic(tb_a, 5032, 5),
463 tracemalloc.Statistic(tb_c, 400, 1),
464 ])
465
466 # stats diff per file
467 diff = snapshot2.compare_to(snapshot, 'filename')
468 self.assertEqual(diff, [
469 tracemalloc.StatisticDiff(tb_a, 5032, 5000, 5, 1),
470 tracemalloc.StatisticDiff(tb_c, 400, 400, 1, 1),
471 tracemalloc.StatisticDiff(tb_b, 0, -66, 0, -1),
472 tracemalloc.StatisticDiff(tb_0, 0, -7, 0, -1),
473 ])
474
475 def test_snapshot_group_by_traceback(self):
476 snapshot, snapshot2 = create_snapshots()
477
478 # stats per file
479 tb1 = traceback(('a.py', 2), ('b.py', 4))
480 tb2 = traceback(('a.py', 5), ('b.py', 4))
481 tb3 = traceback(('b.py', 1))
482 tb4 = traceback(('<unknown>', 0))
483 stats1 = snapshot.statistics('traceback')
484 self.assertEqual(stats1, [
485 tracemalloc.Statistic(tb3, 66, 1),
486 tracemalloc.Statistic(tb1, 30, 3),
487 tracemalloc.Statistic(tb4, 7, 1),
488 tracemalloc.Statistic(tb2, 2, 1),
489 ])
490
491 # stats per file (2)
492 tb5 = traceback(('c.py', 578))
493 stats2 = snapshot2.statistics('traceback')
494 self.assertEqual(stats2, [
495 tracemalloc.Statistic(tb2, 5002, 2),
496 tracemalloc.Statistic(tb5, 400, 1),
497 tracemalloc.Statistic(tb1, 30, 3),
498 ])
499
500 # stats diff per file
501 diff = snapshot2.compare_to(snapshot, 'traceback')
502 self.assertEqual(diff, [
503 tracemalloc.StatisticDiff(tb2, 5002, 5000, 2, 1),
504 tracemalloc.StatisticDiff(tb5, 400, 400, 1, 1),
505 tracemalloc.StatisticDiff(tb3, 0, -66, 0, -1),
506 tracemalloc.StatisticDiff(tb4, 0, -7, 0, -1),
507 tracemalloc.StatisticDiff(tb1, 30, 0, 3, 0),
508 ])
509
510 self.assertRaises(ValueError,
511 snapshot.statistics, 'traceback', cumulative=True)
512
513 def test_snapshot_group_by_cumulative(self):
514 snapshot, snapshot2 = create_snapshots()
515 tb_0 = traceback_filename('<unknown>')
516 tb_a = traceback_filename('a.py')
517 tb_b = traceback_filename('b.py')
518 tb_a_2 = traceback_lineno('a.py', 2)
519 tb_a_5 = traceback_lineno('a.py', 5)
520 tb_b_1 = traceback_lineno('b.py', 1)
521 tb_b_4 = traceback_lineno('b.py', 4)
522
523 # per file
524 stats = snapshot.statistics('filename', True)
525 self.assertEqual(stats, [
526 tracemalloc.Statistic(tb_b, 98, 5),
527 tracemalloc.Statistic(tb_a, 32, 4),
528 tracemalloc.Statistic(tb_0, 7, 1),
529 ])
530
531 # per line
532 stats = snapshot.statistics('lineno', True)
533 self.assertEqual(stats, [
534 tracemalloc.Statistic(tb_b_1, 66, 1),
535 tracemalloc.Statistic(tb_b_4, 32, 4),
536 tracemalloc.Statistic(tb_a_2, 30, 3),
537 tracemalloc.Statistic(tb_0, 7, 1),
538 tracemalloc.Statistic(tb_a_5, 2, 1),
539 ])
540
541 def test_trace_format(self):
542 snapshot, snapshot2 = create_snapshots()
543 trace = snapshot.traces[0]
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100544 self.assertEqual(str(trace), 'b.py:4: 10 B')
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100545 traceback = trace.traceback
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100546 self.assertEqual(str(traceback), 'b.py:4')
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100547 frame = traceback[0]
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100548 self.assertEqual(str(frame), 'b.py:4')
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100549
550 def test_statistic_format(self):
551 snapshot, snapshot2 = create_snapshots()
552 stats = snapshot.statistics('lineno')
553 stat = stats[0]
554 self.assertEqual(str(stat),
555 'b.py:1: size=66 B, count=1, average=66 B')
556
557 def test_statistic_diff_format(self):
558 snapshot, snapshot2 = create_snapshots()
559 stats = snapshot2.compare_to(snapshot, 'lineno')
560 stat = stats[0]
561 self.assertEqual(str(stat),
562 'a.py:5: size=5002 B (+5000 B), count=2 (+1), average=2501 B')
563
Victor Stinner524be302014-02-01 04:07:02 +0100564 def test_slices(self):
565 snapshot, snapshot2 = create_snapshots()
566 self.assertEqual(snapshot.traces[:2],
567 (snapshot.traces[0], snapshot.traces[1]))
568
569 traceback = snapshot.traces[0].traceback
570 self.assertEqual(traceback[:2],
571 (traceback[0], traceback[1]))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100572
Victor Stinner23f628d2014-02-16 23:53:38 +0100573 def test_format_traceback(self):
574 snapshot, snapshot2 = create_snapshots()
575 def getline(filename, lineno):
576 return ' <%s, %s>' % (filename, lineno)
577 with unittest.mock.patch('tracemalloc.linecache.getline',
578 side_effect=getline):
579 tb = snapshot.traces[0].traceback
580 self.assertEqual(tb.format(),
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100581 [' File "b.py", line 4',
582 ' <b.py, 4>',
583 ' File "a.py", line 2',
584 ' <a.py, 2>'])
Victor Stinner23f628d2014-02-16 23:53:38 +0100585
586 self.assertEqual(tb.format(limit=1),
587 [' File "a.py", line 2',
588 ' <a.py, 2>'])
589
590 self.assertEqual(tb.format(limit=-1),
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100591 [' File "b.py", line 4',
592 ' <b.py, 4>'])
593
594 self.assertEqual(tb.format(most_recent_first=True),
595 [' File "a.py", line 2',
596 ' <a.py, 2>',
597 ' File "b.py", line 4',
598 ' <b.py, 4>'])
599
600 self.assertEqual(tb.format(limit=1, most_recent_first=True),
601 [' File "a.py", line 2',
602 ' <a.py, 2>'])
603
604 self.assertEqual(tb.format(limit=-1, most_recent_first=True),
605 [' File "b.py", line 4',
606 ' <b.py, 4>'])
Victor Stinner23f628d2014-02-16 23:53:38 +0100607
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100608
609class TestFilters(unittest.TestCase):
610 maxDiff = 2048
611
612 def test_filter_attributes(self):
613 # test default values
614 f = tracemalloc.Filter(True, "abc")
615 self.assertEqual(f.inclusive, True)
616 self.assertEqual(f.filename_pattern, "abc")
617 self.assertIsNone(f.lineno)
618 self.assertEqual(f.all_frames, False)
619
620 # test custom values
621 f = tracemalloc.Filter(False, "test.py", 123, True)
622 self.assertEqual(f.inclusive, False)
623 self.assertEqual(f.filename_pattern, "test.py")
624 self.assertEqual(f.lineno, 123)
625 self.assertEqual(f.all_frames, True)
626
627 # parameters passed by keyword
628 f = tracemalloc.Filter(inclusive=False, filename_pattern="test.py", lineno=123, all_frames=True)
629 self.assertEqual(f.inclusive, False)
630 self.assertEqual(f.filename_pattern, "test.py")
631 self.assertEqual(f.lineno, 123)
632 self.assertEqual(f.all_frames, True)
633
634 # read-only attribute
635 self.assertRaises(AttributeError, setattr, f, "filename_pattern", "abc")
636
637 def test_filter_match(self):
638 # filter without line number
639 f = tracemalloc.Filter(True, "abc")
640 self.assertTrue(f._match_frame("abc", 0))
641 self.assertTrue(f._match_frame("abc", 5))
642 self.assertTrue(f._match_frame("abc", 10))
643 self.assertFalse(f._match_frame("12356", 0))
644 self.assertFalse(f._match_frame("12356", 5))
645 self.assertFalse(f._match_frame("12356", 10))
646
647 f = tracemalloc.Filter(False, "abc")
648 self.assertFalse(f._match_frame("abc", 0))
649 self.assertFalse(f._match_frame("abc", 5))
650 self.assertFalse(f._match_frame("abc", 10))
651 self.assertTrue(f._match_frame("12356", 0))
652 self.assertTrue(f._match_frame("12356", 5))
653 self.assertTrue(f._match_frame("12356", 10))
654
655 # filter with line number > 0
656 f = tracemalloc.Filter(True, "abc", 5)
657 self.assertFalse(f._match_frame("abc", 0))
658 self.assertTrue(f._match_frame("abc", 5))
659 self.assertFalse(f._match_frame("abc", 10))
660 self.assertFalse(f._match_frame("12356", 0))
661 self.assertFalse(f._match_frame("12356", 5))
662 self.assertFalse(f._match_frame("12356", 10))
663
664 f = tracemalloc.Filter(False, "abc", 5)
665 self.assertTrue(f._match_frame("abc", 0))
666 self.assertFalse(f._match_frame("abc", 5))
667 self.assertTrue(f._match_frame("abc", 10))
668 self.assertTrue(f._match_frame("12356", 0))
669 self.assertTrue(f._match_frame("12356", 5))
670 self.assertTrue(f._match_frame("12356", 10))
671
672 # filter with line number 0
673 f = tracemalloc.Filter(True, "abc", 0)
674 self.assertTrue(f._match_frame("abc", 0))
675 self.assertFalse(f._match_frame("abc", 5))
676 self.assertFalse(f._match_frame("abc", 10))
677 self.assertFalse(f._match_frame("12356", 0))
678 self.assertFalse(f._match_frame("12356", 5))
679 self.assertFalse(f._match_frame("12356", 10))
680
681 f = tracemalloc.Filter(False, "abc", 0)
682 self.assertFalse(f._match_frame("abc", 0))
683 self.assertTrue(f._match_frame("abc", 5))
684 self.assertTrue(f._match_frame("abc", 10))
685 self.assertTrue(f._match_frame("12356", 0))
686 self.assertTrue(f._match_frame("12356", 5))
687 self.assertTrue(f._match_frame("12356", 10))
688
689 def test_filter_match_filename(self):
690 def fnmatch(inclusive, filename, pattern):
691 f = tracemalloc.Filter(inclusive, pattern)
692 return f._match_frame(filename, 0)
693
694 self.assertTrue(fnmatch(True, "abc", "abc"))
695 self.assertFalse(fnmatch(True, "12356", "abc"))
696 self.assertFalse(fnmatch(True, "<unknown>", "abc"))
697
698 self.assertFalse(fnmatch(False, "abc", "abc"))
699 self.assertTrue(fnmatch(False, "12356", "abc"))
700 self.assertTrue(fnmatch(False, "<unknown>", "abc"))
701
702 def test_filter_match_filename_joker(self):
703 def fnmatch(filename, pattern):
704 filter = tracemalloc.Filter(True, pattern)
705 return filter._match_frame(filename, 0)
706
707 # empty string
708 self.assertFalse(fnmatch('abc', ''))
709 self.assertFalse(fnmatch('', 'abc'))
710 self.assertTrue(fnmatch('', ''))
711 self.assertTrue(fnmatch('', '*'))
712
713 # no *
714 self.assertTrue(fnmatch('abc', 'abc'))
715 self.assertFalse(fnmatch('abc', 'abcd'))
716 self.assertFalse(fnmatch('abc', 'def'))
717
718 # a*
719 self.assertTrue(fnmatch('abc', 'a*'))
720 self.assertTrue(fnmatch('abc', 'abc*'))
721 self.assertFalse(fnmatch('abc', 'b*'))
722 self.assertFalse(fnmatch('abc', 'abcd*'))
723
724 # a*b
725 self.assertTrue(fnmatch('abc', 'a*c'))
726 self.assertTrue(fnmatch('abcdcx', 'a*cx'))
727 self.assertFalse(fnmatch('abb', 'a*c'))
728 self.assertFalse(fnmatch('abcdce', 'a*cx'))
729
730 # a*b*c
731 self.assertTrue(fnmatch('abcde', 'a*c*e'))
732 self.assertTrue(fnmatch('abcbdefeg', 'a*bd*eg'))
733 self.assertFalse(fnmatch('abcdd', 'a*c*e'))
734 self.assertFalse(fnmatch('abcbdefef', 'a*bd*eg'))
735
Brett Cannonf299abd2015-04-13 14:21:02 -0400736 # replace .pyc suffix with .py
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100737 self.assertTrue(fnmatch('a.pyc', 'a.py'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100738 self.assertTrue(fnmatch('a.py', 'a.pyc'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100739
740 if os.name == 'nt':
741 # case insensitive
742 self.assertTrue(fnmatch('aBC', 'ABc'))
743 self.assertTrue(fnmatch('aBcDe', 'Ab*dE'))
744
745 self.assertTrue(fnmatch('a.pyc', 'a.PY'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100746 self.assertTrue(fnmatch('a.py', 'a.PYC'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100747 else:
748 # case sensitive
749 self.assertFalse(fnmatch('aBC', 'ABc'))
750 self.assertFalse(fnmatch('aBcDe', 'Ab*dE'))
751
752 self.assertFalse(fnmatch('a.pyc', 'a.PY'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100753 self.assertFalse(fnmatch('a.py', 'a.PYC'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100754
755 if os.name == 'nt':
756 # normalize alternate separator "/" to the standard separator "\"
757 self.assertTrue(fnmatch(r'a/b', r'a\b'))
758 self.assertTrue(fnmatch(r'a\b', r'a/b'))
759 self.assertTrue(fnmatch(r'a/b\c', r'a\b/c'))
760 self.assertTrue(fnmatch(r'a/b/c', r'a\b\c'))
761 else:
762 # there is no alternate separator
763 self.assertFalse(fnmatch(r'a/b', r'a\b'))
764 self.assertFalse(fnmatch(r'a\b', r'a/b'))
765 self.assertFalse(fnmatch(r'a/b\c', r'a\b/c'))
766 self.assertFalse(fnmatch(r'a/b/c', r'a\b\c'))
767
Zachary Wared9b25bb2015-05-13 00:27:01 -0500768 # as of 3.5, .pyo is no longer munged to .py
769 self.assertFalse(fnmatch('a.pyo', 'a.py'))
770
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100771 def test_filter_match_trace(self):
772 t1 = (("a.py", 2), ("b.py", 3))
773 t2 = (("b.py", 4), ("b.py", 5))
774 t3 = (("c.py", 5), ('<unknown>', 0))
775 unknown = (('<unknown>', 0),)
776
777 f = tracemalloc.Filter(True, "b.py", all_frames=True)
778 self.assertTrue(f._match_traceback(t1))
779 self.assertTrue(f._match_traceback(t2))
780 self.assertFalse(f._match_traceback(t3))
781 self.assertFalse(f._match_traceback(unknown))
782
783 f = tracemalloc.Filter(True, "b.py", all_frames=False)
784 self.assertFalse(f._match_traceback(t1))
785 self.assertTrue(f._match_traceback(t2))
786 self.assertFalse(f._match_traceback(t3))
787 self.assertFalse(f._match_traceback(unknown))
788
789 f = tracemalloc.Filter(False, "b.py", all_frames=True)
790 self.assertFalse(f._match_traceback(t1))
791 self.assertFalse(f._match_traceback(t2))
792 self.assertTrue(f._match_traceback(t3))
793 self.assertTrue(f._match_traceback(unknown))
794
795 f = tracemalloc.Filter(False, "b.py", all_frames=False)
796 self.assertTrue(f._match_traceback(t1))
797 self.assertFalse(f._match_traceback(t2))
798 self.assertTrue(f._match_traceback(t3))
799 self.assertTrue(f._match_traceback(unknown))
800
801 f = tracemalloc.Filter(False, "<unknown>", all_frames=False)
802 self.assertTrue(f._match_traceback(t1))
803 self.assertTrue(f._match_traceback(t2))
804 self.assertTrue(f._match_traceback(t3))
805 self.assertFalse(f._match_traceback(unknown))
806
807 f = tracemalloc.Filter(True, "<unknown>", all_frames=True)
808 self.assertFalse(f._match_traceback(t1))
809 self.assertFalse(f._match_traceback(t2))
810 self.assertTrue(f._match_traceback(t3))
811 self.assertTrue(f._match_traceback(unknown))
812
813 f = tracemalloc.Filter(False, "<unknown>", all_frames=True)
814 self.assertTrue(f._match_traceback(t1))
815 self.assertTrue(f._match_traceback(t2))
816 self.assertFalse(f._match_traceback(t3))
817 self.assertFalse(f._match_traceback(unknown))
818
819
820class TestCommandLine(unittest.TestCase):
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800821 def test_env_var_disabled_by_default(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100822 # not tracing by default
823 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
824 ok, stdout, stderr = assert_python_ok('-c', code)
825 stdout = stdout.rstrip()
826 self.assertEqual(stdout, b'False')
827
Berker Peksagce643912015-05-06 06:33:17 +0300828 @unittest.skipIf(interpreter_requires_environment(),
Gregory P. Smithb9a3dd92015-02-04 00:59:40 -0800829 'Cannot run -E tests when PYTHON env vars are required.')
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800830 def test_env_var_ignored_with_E(self):
831 """PYTHON* environment variables must be ignored when -E is present."""
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100832 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
833 ok, stdout, stderr = assert_python_ok('-E', '-c', code, PYTHONTRACEMALLOC='1')
834 stdout = stdout.rstrip()
835 self.assertEqual(stdout, b'False')
836
Victor Stinner60b04c92018-07-25 19:23:53 +0200837 def test_env_var_disabled(self):
838 # tracing at startup
839 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
840 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='0')
841 stdout = stdout.rstrip()
842 self.assertEqual(stdout, b'False')
843
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800844 def test_env_var_enabled_at_startup(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100845 # tracing at startup
846 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
847 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='1')
848 stdout = stdout.rstrip()
849 self.assertEqual(stdout, b'True')
850
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800851 def test_env_limit(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100852 # start and set the number of frames
853 code = 'import tracemalloc; print(tracemalloc.get_traceback_limit())'
854 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='10')
855 stdout = stdout.rstrip()
856 self.assertEqual(stdout, b'10')
857
Victor Stinnera7368ac2017-11-15 18:11:45 -0800858 def check_env_var_invalid(self, nframe):
859 with support.SuppressCrashReport():
860 ok, stdout, stderr = assert_python_failure(
861 '-c', 'pass',
862 PYTHONTRACEMALLOC=str(nframe))
863
864 if b'ValueError: the number of frames must be in range' in stderr:
865 return
866 if b'PYTHONTRACEMALLOC: invalid number of frames' in stderr:
867 return
868 self.fail(f"unexpeced output: {stderr!a}")
869
870
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100871 def test_env_var_invalid(self):
Victor Stinner60b04c92018-07-25 19:23:53 +0200872 for nframe in INVALID_NFRAME:
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100873 with self.subTest(nframe=nframe):
Victor Stinnera7368ac2017-11-15 18:11:45 -0800874 self.check_env_var_invalid(nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100875
876 def test_sys_xoptions(self):
877 for xoptions, nframe in (
878 ('tracemalloc', 1),
879 ('tracemalloc=1', 1),
880 ('tracemalloc=15', 15),
881 ):
882 with self.subTest(xoptions=xoptions, nframe=nframe):
883 code = 'import tracemalloc; print(tracemalloc.get_traceback_limit())'
884 ok, stdout, stderr = assert_python_ok('-X', xoptions, '-c', code)
885 stdout = stdout.rstrip()
886 self.assertEqual(stdout, str(nframe).encode('ascii'))
887
Victor Stinnera7368ac2017-11-15 18:11:45 -0800888 def check_sys_xoptions_invalid(self, nframe):
889 args = ('-X', 'tracemalloc=%s' % nframe, '-c', 'pass')
890 with support.SuppressCrashReport():
891 ok, stdout, stderr = assert_python_failure(*args)
892
893 if b'ValueError: the number of frames must be in range' in stderr:
894 return
895 if b'-X tracemalloc=NFRAME: invalid number of frames' in stderr:
896 return
897 self.fail(f"unexpeced output: {stderr!a}")
898
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100899 def test_sys_xoptions_invalid(self):
Victor Stinner60b04c92018-07-25 19:23:53 +0200900 for nframe in INVALID_NFRAME:
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100901 with self.subTest(nframe=nframe):
Victor Stinnera7368ac2017-11-15 18:11:45 -0800902 self.check_sys_xoptions_invalid(nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100903
Serhiy Storchaka24c738a2017-03-19 20:20:10 +0200904 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Victor Stinner8dd49fe2014-06-02 21:36:59 +0200905 def test_pymem_alloc0(self):
906 # Issue #21639: Check that PyMem_Malloc(0) with tracemalloc enabled
907 # does not crash.
908 code = 'import _testcapi; _testcapi.test_pymem_alloc0(); 1'
909 assert_python_ok('-X', 'tracemalloc', '-c', code)
910
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100911
Victor Stinner10b73e12016-03-22 13:39:05 +0100912@unittest.skipIf(_testcapi is None, 'need _testcapi')
913class TestCAPI(unittest.TestCase):
914 maxDiff = 80 * 20
915
916 def setUp(self):
917 if tracemalloc.is_tracing():
918 self.skipTest("tracemalloc must be stopped before the test")
919
920 self.domain = 5
921 self.size = 123
922 self.obj = allocate_bytes(self.size)[0]
923
924 # for the type "object", id(obj) is the address of its memory block.
925 # This type is not tracked by the garbage collector
926 self.ptr = id(self.obj)
927
928 def tearDown(self):
929 tracemalloc.stop()
930
931 def get_traceback(self):
932 frames = _testcapi.tracemalloc_get_traceback(self.domain, self.ptr)
933 if frames is not None:
934 return tracemalloc.Traceback(frames)
935 else:
936 return None
937
938 def track(self, release_gil=False, nframe=1):
939 frames = get_frames(nframe, 2)
940 _testcapi.tracemalloc_track(self.domain, self.ptr, self.size,
941 release_gil)
942 return frames
943
944 def untrack(self):
945 _testcapi.tracemalloc_untrack(self.domain, self.ptr)
946
947 def get_traced_memory(self):
948 # Get the traced size in the domain
949 snapshot = tracemalloc.take_snapshot()
950 domain_filter = tracemalloc.DomainFilter(True, self.domain)
951 snapshot = snapshot.filter_traces([domain_filter])
952 return sum(trace.size for trace in snapshot.traces)
953
954 def check_track(self, release_gil):
955 nframe = 5
956 tracemalloc.start(nframe)
957
958 size = tracemalloc.get_traced_memory()[0]
959
960 frames = self.track(release_gil, nframe)
961 self.assertEqual(self.get_traceback(),
962 tracemalloc.Traceback(frames))
963
964 self.assertEqual(self.get_traced_memory(), self.size)
965
966 def test_track(self):
967 self.check_track(False)
968
969 def test_track_without_gil(self):
970 # check that calling _PyTraceMalloc_Track() without holding the GIL
971 # works too
972 self.check_track(True)
973
974 def test_track_already_tracked(self):
975 nframe = 5
976 tracemalloc.start(nframe)
977
978 # track a first time
979 self.track()
980
981 # calling _PyTraceMalloc_Track() must remove the old trace and add
982 # a new trace with the new traceback
983 frames = self.track(nframe=nframe)
984 self.assertEqual(self.get_traceback(),
985 tracemalloc.Traceback(frames))
986
987 def test_untrack(self):
988 tracemalloc.start()
989
990 self.track()
991 self.assertIsNotNone(self.get_traceback())
992 self.assertEqual(self.get_traced_memory(), self.size)
993
994 # untrack must remove the trace
995 self.untrack()
996 self.assertIsNone(self.get_traceback())
997 self.assertEqual(self.get_traced_memory(), 0)
998
999 # calling _PyTraceMalloc_Untrack() multiple times must not crash
1000 self.untrack()
1001 self.untrack()
1002
1003 def test_stop_track(self):
1004 tracemalloc.start()
1005 tracemalloc.stop()
1006
1007 with self.assertRaises(RuntimeError):
1008 self.track()
1009 self.assertIsNone(self.get_traceback())
1010
1011 def test_stop_untrack(self):
1012 tracemalloc.start()
1013 self.track()
1014
1015 tracemalloc.stop()
1016 with self.assertRaises(RuntimeError):
1017 self.untrack()
1018
1019
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001020def test_main():
1021 support.run_unittest(
1022 TestTracemallocEnabled,
1023 TestSnapshot,
1024 TestFilters,
1025 TestCommandLine,
Victor Stinner10b73e12016-03-22 13:39:05 +01001026 TestCAPI,
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001027 )
1028
1029if __name__ == "__main__":
1030 test_main()