annotate tests/fakepatchtime.py @ 26457:7e81305092a0

demandimport: replace more references to _demandmod instances _demandmod instances may be referenced by multiple importing modules. Before this patch, the _demandmod instance only maintained a reference to its first consumer when using the "from X import Y" syntax. This is because we only created a single _demandmod instance (attached to the parent X module). If multiple modules A and B performed "from X import Y", we'd produce a single _demandmod instance "demandmod" with the following references: X.Y = <demandmod> A.Y = <demandmod> B.Y = <demandmod> The locals from the first consumer (A) would be stored in <demandmod1>. When <demandmod1> was loaded, we'd look at the locals for the first consumer and replace the symbol, if necessary. This resulted in state: X.Y = <module> A.Y = <module> B.Y = <demandmod> B's reference to Y wasn't updated and was still using the proxy object because we just didn't record that B had a reference to <demandmod> that needed updating! With this patch, we add support for tracking which modules in addition to the initial importer have a reference to the _demandmod instance and we replace those references at module load time. In the case of posix.py, this fixes an issue where the "encoding" module was being proxied, resulting in hundreds of thousands of __getattribute__ lookups on the _demandmod instance during dirstate operations on mozilla-central, speeding up execution by many milliseconds. There are likely several other operation that benefit from this change as well. The new mechanism isn't perfect: references in locals (not globals) may likely linger. So, if there is an import inside a function and a symbol from that module is used in a hot loop, we could have unwanted overhead from proxying through _demandmod. Non-global imports are discouraged anyway. So hopefully this isn't a big deal in practice. We could potentially deploy a code checker that bans use of attribute lookups of function-level-imported modules inside loops. This deficiency in theory could be avoided by storing the set of globals and locals dicts to update in the _demandmod instance. However, I tried this and it didn't work. One reason is that some globals are _demandmod instances. We could work around this, but it's a bit more work. There also might be other module import foo at play. The solution as implemented is better than what we had and IMO is good enough for the time being. It's worth noting that this sub-optimal behavior was made worse by the introduction of absolute_import and its recommended "from . import X" syntax for importing modules from the "mercurial" package. If we ever wrote performance tests, measuring the amount of module imports and __getattribute__ proxy calls through _demandmod instances would be something I'd have it check.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sun, 04 Oct 2015 11:17:43 -0700
parents a4a41525180c
children f624b0e69105
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
25756
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
1 # extension to emulate invoking 'patch.internalpatch()' at the time
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
2 # specified by '[fakepatchtime] fakenow'
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
3
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
4 from mercurial import extensions, patch as patchmod, util
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
5
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
6 def internalpatch(orig, ui, repo, patchobj, strip,
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
7 prefix='', files=None,
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
8 eolmode='strict', similarity=0):
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
9 if files is None:
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
10 files = set()
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
11 r = orig(ui, repo, patchobj, strip,
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
12 prefix=prefix, files=files,
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
13 eolmode=eolmode, similarity=similarity)
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
14
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
15 fakenow = ui.config('fakepatchtime', 'fakenow')
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
16 if fakenow:
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
17 # parsing 'fakenow' in YYYYmmddHHMM format makes comparison between
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
18 # 'fakenow' value and 'touch -t YYYYmmddHHMM' argument easy
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
19 fakenow = util.parsedate(fakenow, ['%Y%m%d%H%M'])[0]
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
20 for f in files:
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
21 repo.wvfs.utime(f, (fakenow, fakenow))
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
22
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
23 return r
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
24
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
25 def extsetup(ui):
a4a41525180c tests: add extension to emulate invoking internalpatch at the specific time
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents:
diff changeset
26 extensions.wrapfunction(patchmod, 'internalpatch', internalpatch)