[PATCH 1 of 3 v3] profiling: allow nested usage of profile context manager

Arun Kulshreshtha kulshrax at fb.com
Tue Sep 20 20:35:20 UTC 2016


# HG changeset patch
# User Arun Kulshreshtha <kulshrax at fb.com>
# Date 1474402733 25200
#      Tue Sep 20 13:18:53 2016 -0700
# Node ID 69499ec91691f952a8a28092c361a0e3daccc429
# Parent  285a8c3e53f2183438f0cdbc238e4ab851d0d110
profiling: allow nested usage of profile context manager

Add a check to the profile context manager to ensure that profiling
is only enabled once in nested invocations of this context manager.
The flag to guard against nesting is stored in thead-local storage,
so this only prevents nested usage within the same thread. (i.e.,
if a thread is spawned while profiling is active, the child thread
is also able to enable profiling.)

diff --git a/mercurial/profiling.py b/mercurial/profiling.py
--- a/mercurial/profiling.py
+++ b/mercurial/profiling.py
@@ -10,6 +10,7 @@
 import contextlib
 import os
 import sys
+import threading
 import time
 
 from .i18n import _
@@ -108,6 +109,22 @@
     Profiling is active when the context manager is active. When the context
     manager exits, profiling results will be written to the configured output.
     """
+
+    # Initialize thread-local storage for profiling.
+    if not util.safehasattr(profile, 'threadlocal'):
+        profile.threadlocal = threading.local()
+
+    # Flag attribute will be re-initialized in each new thread.
+    if not util.safehasattr(profile.threadlocal, 'started'):
+        profile.threadlocal.started = False
+
+    # Guard against nested invocations of this context manager within
+    # the same thread. Only the outermost invocation will run.
+    if profile.threadlocal.started:
+        yield
+        return
+    profile.threadlocal.started = True
+
     profiler = os.getenv('HGPROF')
     if profiler is None:
         profiler = ui.config('profiling', 'type', default='ls')
@@ -145,6 +162,7 @@
                 val = val.replace('%', '%%')
                 ui.log('profile', val)
             fp.close()
+        profile.threadlocal.started = False
 
 @contextlib.contextmanager
 def maybeprofile(ui):


More information about the Mercurial-devel mailing list