Skip to content

Commit 5279df8

Browse files
committed
Add regression test and comment for negative increments in loops (Closes #219)
1 parent 83172f9 commit 5279df8

3 files changed

Lines changed: 44 additions & 4 deletions

File tree

‎Makefile‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ test:
2020
$(PYTHON) test/test_mprof.py
2121
$(PYTHON) test/test_async.py
2222
$(PYTHON) test/test_ipython.py
23+
$(PYTHON) test/test_increment_display.py
2324
mprof run test/test_func.py
2425

2526
develop:

‎memory_profiler.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,9 @@ def trace(self, code, lineno, prev_lineno):
680680
previous_inc = prev_value[0] if prev_value else 0
681681

682682
prev_line_value = self[code].get(prev_lineno, None) if prev_lineno else None
683+
# Use the most recent memory of the previous line (index 3) rather than
684+
# its historical maximum (index 1) so loops do not accumulate false
685+
# negative increments when memory drops below an earlier peak (#219).
683686
prev_line_memory = prev_line_value[3] if prev_line_value else 0
684687
occ_count = self[code][lineno][2] + 1 if lineno in self[code] else 1
685688
self[code][lineno] = (

‎test/test_increment_display.py‎

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import tracemalloc
12
import unittest
23

34
from memory_profiler import LineProfiler, profile, show_results
@@ -7,13 +8,19 @@
78
class TestIncrementDisplay(unittest.TestCase):
89
"""Tests memory incrementation / decrementation display"""
910

11+
def setUp(self):
12+
tracemalloc.start()
13+
14+
def tearDown(self):
15+
tracemalloc.stop()
16+
1017
def test_loop_count(self):
1118

1219
def some_loop():
1320
for i in range(12): # line -2
1421
a = 1 # line -1
1522

16-
profiler = LineProfiler()
23+
profiler = LineProfiler(backend='tracemalloc')
1724
wrapped = profiler(some_loop)
1825
wrapped()
1926
show_results(profiler)
@@ -28,7 +35,7 @@ def test_normal_incr(self):
2835
def normal_incr():
2936
use_some_memory = [1] * (10 ** 6)
3037

31-
profiler = LineProfiler()
38+
profiler = LineProfiler(backend='tracemalloc')
3239
wrapped = profiler(normal_incr)
3340
wrapped()
3441

@@ -48,7 +55,7 @@ def loop_incr():
4855
c = [2] * (2 * 10 ** 7) # line -2
4956
a.append(c)
5057

51-
profiler = LineProfiler()
58+
profiler = LineProfiler(backend='tracemalloc')
5259
wrapped = profiler(loop_incr)
5360
wrapped()
5461

@@ -64,7 +71,7 @@ def del_stuff():
6471
b = [2] * (2 * 10 ** 7)
6572
del b
6673

67-
profiler = LineProfiler()
74+
profiler = LineProfiler(backend='tracemalloc')
6875
wrapped = profiler(del_stuff)
6976
wrapped()
7077

@@ -76,6 +83,35 @@ def del_stuff():
7683
self.assertGreater(del_line[1], 0)
7784
self.assertAlmostEqual(-del_line[0], b_line[0], delta=1)
7885

86+
def test_no_false_negative_incr_after_peak_in_loop(self):
87+
"""Regression test for Issue #219 / PR #350.
88+
89+
When a line inside a loop reaches a high memory peak on an early
90+
iteration that is later freed, subsequent iterations of the following
91+
line must compare against the previous line's most recent memory,
92+
not its historical maximum memory (which would accumulate bogus
93+
negative increments on every iteration).
94+
"""
95+
def loop_with_early_peak():
96+
for i in range(5):
97+
# Peaks on i == 0 (~150 MiB), small on i > 0
98+
x = [1] * (2 * 10 ** 7 if i == 0 else 10)
99+
y = 1 # Must NOT accumulate a ~-150 MiB decrement on i = 1..4
100+
del x
101+
102+
profiler = LineProfiler(backend='tracemalloc')
103+
wrapped = profiler(loop_with_early_peak)
104+
wrapped()
105+
106+
show_results(profiler)
107+
measures = list(profiler.code_map.values())[0]
108+
# Ordered lines: for, x = ..., y = 1, del x
109+
y_line = [measures[lineno] for lineno in sorted(measures)][-2]
110+
y_inc = y_line[0]
111+
# Before PR #350, y_inc was around -600 MiB (4 * -150 MiB).
112+
# With PR #350, y = 1 has ~0 MiB increment.
113+
self.assertGreater(y_inc, -5.0)
114+
79115

80116
if __name__ == '__main__':
81117
unittest.main()

0 commit comments

Comments
 (0)