summary refs log tree commit diff
diff options
context:
space:
mode:
authorSean Quah <seanq@matrix.org>2023-05-22 16:20:18 +0100
committerSean Quah <seanq@matrix.org>2023-05-22 16:20:18 +0100
commitdf6154445534bf5dcf7b168734695382d9dba390 (patch)
tree7e97bbebb9f6418ea2a67692e7d20f8762d20867
parentLimit the size of the `HomeServerConfig` cache in trial test runs (#15646) (diff)
downloadsynapse-squah/trial_memory_leak_tracking.tar.xz
-rw-r--r--tests/unittest.py67
1 files changed, 67 insertions, 0 deletions
diff --git a/tests/unittest.py b/tests/unittest.py
index c73195b32b..fa2ef51f49 100644
--- a/tests/unittest.py
+++ b/tests/unittest.py
@@ -227,13 +227,80 @@ class TestCase(unittest.TestCase):
 
         @around(self)
         def tearDown(orig: Callable[[], R]) -> R:
+            import sys
+            import time
+            import tracemalloc
+
             ret = orig()
             gc.collect(0)
             # Run a full GC every 50 gen-0 GCs.
             gen0_stats = gc.get_stats()[0]
             gen0_collections = gen0_stats["collections"]
             if gen0_collections % 50 == 0:
+                if not getattr(tracemalloc, "aaa", None):
+                    tracemalloc.aaa = True
+                    tracemalloc.start()
+                    tracemalloc.s0 = tracemalloc.take_snapshot()
+                t0 = time.time()
                 gc.collect()
+                dt = time.time() - t0
+                s1 = tracemalloc.take_snapshot()
+                for line in s1.statistics("lineno")[:20]:
+                    sys.stdout.write(f"    {line}\n")
+                sys.stdout.write(f"full collection took {dt} s\n")
+                dt = time.time() - t0
+                sys.stdout.write(f"snapshot took {dt} s\n")
+                if dt > 1.5:
+
+                    def dump_paths(o: object, max_distance: int) -> None:
+                        import pdb
+                        from collections import deque
+
+                        queue: deque[object] = deque()
+                        seen: set[int] = set()
+                        prevs: Dict[int, object] = {}
+                        roots: List[object] = []
+                        distances: Dict[int, int] = {}
+                        whitelist = {id(queue), id(seen), id(prevs), id(roots)}
+                        i = 0
+                        seen.add(id(o))
+                        queue.append(o)
+                        distances[id(o)] = 0
+                        while len(queue) > 0:
+                            o = queue.popleft()
+                            has_referrers = False
+                            if (
+                                not isinstance(o, pdb.Pdb)
+                                and distances[id(o)] < max_distance
+                            ):
+                                referrers = gc.get_referrers(o)
+                                for referrer in referrers:
+                                    if id(referrer) in whitelist:
+                                        continue
+                                    has_referrers = True
+                                    if id(referrer) in seen:
+                                        continue
+                                    prevs[id(referrer)] = o
+                                    distances[id(referrer)] = distances[id(o)] + 1
+                                    seen.add(id(referrer))
+                                    queue.append(referrer)
+
+                            if not has_referrers:
+                                roots.append(o)
+
+                            i += 1
+                        print(f"{len(roots)} roots")
+                        for root in roots:
+                            o = root
+                            while o is not None:
+                                print(str(o)[:200])
+                                o = prevs.get(id(o))
+                            print("")
+                        print(f"{len(roots)} roots")
+
+                    import pdb
+
+                    pdb.set_trace()
             gc.enable()
             set_current_context(SENTINEL_CONTEXT)