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