Patchwork [5,of,7] fileset: roughly adjust weights of functions

login
register
mail settings
Submitter Yuya Nishihara
Date Aug. 3, 2018, 3:01 p.m.
Message ID <1ec115b2c5525f0507ff.1533308502@mimosa>
Download mbox | patch
Permalink /patch/33155/
State Accepted
Headers show

Comments

Yuya Nishihara - Aug. 3, 2018, 3:01 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1532227649 -32400
#      Sun Jul 22 11:47:29 2018 +0900
# Node ID 1ec115b2c5525f0507ff7c4dc2019b57ae391911
# Parent  6c9246c08523616914af131700126cfc408114f7
fileset: roughly adjust weights of functions

... in order to move status predicates far away from basic patterns. I don't
know if each weight is appropriate, but it should be good enough as a start.
Augie Fackler - Aug. 3, 2018, 7:36 p.m.
> On Aug 3, 2018, at 11:01, Yuya Nishihara <yuya@tcha.org> wrote:
> 
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1532227649 -32400
> #      Sun Jul 22 11:47:29 2018 +0900
> # Node ID 1ec115b2c5525f0507ff7c4dc2019b57ae391911
> # Parent  6c9246c08523616914af131700126cfc408114f7
> fileset: roughly adjust weights of functions
> 
> ... in order to move status predicates far away from basic patterns. I don't
> know if each weight is appropriate, but it should be good enough as a start.

Maybe it'd be worth having constants in the fileset module for roughly what we think typical weights are? eg

_WEIGHT_STATUS = 10 # loads dirstate or stats working copy file
_WEIGHT_STATUS_THOROUGH = 50 # might have to enumerate ignored files/dirs
_WEIGHT_READ_CONTENTS = 30 # reads the contents of a file
_WEIGHT_CHECK_FILENAME=0.5 # only examines a filename

(I see you have a comment for that, but maybe even using named constants would be better?)

Love the series, btw, good stuff.

Patch

diff --git a/mercurial/fileset.py b/mercurial/fileset.py
--- a/mercurial/fileset.py
+++ b/mercurial/fileset.py
@@ -88,7 +88,7 @@  symbols = filesetlang.symbols
 
 predicate = registrar.filesetpredicate()
 
-@predicate('modified()', callstatus=True)
+@predicate('modified()', callstatus=True, weight=10)
 def modified(mctx, x):
     """File that is modified according to :hg:`status`.
     """
@@ -97,7 +97,7 @@  def modified(mctx, x):
     s = set(mctx.status().modified)
     return mctx.predicate(s.__contains__, predrepr='modified')
 
-@predicate('added()', callstatus=True)
+@predicate('added()', callstatus=True, weight=10)
 def added(mctx, x):
     """File that is added according to :hg:`status`.
     """
@@ -106,7 +106,7 @@  def added(mctx, x):
     s = set(mctx.status().added)
     return mctx.predicate(s.__contains__, predrepr='added')
 
-@predicate('removed()', callstatus=True)
+@predicate('removed()', callstatus=True, weight=10)
 def removed(mctx, x):
     """File that is removed according to :hg:`status`.
     """
@@ -115,7 +115,7 @@  def removed(mctx, x):
     s = set(mctx.status().removed)
     return mctx.predicate(s.__contains__, predrepr='removed')
 
-@predicate('deleted()', callstatus=True)
+@predicate('deleted()', callstatus=True, weight=10)
 def deleted(mctx, x):
     """Alias for ``missing()``.
     """
@@ -124,7 +124,7 @@  def deleted(mctx, x):
     s = set(mctx.status().deleted)
     return mctx.predicate(s.__contains__, predrepr='deleted')
 
-@predicate('missing()', callstatus=True)
+@predicate('missing()', callstatus=True, weight=10)
 def missing(mctx, x):
     """File that is missing according to :hg:`status`.
     """
@@ -133,7 +133,7 @@  def missing(mctx, x):
     s = set(mctx.status().deleted)
     return mctx.predicate(s.__contains__, predrepr='deleted')
 
-@predicate('unknown()', callstatus=True)
+@predicate('unknown()', callstatus=True, weight=50)
 def unknown(mctx, x):
     """File that is unknown according to :hg:`status`."""
     # i18n: "unknown" is a keyword
@@ -141,7 +141,7 @@  def unknown(mctx, x):
     s = set(mctx.status().unknown)
     return mctx.predicate(s.__contains__, predrepr='unknown')
 
-@predicate('ignored()', callstatus=True)
+@predicate('ignored()', callstatus=True, weight=50)
 def ignored(mctx, x):
     """File that is ignored according to :hg:`status`."""
     # i18n: "ignored" is a keyword
@@ -149,7 +149,7 @@  def ignored(mctx, x):
     s = set(mctx.status().ignored)
     return mctx.predicate(s.__contains__, predrepr='ignored')
 
-@predicate('clean()', callstatus=True)
+@predicate('clean()', callstatus=True, weight=10)
 def clean(mctx, x):
     """File that is clean according to :hg:`status`.
     """
