Patchwork [2,of,2] dispatch: start profiling earlier

login
register
mail settings
Submitter Bryan O'Sullivan
Date Feb. 14, 2017, 4:50 a.m.
Message ID <fa6f486c80910c2a3ce6.1487047811@bryano-mbp.local>
Download mbox | patch
Permalink /patch/18466/
State Accepted
Headers show

Comments

Bryan O'Sullivan - Feb. 14, 2017, 4:50 a.m.
# HG changeset patch
# User Bryan O'Sullivan <bryano@fb.com>
# Date 1487047661 28800
#      Mon Feb 13 20:47:41 2017 -0800
# Node ID fa6f486c80910c2a3ce6df58be0b8e616f2ae679
# Parent  82467bdb090b2500a97ae92e239bcdf72974f3f7
dispatch: start profiling earlier

This makes it possible to profile extension loading and setup, which
takes a substantial fraction of overall execution time for fast
commands.

(99% of this commit is simply changes of indentation to reflect the
hoisting of the two calls to maybeprofile to a single one that
happens earlier.)
Augie Fackler - Feb. 14, 2017, 3:45 p.m.
On Mon, Feb 13, 2017 at 08:50:11PM -0800, Bryan O'Sullivan wrote:
> # HG changeset patch
> # User Bryan O'Sullivan <bryano@fb.com>
> # Date 1487047661 28800
> #      Mon Feb 13 20:47:41 2017 -0800
> # Node ID fa6f486c80910c2a3ce6df58be0b8e616f2ae679
> # Parent  82467bdb090b2500a97ae92e239bcdf72974f3f7
> dispatch: start profiling earlier

Queued these, many thanks.

