blob: 635a9d39816058a79e4299f0acd976af20d71d00 [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
Julien Danjou8d59eb12019-10-15 14:00:16 +020039 return data, tracemalloc.Traceback(frames, min(len(frames), nframe))
Victor Stinnered3b0bc2013-11-23 12:27:24 +010040
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 = [
Julien Danjou8d59eb12019-10-15 14:00:16 +020048 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
49 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
50 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010051
Julien Danjou8d59eb12019-10-15 14:00:16 +020052 (1, 2, (('a.py', 5), ('b.py', 4)), 3),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010053
Julien Danjou8d59eb12019-10-15 14:00:16 +020054 (2, 66, (('b.py', 1),), 1),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010055
Julien Danjou8d59eb12019-10-15 14:00:16 +020056 (3, 7, (('<unknown>', 0),), 1),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010057 ]
58 snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit)
59
60 raw_traces2 = [
Julien Danjou8d59eb12019-10-15 14:00:16 +020061 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
62 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
63 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010064
Julien Danjou8d59eb12019-10-15 14:00:16 +020065 (2, 2, (('a.py', 5), ('b.py', 4)), 3),
66 (2, 5000, (('a.py', 5), ('b.py', 4)), 3),
Victor Stinnered3b0bc2013-11-23 12:27:24 +010067
Julien Danjou8d59eb12019-10-15 14:00:16 +020068 (4, 400, (('c.py', 578),), 1),
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
Victor Stinner9e00e802018-10-25 13:31:16 +0200114 def test_new_reference(self):
115 tracemalloc.clear_traces()
116 # gc.collect() indirectly calls PyList_ClearFreeList()
117 support.gc_collect()
118
119 # Create a list and "destroy it": put it in the PyListObject free list
120 obj = []
121 obj = None
122
123 # Create a list which should reuse the previously created empty list
124 obj = []
125
126 nframe = tracemalloc.get_traceback_limit()
127 frames = get_frames(nframe, -3)
Julien Danjou8d59eb12019-10-15 14:00:16 +0200128 obj_traceback = tracemalloc.Traceback(frames, min(len(frames), nframe))
Victor Stinner9e00e802018-10-25 13:31:16 +0200129
130 traceback = tracemalloc.get_object_traceback(obj)
131 self.assertIsNotNone(traceback)
132 self.assertEqual(traceback, obj_traceback)
133
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100134 def test_set_traceback_limit(self):
135 obj_size = 10
136
Victor Stinner3728d6c2013-11-23 12:37:20 +0100137 tracemalloc.stop()
138 self.assertRaises(ValueError, tracemalloc.start, -1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100139
Victor Stinner3728d6c2013-11-23 12:37:20 +0100140 tracemalloc.stop()
141 tracemalloc.start(10)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100142 obj2, obj2_traceback = allocate_bytes(obj_size)
143 traceback = tracemalloc.get_object_traceback(obj2)
144 self.assertEqual(len(traceback), 10)
145 self.assertEqual(traceback, obj2_traceback)
146
Victor Stinner3728d6c2013-11-23 12:37:20 +0100147 tracemalloc.stop()
148 tracemalloc.start(1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100149 obj, obj_traceback = allocate_bytes(obj_size)
150 traceback = tracemalloc.get_object_traceback(obj)
151 self.assertEqual(len(traceback), 1)
152 self.assertEqual(traceback, obj_traceback)
153
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100154 def find_trace(self, traces, traceback):
155 for trace in traces:
Victor Stinnere492ae52016-03-22 12:58:23 +0100156 if trace[2] == traceback._frames:
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100157 return trace
158
159 self.fail("trace not found")
160
161 def test_get_traces(self):
162 tracemalloc.clear_traces()
163 obj_size = 12345
164 obj, obj_traceback = allocate_bytes(obj_size)
165
166 traces = tracemalloc._get_traces()
167 trace = self.find_trace(traces, obj_traceback)
168
169 self.assertIsInstance(trace, tuple)
Julien Danjou8d59eb12019-10-15 14:00:16 +0200170 domain, size, traceback, length = trace
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100171 self.assertEqual(size, obj_size)
172 self.assertEqual(traceback, obj_traceback._frames)
173
174 tracemalloc.stop()
175 self.assertEqual(tracemalloc._get_traces(), [])
176
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100177 def test_get_traces_intern_traceback(self):
178 # dummy wrappers to get more useful and identical frames in the traceback
179 def allocate_bytes2(size):
180 return allocate_bytes(size)
181 def allocate_bytes3(size):
182 return allocate_bytes2(size)
183 def allocate_bytes4(size):
184 return allocate_bytes3(size)
185
186 # Ensure that two identical tracebacks are not duplicated
Victor Stinner3728d6c2013-11-23 12:37:20 +0100187 tracemalloc.stop()
188 tracemalloc.start(4)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100189 obj_size = 123
190 obj1, obj1_traceback = allocate_bytes4(obj_size)
191 obj2, obj2_traceback = allocate_bytes4(obj_size)
192
193 traces = tracemalloc._get_traces()
194
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100195 obj1_traceback._frames = tuple(reversed(obj1_traceback._frames))
196 obj2_traceback._frames = tuple(reversed(obj2_traceback._frames))
197
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100198 trace1 = self.find_trace(traces, obj1_traceback)
199 trace2 = self.find_trace(traces, obj2_traceback)
Julien Danjou8d59eb12019-10-15 14:00:16 +0200200 domain1, size1, traceback1, length1 = trace1
201 domain2, size2, traceback2, length2 = trace2
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100202 self.assertIs(traceback2, traceback1)
203
204 def test_get_traced_memory(self):
205 # Python allocates some internals objects, so the test must tolerate
206 # a small difference between the expected size and the real usage
207 max_error = 2048
208
209 # allocate one object
210 obj_size = 1024 * 1024
211 tracemalloc.clear_traces()
212 obj, obj_traceback = allocate_bytes(obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100213 size, peak_size = tracemalloc.get_traced_memory()
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100214 self.assertGreaterEqual(size, obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100215 self.assertGreaterEqual(peak_size, size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100216
217 self.assertLessEqual(size - obj_size, max_error)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100218 self.assertLessEqual(peak_size - size, max_error)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100219
220 # destroy the object
221 obj = None
Victor Stinner3c0481d2013-11-27 21:39:49 +0100222 size2, peak_size2 = tracemalloc.get_traced_memory()
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100223 self.assertLess(size2, size)
224 self.assertGreaterEqual(size - size2, obj_size - max_error)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100225 self.assertGreaterEqual(peak_size2, peak_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100226
227 # clear_traces() must reset traced memory counters
228 tracemalloc.clear_traces()
229 self.assertEqual(tracemalloc.get_traced_memory(), (0, 0))
230
231 # allocate another object
232 obj, obj_traceback = allocate_bytes(obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100233 size, peak_size = tracemalloc.get_traced_memory()
234 self.assertGreaterEqual(size, obj_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100235
Victor Stinnera89ecc72013-11-25 09:29:45 +0100236 # stop() also resets traced memory counters
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100237 tracemalloc.stop()
238 self.assertEqual(tracemalloc.get_traced_memory(), (0, 0))
239
240 def test_clear_traces(self):
241 obj, obj_traceback = allocate_bytes(123)
242 traceback = tracemalloc.get_object_traceback(obj)
243 self.assertIsNotNone(traceback)
244
245 tracemalloc.clear_traces()
246 traceback2 = tracemalloc.get_object_traceback(obj)
247 self.assertIsNone(traceback2)
248
249 def test_is_tracing(self):
250 tracemalloc.stop()
251 self.assertFalse(tracemalloc.is_tracing())
252
253 tracemalloc.start()
254 self.assertTrue(tracemalloc.is_tracing())
255
256 def test_snapshot(self):
257 obj, source = allocate_bytes(123)
258
259 # take a snapshot
260 snapshot = tracemalloc.take_snapshot()
261
Julien Danjou8d59eb12019-10-15 14:00:16 +0200262 # This can vary
263 self.assertGreater(snapshot.traces[1].traceback.total_nframe, 10)
264
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100265 # write on disk
266 snapshot.dump(support.TESTFN)
267 self.addCleanup(support.unlink, support.TESTFN)
268
269 # load from disk
270 snapshot2 = tracemalloc.Snapshot.load(support.TESTFN)
271 self.assertEqual(snapshot2.traces, snapshot.traces)
272
273 # tracemalloc must be tracing memory allocations to take a snapshot
274 tracemalloc.stop()
275 with self.assertRaises(RuntimeError) as cm:
276 tracemalloc.take_snapshot()
277 self.assertEqual(str(cm.exception),
278 "the tracemalloc module must be tracing memory "
279 "allocations to take a snapshot")
280
281 def test_snapshot_save_attr(self):
282 # take a snapshot with a new attribute
283 snapshot = tracemalloc.take_snapshot()
284 snapshot.test_attr = "new"
285 snapshot.dump(support.TESTFN)
286 self.addCleanup(support.unlink, support.TESTFN)
287
Martin Panter8f265652016-04-19 04:03:41 +0000288 # load() should recreate the attribute
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100289 snapshot2 = tracemalloc.Snapshot.load(support.TESTFN)
290 self.assertEqual(snapshot2.test_attr, "new")
291
292 def fork_child(self):
293 if not tracemalloc.is_tracing():
294 return 2
295
296 obj_size = 12345
297 obj, obj_traceback = allocate_bytes(obj_size)
298 traceback = tracemalloc.get_object_traceback(obj)
299 if traceback is None:
300 return 3
301
302 # everything is fine
303 return 0
304
305 @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()')
306 def test_fork(self):
307 # check that tracemalloc is still working after fork
308 pid = os.fork()
309 if not pid:
310 # child
311 exitcode = 1
312 try:
313 exitcode = self.fork_child()
314 finally:
315 os._exit(exitcode)
316 else:
Victor Stinner278c1e12020-03-31 20:08:12 +0200317 support.wait_process(pid, exitcode=0)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100318
319
320class TestSnapshot(unittest.TestCase):
321 maxDiff = 4000
322
323 def test_create_snapshot(self):
Julien Danjou8d59eb12019-10-15 14:00:16 +0200324 raw_traces = [(0, 5, (('a.py', 2),), 10)]
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100325
326 with contextlib.ExitStack() as stack:
327 stack.enter_context(patch.object(tracemalloc, 'is_tracing',
328 return_value=True))
329 stack.enter_context(patch.object(tracemalloc, 'get_traceback_limit',
330 return_value=5))
331 stack.enter_context(patch.object(tracemalloc, '_get_traces',
332 return_value=raw_traces))
333
334 snapshot = tracemalloc.take_snapshot()
335 self.assertEqual(snapshot.traceback_limit, 5)
336 self.assertEqual(len(snapshot.traces), 1)
337 trace = snapshot.traces[0]
338 self.assertEqual(trace.size, 5)
Julien Danjou8d59eb12019-10-15 14:00:16 +0200339 self.assertEqual(trace.traceback.total_nframe, 10)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100340 self.assertEqual(len(trace.traceback), 1)
341 self.assertEqual(trace.traceback[0].filename, 'a.py')
342 self.assertEqual(trace.traceback[0].lineno, 2)
343
344 def test_filter_traces(self):
345 snapshot, snapshot2 = create_snapshots()
346 filter1 = tracemalloc.Filter(False, "b.py")
347 filter2 = tracemalloc.Filter(True, "a.py", 2)
348 filter3 = tracemalloc.Filter(True, "a.py", 5)
349
350 original_traces = list(snapshot.traces._traces)
351
352 # exclude b.py
353 snapshot3 = snapshot.filter_traces((filter1,))
354 self.assertEqual(snapshot3.traces._traces, [
Julien Danjou8d59eb12019-10-15 14:00:16 +0200355 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
356 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
357 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
358 (1, 2, (('a.py', 5), ('b.py', 4)), 3),
359 (3, 7, (('<unknown>', 0),), 1),
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100360 ])
361
362 # filter_traces() must not touch the original snapshot
363 self.assertEqual(snapshot.traces._traces, original_traces)
364
365 # only include two lines of a.py
366 snapshot4 = snapshot3.filter_traces((filter2, filter3))
367 self.assertEqual(snapshot4.traces._traces, [
Julien Danjou8d59eb12019-10-15 14:00:16 +0200368 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
369 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
370 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
371 (1, 2, (('a.py', 5), ('b.py', 4)), 3),
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100372 ])
373
374 # No filter: just duplicate the snapshot
375 snapshot5 = snapshot.filter_traces(())
376 self.assertIsNot(snapshot5, snapshot)
377 self.assertIsNot(snapshot5.traces, snapshot.traces)
378 self.assertEqual(snapshot5.traces, snapshot.traces)
379
Victor Stinner8ce8ff92014-03-10 11:05:07 +0100380 self.assertRaises(TypeError, snapshot.filter_traces, filter1)
381
Victor Stinnere492ae52016-03-22 12:58:23 +0100382 def test_filter_traces_domain(self):
383 snapshot, snapshot2 = create_snapshots()
384 filter1 = tracemalloc.Filter(False, "a.py", domain=1)
385 filter2 = tracemalloc.Filter(True, "a.py", domain=1)
386
387 original_traces = list(snapshot.traces._traces)
388
389 # exclude a.py of domain 1
390 snapshot3 = snapshot.filter_traces((filter1,))
391 self.assertEqual(snapshot3.traces._traces, [
Julien Danjou8d59eb12019-10-15 14:00:16 +0200392 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
393 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
394 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
395 (2, 66, (('b.py', 1),), 1),
396 (3, 7, (('<unknown>', 0),), 1),
Victor Stinnere492ae52016-03-22 12:58:23 +0100397 ])
398
399 # include domain 1
400 snapshot3 = snapshot.filter_traces((filter1,))
401 self.assertEqual(snapshot3.traces._traces, [
Julien Danjou8d59eb12019-10-15 14:00:16 +0200402 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
403 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
404 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
405 (2, 66, (('b.py', 1),), 1),
406 (3, 7, (('<unknown>', 0),), 1),
Victor Stinnere492ae52016-03-22 12:58:23 +0100407 ])
408
409 def test_filter_traces_domain_filter(self):
410 snapshot, snapshot2 = create_snapshots()
411 filter1 = tracemalloc.DomainFilter(False, domain=3)
412 filter2 = tracemalloc.DomainFilter(True, domain=3)
413
414 # exclude domain 2
415 snapshot3 = snapshot.filter_traces((filter1,))
416 self.assertEqual(snapshot3.traces._traces, [
Julien Danjou8d59eb12019-10-15 14:00:16 +0200417 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
418 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
419 (0, 10, (('a.py', 2), ('b.py', 4)), 3),
420 (1, 2, (('a.py', 5), ('b.py', 4)), 3),
421 (2, 66, (('b.py', 1),), 1),
Victor Stinnere492ae52016-03-22 12:58:23 +0100422 ])
423
424 # include domain 2
425 snapshot3 = snapshot.filter_traces((filter2,))
426 self.assertEqual(snapshot3.traces._traces, [
Julien Danjou8d59eb12019-10-15 14:00:16 +0200427 (3, 7, (('<unknown>', 0),), 1),
Victor Stinnere492ae52016-03-22 12:58:23 +0100428 ])
429
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100430 def test_snapshot_group_by_line(self):
431 snapshot, snapshot2 = create_snapshots()
432 tb_0 = traceback_lineno('<unknown>', 0)
433 tb_a_2 = traceback_lineno('a.py', 2)
434 tb_a_5 = traceback_lineno('a.py', 5)
435 tb_b_1 = traceback_lineno('b.py', 1)
436 tb_c_578 = traceback_lineno('c.py', 578)
437
438 # stats per file and line
439 stats1 = snapshot.statistics('lineno')
440 self.assertEqual(stats1, [
441 tracemalloc.Statistic(tb_b_1, 66, 1),
442 tracemalloc.Statistic(tb_a_2, 30, 3),
443 tracemalloc.Statistic(tb_0, 7, 1),
444 tracemalloc.Statistic(tb_a_5, 2, 1),
445 ])
446
447 # stats per file and line (2)
448 stats2 = snapshot2.statistics('lineno')
449 self.assertEqual(stats2, [
450 tracemalloc.Statistic(tb_a_5, 5002, 2),
451 tracemalloc.Statistic(tb_c_578, 400, 1),
452 tracemalloc.Statistic(tb_a_2, 30, 3),
453 ])
454
455 # stats diff per file and line
456 statistics = snapshot2.compare_to(snapshot, 'lineno')
457 self.assertEqual(statistics, [
458 tracemalloc.StatisticDiff(tb_a_5, 5002, 5000, 2, 1),
459 tracemalloc.StatisticDiff(tb_c_578, 400, 400, 1, 1),
460 tracemalloc.StatisticDiff(tb_b_1, 0, -66, 0, -1),
461 tracemalloc.StatisticDiff(tb_0, 0, -7, 0, -1),
462 tracemalloc.StatisticDiff(tb_a_2, 30, 0, 3, 0),
463 ])
464
465 def test_snapshot_group_by_file(self):
466 snapshot, snapshot2 = create_snapshots()
467 tb_0 = traceback_filename('<unknown>')
468 tb_a = traceback_filename('a.py')
469 tb_b = traceback_filename('b.py')
470 tb_c = traceback_filename('c.py')
471
472 # stats per file
473 stats1 = snapshot.statistics('filename')
474 self.assertEqual(stats1, [
475 tracemalloc.Statistic(tb_b, 66, 1),
476 tracemalloc.Statistic(tb_a, 32, 4),
477 tracemalloc.Statistic(tb_0, 7, 1),
478 ])
479
480 # stats per file (2)
481 stats2 = snapshot2.statistics('filename')
482 self.assertEqual(stats2, [
483 tracemalloc.Statistic(tb_a, 5032, 5),
484 tracemalloc.Statistic(tb_c, 400, 1),
485 ])
486
487 # stats diff per file
488 diff = snapshot2.compare_to(snapshot, 'filename')
489 self.assertEqual(diff, [
490 tracemalloc.StatisticDiff(tb_a, 5032, 5000, 5, 1),
491 tracemalloc.StatisticDiff(tb_c, 400, 400, 1, 1),
492 tracemalloc.StatisticDiff(tb_b, 0, -66, 0, -1),
493 tracemalloc.StatisticDiff(tb_0, 0, -7, 0, -1),
494 ])
495
496 def test_snapshot_group_by_traceback(self):
497 snapshot, snapshot2 = create_snapshots()
498
499 # stats per file
500 tb1 = traceback(('a.py', 2), ('b.py', 4))
501 tb2 = traceback(('a.py', 5), ('b.py', 4))
502 tb3 = traceback(('b.py', 1))
503 tb4 = traceback(('<unknown>', 0))
504 stats1 = snapshot.statistics('traceback')
505 self.assertEqual(stats1, [
506 tracemalloc.Statistic(tb3, 66, 1),
507 tracemalloc.Statistic(tb1, 30, 3),
508 tracemalloc.Statistic(tb4, 7, 1),
509 tracemalloc.Statistic(tb2, 2, 1),
510 ])
511
512 # stats per file (2)
513 tb5 = traceback(('c.py', 578))
514 stats2 = snapshot2.statistics('traceback')
515 self.assertEqual(stats2, [
516 tracemalloc.Statistic(tb2, 5002, 2),
517 tracemalloc.Statistic(tb5, 400, 1),
518 tracemalloc.Statistic(tb1, 30, 3),
519 ])
520
521 # stats diff per file
522 diff = snapshot2.compare_to(snapshot, 'traceback')
523 self.assertEqual(diff, [
524 tracemalloc.StatisticDiff(tb2, 5002, 5000, 2, 1),
525 tracemalloc.StatisticDiff(tb5, 400, 400, 1, 1),
526 tracemalloc.StatisticDiff(tb3, 0, -66, 0, -1),
527 tracemalloc.StatisticDiff(tb4, 0, -7, 0, -1),
528 tracemalloc.StatisticDiff(tb1, 30, 0, 3, 0),
529 ])
530
531 self.assertRaises(ValueError,
532 snapshot.statistics, 'traceback', cumulative=True)
533
534 def test_snapshot_group_by_cumulative(self):
535 snapshot, snapshot2 = create_snapshots()
536 tb_0 = traceback_filename('<unknown>')
537 tb_a = traceback_filename('a.py')
538 tb_b = traceback_filename('b.py')
539 tb_a_2 = traceback_lineno('a.py', 2)
540 tb_a_5 = traceback_lineno('a.py', 5)
541 tb_b_1 = traceback_lineno('b.py', 1)
542 tb_b_4 = traceback_lineno('b.py', 4)
543
544 # per file
545 stats = snapshot.statistics('filename', True)
546 self.assertEqual(stats, [
547 tracemalloc.Statistic(tb_b, 98, 5),
548 tracemalloc.Statistic(tb_a, 32, 4),
549 tracemalloc.Statistic(tb_0, 7, 1),
550 ])
551
552 # per line
553 stats = snapshot.statistics('lineno', True)
554 self.assertEqual(stats, [
555 tracemalloc.Statistic(tb_b_1, 66, 1),
556 tracemalloc.Statistic(tb_b_4, 32, 4),
557 tracemalloc.Statistic(tb_a_2, 30, 3),
558 tracemalloc.Statistic(tb_0, 7, 1),
559 tracemalloc.Statistic(tb_a_5, 2, 1),
560 ])
561
562 def test_trace_format(self):
563 snapshot, snapshot2 = create_snapshots()
564 trace = snapshot.traces[0]
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100565 self.assertEqual(str(trace), 'b.py:4: 10 B')
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100566 traceback = trace.traceback
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100567 self.assertEqual(str(traceback), 'b.py:4')
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100568 frame = traceback[0]
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100569 self.assertEqual(str(frame), 'b.py:4')
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100570
571 def test_statistic_format(self):
572 snapshot, snapshot2 = create_snapshots()
573 stats = snapshot.statistics('lineno')
574 stat = stats[0]
575 self.assertEqual(str(stat),
576 'b.py:1: size=66 B, count=1, average=66 B')
577
578 def test_statistic_diff_format(self):
579 snapshot, snapshot2 = create_snapshots()
580 stats = snapshot2.compare_to(snapshot, 'lineno')
581 stat = stats[0]
582 self.assertEqual(str(stat),
583 'a.py:5: size=5002 B (+5000 B), count=2 (+1), average=2501 B')
584
Victor Stinner524be302014-02-01 04:07:02 +0100585 def test_slices(self):
586 snapshot, snapshot2 = create_snapshots()
587 self.assertEqual(snapshot.traces[:2],
588 (snapshot.traces[0], snapshot.traces[1]))
589
590 traceback = snapshot.traces[0].traceback
591 self.assertEqual(traceback[:2],
592 (traceback[0], traceback[1]))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100593
Victor Stinner23f628d2014-02-16 23:53:38 +0100594 def test_format_traceback(self):
595 snapshot, snapshot2 = create_snapshots()
596 def getline(filename, lineno):
597 return ' <%s, %s>' % (filename, lineno)
598 with unittest.mock.patch('tracemalloc.linecache.getline',
599 side_effect=getline):
600 tb = snapshot.traces[0].traceback
601 self.assertEqual(tb.format(),
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100602 [' File "b.py", line 4',
603 ' <b.py, 4>',
604 ' File "a.py", line 2',
605 ' <a.py, 2>'])
Victor Stinner23f628d2014-02-16 23:53:38 +0100606
607 self.assertEqual(tb.format(limit=1),
608 [' File "a.py", line 2',
609 ' <a.py, 2>'])
610
611 self.assertEqual(tb.format(limit=-1),
Jesse-Bakker706e10b2017-11-30 00:05:07 +0100612 [' File "b.py", line 4',
613 ' <b.py, 4>'])
614
615 self.assertEqual(tb.format(most_recent_first=True),
616 [' File "a.py", line 2',
617 ' <a.py, 2>',
618 ' File "b.py", line 4',
619 ' <b.py, 4>'])
620
621 self.assertEqual(tb.format(limit=1, most_recent_first=True),
622 [' File "a.py", line 2',
623 ' <a.py, 2>'])
624
625 self.assertEqual(tb.format(limit=-1, most_recent_first=True),
626 [' File "b.py", line 4',
627 ' <b.py, 4>'])
Victor Stinner23f628d2014-02-16 23:53:38 +0100628
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100629
630class TestFilters(unittest.TestCase):
631 maxDiff = 2048
632
633 def test_filter_attributes(self):
634 # test default values
635 f = tracemalloc.Filter(True, "abc")
636 self.assertEqual(f.inclusive, True)
637 self.assertEqual(f.filename_pattern, "abc")
638 self.assertIsNone(f.lineno)
639 self.assertEqual(f.all_frames, False)
640
641 # test custom values
642 f = tracemalloc.Filter(False, "test.py", 123, True)
643 self.assertEqual(f.inclusive, False)
644 self.assertEqual(f.filename_pattern, "test.py")
645 self.assertEqual(f.lineno, 123)
646 self.assertEqual(f.all_frames, True)
647
648 # parameters passed by keyword
649 f = tracemalloc.Filter(inclusive=False, filename_pattern="test.py", lineno=123, all_frames=True)
650 self.assertEqual(f.inclusive, False)
651 self.assertEqual(f.filename_pattern, "test.py")
652 self.assertEqual(f.lineno, 123)
653 self.assertEqual(f.all_frames, True)
654
655 # read-only attribute
656 self.assertRaises(AttributeError, setattr, f, "filename_pattern", "abc")
657
658 def test_filter_match(self):
659 # filter without line number
660 f = tracemalloc.Filter(True, "abc")
661 self.assertTrue(f._match_frame("abc", 0))
662 self.assertTrue(f._match_frame("abc", 5))
663 self.assertTrue(f._match_frame("abc", 10))
664 self.assertFalse(f._match_frame("12356", 0))
665 self.assertFalse(f._match_frame("12356", 5))
666 self.assertFalse(f._match_frame("12356", 10))
667
668 f = tracemalloc.Filter(False, "abc")
669 self.assertFalse(f._match_frame("abc", 0))
670 self.assertFalse(f._match_frame("abc", 5))
671 self.assertFalse(f._match_frame("abc", 10))
672 self.assertTrue(f._match_frame("12356", 0))
673 self.assertTrue(f._match_frame("12356", 5))
674 self.assertTrue(f._match_frame("12356", 10))
675
676 # filter with line number > 0
677 f = tracemalloc.Filter(True, "abc", 5)
678 self.assertFalse(f._match_frame("abc", 0))
679 self.assertTrue(f._match_frame("abc", 5))
680 self.assertFalse(f._match_frame("abc", 10))
681 self.assertFalse(f._match_frame("12356", 0))
682 self.assertFalse(f._match_frame("12356", 5))
683 self.assertFalse(f._match_frame("12356", 10))
684
685 f = tracemalloc.Filter(False, "abc", 5)
686 self.assertTrue(f._match_frame("abc", 0))
687 self.assertFalse(f._match_frame("abc", 5))
688 self.assertTrue(f._match_frame("abc", 10))
689 self.assertTrue(f._match_frame("12356", 0))
690 self.assertTrue(f._match_frame("12356", 5))
691 self.assertTrue(f._match_frame("12356", 10))
692
693 # filter with line number 0
694 f = tracemalloc.Filter(True, "abc", 0)
695 self.assertTrue(f._match_frame("abc", 0))
696 self.assertFalse(f._match_frame("abc", 5))
697 self.assertFalse(f._match_frame("abc", 10))
698 self.assertFalse(f._match_frame("12356", 0))
699 self.assertFalse(f._match_frame("12356", 5))
700 self.assertFalse(f._match_frame("12356", 10))
701
702 f = tracemalloc.Filter(False, "abc", 0)
703 self.assertFalse(f._match_frame("abc", 0))
704 self.assertTrue(f._match_frame("abc", 5))
705 self.assertTrue(f._match_frame("abc", 10))
706 self.assertTrue(f._match_frame("12356", 0))
707 self.assertTrue(f._match_frame("12356", 5))
708 self.assertTrue(f._match_frame("12356", 10))
709
710 def test_filter_match_filename(self):
711 def fnmatch(inclusive, filename, pattern):
712 f = tracemalloc.Filter(inclusive, pattern)
713 return f._match_frame(filename, 0)
714
715 self.assertTrue(fnmatch(True, "abc", "abc"))
716 self.assertFalse(fnmatch(True, "12356", "abc"))
717 self.assertFalse(fnmatch(True, "<unknown>", "abc"))
718
719 self.assertFalse(fnmatch(False, "abc", "abc"))
720 self.assertTrue(fnmatch(False, "12356", "abc"))
721 self.assertTrue(fnmatch(False, "<unknown>", "abc"))
722
723 def test_filter_match_filename_joker(self):
724 def fnmatch(filename, pattern):
725 filter = tracemalloc.Filter(True, pattern)
726 return filter._match_frame(filename, 0)
727
728 # empty string
729 self.assertFalse(fnmatch('abc', ''))
730 self.assertFalse(fnmatch('', 'abc'))
731 self.assertTrue(fnmatch('', ''))
732 self.assertTrue(fnmatch('', '*'))
733
734 # no *
735 self.assertTrue(fnmatch('abc', 'abc'))
736 self.assertFalse(fnmatch('abc', 'abcd'))
737 self.assertFalse(fnmatch('abc', 'def'))
738
739 # a*
740 self.assertTrue(fnmatch('abc', 'a*'))
741 self.assertTrue(fnmatch('abc', 'abc*'))
742 self.assertFalse(fnmatch('abc', 'b*'))
743 self.assertFalse(fnmatch('abc', 'abcd*'))
744
745 # a*b
746 self.assertTrue(fnmatch('abc', 'a*c'))
747 self.assertTrue(fnmatch('abcdcx', 'a*cx'))
748 self.assertFalse(fnmatch('abb', 'a*c'))
749 self.assertFalse(fnmatch('abcdce', 'a*cx'))
750
751 # a*b*c
752 self.assertTrue(fnmatch('abcde', 'a*c*e'))
753 self.assertTrue(fnmatch('abcbdefeg', 'a*bd*eg'))
754 self.assertFalse(fnmatch('abcdd', 'a*c*e'))
755 self.assertFalse(fnmatch('abcbdefef', 'a*bd*eg'))
756
Brett Cannonf299abd2015-04-13 14:21:02 -0400757 # replace .pyc suffix with .py
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100758 self.assertTrue(fnmatch('a.pyc', 'a.py'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100759 self.assertTrue(fnmatch('a.py', 'a.pyc'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100760
761 if os.name == 'nt':
762 # case insensitive
763 self.assertTrue(fnmatch('aBC', 'ABc'))
764 self.assertTrue(fnmatch('aBcDe', 'Ab*dE'))
765
766 self.assertTrue(fnmatch('a.pyc', 'a.PY'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100767 self.assertTrue(fnmatch('a.py', 'a.PYC'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100768 else:
769 # case sensitive
770 self.assertFalse(fnmatch('aBC', 'ABc'))
771 self.assertFalse(fnmatch('aBcDe', 'Ab*dE'))
772
773 self.assertFalse(fnmatch('a.pyc', 'a.PY'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100774 self.assertFalse(fnmatch('a.py', 'a.PYC'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100775
776 if os.name == 'nt':
777 # normalize alternate separator "/" to the standard separator "\"
778 self.assertTrue(fnmatch(r'a/b', r'a\b'))
779 self.assertTrue(fnmatch(r'a\b', r'a/b'))
780 self.assertTrue(fnmatch(r'a/b\c', r'a\b/c'))
781 self.assertTrue(fnmatch(r'a/b/c', r'a\b\c'))
782 else:
783 # there is no alternate separator
784 self.assertFalse(fnmatch(r'a/b', r'a\b'))
785 self.assertFalse(fnmatch(r'a\b', r'a/b'))
786 self.assertFalse(fnmatch(r'a/b\c', r'a\b/c'))
787 self.assertFalse(fnmatch(r'a/b/c', r'a\b\c'))
788
Zachary Wared9b25bb2015-05-13 00:27:01 -0500789 # as of 3.5, .pyo is no longer munged to .py
790 self.assertFalse(fnmatch('a.pyo', 'a.py'))
791
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100792 def test_filter_match_trace(self):
793 t1 = (("a.py", 2), ("b.py", 3))
794 t2 = (("b.py", 4), ("b.py", 5))
795 t3 = (("c.py", 5), ('<unknown>', 0))
796 unknown = (('<unknown>', 0),)
797
798 f = tracemalloc.Filter(True, "b.py", all_frames=True)
799 self.assertTrue(f._match_traceback(t1))
800 self.assertTrue(f._match_traceback(t2))
801 self.assertFalse(f._match_traceback(t3))
802 self.assertFalse(f._match_traceback(unknown))
803
804 f = tracemalloc.Filter(True, "b.py", all_frames=False)
805 self.assertFalse(f._match_traceback(t1))
806 self.assertTrue(f._match_traceback(t2))
807 self.assertFalse(f._match_traceback(t3))
808 self.assertFalse(f._match_traceback(unknown))
809
810 f = tracemalloc.Filter(False, "b.py", all_frames=True)
811 self.assertFalse(f._match_traceback(t1))
812 self.assertFalse(f._match_traceback(t2))
813 self.assertTrue(f._match_traceback(t3))
814 self.assertTrue(f._match_traceback(unknown))
815
816 f = tracemalloc.Filter(False, "b.py", all_frames=False)
817 self.assertTrue(f._match_traceback(t1))
818 self.assertFalse(f._match_traceback(t2))
819 self.assertTrue(f._match_traceback(t3))
820 self.assertTrue(f._match_traceback(unknown))
821
822 f = tracemalloc.Filter(False, "<unknown>", all_frames=False)
823 self.assertTrue(f._match_traceback(t1))
824 self.assertTrue(f._match_traceback(t2))
825 self.assertTrue(f._match_traceback(t3))
826 self.assertFalse(f._match_traceback(unknown))
827
828 f = tracemalloc.Filter(True, "<unknown>", all_frames=True)
829 self.assertFalse(f._match_traceback(t1))
830 self.assertFalse(f._match_traceback(t2))
831 self.assertTrue(f._match_traceback(t3))
832 self.assertTrue(f._match_traceback(unknown))
833
834 f = tracemalloc.Filter(False, "<unknown>", all_frames=True)
835 self.assertTrue(f._match_traceback(t1))
836 self.assertTrue(f._match_traceback(t2))
837 self.assertFalse(f._match_traceback(t3))
838 self.assertFalse(f._match_traceback(unknown))
839
840
841class TestCommandLine(unittest.TestCase):
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800842 def test_env_var_disabled_by_default(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100843 # not tracing by default
844 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
845 ok, stdout, stderr = assert_python_ok('-c', code)
846 stdout = stdout.rstrip()
847 self.assertEqual(stdout, b'False')
848
Berker Peksagce643912015-05-06 06:33:17 +0300849 @unittest.skipIf(interpreter_requires_environment(),
Gregory P. Smithb9a3dd92015-02-04 00:59:40 -0800850 'Cannot run -E tests when PYTHON env vars are required.')
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800851 def test_env_var_ignored_with_E(self):
852 """PYTHON* environment variables must be ignored when -E is present."""
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100853 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
854 ok, stdout, stderr = assert_python_ok('-E', '-c', code, PYTHONTRACEMALLOC='1')
855 stdout = stdout.rstrip()
856 self.assertEqual(stdout, b'False')
857
Victor Stinner60b04c92018-07-25 19:23:53 +0200858 def test_env_var_disabled(self):
859 # tracing at startup
860 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
861 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='0')
862 stdout = stdout.rstrip()
863 self.assertEqual(stdout, b'False')
864
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800865 def test_env_var_enabled_at_startup(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100866 # tracing at startup
867 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
868 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='1')
869 stdout = stdout.rstrip()
870 self.assertEqual(stdout, b'True')
871
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800872 def test_env_limit(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100873 # start and set the number of frames
874 code = 'import tracemalloc; print(tracemalloc.get_traceback_limit())'
875 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='10')
876 stdout = stdout.rstrip()
877 self.assertEqual(stdout, b'10')
878
Victor Stinnera7368ac2017-11-15 18:11:45 -0800879 def check_env_var_invalid(self, nframe):
880 with support.SuppressCrashReport():
881 ok, stdout, stderr = assert_python_failure(
882 '-c', 'pass',
883 PYTHONTRACEMALLOC=str(nframe))
884
885 if b'ValueError: the number of frames must be in range' in stderr:
886 return
887 if b'PYTHONTRACEMALLOC: invalid number of frames' in stderr:
888 return
Min ho Kim39d87b52019-08-31 06:21:19 +1000889 self.fail(f"unexpected output: {stderr!a}")
Victor Stinnera7368ac2017-11-15 18:11:45 -0800890
891
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100892 def test_env_var_invalid(self):
Victor Stinner60b04c92018-07-25 19:23:53 +0200893 for nframe in INVALID_NFRAME:
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100894 with self.subTest(nframe=nframe):
Victor Stinnera7368ac2017-11-15 18:11:45 -0800895 self.check_env_var_invalid(nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100896
897 def test_sys_xoptions(self):
898 for xoptions, nframe in (
899 ('tracemalloc', 1),
900 ('tracemalloc=1', 1),
901 ('tracemalloc=15', 15),
902 ):
903 with self.subTest(xoptions=xoptions, nframe=nframe):
904 code = 'import tracemalloc; print(tracemalloc.get_traceback_limit())'
905 ok, stdout, stderr = assert_python_ok('-X', xoptions, '-c', code)
906 stdout = stdout.rstrip()
907 self.assertEqual(stdout, str(nframe).encode('ascii'))
908
Victor Stinnera7368ac2017-11-15 18:11:45 -0800909 def check_sys_xoptions_invalid(self, nframe):
910 args = ('-X', 'tracemalloc=%s' % nframe, '-c', 'pass')
911 with support.SuppressCrashReport():
912 ok, stdout, stderr = assert_python_failure(*args)
913
914 if b'ValueError: the number of frames must be in range' in stderr:
915 return
916 if b'-X tracemalloc=NFRAME: invalid number of frames' in stderr:
917 return
Min ho Kim39d87b52019-08-31 06:21:19 +1000918 self.fail(f"unexpected output: {stderr!a}")
Victor Stinnera7368ac2017-11-15 18:11:45 -0800919
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100920 def test_sys_xoptions_invalid(self):
Victor Stinner60b04c92018-07-25 19:23:53 +0200921 for nframe in INVALID_NFRAME:
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100922 with self.subTest(nframe=nframe):
Victor Stinnera7368ac2017-11-15 18:11:45 -0800923 self.check_sys_xoptions_invalid(nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100924
Serhiy Storchaka24c738a2017-03-19 20:20:10 +0200925 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Victor Stinner8dd49fe2014-06-02 21:36:59 +0200926 def test_pymem_alloc0(self):
927 # Issue #21639: Check that PyMem_Malloc(0) with tracemalloc enabled
928 # does not crash.
929 code = 'import _testcapi; _testcapi.test_pymem_alloc0(); 1'
930 assert_python_ok('-X', 'tracemalloc', '-c', code)
931
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100932
Victor Stinner10b73e12016-03-22 13:39:05 +0100933@unittest.skipIf(_testcapi is None, 'need _testcapi')
934class TestCAPI(unittest.TestCase):
935 maxDiff = 80 * 20
936
937 def setUp(self):
938 if tracemalloc.is_tracing():
939 self.skipTest("tracemalloc must be stopped before the test")
940
941 self.domain = 5
942 self.size = 123
943 self.obj = allocate_bytes(self.size)[0]
944
945 # for the type "object", id(obj) is the address of its memory block.
946 # This type is not tracked by the garbage collector
947 self.ptr = id(self.obj)
948
949 def tearDown(self):
950 tracemalloc.stop()
951
952 def get_traceback(self):
953 frames = _testcapi.tracemalloc_get_traceback(self.domain, self.ptr)
954 if frames is not None:
955 return tracemalloc.Traceback(frames)
956 else:
957 return None
958
959 def track(self, release_gil=False, nframe=1):
Serhiy Storchakada8d72c2018-09-17 15:17:29 +0300960 frames = get_frames(nframe, 1)
Victor Stinner10b73e12016-03-22 13:39:05 +0100961 _testcapi.tracemalloc_track(self.domain, self.ptr, self.size,
962 release_gil)
963 return frames
964
965 def untrack(self):
966 _testcapi.tracemalloc_untrack(self.domain, self.ptr)
967
968 def get_traced_memory(self):
969 # Get the traced size in the domain
970 snapshot = tracemalloc.take_snapshot()
971 domain_filter = tracemalloc.DomainFilter(True, self.domain)
972 snapshot = snapshot.filter_traces([domain_filter])
973 return sum(trace.size for trace in snapshot.traces)
974
975 def check_track(self, release_gil):
976 nframe = 5
977 tracemalloc.start(nframe)
978
979 size = tracemalloc.get_traced_memory()[0]
980
981 frames = self.track(release_gil, nframe)
982 self.assertEqual(self.get_traceback(),
983 tracemalloc.Traceback(frames))
984
985 self.assertEqual(self.get_traced_memory(), self.size)
986
987 def test_track(self):
988 self.check_track(False)
989
990 def test_track_without_gil(self):
991 # check that calling _PyTraceMalloc_Track() without holding the GIL
992 # works too
993 self.check_track(True)
994
995 def test_track_already_tracked(self):
996 nframe = 5
997 tracemalloc.start(nframe)
998
999 # track a first time
1000 self.track()
1001
1002 # calling _PyTraceMalloc_Track() must remove the old trace and add
1003 # a new trace with the new traceback
1004 frames = self.track(nframe=nframe)
1005 self.assertEqual(self.get_traceback(),
1006 tracemalloc.Traceback(frames))
1007
1008 def test_untrack(self):
1009 tracemalloc.start()
1010
1011 self.track()
1012 self.assertIsNotNone(self.get_traceback())
1013 self.assertEqual(self.get_traced_memory(), self.size)
1014
1015 # untrack must remove the trace
1016 self.untrack()
1017 self.assertIsNone(self.get_traceback())
1018 self.assertEqual(self.get_traced_memory(), 0)
1019
1020 # calling _PyTraceMalloc_Untrack() multiple times must not crash
1021 self.untrack()
1022 self.untrack()
1023
1024 def test_stop_track(self):
1025 tracemalloc.start()
1026 tracemalloc.stop()
1027
1028 with self.assertRaises(RuntimeError):
1029 self.track()
1030 self.assertIsNone(self.get_traceback())
1031
1032 def test_stop_untrack(self):
1033 tracemalloc.start()
1034 self.track()
1035
1036 tracemalloc.stop()
1037 with self.assertRaises(RuntimeError):
1038 self.untrack()
1039
1040
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001041def test_main():
1042 support.run_unittest(
1043 TestTracemallocEnabled,
1044 TestSnapshot,
1045 TestFilters,
1046 TestCommandLine,
Victor Stinner10b73e12016-03-22 13:39:05 +01001047 TestCAPI,
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001048 )
1049
1050if __name__ == "__main__":
1051 test_main()