@@ -165,7 +165,7 @@  def tracked(mctx, x):
     getargs(x, 0, 0, _("tracked takes no arguments"))
     return mctx.predicate(mctx.ctx.__contains__, predrepr='tracked')
 
-@predicate('binary()')
+@predicate('binary()', weight=30)
 def binary(mctx, x):
     """File that appears to be binary (contains NUL bytes).
     """
@@ -192,7 +192,7 @@  def symlink(mctx, x):
     ctx = mctx.ctx
     return mctx.predicate(lambda f: ctx.flags(f) == 'l', predrepr='symlink')
 
-@predicate('resolved()')
+@predicate('resolved()', weight=10)
 def resolved(mctx, x):
     """File that is marked resolved according to :hg:`resolve -l`.
     """
@@ -204,7 +204,7 @@  def resolved(mctx, x):
     return mctx.predicate(lambda f: f in ms and ms[f] == 'r',
                           predrepr='resolved')
 
-@predicate('unresolved()')
+@predicate('unresolved()', weight=10)
 def unresolved(mctx, x):
     """File that is marked unresolved according to :hg:`resolve -l`.
     """
@@ -216,7 +216,7 @@  def unresolved(mctx, x):
     return mctx.predicate(lambda f: f in ms and ms[f] == 'u',
                           predrepr='unresolved')
 
-@predicate('hgignore()')
+@predicate('hgignore()', weight=10)
 def hgignore(mctx, x):
     """File that matches the active .hgignore pattern.
     """
@@ -224,7 +224,7 @@  def hgignore(mctx, x):
     getargs(x, 0, 0, _("hgignore takes no arguments"))
     return mctx.ctx.repo().dirstate._ignore
 
-@predicate('portable()')
+@predicate('portable()', weight=0.5)
 def portable(mctx, x):
     """File that has a portable name. (This doesn't include filenames with case
     collisions.)
@@ -234,7 +234,7 @@  def portable(mctx, x):
     return mctx.predicate(lambda f: util.checkwinfilename(f) is None,
                           predrepr='portable')
 
-@predicate('grep(regex)')
+@predicate('grep(regex)', weight=30)
 def grep(mctx, x):
     """File contains the given regular expression.
     """
@@ -288,7 +288,7 @@  def sizematcher(expr):
         b = _sizetomax(expr)
         return lambda x: x >= a and x <= b
 
-@predicate('size(expression)')
+@predicate('size(expression)', weight=10)
 def size(mctx, x):
     """File size matches the given expression. Examples:
 
@@ -303,7 +303,7 @@  def size(mctx, x):
     return mctx.fpredicate(lambda fctx: m(fctx.size()),
                            predrepr=('size(%r)', expr), cache=True)
 
-@predicate('encoding(name)')
+@predicate('encoding(name)', weight=30)
 def encoding(mctx, x):
     """File can be successfully decoded with the given character
     encoding. May not be useful for encodings other than ASCII and
@@ -325,7 +325,7 @@  def encoding(mctx, x):
 
     return mctx.fpredicate(encp, predrepr=('encoding(%r)', enc), cache=True)
 
-@predicate('eol(style)')
+@predicate('eol(style)', weight=30)
 def eol(mctx, x):
     """File contains newlines of the given style (dos, unix, mac). Binary
     files are excluded, files with mixed line endings match multiple
@@ -359,7 +359,7 @@  def copied(mctx, x):
         return p and p[0].path() != fctx.path()
     return mctx.fpredicate(copiedp, predrepr='copied', cache=True)
 
-@predicate('revs(revs, pattern)')
+@predicate('revs(revs, pattern)', weight=10)
 def revs(mctx, x):
     """Evaluate set in the specified revisions. If the revset match multiple
     revs, this will return file matching pattern in any of the revision.
@@ -381,7 +381,7 @@  def revs(mctx, x):
         return matchers[0]
     return matchmod.unionmatcher(matchers)
 
-@predicate('status(base, rev, pattern)')
+@predicate('status(base, rev, pattern)', weight=10)
 def status(mctx, x):
     """Evaluate predicate using status change between ``base`` and
     ``rev``. Examples:
diff --git a/mercurial/registrar.py b/mercurial/registrar.py
--- a/mercurial/registrar.py
+++ b/mercurial/registrar.py
@@ -250,6 +250,15 @@  class filesetpredicate(_funcregistrarbas
     Optional argument 'weight' indicates the estimated run-time cost, useful
     for static optimization, default is 1. Higher weight means more expensive.
 
+    ====== =============================================================
+    Weight Description and examples
+    ====== =============================================================
+    0.5    basic match patterns (e.g. a symbol)
+    10     computing status (e.g. added()) or accessing a few files
+    30     reading file content for each (e.g. grep())
+    50     scanning working directory (ignored())
+    ====== =============================================================
+
     'filesetpredicate' instance in example above can be used to
     decorate multiple functions.