blob: f65e36118c2202533311f82d1a1f03804d78f486 [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
Victor Stinnered3b0bc2013-11-23 12:27:24 +010010try:
11 import threading
12except ImportError:
13 threading = None
14
15EMPTY_STRING_SIZE = sys.getsizeof(b'')
16
17def get_frames(nframe, lineno_delta):
18 frames = []
19 frame = sys._getframe(1)
20 for index in range(nframe):
21 code = frame.f_code
22 lineno = frame.f_lineno + lineno_delta
23 frames.append((code.co_filename, lineno))
24 lineno_delta = 0
25 frame = frame.f_back
26 if frame is None:
27 break
28 return tuple(frames)
29
30def allocate_bytes(size):
31 nframe = tracemalloc.get_traceback_limit()
32 bytes_len = (size - EMPTY_STRING_SIZE)
33 frames = get_frames(nframe, 1)
34 data = b'x' * bytes_len
35 return data, tracemalloc.Traceback(frames)
36
37def create_snapshots():
38 traceback_limit = 2
39
40 raw_traces = [
41 (10, (('a.py', 2), ('b.py', 4))),
42 (10, (('a.py', 2), ('b.py', 4))),
43 (10, (('a.py', 2), ('b.py', 4))),
44
45 (2, (('a.py', 5), ('b.py', 4))),
46
47 (66, (('b.py', 1),)),
48
49 (7, (('<unknown>', 0),)),
50 ]
51 snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit)
52
53 raw_traces2 = [
54 (10, (('a.py', 2), ('b.py', 4))),
55 (10, (('a.py', 2), ('b.py', 4))),
56 (10, (('a.py', 2), ('b.py', 4))),
57
58 (2, (('a.py', 5), ('b.py', 4))),
59 (5000, (('a.py', 5), ('b.py', 4))),
60
61 (400, (('c.py', 578),)),
62 ]
63 snapshot2 = tracemalloc.Snapshot(raw_traces2, traceback_limit)
64
65 return (snapshot, snapshot2)
66
67def frame(filename, lineno):
68 return tracemalloc._Frame((filename, lineno))
69
70def traceback(*frames):
71 return tracemalloc.Traceback(frames)
72
73def traceback_lineno(filename, lineno):
74 return traceback((filename, lineno))
75
76def traceback_filename(filename):
77 return traceback_lineno(filename, 0)
78
79
80class TestTracemallocEnabled(unittest.TestCase):
81 def setUp(self):
82 if tracemalloc.is_tracing():
83 self.skipTest("tracemalloc must be stopped before the test")
84
Victor Stinner3728d6c2013-11-23 12:37:20 +010085 tracemalloc.start(1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010086
87 def tearDown(self):
88 tracemalloc.stop()
89
90 def test_get_tracemalloc_memory(self):
91 data = [allocate_bytes(123) for count in range(1000)]
92 size = tracemalloc.get_tracemalloc_memory()
93 self.assertGreaterEqual(size, 0)
94
95 tracemalloc.clear_traces()
96 size2 = tracemalloc.get_tracemalloc_memory()
97 self.assertGreaterEqual(size2, 0)
98 self.assertLessEqual(size2, size)
99
100 def test_get_object_traceback(self):
101 tracemalloc.clear_traces()
102 obj_size = 12345
103 obj, obj_traceback = allocate_bytes(obj_size)
104 traceback = tracemalloc.get_object_traceback(obj)
105 self.assertEqual(traceback, obj_traceback)
106
107 def test_set_traceback_limit(self):
108 obj_size = 10
109
Victor Stinner3728d6c2013-11-23 12:37:20 +0100110 tracemalloc.stop()
111 self.assertRaises(ValueError, tracemalloc.start, -1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100112
Victor Stinner3728d6c2013-11-23 12:37:20 +0100113 tracemalloc.stop()
114 tracemalloc.start(10)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100115 obj2, obj2_traceback = allocate_bytes(obj_size)
116 traceback = tracemalloc.get_object_traceback(obj2)
117 self.assertEqual(len(traceback), 10)
118 self.assertEqual(traceback, obj2_traceback)
119
Victor Stinner3728d6c2013-11-23 12:37:20 +0100120 tracemalloc.stop()
121 tracemalloc.start(1)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100122 obj, obj_traceback = allocate_bytes(obj_size)
123 traceback = tracemalloc.get_object_traceback(obj)
124 self.assertEqual(len(traceback), 1)
125 self.assertEqual(traceback, obj_traceback)
126
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100127 def find_trace(self, traces, traceback):
128 for trace in traces:
129 if trace[1] == traceback._frames:
130 return trace
131
132 self.fail("trace not found")
133
134 def test_get_traces(self):
135 tracemalloc.clear_traces()
136 obj_size = 12345
137 obj, obj_traceback = allocate_bytes(obj_size)
138
139 traces = tracemalloc._get_traces()
140 trace = self.find_trace(traces, obj_traceback)
141
142 self.assertIsInstance(trace, tuple)
143 size, traceback = trace
144 self.assertEqual(size, obj_size)
145 self.assertEqual(traceback, obj_traceback._frames)
146
147 tracemalloc.stop()
148 self.assertEqual(tracemalloc._get_traces(), [])
149
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100150 def test_get_traces_intern_traceback(self):
151 # dummy wrappers to get more useful and identical frames in the traceback
152 def allocate_bytes2(size):
153 return allocate_bytes(size)
154 def allocate_bytes3(size):
155 return allocate_bytes2(size)
156 def allocate_bytes4(size):
157 return allocate_bytes3(size)
158
159 # Ensure that two identical tracebacks are not duplicated
Victor Stinner3728d6c2013-11-23 12:37:20 +0100160 tracemalloc.stop()
161 tracemalloc.start(4)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100162 obj_size = 123
163 obj1, obj1_traceback = allocate_bytes4(obj_size)
164 obj2, obj2_traceback = allocate_bytes4(obj_size)
165
166 traces = tracemalloc._get_traces()
167
168 trace1 = self.find_trace(traces, obj1_traceback)
169 trace2 = self.find_trace(traces, obj2_traceback)
170 size1, traceback1 = trace1
171 size2, traceback2 = trace2
172 self.assertEqual(traceback2, traceback1)
173 self.assertIs(traceback2, traceback1)
174
175 def test_get_traced_memory(self):
176 # Python allocates some internals objects, so the test must tolerate
177 # a small difference between the expected size and the real usage
178 max_error = 2048
179
180 # allocate one object
181 obj_size = 1024 * 1024
182 tracemalloc.clear_traces()
183 obj, obj_traceback = allocate_bytes(obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100184 size, peak_size = tracemalloc.get_traced_memory()
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100185 self.assertGreaterEqual(size, obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100186 self.assertGreaterEqual(peak_size, size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100187
188 self.assertLessEqual(size - obj_size, max_error)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100189 self.assertLessEqual(peak_size - size, max_error)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100190
191 # destroy the object
192 obj = None
Victor Stinner3c0481d2013-11-27 21:39:49 +0100193 size2, peak_size2 = tracemalloc.get_traced_memory()
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100194 self.assertLess(size2, size)
195 self.assertGreaterEqual(size - size2, obj_size - max_error)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100196 self.assertGreaterEqual(peak_size2, peak_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100197
198 # clear_traces() must reset traced memory counters
199 tracemalloc.clear_traces()
200 self.assertEqual(tracemalloc.get_traced_memory(), (0, 0))
201
202 # allocate another object
203 obj, obj_traceback = allocate_bytes(obj_size)
Victor Stinner3c0481d2013-11-27 21:39:49 +0100204 size, peak_size = tracemalloc.get_traced_memory()
205 self.assertGreaterEqual(size, obj_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100206
Victor Stinnera89ecc72013-11-25 09:29:45 +0100207 # stop() also resets traced memory counters
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100208 tracemalloc.stop()
209 self.assertEqual(tracemalloc.get_traced_memory(), (0, 0))
210
211 def test_clear_traces(self):
212 obj, obj_traceback = allocate_bytes(123)
213 traceback = tracemalloc.get_object_traceback(obj)
214 self.assertIsNotNone(traceback)
215
216 tracemalloc.clear_traces()
217 traceback2 = tracemalloc.get_object_traceback(obj)
218 self.assertIsNone(traceback2)
219
220 def test_is_tracing(self):
221 tracemalloc.stop()
222 self.assertFalse(tracemalloc.is_tracing())
223
224 tracemalloc.start()
225 self.assertTrue(tracemalloc.is_tracing())
226
227 def test_snapshot(self):
228 obj, source = allocate_bytes(123)
229
230 # take a snapshot
231 snapshot = tracemalloc.take_snapshot()
232
233 # write on disk
234 snapshot.dump(support.TESTFN)
235 self.addCleanup(support.unlink, support.TESTFN)
236
237 # load from disk
238 snapshot2 = tracemalloc.Snapshot.load(support.TESTFN)
239 self.assertEqual(snapshot2.traces, snapshot.traces)
240
241 # tracemalloc must be tracing memory allocations to take a snapshot
242 tracemalloc.stop()
243 with self.assertRaises(RuntimeError) as cm:
244 tracemalloc.take_snapshot()
245 self.assertEqual(str(cm.exception),
246 "the tracemalloc module must be tracing memory "
247 "allocations to take a snapshot")
248
249 def test_snapshot_save_attr(self):
250 # take a snapshot with a new attribute
251 snapshot = tracemalloc.take_snapshot()
252 snapshot.test_attr = "new"
253 snapshot.dump(support.TESTFN)
254 self.addCleanup(support.unlink, support.TESTFN)
255
256 # load() should recreates the attribute
257 snapshot2 = tracemalloc.Snapshot.load(support.TESTFN)
258 self.assertEqual(snapshot2.test_attr, "new")
259
260 def fork_child(self):
261 if not tracemalloc.is_tracing():
262 return 2
263
264 obj_size = 12345
265 obj, obj_traceback = allocate_bytes(obj_size)
266 traceback = tracemalloc.get_object_traceback(obj)
267 if traceback is None:
268 return 3
269
270 # everything is fine
271 return 0
272
273 @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()')
274 def test_fork(self):
275 # check that tracemalloc is still working after fork
276 pid = os.fork()
277 if not pid:
278 # child
279 exitcode = 1
280 try:
281 exitcode = self.fork_child()
282 finally:
283 os._exit(exitcode)
284 else:
285 pid2, status = os.waitpid(pid, 0)
286 self.assertTrue(os.WIFEXITED(status))
287 exitcode = os.WEXITSTATUS(status)
288 self.assertEqual(exitcode, 0)
289
290
291class TestSnapshot(unittest.TestCase):
292 maxDiff = 4000
293
294 def test_create_snapshot(self):
295 raw_traces = [(5, (('a.py', 2),))]
296
297 with contextlib.ExitStack() as stack:
298 stack.enter_context(patch.object(tracemalloc, 'is_tracing',
299 return_value=True))
300 stack.enter_context(patch.object(tracemalloc, 'get_traceback_limit',
301 return_value=5))
302 stack.enter_context(patch.object(tracemalloc, '_get_traces',
303 return_value=raw_traces))
304
305 snapshot = tracemalloc.take_snapshot()
306 self.assertEqual(snapshot.traceback_limit, 5)
307 self.assertEqual(len(snapshot.traces), 1)
308 trace = snapshot.traces[0]
309 self.assertEqual(trace.size, 5)
310 self.assertEqual(len(trace.traceback), 1)
311 self.assertEqual(trace.traceback[0].filename, 'a.py')
312 self.assertEqual(trace.traceback[0].lineno, 2)
313
314 def test_filter_traces(self):
315 snapshot, snapshot2 = create_snapshots()
316 filter1 = tracemalloc.Filter(False, "b.py")
317 filter2 = tracemalloc.Filter(True, "a.py", 2)
318 filter3 = tracemalloc.Filter(True, "a.py", 5)
319
320 original_traces = list(snapshot.traces._traces)
321
322 # exclude b.py
323 snapshot3 = snapshot.filter_traces((filter1,))
324 self.assertEqual(snapshot3.traces._traces, [
325 (10, (('a.py', 2), ('b.py', 4))),
326 (10, (('a.py', 2), ('b.py', 4))),
327 (10, (('a.py', 2), ('b.py', 4))),
328 (2, (('a.py', 5), ('b.py', 4))),
329 (7, (('<unknown>', 0),)),
330 ])
331
332 # filter_traces() must not touch the original snapshot
333 self.assertEqual(snapshot.traces._traces, original_traces)
334
335 # only include two lines of a.py
336 snapshot4 = snapshot3.filter_traces((filter2, filter3))
337 self.assertEqual(snapshot4.traces._traces, [
338 (10, (('a.py', 2), ('b.py', 4))),
339 (10, (('a.py', 2), ('b.py', 4))),
340 (10, (('a.py', 2), ('b.py', 4))),
341 (2, (('a.py', 5), ('b.py', 4))),
342 ])
343
344 # No filter: just duplicate the snapshot
345 snapshot5 = snapshot.filter_traces(())
346 self.assertIsNot(snapshot5, snapshot)
347 self.assertIsNot(snapshot5.traces, snapshot.traces)
348 self.assertEqual(snapshot5.traces, snapshot.traces)
349
Victor Stinner8ce8ff92014-03-10 11:05:07 +0100350 self.assertRaises(TypeError, snapshot.filter_traces, filter1)
351
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100352 def test_snapshot_group_by_line(self):
353 snapshot, snapshot2 = create_snapshots()
354 tb_0 = traceback_lineno('<unknown>', 0)
355 tb_a_2 = traceback_lineno('a.py', 2)
356 tb_a_5 = traceback_lineno('a.py', 5)
357 tb_b_1 = traceback_lineno('b.py', 1)
358 tb_c_578 = traceback_lineno('c.py', 578)
359
360 # stats per file and line
361 stats1 = snapshot.statistics('lineno')
362 self.assertEqual(stats1, [
363 tracemalloc.Statistic(tb_b_1, 66, 1),
364 tracemalloc.Statistic(tb_a_2, 30, 3),
365 tracemalloc.Statistic(tb_0, 7, 1),
366 tracemalloc.Statistic(tb_a_5, 2, 1),
367 ])
368
369 # stats per file and line (2)
370 stats2 = snapshot2.statistics('lineno')
371 self.assertEqual(stats2, [
372 tracemalloc.Statistic(tb_a_5, 5002, 2),
373 tracemalloc.Statistic(tb_c_578, 400, 1),
374 tracemalloc.Statistic(tb_a_2, 30, 3),
375 ])
376
377 # stats diff per file and line
378 statistics = snapshot2.compare_to(snapshot, 'lineno')
379 self.assertEqual(statistics, [
380 tracemalloc.StatisticDiff(tb_a_5, 5002, 5000, 2, 1),
381 tracemalloc.StatisticDiff(tb_c_578, 400, 400, 1, 1),
382 tracemalloc.StatisticDiff(tb_b_1, 0, -66, 0, -1),
383 tracemalloc.StatisticDiff(tb_0, 0, -7, 0, -1),
384 tracemalloc.StatisticDiff(tb_a_2, 30, 0, 3, 0),
385 ])
386
387 def test_snapshot_group_by_file(self):
388 snapshot, snapshot2 = create_snapshots()
389 tb_0 = traceback_filename('<unknown>')
390 tb_a = traceback_filename('a.py')
391 tb_b = traceback_filename('b.py')
392 tb_c = traceback_filename('c.py')
393
394 # stats per file
395 stats1 = snapshot.statistics('filename')
396 self.assertEqual(stats1, [
397 tracemalloc.Statistic(tb_b, 66, 1),
398 tracemalloc.Statistic(tb_a, 32, 4),
399 tracemalloc.Statistic(tb_0, 7, 1),
400 ])
401
402 # stats per file (2)
403 stats2 = snapshot2.statistics('filename')
404 self.assertEqual(stats2, [
405 tracemalloc.Statistic(tb_a, 5032, 5),
406 tracemalloc.Statistic(tb_c, 400, 1),
407 ])
408
409 # stats diff per file
410 diff = snapshot2.compare_to(snapshot, 'filename')
411 self.assertEqual(diff, [
412 tracemalloc.StatisticDiff(tb_a, 5032, 5000, 5, 1),
413 tracemalloc.StatisticDiff(tb_c, 400, 400, 1, 1),
414 tracemalloc.StatisticDiff(tb_b, 0, -66, 0, -1),
415 tracemalloc.StatisticDiff(tb_0, 0, -7, 0, -1),
416 ])
417
418 def test_snapshot_group_by_traceback(self):
419 snapshot, snapshot2 = create_snapshots()
420
421 # stats per file
422 tb1 = traceback(('a.py', 2), ('b.py', 4))
423 tb2 = traceback(('a.py', 5), ('b.py', 4))
424 tb3 = traceback(('b.py', 1))
425 tb4 = traceback(('<unknown>', 0))
426 stats1 = snapshot.statistics('traceback')
427 self.assertEqual(stats1, [
428 tracemalloc.Statistic(tb3, 66, 1),
429 tracemalloc.Statistic(tb1, 30, 3),
430 tracemalloc.Statistic(tb4, 7, 1),
431 tracemalloc.Statistic(tb2, 2, 1),
432 ])
433
434 # stats per file (2)
435 tb5 = traceback(('c.py', 578))
436 stats2 = snapshot2.statistics('traceback')
437 self.assertEqual(stats2, [
438 tracemalloc.Statistic(tb2, 5002, 2),
439 tracemalloc.Statistic(tb5, 400, 1),
440 tracemalloc.Statistic(tb1, 30, 3),
441 ])
442
443 # stats diff per file
444 diff = snapshot2.compare_to(snapshot, 'traceback')
445 self.assertEqual(diff, [
446 tracemalloc.StatisticDiff(tb2, 5002, 5000, 2, 1),
447 tracemalloc.StatisticDiff(tb5, 400, 400, 1, 1),
448 tracemalloc.StatisticDiff(tb3, 0, -66, 0, -1),
449 tracemalloc.StatisticDiff(tb4, 0, -7, 0, -1),
450 tracemalloc.StatisticDiff(tb1, 30, 0, 3, 0),
451 ])
452
453 self.assertRaises(ValueError,
454 snapshot.statistics, 'traceback', cumulative=True)
455
456 def test_snapshot_group_by_cumulative(self):
457 snapshot, snapshot2 = create_snapshots()
458 tb_0 = traceback_filename('<unknown>')
459 tb_a = traceback_filename('a.py')
460 tb_b = traceback_filename('b.py')
461 tb_a_2 = traceback_lineno('a.py', 2)
462 tb_a_5 = traceback_lineno('a.py', 5)
463 tb_b_1 = traceback_lineno('b.py', 1)
464 tb_b_4 = traceback_lineno('b.py', 4)
465
466 # per file
467 stats = snapshot.statistics('filename', True)
468 self.assertEqual(stats, [
469 tracemalloc.Statistic(tb_b, 98, 5),
470 tracemalloc.Statistic(tb_a, 32, 4),
471 tracemalloc.Statistic(tb_0, 7, 1),
472 ])
473
474 # per line
475 stats = snapshot.statistics('lineno', True)
476 self.assertEqual(stats, [
477 tracemalloc.Statistic(tb_b_1, 66, 1),
478 tracemalloc.Statistic(tb_b_4, 32, 4),
479 tracemalloc.Statistic(tb_a_2, 30, 3),
480 tracemalloc.Statistic(tb_0, 7, 1),
481 tracemalloc.Statistic(tb_a_5, 2, 1),
482 ])
483
484 def test_trace_format(self):
485 snapshot, snapshot2 = create_snapshots()
486 trace = snapshot.traces[0]
487 self.assertEqual(str(trace), 'a.py:2: 10 B')
488 traceback = trace.traceback
489 self.assertEqual(str(traceback), 'a.py:2')
490 frame = traceback[0]
491 self.assertEqual(str(frame), 'a.py:2')
492
493 def test_statistic_format(self):
494 snapshot, snapshot2 = create_snapshots()
495 stats = snapshot.statistics('lineno')
496 stat = stats[0]
497 self.assertEqual(str(stat),
498 'b.py:1: size=66 B, count=1, average=66 B')
499
500 def test_statistic_diff_format(self):
501 snapshot, snapshot2 = create_snapshots()
502 stats = snapshot2.compare_to(snapshot, 'lineno')
503 stat = stats[0]
504 self.assertEqual(str(stat),
505 'a.py:5: size=5002 B (+5000 B), count=2 (+1), average=2501 B')
506
Victor Stinner524be302014-02-01 04:07:02 +0100507 def test_slices(self):
508 snapshot, snapshot2 = create_snapshots()
509 self.assertEqual(snapshot.traces[:2],
510 (snapshot.traces[0], snapshot.traces[1]))
511
512 traceback = snapshot.traces[0].traceback
513 self.assertEqual(traceback[:2],
514 (traceback[0], traceback[1]))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100515
Victor Stinner23f628d2014-02-16 23:53:38 +0100516 def test_format_traceback(self):
517 snapshot, snapshot2 = create_snapshots()
518 def getline(filename, lineno):
519 return ' <%s, %s>' % (filename, lineno)
520 with unittest.mock.patch('tracemalloc.linecache.getline',
521 side_effect=getline):
522 tb = snapshot.traces[0].traceback
523 self.assertEqual(tb.format(),
524 [' File "a.py", line 2',
525 ' <a.py, 2>',
526 ' File "b.py", line 4',
527 ' <b.py, 4>'])
528
529 self.assertEqual(tb.format(limit=1),
530 [' File "a.py", line 2',
531 ' <a.py, 2>'])
532
533 self.assertEqual(tb.format(limit=-1),
534 [])
535
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100536
537class TestFilters(unittest.TestCase):
538 maxDiff = 2048
539
540 def test_filter_attributes(self):
541 # test default values
542 f = tracemalloc.Filter(True, "abc")
543 self.assertEqual(f.inclusive, True)
544 self.assertEqual(f.filename_pattern, "abc")
545 self.assertIsNone(f.lineno)
546 self.assertEqual(f.all_frames, False)
547
548 # test custom values
549 f = tracemalloc.Filter(False, "test.py", 123, True)
550 self.assertEqual(f.inclusive, False)
551 self.assertEqual(f.filename_pattern, "test.py")
552 self.assertEqual(f.lineno, 123)
553 self.assertEqual(f.all_frames, True)
554
555 # parameters passed by keyword
556 f = tracemalloc.Filter(inclusive=False, filename_pattern="test.py", lineno=123, all_frames=True)
557 self.assertEqual(f.inclusive, False)
558 self.assertEqual(f.filename_pattern, "test.py")
559 self.assertEqual(f.lineno, 123)
560 self.assertEqual(f.all_frames, True)
561
562 # read-only attribute
563 self.assertRaises(AttributeError, setattr, f, "filename_pattern", "abc")
564
565 def test_filter_match(self):
566 # filter without line number
567 f = tracemalloc.Filter(True, "abc")
568 self.assertTrue(f._match_frame("abc", 0))
569 self.assertTrue(f._match_frame("abc", 5))
570 self.assertTrue(f._match_frame("abc", 10))
571 self.assertFalse(f._match_frame("12356", 0))
572 self.assertFalse(f._match_frame("12356", 5))
573 self.assertFalse(f._match_frame("12356", 10))
574
575 f = tracemalloc.Filter(False, "abc")
576 self.assertFalse(f._match_frame("abc", 0))
577 self.assertFalse(f._match_frame("abc", 5))
578 self.assertFalse(f._match_frame("abc", 10))
579 self.assertTrue(f._match_frame("12356", 0))
580 self.assertTrue(f._match_frame("12356", 5))
581 self.assertTrue(f._match_frame("12356", 10))
582
583 # filter with line number > 0
584 f = tracemalloc.Filter(True, "abc", 5)
585 self.assertFalse(f._match_frame("abc", 0))
586 self.assertTrue(f._match_frame("abc", 5))
587 self.assertFalse(f._match_frame("abc", 10))
588 self.assertFalse(f._match_frame("12356", 0))
589 self.assertFalse(f._match_frame("12356", 5))
590 self.assertFalse(f._match_frame("12356", 10))
591
592 f = tracemalloc.Filter(False, "abc", 5)
593 self.assertTrue(f._match_frame("abc", 0))
594 self.assertFalse(f._match_frame("abc", 5))
595 self.assertTrue(f._match_frame("abc", 10))
596 self.assertTrue(f._match_frame("12356", 0))
597 self.assertTrue(f._match_frame("12356", 5))
598 self.assertTrue(f._match_frame("12356", 10))
599
600 # filter with line number 0
601 f = tracemalloc.Filter(True, "abc", 0)
602 self.assertTrue(f._match_frame("abc", 0))
603 self.assertFalse(f._match_frame("abc", 5))
604 self.assertFalse(f._match_frame("abc", 10))
605 self.assertFalse(f._match_frame("12356", 0))
606 self.assertFalse(f._match_frame("12356", 5))
607 self.assertFalse(f._match_frame("12356", 10))
608
609 f = tracemalloc.Filter(False, "abc", 0)
610 self.assertFalse(f._match_frame("abc", 0))
611 self.assertTrue(f._match_frame("abc", 5))
612 self.assertTrue(f._match_frame("abc", 10))
613 self.assertTrue(f._match_frame("12356", 0))
614 self.assertTrue(f._match_frame("12356", 5))
615 self.assertTrue(f._match_frame("12356", 10))
616
617 def test_filter_match_filename(self):
618 def fnmatch(inclusive, filename, pattern):
619 f = tracemalloc.Filter(inclusive, pattern)
620 return f._match_frame(filename, 0)
621
622 self.assertTrue(fnmatch(True, "abc", "abc"))
623 self.assertFalse(fnmatch(True, "12356", "abc"))
624 self.assertFalse(fnmatch(True, "<unknown>", "abc"))
625
626 self.assertFalse(fnmatch(False, "abc", "abc"))
627 self.assertTrue(fnmatch(False, "12356", "abc"))
628 self.assertTrue(fnmatch(False, "<unknown>", "abc"))
629
630 def test_filter_match_filename_joker(self):
631 def fnmatch(filename, pattern):
632 filter = tracemalloc.Filter(True, pattern)
633 return filter._match_frame(filename, 0)
634
635 # empty string
636 self.assertFalse(fnmatch('abc', ''))
637 self.assertFalse(fnmatch('', 'abc'))
638 self.assertTrue(fnmatch('', ''))
639 self.assertTrue(fnmatch('', '*'))
640
641 # no *
642 self.assertTrue(fnmatch('abc', 'abc'))
643 self.assertFalse(fnmatch('abc', 'abcd'))
644 self.assertFalse(fnmatch('abc', 'def'))
645
646 # a*
647 self.assertTrue(fnmatch('abc', 'a*'))
648 self.assertTrue(fnmatch('abc', 'abc*'))
649 self.assertFalse(fnmatch('abc', 'b*'))
650 self.assertFalse(fnmatch('abc', 'abcd*'))
651
652 # a*b
653 self.assertTrue(fnmatch('abc', 'a*c'))
654 self.assertTrue(fnmatch('abcdcx', 'a*cx'))
655 self.assertFalse(fnmatch('abb', 'a*c'))
656 self.assertFalse(fnmatch('abcdce', 'a*cx'))
657
658 # a*b*c
659 self.assertTrue(fnmatch('abcde', 'a*c*e'))
660 self.assertTrue(fnmatch('abcbdefeg', 'a*bd*eg'))
661 self.assertFalse(fnmatch('abcdd', 'a*c*e'))
662 self.assertFalse(fnmatch('abcbdefef', 'a*bd*eg'))
663
Brett Cannonf299abd2015-04-13 14:21:02 -0400664 # replace .pyc suffix with .py
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100665 self.assertTrue(fnmatch('a.pyc', 'a.py'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100666 self.assertTrue(fnmatch('a.py', 'a.pyc'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100667
668 if os.name == 'nt':
669 # case insensitive
670 self.assertTrue(fnmatch('aBC', 'ABc'))
671 self.assertTrue(fnmatch('aBcDe', 'Ab*dE'))
672
673 self.assertTrue(fnmatch('a.pyc', 'a.PY'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100674 self.assertTrue(fnmatch('a.py', 'a.PYC'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100675 else:
676 # case sensitive
677 self.assertFalse(fnmatch('aBC', 'ABc'))
678 self.assertFalse(fnmatch('aBcDe', 'Ab*dE'))
679
680 self.assertFalse(fnmatch('a.pyc', 'a.PY'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100681 self.assertFalse(fnmatch('a.py', 'a.PYC'))
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100682
683 if os.name == 'nt':
684 # normalize alternate separator "/" to the standard separator "\"
685 self.assertTrue(fnmatch(r'a/b', r'a\b'))
686 self.assertTrue(fnmatch(r'a\b', r'a/b'))
687 self.assertTrue(fnmatch(r'a/b\c', r'a\b/c'))
688 self.assertTrue(fnmatch(r'a/b/c', r'a\b\c'))
689 else:
690 # there is no alternate separator
691 self.assertFalse(fnmatch(r'a/b', r'a\b'))
692 self.assertFalse(fnmatch(r'a\b', r'a/b'))
693 self.assertFalse(fnmatch(r'a/b\c', r'a\b/c'))
694 self.assertFalse(fnmatch(r'a/b/c', r'a\b\c'))
695
Zachary Wared9b25bb2015-05-13 00:27:01 -0500696 # as of 3.5, .pyo is no longer munged to .py
697 self.assertFalse(fnmatch('a.pyo', 'a.py'))
698
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100699 def test_filter_match_trace(self):
700 t1 = (("a.py", 2), ("b.py", 3))
701 t2 = (("b.py", 4), ("b.py", 5))
702 t3 = (("c.py", 5), ('<unknown>', 0))
703 unknown = (('<unknown>', 0),)
704
705 f = tracemalloc.Filter(True, "b.py", all_frames=True)
706 self.assertTrue(f._match_traceback(t1))
707 self.assertTrue(f._match_traceback(t2))
708 self.assertFalse(f._match_traceback(t3))
709 self.assertFalse(f._match_traceback(unknown))
710
711 f = tracemalloc.Filter(True, "b.py", all_frames=False)
712 self.assertFalse(f._match_traceback(t1))
713 self.assertTrue(f._match_traceback(t2))
714 self.assertFalse(f._match_traceback(t3))
715 self.assertFalse(f._match_traceback(unknown))
716
717 f = tracemalloc.Filter(False, "b.py", all_frames=True)
718 self.assertFalse(f._match_traceback(t1))
719 self.assertFalse(f._match_traceback(t2))
720 self.assertTrue(f._match_traceback(t3))
721 self.assertTrue(f._match_traceback(unknown))
722
723 f = tracemalloc.Filter(False, "b.py", all_frames=False)
724 self.assertTrue(f._match_traceback(t1))
725 self.assertFalse(f._match_traceback(t2))
726 self.assertTrue(f._match_traceback(t3))
727 self.assertTrue(f._match_traceback(unknown))
728
729 f = tracemalloc.Filter(False, "<unknown>", all_frames=False)
730 self.assertTrue(f._match_traceback(t1))
731 self.assertTrue(f._match_traceback(t2))
732 self.assertTrue(f._match_traceback(t3))
733 self.assertFalse(f._match_traceback(unknown))
734
735 f = tracemalloc.Filter(True, "<unknown>", all_frames=True)
736 self.assertFalse(f._match_traceback(t1))
737 self.assertFalse(f._match_traceback(t2))
738 self.assertTrue(f._match_traceback(t3))
739 self.assertTrue(f._match_traceback(unknown))
740
741 f = tracemalloc.Filter(False, "<unknown>", all_frames=True)
742 self.assertTrue(f._match_traceback(t1))
743 self.assertTrue(f._match_traceback(t2))
744 self.assertFalse(f._match_traceback(t3))
745 self.assertFalse(f._match_traceback(unknown))
746
747
748class TestCommandLine(unittest.TestCase):
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800749 def test_env_var_disabled_by_default(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100750 # not tracing by default
751 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
752 ok, stdout, stderr = assert_python_ok('-c', code)
753 stdout = stdout.rstrip()
754 self.assertEqual(stdout, b'False')
755
Berker Peksagce643912015-05-06 06:33:17 +0300756 @unittest.skipIf(interpreter_requires_environment(),
Gregory P. Smithb9a3dd92015-02-04 00:59:40 -0800757 'Cannot run -E tests when PYTHON env vars are required.')
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800758 def test_env_var_ignored_with_E(self):
759 """PYTHON* environment variables must be ignored when -E is present."""
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100760 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
761 ok, stdout, stderr = assert_python_ok('-E', '-c', code, PYTHONTRACEMALLOC='1')
762 stdout = stdout.rstrip()
763 self.assertEqual(stdout, b'False')
764
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800765 def test_env_var_enabled_at_startup(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100766 # tracing at startup
767 code = 'import tracemalloc; print(tracemalloc.is_tracing())'
768 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='1')
769 stdout = stdout.rstrip()
770 self.assertEqual(stdout, b'True')
771
Gregory P. Smith34cd2ae2015-01-22 14:38:00 -0800772 def test_env_limit(self):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100773 # start and set the number of frames
774 code = 'import tracemalloc; print(tracemalloc.get_traceback_limit())'
775 ok, stdout, stderr = assert_python_ok('-c', code, PYTHONTRACEMALLOC='10')
776 stdout = stdout.rstrip()
777 self.assertEqual(stdout, b'10')
778
779 def test_env_var_invalid(self):
Victor Stinnerf28ce602013-11-27 22:27:13 +0100780 for nframe in (-1, 0, 2**30):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100781 with self.subTest(nframe=nframe):
782 with support.SuppressCrashReport():
783 ok, stdout, stderr = assert_python_failure(
784 '-c', 'pass',
785 PYTHONTRACEMALLOC=str(nframe))
Victor Stinnerf28ce602013-11-27 22:27:13 +0100786 self.assertIn(b'PYTHONTRACEMALLOC: invalid '
787 b'number of frames',
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100788 stderr)
789
790 def test_sys_xoptions(self):
791 for xoptions, nframe in (
792 ('tracemalloc', 1),
793 ('tracemalloc=1', 1),
794 ('tracemalloc=15', 15),
795 ):
796 with self.subTest(xoptions=xoptions, nframe=nframe):
797 code = 'import tracemalloc; print(tracemalloc.get_traceback_limit())'
798 ok, stdout, stderr = assert_python_ok('-X', xoptions, '-c', code)
799 stdout = stdout.rstrip()
800 self.assertEqual(stdout, str(nframe).encode('ascii'))
801
802 def test_sys_xoptions_invalid(self):
Victor Stinnerf28ce602013-11-27 22:27:13 +0100803 for nframe in (-1, 0, 2**30):
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100804 with self.subTest(nframe=nframe):
805 with support.SuppressCrashReport():
806 args = ('-X', 'tracemalloc=%s' % nframe, '-c', 'pass')
807 ok, stdout, stderr = assert_python_failure(*args)
Victor Stinnerf28ce602013-11-27 22:27:13 +0100808 self.assertIn(b'-X tracemalloc=NFRAME: invalid '
809 b'number of frames',
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100810 stderr)
811
Victor Stinner8dd49fe2014-06-02 21:36:59 +0200812 def test_pymem_alloc0(self):
813 # Issue #21639: Check that PyMem_Malloc(0) with tracemalloc enabled
814 # does not crash.
815 code = 'import _testcapi; _testcapi.test_pymem_alloc0(); 1'
816 assert_python_ok('-X', 'tracemalloc', '-c', code)
817
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100818
819def test_main():
820 support.run_unittest(
821 TestTracemallocEnabled,
822 TestSnapshot,
823 TestFilters,
824 TestCommandLine,
825 )
826
827if __name__ == "__main__":
828 test_main()