Repository: pythonprofilers/memory_profiler

Issue:
The first example in readme not working correctly
Here's what I get on both windows and linux. 
```
Line #    Mem usage    Increment   Line Contents
================================================
     1   37.754 MiB   37.754 MiB   @profile
     2                             def my_func():
     3   45.195 MiB    7.441 MiB       a = [1] * (10 ** 6)
     4  197.820 MiB  152.625 MiB       b = [2] * (2 * 10 ** 7)
     5   45.449 MiB    0.000 MiB       del b
     6   45.449 MiB    0.000 MiB       return a
```
I would expect it to show released memory after `del b` as it is described in the readme file.


Comments:

Patch:
diff --git a/README.rst b/README.rst
index b52b6f2..79d1c6b 100644
--- a/README.rst
+++ b/README.rst
@@ -64,14 +64,14 @@ this would result in::
 
 Output will follow::
 
-    Line #    Mem usage  Increment   Line Contents
-    ==============================================
-         3                           @profile
-         4      5.97 MB    0.00 MB   def my_func():
-         5     13.61 MB    7.64 MB       a = [1] * (10 ** 6)
-         6    166.20 MB  152.59 MB       b = [2] * (2 * 10 ** 7)
-         7     13.61 MB -152.59 MB       del b
-         8     13.61 MB    0.00 MB       return a
+    Line #    Mem usage    Increment  Occurences   Line Contents
+    ============================================================
+         3   38.816 MiB   38.816 MiB           1   @profile
+         4                                         def my_func():
+         5   46.492 MiB    7.676 MiB           1       a = [1] * (10 ** 6)
+         6  199.117 MiB  152.625 MiB           1       b = [2] * (2 * 10 ** 7)
+         7   46.629 MiB -152.488 MiB           1       del b
+         8   46.629 MiB    0.000 MiB           1       return a
 
 
 The first column represents the line number of the code that has been
diff --git a/memory_profiler.py b/memory_profiler.py
index cd4ba4f..632bee3 100644
--- a/memory_profiler.py
+++ b/memory_profiler.py
@@ -280,10 +280,10 @@ def memory_usage(proc=-1, interval=.1, timeout=None, timestamps=False,
         to this file instead of stored in memory and returned at the end of
         the subprocess. Useful for long-running processes.
         Implies timestamps=True.
-        
+
     max_iterations : int
         Limits the number of iterations (calls to the process being monitored). Relevent
-        when the process is a python function. 
+        when the process is a python function.
 
     Returns
     -------
@@ -357,7 +357,7 @@ def memory_usage(proc=-1, interval=.1, timeout=None, timestamps=False,
                 raise
 
             p.join(5 * interval)
-            
+
             if (n_measurements > 4) or (current_iter == max_iter) or (interval < 1e-6):
                 break
             interval /= 10.
@@ -643,7 +643,12 @@ class CodeMap(dict):
 
         prev_line_value = self[code].get(prev_lineno, None) if prev_lineno else None
         prev_line_memory = prev_line_value[1] if prev_line_value else 0
-        self[code][lineno] = (max(previous_inc, memory-prev_line_memory), max(memory, previous_memory))
+        occ_count = self[code][lineno][2] + 1 if lineno in self[code] else 1
+        self[code][lineno] = (
+            previous_inc + (memory - prev_line_memory),
+            max(memory, previous_memory),
+            occ_count,
+        )
 
     def items(self):
         """Iterate on the toplevel code blocks."""
@@ -800,10 +805,10 @@ class LineProfiler(object):
 def show_results(prof, stream=None, precision=1):
     if stream is None:
         stream = sys.stdout
-    template = '{0:>6} {1:>12} {2:>12}   {3:<}'
+    template = '{0:>6} {1:>12} {2:>12}  {3:>10}   {4:<}'
 
     for (filename, lines) in prof.code_map.items():
-        header = template.format('Line #', 'Mem usage', 'Increment',
+        header = template.format('Line #', 'Mem usage', 'Increment', 'Occurences',
                                  'Line Contents')
 
         stream.write(u'Filename: ' + filename + '\n\n')
@@ -817,13 +822,15 @@ def show_results(prof, stream=None, precision=1):
         for (lineno, mem) in lines:
             if mem:
                 inc = mem[0]
-                mem = mem[1]
-                mem = template_mem.format(mem)
+                total_mem = mem[1]
+                total_mem = template_mem.format(total_mem)
+                occurences = mem[2]
                 inc = template_mem.format(inc)
             else:
-                mem = u''
+                total_mem = u''
                 inc = u''
-            tmp = template.format(lineno, mem, inc, all_lines[lineno - 1])
+                occurences = u''
+            tmp = template.format(lineno, total_mem, inc, occurences, all_lines[lineno - 1])
             stream.write(to_str(tmp))
         stream.write(u'\n\n')
 


Test patch:
diff --git a/test/test_increment_display.py b/test/test_increment_display.py
new file mode 100644
index 0000000..b0dbe51
--- /dev/null
+++ b/test/test_increment_display.py
@@ -0,0 +1,81 @@
+import unittest
+
+from memory_profiler import LineProfiler, profile, show_results
+from io import StringIO
+
+
+class TestIncrementDisplay(unittest.TestCase):
+    """Tests memory incrementation / decrementation display"""
+
+    def test_loop_count(self):
+
+        def some_loop():
+            for i in range(12):  # line -2
+                a = 1            # line -1
+
+        profiler = LineProfiler()
+        wrapped = profiler(some_loop)
+        wrapped()
+        show_results(profiler)
+        for_line = list(list(profiler.code_map.values())[0].values())[-2]
+        looped_instruction = list(list(profiler.code_map.values())[0].values())[-1]
+
+        self.assertEqual(for_line[2], 13)
+        self.assertEqual(looped_instruction[2], 12)
+
+    def test_normal_incr(self):
+
+        def normal_incr():
+            use_some_memory = [1] * (10 ** 6)
+
+        profiler = LineProfiler()
+        wrapped = profiler(normal_incr)
+        wrapped()
+
+        show_results(profiler)
+        results = list(list(profiler.code_map.values())[0].values())[-1]
+
+        self.assertGreater(results[0], 0)
+        self.assertGreater(results[1], results[0])
+        self.assertEqual(results[2], 1)
+
+    def test_loop_incr(self):
+
+        def loop_incr():
+            a = []
+            b = [2] * (2 * 10 ** 7)      # line -4
+            for i in range(3):
+                c = [2] * (2 * 10 ** 7)  # line -2
+                a.append(c)
+
+        profiler = LineProfiler()
+        wrapped = profiler(loop_incr)
+        wrapped()
+
+        show_results(profiler)
+        b_line = list(list(profiler.code_map.values())[0].values())[-4]
+        c_line = list(list(profiler.code_map.values())[0].values())[-2]
+        self.assertAlmostEqual(b_line[2] * 3, c_line[2], delta=1)
+        self.assertEqual(c_line[2], 3)
+
+    def test_decr(self):
+
+        def del_stuff():
+            b = [2] * (2 * 10 ** 7)
+            del b
+
+        profiler = LineProfiler()
+        wrapped = profiler(del_stuff)
+        wrapped()
+
+        show_results(profiler)
+        b_line = list(list(profiler.code_map.values())[0].values())[-2]
+        del_line = list(list(profiler.code_map.values())[0].values())[-1]
+
+        self.assertGreater(0, del_line[0])
+        self.assertGreater(del_line[1], 0)
+        self.assertAlmostEqual(-del_line[0], b_line[0], delta=1)
+
+
+if __name__ == '__main__':
+    unittest.main()