>
> This makes it possible to profile extension loading and setup, which
> takes a substantial fraction of overall execution time for fast
> commands.
>
> (99% of this commit is simply changes of indentation to reflect the
> hoisting of the two calls to maybeprofile to a single one that
> happens earlier.)
>
> diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
> --- a/mercurial/dispatch.py
> +++ b/mercurial/dispatch.py
> @@ -664,98 +664,97 @@ def _dispatch(req):
>          for ui_ in uis:
>              ui_.setconfig('profiling', 'enabled', 'true', '--profile')
>
> -    # Configure extensions in phases: uisetup, extsetup, cmdtable, and
> -    # reposetup. Programs like TortoiseHg will call _dispatch several
> -    # times so we keep track of configured extensions in _loaded.
> -    extensions.loadall(lui)
> -    exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
> -    # Propagate any changes to lui.__class__ by extensions
> -    ui.__class__ = lui.__class__
> +    with profiling.maybeprofile(lui):
> +        # Configure extensions in phases: uisetup, extsetup, cmdtable, and
> +        # reposetup. Programs like TortoiseHg will call _dispatch several
> +        # times so we keep track of configured extensions in _loaded.
> +        extensions.loadall(lui)
> +        exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
> +        # Propagate any changes to lui.__class__ by extensions
> +        ui.__class__ = lui.__class__
>
> -    # (uisetup and extsetup are handled in extensions.loadall)
> +        # (uisetup and extsetup are handled in extensions.loadall)
>
> -    for name, module in exts:
> -        for objname, loadermod, loadername in extraloaders:
> -            extraobj = getattr(module, objname, None)
> -            if extraobj is not None:
> -                getattr(loadermod, loadername)(ui, name, extraobj)
> -        _loaded.add(name)
> +        for name, module in exts:
> +            for objname, loadermod, loadername in extraloaders:
> +                extraobj = getattr(module, objname, None)
> +                if extraobj is not None:
> +                    getattr(loadermod, loadername)(ui, name, extraobj)
> +            _loaded.add(name)
>
> -    # (reposetup is handled in hg.repository)
> +        # (reposetup is handled in hg.repository)
>
> -    # Side-effect of accessing is debugcommands module is guaranteed to be
> -    # imported and commands.table is populated.
> -    debugcommands.command
> -
> -    addaliases(lui, commands.table)
> +        # Side-effect of accessing is debugcommands module is guaranteed to be
> +        # imported and commands.table is populated.
> +        debugcommands.command
>
> -    # All aliases and commands are completely defined, now.
> -    # Check abbreviation/ambiguity of shell alias.
> -    shellaliasfn = _checkshellalias(lui, ui, args)
> -    if shellaliasfn:
> -        with profiling.maybeprofile(lui):
> +        addaliases(lui, commands.table)
> +
> +        # All aliases and commands are completely defined, now.
> +        # Check abbreviation/ambiguity of shell alias.
> +        shellaliasfn = _checkshellalias(lui, ui, args)
> +        if shellaliasfn:
>              return shellaliasfn()
>
> -    # check for fallback encoding
> -    fallback = lui.config('ui', 'fallbackencoding')
> -    if fallback:
> -        encoding.fallbackencoding = fallback
> +        # check for fallback encoding
> +        fallback = lui.config('ui', 'fallbackencoding')
> +        if fallback:
> +            encoding.fallbackencoding = fallback
>
> -    fullargs = args
> -    cmd, func, args, options, cmdoptions = _parse(lui, args)
> +        fullargs = args
> +        cmd, func, args, options, cmdoptions = _parse(lui, args)
>
> -    if options["config"]:
> -        raise error.Abort(_("option --config may not be abbreviated!"))
> -    if options["cwd"]:
> -        raise error.Abort(_("option --cwd may not be abbreviated!"))
> -    if options["repository"]:
> -        raise error.Abort(_(
> -            "option -R has to be separated from other options (e.g. not -qR) "
> -            "and --repository may only be abbreviated as --repo!"))
> +        if options["config"]:
> +            raise error.Abort(_("option --config may not be abbreviated!"))
> +        if options["cwd"]:
> +            raise error.Abort(_("option --cwd may not be abbreviated!"))
> +        if options["repository"]:
> +            raise error.Abort(_(
> +                "option -R has to be separated from other options (e.g. not -qR) "
> +                "and --repository may only be abbreviated as --repo!"))
>
> -    if options["encoding"]:
> -        encoding.encoding = options["encoding"]
> -    if options["encodingmode"]:
> -        encoding.encodingmode = options["encodingmode"]
> -    if options["time"]:
> -        def get_times():
> -            t = os.times()
> -            if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
> -                t = (t[0], t[1], t[2], t[3], time.clock())
> -            return t
> -        s = get_times()
> -        def print_time():
> -            t = get_times()
> -            ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
> -                (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
> -        atexit.register(print_time)
> +        if options["encoding"]:
> +            encoding.encoding = options["encoding"]
> +        if options["encodingmode"]:
> +            encoding.encodingmode = options["encodingmode"]
> +        if options["time"]:
> +            def get_times():
> +                t = os.times()
> +                if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
> +                    t = (t[0], t[1], t[2], t[3], time.clock())
> +                return t
> +            s = get_times()
> +            def print_time():
> +                t = get_times()
> +                ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
> +                    (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
> +            atexit.register(print_time)
>
> -    if options['verbose'] or options['debug'] or options['quiet']:
> -        for opt in ('verbose', 'debug', 'quiet'):
> -            val = str(bool(options[opt]))
> +        if options['verbose'] or options['debug'] or options['quiet']:
> +            for opt in ('verbose', 'debug', 'quiet'):
> +                val = str(bool(options[opt]))
> +                for ui_ in uis:
> +                    ui_.setconfig('ui', opt, val, '--' + opt)
> +
> +        if options['traceback']:
>              for ui_ in uis:
> -                ui_.setconfig('ui', opt, val, '--' + opt)
> +                ui_.setconfig('ui', 'traceback', 'on', '--traceback')
>
> -    if options['traceback']:
> -        for ui_ in uis:
> -            ui_.setconfig('ui', 'traceback', 'on', '--traceback')
> -
> -    if options['noninteractive']:
> -        for ui_ in uis:
> -            ui_.setconfig('ui', 'interactive', 'off', '-y')
> +        if options['noninteractive']:
> +            for ui_ in uis:
> +                ui_.setconfig('ui', 'interactive', 'off', '-y')
>
> -    if cmdoptions.get('insecure', False):
> -        for ui_ in uis:
> -            ui_.insecureconnections = True
> +        if cmdoptions.get('insecure', False):
> +            for ui_ in uis:
> +                ui_.insecureconnections = True
>
> -    if options['version']:
> -        return commands.version_(ui)
> -    if options['help']:
> -        return commands.help_(ui, cmd, command=cmd is not None)
> -    elif not cmd:
> -        return commands.help_(ui, 'shortlist')
> +        if options['version']:
> +            return commands.version_(ui)
> +        if options['help']:
> +            return commands.help_(ui, cmd, command=cmd is not None)
> +        elif not cmd:
> +            return commands.help_(ui, 'shortlist')
>
> -    with profiling.maybeprofile(lui):
>          repo = None
>          cmdpats = args[:]
>          if not func.norepo:
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Patch

diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -664,98 +664,97 @@  def _dispatch(req):
         for ui_ in uis:
             ui_.setconfig('profiling', 'enabled', 'true', '--profile')
 
-    # Configure extensions in phases: uisetup, extsetup, cmdtable, and
-    # reposetup. Programs like TortoiseHg will call _dispatch several
-    # times so we keep track of configured extensions in _loaded.
-    extensions.loadall(lui)
-    exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
-    # Propagate any changes to lui.__class__ by extensions
-    ui.__class__ = lui.__class__
+    with profiling.maybeprofile(lui):
+        # Configure extensions in phases: uisetup, extsetup, cmdtable, and
+        # reposetup. Programs like TortoiseHg will call _dispatch several
+        # times so we keep track of configured extensions in _loaded.
+        extensions.loadall(lui)
+        exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
+        # Propagate any changes to lui.__class__ by extensions
+        ui.__class__ = lui.__class__
 
-    # (uisetup and extsetup are handled in extensions.loadall)
+        # (uisetup and extsetup are handled in extensions.loadall)
 
-    for name, module in exts:
-        for objname, loadermod, loadername in extraloaders:
-            extraobj = getattr(module, objname, None)
-            if extraobj is not None:
-                getattr(loadermod, loadername)(ui, name, extraobj)
-        _loaded.add(name)
+        for name, module in exts:
+            for objname, loadermod, loadername in extraloaders:
+                extraobj = getattr(module, objname, None)
+                if extraobj is not None:
+                    getattr(loadermod, loadername)(ui, name, extraobj)
+            _loaded.add(name)
 
-    # (reposetup is handled in hg.repository)
+        # (reposetup is handled in hg.repository)
 
-    # Side-effect of accessing is debugcommands module is guaranteed to be
-    # imported and commands.table is populated.
-    debugcommands.command
-
-    addaliases(lui, commands.table)
+        # Side-effect of accessing is debugcommands module is guaranteed to be
+        # imported and commands.table is populated.
+        debugcommands.command
 
-    # All aliases and commands are completely defined, now.
-    # Check abbreviation/ambiguity of shell alias.
-    shellaliasfn = _checkshellalias(lui, ui, args)
-    if shellaliasfn:
-        with profiling.maybeprofile(lui):
+        addaliases(lui, commands.table)
+
+        # All aliases and commands are completely defined, now.
+        # Check abbreviation/ambiguity of shell alias.
+        shellaliasfn = _checkshellalias(lui, ui, args)
+        if shellaliasfn:
             return shellaliasfn()
 
-    # check for fallback encoding
-    fallback = lui.config('ui', 'fallbackencoding')
-    if fallback:
-        encoding.fallbackencoding = fallback
+        # check for fallback encoding
+        fallback = lui.config('ui', 'fallbackencoding')
+        if fallback:
+            encoding.fallbackencoding = fallback
 
-    fullargs = args
-    cmd, func, args, options, cmdoptions = _parse(lui, args)
+        fullargs = args
+        cmd, func, args, options, cmdoptions = _parse(lui, args)
 
-    if options["config"]:
-        raise error.Abort(_("option --config may not be abbreviated!"))
-    if options["cwd"]:
-        raise error.Abort(_("option --cwd may not be abbreviated!"))
-    if options["repository"]:
-        raise error.Abort(_(
-            "option -R has to be separated from other options (e.g. not -qR) "
-            "and --repository may only be abbreviated as --repo!"))
+        if options["config"]:
+            raise error.Abort(_("option --config may not be abbreviated!"))
+        if options["cwd"]:
+            raise error.Abort(_("option --cwd may not be abbreviated!"))
+        if options["repository"]:
+            raise error.Abort(_(
+                "option -R has to be separated from other options (e.g. not -qR) "
+                "and --repository may only be abbreviated as --repo!"))
 
-    if options["encoding"]:
-        encoding.encoding = options["encoding"]
-    if options["encodingmode"]:
-        encoding.encodingmode = options["encodingmode"]
-    if options["time"]:
-        def get_times():
-            t = os.times()
-            if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
-                t = (t[0], t[1], t[2], t[3], time.clock())
-            return t
-        s = get_times()
-        def print_time():
-            t = get_times()
-            ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
-                (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
-        atexit.register(print_time)
+        if options["encoding"]:
+            encoding.encoding = options["encoding"]
+        if options["encodingmode"]:
+            encoding.encodingmode = options["encodingmode"]
+        if options["time"]:
+            def get_times():
+                t = os.times()
+                if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
+                    t = (t[0], t[1], t[2], t[3], time.clock())
+                return t
+            s = get_times()
+            def print_time():
+                t = get_times()
+                ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
+                    (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
+            atexit.register(print_time)
 
-    if options['verbose'] or options['debug'] or options['quiet']:
-        for opt in ('verbose', 'debug', 'quiet'):
-            val = str(bool(options[opt]))
+        if options['verbose'] or options['debug'] or options['quiet']:
+            for opt in ('verbose', 'debug', 'quiet'):
+                val = str(bool(options[opt]))
+                for ui_ in uis:
+                    ui_.setconfig('ui', opt, val, '--' + opt)
+
+        if options['traceback']:
             for ui_ in uis:
-                ui_.setconfig('ui', opt, val, '--' + opt)
+                ui_.setconfig('ui', 'traceback', 'on', '--traceback')
 
-    if options['traceback']:
-        for ui_ in uis:
-            ui_.setconfig('ui', 'traceback', 'on', '--traceback')
-
-    if options['noninteractive']:
-        for ui_ in uis:
-            ui_.setconfig('ui', 'interactive', 'off', '-y')
+        if options['noninteractive']:
+            for ui_ in uis:
+                ui_.setconfig('ui', 'interactive', 'off', '-y')
 
-    if cmdoptions.get('insecure', False):
-        for ui_ in uis:
-            ui_.insecureconnections = True
+        if cmdoptions.get('insecure', False):
+            for ui_ in uis:
+                ui_.insecureconnections = True
 
-    if options['version']:
-        return commands.version_(ui)
-    if options['help']:
-        return commands.help_(ui, cmd, command=cmd is not None)
-    elif not cmd:
-        return commands.help_(ui, 'shortlist')
+        if options['version']:
+            return commands.version_(ui)
+        if options['help']:
+            return commands.help_(ui, cmd, command=cmd is not None)
+        elif not cmd:
+            return commands.help_(ui, 'shortlist')
 
-    with profiling.maybeprofile(lui):
         repo = None
         cmdpats = args[:]
         if not func.norepo: