mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	bpo-37961, tracemalloc: add Traceback.total_nframe (GH-15545)
Add a total_nframe field to the traces collected by the tracemalloc module. This field indicates the original number of frames before it was truncated.
This commit is contained in:
		
							parent
							
								
									f3ef06a7cb
								
							
						
					
					
						commit
						8d59eb1b66
					
				
					 5 changed files with 114 additions and 64 deletions
				
			
		| 
						 | 
				
			
			@ -36,7 +36,7 @@ def allocate_bytes(size):
 | 
			
		|||
    bytes_len = (size - EMPTY_STRING_SIZE)
 | 
			
		||||
    frames = get_frames(nframe, 1)
 | 
			
		||||
    data = b'x' * bytes_len
 | 
			
		||||
    return data, tracemalloc.Traceback(frames)
 | 
			
		||||
    return data, tracemalloc.Traceback(frames, min(len(frames), nframe))
 | 
			
		||||
 | 
			
		||||
def create_snapshots():
 | 
			
		||||
    traceback_limit = 2
 | 
			
		||||
| 
						 | 
				
			
			@ -45,27 +45,27 @@ def create_snapshots():
 | 
			
		|||
    # traceback_frames) tuples. traceback_frames is a tuple of (filename,
 | 
			
		||||
    # line_number) tuples.
 | 
			
		||||
    raw_traces = [
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
 | 
			
		||||
        (1, 2, (('a.py', 5), ('b.py', 4))),
 | 
			
		||||
        (1, 2, (('a.py', 5), ('b.py', 4)), 3),
 | 
			
		||||
 | 
			
		||||
        (2, 66, (('b.py', 1),)),
 | 
			
		||||
        (2, 66, (('b.py', 1),), 1),
 | 
			
		||||
 | 
			
		||||
        (3, 7, (('<unknown>', 0),)),
 | 
			
		||||
        (3, 7, (('<unknown>', 0),), 1),
 | 
			
		||||
    ]
 | 
			
		||||
    snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit)
 | 
			
		||||
 | 
			
		||||
    raw_traces2 = [
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
        (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
 | 
			
		||||
        (2, 2, (('a.py', 5), ('b.py', 4))),
 | 
			
		||||
        (2, 5000, (('a.py', 5), ('b.py', 4))),
 | 
			
		||||
        (2, 2, (('a.py', 5), ('b.py', 4)), 3),
 | 
			
		||||
        (2, 5000, (('a.py', 5), ('b.py', 4)), 3),
 | 
			
		||||
 | 
			
		||||
        (4, 400, (('c.py', 578),)),
 | 
			
		||||
        (4, 400, (('c.py', 578),), 1),
 | 
			
		||||
    ]
 | 
			
		||||
    snapshot2 = tracemalloc.Snapshot(raw_traces2, traceback_limit)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -125,7 +125,7 @@ def test_new_reference(self):
 | 
			
		|||
 | 
			
		||||
        nframe = tracemalloc.get_traceback_limit()
 | 
			
		||||
        frames = get_frames(nframe, -3)
 | 
			
		||||
        obj_traceback = tracemalloc.Traceback(frames)
 | 
			
		||||
        obj_traceback = tracemalloc.Traceback(frames, min(len(frames), nframe))
 | 
			
		||||
 | 
			
		||||
        traceback = tracemalloc.get_object_traceback(obj)
 | 
			
		||||
        self.assertIsNotNone(traceback)
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +167,7 @@ def test_get_traces(self):
 | 
			
		|||
        trace = self.find_trace(traces, obj_traceback)
 | 
			
		||||
 | 
			
		||||
        self.assertIsInstance(trace, tuple)
 | 
			
		||||
        domain, size, traceback = trace
 | 
			
		||||
        domain, size, traceback, length = trace
 | 
			
		||||
        self.assertEqual(size, obj_size)
 | 
			
		||||
        self.assertEqual(traceback, obj_traceback._frames)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -197,8 +197,8 @@ def allocate_bytes4(size):
 | 
			
		|||
 | 
			
		||||
        trace1 = self.find_trace(traces, obj1_traceback)
 | 
			
		||||
        trace2 = self.find_trace(traces, obj2_traceback)
 | 
			
		||||
        domain1, size1, traceback1 = trace1
 | 
			
		||||
        domain2, size2, traceback2 = trace2
 | 
			
		||||
        domain1, size1, traceback1, length1 = trace1
 | 
			
		||||
        domain2, size2, traceback2, length2 = trace2
 | 
			
		||||
        self.assertIs(traceback2, traceback1)
 | 
			
		||||
 | 
			
		||||
    def test_get_traced_memory(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -259,6 +259,9 @@ def test_snapshot(self):
 | 
			
		|||
        # take a snapshot
 | 
			
		||||
        snapshot = tracemalloc.take_snapshot()
 | 
			
		||||
 | 
			
		||||
        # This can vary
 | 
			
		||||
        self.assertGreater(snapshot.traces[1].traceback.total_nframe, 10)
 | 
			
		||||
 | 
			
		||||
        # write on disk
 | 
			
		||||
        snapshot.dump(support.TESTFN)
 | 
			
		||||
        self.addCleanup(support.unlink, support.TESTFN)
 | 
			
		||||
| 
						 | 
				
			
			@ -321,7 +324,7 @@ class TestSnapshot(unittest.TestCase):
 | 
			
		|||
    maxDiff = 4000
 | 
			
		||||
 | 
			
		||||
    def test_create_snapshot(self):
 | 
			
		||||
        raw_traces = [(0, 5, (('a.py', 2),))]
 | 
			
		||||
        raw_traces = [(0, 5, (('a.py', 2),), 10)]
 | 
			
		||||
 | 
			
		||||
        with contextlib.ExitStack() as stack:
 | 
			
		||||
            stack.enter_context(patch.object(tracemalloc, 'is_tracing',
 | 
			
		||||
| 
						 | 
				
			
			@ -336,6 +339,7 @@ def test_create_snapshot(self):
 | 
			
		|||
            self.assertEqual(len(snapshot.traces), 1)
 | 
			
		||||
            trace = snapshot.traces[0]
 | 
			
		||||
            self.assertEqual(trace.size, 5)
 | 
			
		||||
            self.assertEqual(trace.traceback.total_nframe, 10)
 | 
			
		||||
            self.assertEqual(len(trace.traceback), 1)
 | 
			
		||||
            self.assertEqual(trace.traceback[0].filename, 'a.py')
 | 
			
		||||
            self.assertEqual(trace.traceback[0].lineno, 2)
 | 
			
		||||
| 
						 | 
				
			
			@ -351,11 +355,11 @@ def test_filter_traces(self):
 | 
			
		|||
        # exclude b.py
 | 
			
		||||
        snapshot3 = snapshot.filter_traces((filter1,))
 | 
			
		||||
        self.assertEqual(snapshot3.traces._traces, [
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (1, 2, (('a.py', 5), ('b.py', 4))),
 | 
			
		||||
            (3, 7, (('<unknown>', 0),)),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (1, 2, (('a.py', 5), ('b.py', 4)), 3),
 | 
			
		||||
            (3, 7, (('<unknown>', 0),), 1),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        # filter_traces() must not touch the original snapshot
 | 
			
		||||
| 
						 | 
				
			
			@ -364,10 +368,10 @@ def test_filter_traces(self):
 | 
			
		|||
        # only include two lines of a.py
 | 
			
		||||
        snapshot4 = snapshot3.filter_traces((filter2, filter3))
 | 
			
		||||
        self.assertEqual(snapshot4.traces._traces, [
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (1, 2, (('a.py', 5), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (1, 2, (('a.py', 5), ('b.py', 4)), 3),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        # No filter: just duplicate the snapshot
 | 
			
		||||
| 
						 | 
				
			
			@ -388,21 +392,21 @@ def test_filter_traces_domain(self):
 | 
			
		|||
        # exclude a.py of domain 1
 | 
			
		||||
        snapshot3 = snapshot.filter_traces((filter1,))
 | 
			
		||||
        self.assertEqual(snapshot3.traces._traces, [
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (2, 66, (('b.py', 1),)),
 | 
			
		||||
            (3, 7, (('<unknown>', 0),)),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (2, 66, (('b.py', 1),), 1),
 | 
			
		||||
            (3, 7, (('<unknown>', 0),), 1),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        # include domain 1
 | 
			
		||||
        snapshot3 = snapshot.filter_traces((filter1,))
 | 
			
		||||
        self.assertEqual(snapshot3.traces._traces, [
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (2, 66, (('b.py', 1),)),
 | 
			
		||||
            (3, 7, (('<unknown>', 0),)),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (2, 66, (('b.py', 1),), 1),
 | 
			
		||||
            (3, 7, (('<unknown>', 0),), 1),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
    def test_filter_traces_domain_filter(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -413,17 +417,17 @@ def test_filter_traces_domain_filter(self):
 | 
			
		|||
        # exclude domain 2
 | 
			
		||||
        snapshot3 = snapshot.filter_traces((filter1,))
 | 
			
		||||
        self.assertEqual(snapshot3.traces._traces, [
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4))),
 | 
			
		||||
            (1, 2, (('a.py', 5), ('b.py', 4))),
 | 
			
		||||
            (2, 66, (('b.py', 1),)),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (0, 10, (('a.py', 2), ('b.py', 4)), 3),
 | 
			
		||||
            (1, 2, (('a.py', 5), ('b.py', 4)), 3),
 | 
			
		||||
            (2, 66, (('b.py', 1),), 1),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        # include domain 2
 | 
			
		||||
        snapshot3 = snapshot.filter_traces((filter2,))
 | 
			
		||||
        self.assertEqual(snapshot3.traces._traces, [
 | 
			
		||||
            (3, 7, (('<unknown>', 0),)),
 | 
			
		||||
            (3, 7, (('<unknown>', 0),), 1),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
    def test_snapshot_group_by_line(self):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue