Patchwork nogc: do disable gc for CPython

login
register
mail settings
Submitter Jun Wu
Date May 23, 2017, 8:20 p.m.
Message ID <66dc3a3b4631507fed3e.1495570800@x1c>
Download mbox | patch
Permalink /patch/20871/
State Changes Requested
Headers show

Comments

Jun Wu - May 23, 2017, 8:20 p.m.
# HG changeset patch
# User Jun Wu <quark@fb.com>
# Date 1495570793 25200
#      Tue May 23 13:19:53 2017 -0700
# Node ID 66dc3a3b4631507fed3ea7fd2fa3e3356ea820fe
# Parent  34e9b8b94f66db7ebe366f67cea7b64bd0ec6968
# Available At https://bitbucket.org/quark-zju/hg-draft
#              hg pull https://bitbucket.org/quark-zju/hg-draft -r 66dc3a3b4631
nogc: do disable gc for CPython

279cd8 makes util.nogc a no-op for Python >= 2.7. That's actually hurting
performance. For example, _fm1readmarkers takes 70ms with gc disabled, 190ms
with gc enabled.

This patch makes util.nogc effective for CPython and only a no-op for PyPy.
Gregory Szorc - May 24, 2017, 1:03 a.m.
On Tue, May 23, 2017 at 1:20 PM, Jun Wu <quark@fb.com> wrote:

> # HG changeset patch
> # User Jun Wu <quark@fb.com>
> # Date 1495570793 25200
> #      Tue May 23 13:19:53 2017 -0700
> # Node ID 66dc3a3b4631507fed3ea7fd2fa3e3356ea820fe
> # Parent  34e9b8b94f66db7ebe366f67cea7b64bd0ec6968
> # Available At https://bitbucket.org/quark-zju/hg-draft
> #              hg pull https://bitbucket.org/quark-zju/hg-draft -r
> 66dc3a3b4631
> nogc: do disable gc for CPython
>
> 279cd8 makes util.nogc a no-op for Python >= 2.7. That's actually hurting
> performance. For example, _fm1readmarkers takes 70ms with gc disabled,
> 190ms
> with gc enabled.
>
> This patch makes util.nogc effective for CPython and only a no-op for PyPy.
>
> diff --git a/mercurial/util.py b/mercurial/util.py
> --- a/mercurial/util.py
> +++ b/mercurial/util.py
> @@ -910,9 +910,5 @@ def nogc(func):
>      into. As a workaround, disable GC while building complex (huge)
>      containers.
> -
> -    This garbage collector issue have been fixed in 2.7.
>      """
> -    if sys.version_info >= (2, 7):
> -        return func
>      def wrapper(*args, **kwargs):
>          gcenabled = gc.isenabled()
> @@ -925,4 +921,9 @@ def nogc(func):
>      return wrapper
>
> +if pyplatform.python_implementation() != 'CPython':
> +    # PyPy becomes slower with gc disabled
>

Since this patch sounds like it has more to do with PyPy, then
implementation should check for =pypy, not !=cpython. Other than that, I'm
fine keeping the GC in place on PyPy, as its JIT should mitigate impact
from garbage spewing code.

Also, regarding this whole no gc concept, I'll argue that any operation
needing to disable GC should be implemented in C in such a way that it
isn't instantiating thousands of CPython objects. So many of our C routines
are relatively slow (revlog index, obsmarkers, dag walking, etc) because
they operate on PyObject instead of raw C data structures. If we remove
PyObject from critical path code, we eliminate most GC concerns and likely
make execution at *least* 5x faster.


> +    def nogc(func):
> +        return func
> +
>  def pathto(root, n1, n2):
>      '''return the relative path from one place to another.
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
Yuya Nishihara - May 24, 2017, 3:30 p.m.
On Tue, 23 May 2017 18:03:53 -0700, Gregory Szorc wrote:
> On Tue, May 23, 2017 at 1:20 PM, Jun Wu <quark@fb.com> wrote:
> > # HG changeset patch
> > # User Jun Wu <quark@fb.com>
> > # Date 1495570793 25200
> > #      Tue May 23 13:19:53 2017 -0700
> > # Node ID 66dc3a3b4631507fed3ea7fd2fa3e3356ea820fe
> > # Parent  34e9b8b94f66db7ebe366f67cea7b64bd0ec6968
> > # Available At https://bitbucket.org/quark-zju/hg-draft
> > #              hg pull https://bitbucket.org/quark-zju/hg-draft -r
> > 66dc3a3b4631
> > nogc: do disable gc for CPython
> >
> > 279cd8 makes util.nogc a no-op for Python >= 2.7. That's actually hurting
> > performance. For example, _fm1readmarkers takes 70ms with gc disabled,
> > 190ms
> > with gc enabled.
> >
> > This patch makes util.nogc effective for CPython and only a no-op for PyPy.
> >
> > diff --git a/mercurial/util.py b/mercurial/util.py
> > --- a/mercurial/util.py
> > +++ b/mercurial/util.py
> > @@ -910,9 +910,5 @@ def nogc(func):
> >      into. As a workaround, disable GC while building complex (huge)
> >      containers.
> > -
> > -    This garbage collector issue have been fixed in 2.7.
> >      """
> > -    if sys.version_info >= (2, 7):
> > -        return func
> >      def wrapper(*args, **kwargs):
> >          gcenabled = gc.isenabled()
> > @@ -925,4 +921,9 @@ def nogc(func):
> >      return wrapper
> >
> > +if pyplatform.python_implementation() != 'CPython':
> > +    # PyPy becomes slower with gc disabled
> >
> 
> Since this patch sounds like it has more to do with PyPy, then
> implementation should check for =pypy, not !=cpython. Other than that, I'm
> fine keeping the GC in place on PyPy, as its JIT should mitigate impact
> from garbage spewing code.
> 
> Also, regarding this whole no gc concept, I'll argue that any operation
> needing to disable GC should be implemented in C in such a way that it
> isn't instantiating thousands of CPython objects.

Last time I tested fm1readmarkers() of C extension, I didn't see noticeable
difference with/without GC (though I just checked wall clock.) So I suspect
the perf result depends on system, size of obsstore, etc.

> So many of our C routines
> are relatively slow (revlog index, obsmarkers, dag walking, etc) because
> they operate on PyObject instead of raw C data structures. If we remove
> PyObject from critical path code, we eliminate most GC concerns and likely
> make execution at *least* 5x faster.

That's true for obsmarkers, but IIRC revlog index doesn't create a boxed
object until it is accessed.
Gregory Szorc - May 24, 2017, 3:52 p.m.
On Wed, May 24, 2017 at 8:30 AM, Yuya Nishihara <yuya@tcha.org> wrote:

> On Tue, 23 May 2017 18:03:53 -0700, Gregory Szorc wrote:
> > On Tue, May 23, 2017 at 1:20 PM, Jun Wu <quark@fb.com> wrote:
> > > # HG changeset patch
> > > # User Jun Wu <quark@fb.com>
> > > # Date 1495570793 25200
> > > #      Tue May 23 13:19:53 2017 -0700
> > > # Node ID 66dc3a3b4631507fed3ea7fd2fa3e3356ea820fe
> > > # Parent  34e9b8b94f66db7ebe366f67cea7b64bd0ec6968
> > > # Available At https://bitbucket.org/quark-zju/hg-draft
> > > #              hg pull https://bitbucket.org/quark-zju/hg-draft -r
> > > 66dc3a3b4631
> > > nogc: do disable gc for CPython
> > >
> > > 279cd8 makes util.nogc a no-op for Python >= 2.7. That's actually
> hurting
> > > performance. For example, _fm1readmarkers takes 70ms with gc disabled,
> > > 190ms
> > > with gc enabled.
> > >
> > > This patch makes util.nogc effective for CPython and only a no-op for
> PyPy.
> > >
> > > diff --git a/mercurial/util.py b/mercurial/util.py
> > > --- a/mercurial/util.py
> > > +++ b/mercurial/util.py
> > > @@ -910,9 +910,5 @@ def nogc(func):
> > >      into. As a workaround, disable GC while building complex (huge)
> > >      containers.
> > > -
> > > -    This garbage collector issue have been fixed in 2.7.
> > >      """
> > > -    if sys.version_info >= (2, 7):
> > > -        return func
> > >      def wrapper(*args, **kwargs):
> > >          gcenabled = gc.isenabled()
> > > @@ -925,4 +921,9 @@ def nogc(func):
> > >      return wrapper
> > >
> > > +if pyplatform.python_implementation() != 'CPython':
> > > +    # PyPy becomes slower with gc disabled
> > >
> >
> > Since this patch sounds like it has more to do with PyPy, then
> > implementation should check for =pypy, not !=cpython. Other than that,
> I'm
> > fine keeping the GC in place on PyPy, as its JIT should mitigate impact
> > from garbage spewing code.
> >
> > Also, regarding this whole no gc concept, I'll argue that any operation
> > needing to disable GC should be implemented in C in such a way that it
> > isn't instantiating thousands of CPython objects.
>
> Last time I tested fm1readmarkers() of C extension, I didn't see noticeable
> difference with/without GC (though I just checked wall clock.) So I suspect
> the perf result depends on system, size of obsstore, etc.
>
> > So many of our C routines
> > are relatively slow (revlog index, obsmarkers, dag walking, etc) because
> > they operate on PyObject instead of raw C data structures. If we remove
> > PyObject from critical path code, we eliminate most GC concerns and
> likely
> > make execution at *least* 5x faster.
>
> That's true for obsmarkers, but IIRC revlog index doesn't create a boxed
> object until it is accessed.
>

That is true. And it is smart enough to reuse the PyObject on subsequent
access. However, many things realize PyObject when they don't need to. For
example, when calling revlog.revision(), one has to determine the delta
chain and start and end offsets for each revision. This requires
constructing the index entry tuples (which consist of 9 PyObject - the
tuple and its 8 members). For a delta chain of 10,000 (not uncommon for
manifests on large repos), you've created 90,000+ PyObjects! A better
solution is to implement these critical functions in !Python and/or pass
around arrays of "packed" data so we only realize the Python objects on
demand.
Yuya Nishihara - May 24, 2017, 4:11 p.m.
On Wed, 24 May 2017 08:52:24 -0700, Gregory Szorc wrote:
> On Wed, May 24, 2017 at 8:30 AM, Yuya Nishihara <yuya@tcha.org> wrote:
> 
> > On Tue, 23 May 2017 18:03:53 -0700, Gregory Szorc wrote:
> > > On Tue, May 23, 2017 at 1:20 PM, Jun Wu <quark@fb.com> wrote:
> > > > # HG changeset patch
> > > > # User Jun Wu <quark@fb.com>
> > > > # Date 1495570793 25200
> > > > #      Tue May 23 13:19:53 2017 -0700
> > > > # Node ID 66dc3a3b4631507fed3ea7fd2fa3e3356ea820fe
> > > > # Parent  34e9b8b94f66db7ebe366f67cea7b64bd0ec6968
> > > > # Available At https://bitbucket.org/quark-zju/hg-draft
> > > > #              hg pull https://bitbucket.org/quark-zju/hg-draft -r
> > > > 66dc3a3b4631
> > > > nogc: do disable gc for CPython
> > > >
> > > > 279cd8 makes util.nogc a no-op for Python >= 2.7. That's actually
> > hurting
> > > > performance. For example, _fm1readmarkers takes 70ms with gc disabled,
> > > > 190ms
> > > > with gc enabled.
> > > >
> > > > This patch makes util.nogc effective for CPython and only a no-op for
> > PyPy.
> > > >
> > > > diff --git a/mercurial/util.py b/mercurial/util.py
> > > > --- a/mercurial/util.py
> > > > +++ b/mercurial/util.py
> > > > @@ -910,9 +910,5 @@ def nogc(func):
> > > >      into. As a workaround, disable GC while building complex (huge)
> > > >      containers.
> > > > -
> > > > -    This garbage collector issue have been fixed in 2.7.
> > > >      """
> > > > -    if sys.version_info >= (2, 7):
> > > > -        return func
> > > >      def wrapper(*args, **kwargs):
> > > >          gcenabled = gc.isenabled()
> > > > @@ -925,4 +921,9 @@ def nogc(func):
> > > >      return wrapper
> > > >
> > > > +if pyplatform.python_implementation() != 'CPython':
> > > > +    # PyPy becomes slower with gc disabled
> > > >
> > >
> > > Since this patch sounds like it has more to do with PyPy, then
> > > implementation should check for =pypy, not !=cpython. Other than that,
> > I'm
> > > fine keeping the GC in place on PyPy, as its JIT should mitigate impact
> > > from garbage spewing code.
> > >
> > > Also, regarding this whole no gc concept, I'll argue that any operation
> > > needing to disable GC should be implemented in C in such a way that it
> > > isn't instantiating thousands of CPython objects.
> >
> > Last time I tested fm1readmarkers() of C extension, I didn't see noticeable
> > difference with/without GC (though I just checked wall clock.) So I suspect
> > the perf result depends on system, size of obsstore, etc.
> >
> > > So many of our C routines
> > > are relatively slow (revlog index, obsmarkers, dag walking, etc) because
> > > they operate on PyObject instead of raw C data structures. If we remove
> > > PyObject from critical path code, we eliminate most GC concerns and
> > likely
> > > make execution at *least* 5x faster.
> >
> > That's true for obsmarkers, but IIRC revlog index doesn't create a boxed
> > object until it is accessed.
> 
> That is true. And it is smart enough to reuse the PyObject on subsequent
> access. However, many things realize PyObject when they don't need to. For
> example, when calling revlog.revision(), one has to determine the delta
> chain and start and end offsets for each revision. This requires
> constructing the index entry tuples (which consist of 9 PyObject - the
> tuple and its 8 members). For a delta chain of 10,000 (not uncommon for
> manifests on large repos), you've created 90,000+ PyObjects!

Got it, thanks. Maybe the first example could be mitigated by using a dedicated
type backed by C struct (like dirstate tuple), but it would just make the number
of PyObjects to x1/9.

> A better
> solution is to implement these critical functions in !Python and/or pass
> around arrays of "packed" data so we only realize the Python objects on
> demand.

(I read !Python = Rust or anything else that isn't C of CPython. I don't
wanna fix bugs of ref-counting. :)
Gregory Szorc - May 24, 2017, 5:49 p.m.
On Wed, May 24, 2017 at 9:11 AM, Yuya Nishihara <yuya@tcha.org> wrote:

> On Wed, 24 May 2017 08:52:24 -0700, Gregory Szorc wrote:
> > On Wed, May 24, 2017 at 8:30 AM, Yuya Nishihara <yuya@tcha.org> wrote:
> >
> > > On Tue, 23 May 2017 18:03:53 -0700, Gregory Szorc wrote:
> > > > On Tue, May 23, 2017 at 1:20 PM, Jun Wu <quark@fb.com> wrote:
> > > > > # HG changeset patch
> > > > > # User Jun Wu <quark@fb.com>
> > > > > # Date 1495570793 25200
> > > > > #      Tue May 23 13:19:53 2017 -0700
> > > > > # Node ID 66dc3a3b4631507fed3ea7fd2fa3e3356ea820fe
> > > > > # Parent  34e9b8b94f66db7ebe366f67cea7b64bd0ec6968
> > > > > # Available At https://bitbucket.org/quark-zju/hg-draft
> > > > > #              hg pull https://bitbucket.org/quark-zju/hg-draft -r
> > > > > 66dc3a3b4631
> > > > > nogc: do disable gc for CPython
> > > > >
> > > > > 279cd8 makes util.nogc a no-op for Python >= 2.7. That's actually
> > > hurting
> > > > > performance. For example, _fm1readmarkers takes 70ms with gc
> disabled,
> > > > > 190ms
> > > > > with gc enabled.
> > > > >
> > > > > This patch makes util.nogc effective for CPython and only a no-op
> for
> > > PyPy.
> > > > >
> > > > > diff --git a/mercurial/util.py b/mercurial/util.py
> > > > > --- a/mercurial/util.py
> > > > > +++ b/mercurial/util.py
> > > > > @@ -910,9 +910,5 @@ def nogc(func):
> > > > >      into. As a workaround, disable GC while building complex
> (huge)
> > > > >      containers.
> > > > > -
> > > > > -    This garbage collector issue have been fixed in 2.7.
> > > > >      """
> > > > > -    if sys.version_info >= (2, 7):
> > > > > -        return func
> > > > >      def wrapper(*args, **kwargs):
> > > > >          gcenabled = gc.isenabled()
> > > > > @@ -925,4 +921,9 @@ def nogc(func):
> > > > >      return wrapper
> > > > >
> > > > > +if pyplatform.python_implementation() != 'CPython':
> > > > > +    # PyPy becomes slower with gc disabled
> > > > >
> > > >
> > > > Since this patch sounds like it has more to do with PyPy, then
> > > > implementation should check for =pypy, not !=cpython. Other than
> that,
> > > I'm
> > > > fine keeping the GC in place on PyPy, as its JIT should mitigate
> impact
> > > > from garbage spewing code.
> > > >
> > > > Also, regarding this whole no gc concept, I'll argue that any
> operation
> > > > needing to disable GC should be implemented in C in such a way that
> it
> > > > isn't instantiating thousands of CPython objects.
> > >
> > > Last time I tested fm1readmarkers() of C extension, I didn't see
> noticeable
> > > difference with/without GC (though I just checked wall clock.) So I
> suspect
> > > the perf result depends on system, size of obsstore, etc.
> > >
> > > > So many of our C routines
> > > > are relatively slow (revlog index, obsmarkers, dag walking, etc)
> because
> > > > they operate on PyObject instead of raw C data structures. If we
> remove
> > > > PyObject from critical path code, we eliminate most GC concerns and
> > > likely
> > > > make execution at *least* 5x faster.
> > >
> > > That's true for obsmarkers, but IIRC revlog index doesn't create a
> boxed
> > > object until it is accessed.
> >
> > That is true. And it is smart enough to reuse the PyObject on subsequent
> > access. However, many things realize PyObject when they don't need to.
> For
> > example, when calling revlog.revision(), one has to determine the delta
> > chain and start and end offsets for each revision. This requires
> > constructing the index entry tuples (which consist of 9 PyObject - the
> > tuple and its 8 members). For a delta chain of 10,000 (not uncommon for
> > manifests on large repos), you've created 90,000+ PyObjects!
>
> Got it, thanks. Maybe the first example could be mitigated by using a
> dedicated
> type backed by C struct (like dirstate tuple), but it would just make the
> number
> of PyObjects to x1/9.
>

Agreed. I want to convert the index type from a tuple to at least a named
tuple. At the point you have a custom type, it isn't that much work to
instantiate the PyObject members lazily.


>
> > A better
> > solution is to implement these critical functions in !Python and/or pass
> > around arrays of "packed" data so we only realize the Python objects on
> > demand.
>
> (I read !Python = Rust or anything else that isn't C of CPython. I don't
> wanna fix bugs of ref-counting. :)
>
Augie Fackler - May 24, 2017, 8:13 p.m.
On Tue, May 23, 2017 at 06:03:53PM -0700, Gregory Szorc wrote:
> On Tue, May 23, 2017 at 1:20 PM, Jun Wu <quark@fb.com> wrote:
>
> > # HG changeset patch
> > # User Jun Wu <quark@fb.com>
> > # Date 1495570793 25200
> > #      Tue May 23 13:19:53 2017 -0700
> > # Node ID 66dc3a3b4631507fed3ea7fd2fa3e3356ea820fe
> > # Parent  34e9b8b94f66db7ebe366f67cea7b64bd0ec6968
> > # Available At https://bitbucket.org/quark-zju/hg-draft
> > #              hg pull https://bitbucket.org/quark-zju/hg-draft -r
> > 66dc3a3b4631
> > nogc: do disable gc for CPython

[...]

> >
> > +if pyplatform.python_implementation() != 'CPython':
> > +    # PyPy becomes slower with gc disabled
> >
>
> Since this patch sounds like it has more to do with PyPy, then
> implementation should check for =pypy, not !=cpython. Other than that, I'm
> fine keeping the GC in place on PyPy, as its JIT should mitigate impact
> from garbage spewing code.

I agree - this should be cpython-only.

>
> Also, regarding this whole no gc concept, I'll argue that any operation
> needing to disable GC should be implemented in C in such a way that it
> isn't instantiating thousands of CPython objects. So many of our C routines
> are relatively slow (revlog index, obsmarkers, dag walking, etc) because
> they operate on PyObject instead of raw C data structures. If we remove
> PyObject from critical path code, we eliminate most GC concerns and likely
> make execution at *least* 5x faster.

I also concur here - any uses of nogc are things that are ripe for
reworking into C code or something lazy.
Jun Wu - May 24, 2017, 9:07 p.m.
Excerpts from Gregory Szorc's message of 2017-05-23 18:03:53 -0700:
> Since this patch sounds like it has more to do with PyPy, then
> implementation should check for =pypy, not !=cpython. Other than that, I'm
> fine keeping the GC in place on PyPy, as its JIT should mitigate impact
> from garbage spewing code.

I'll change it to PyPy.

> Also, regarding this whole no gc concept, I'll argue that any operation
> needing to disable GC should be implemented in C in such a way that it
> isn't instantiating thousands of CPython objects. So many of our C routines
> are relatively slow (revlog index, obsmarkers, dag walking, etc) because
> they operate on PyObject instead of raw C data structures. If we remove
> PyObject from critical path code, we eliminate most GC concerns and likely
> make execution at *least* 5x faster.

There are multiple ways to solve perf issues. For obsmarkers, building an
index is a time complexity change that reduces O(N) to O(1-ish). It'll
greatly reduce object count. After that, constant time changes (like not
creating Python tuples) may become less important.

Regardless, this nogc stuff is an easy win restoring what we have before
279cd80059.
Augie Fackler - May 24, 2017, 9:32 p.m.
On Wed, May 24, 2017 at 02:07:25PM -0700, Jun Wu wrote:
> Excerpts from Gregory Szorc's message of 2017-05-23 18:03:53 -0700:
> > Since this patch sounds like it has more to do with PyPy, then
> > implementation should check for =pypy, not !=cpython. Other than that, I'm
> > fine keeping the GC in place on PyPy, as its JIT should mitigate impact
> > from garbage spewing code.
>
> I'll change it to PyPy.

Please change it to not-cpython, rather than pypy specifically: I'd
expect our code to be fine in Jython's GC as well.

>
> > Also, regarding this whole no gc concept, I'll argue that any operation
> > needing to disable GC should be implemented in C in such a way that it
> > isn't instantiating thousands of CPython objects. So many of our C routines
> > are relatively slow (revlog index, obsmarkers, dag walking, etc) because
> > they operate on PyObject instead of raw C data structures. If we remove
> > PyObject from critical path code, we eliminate most GC concerns and likely
> > make execution at *least* 5x faster.
>
> There are multiple ways to solve perf issues. For obsmarkers, building an
> index is a time complexity change that reduces O(N) to O(1-ish). It'll
> greatly reduce object count. After that, constant time changes (like not
> creating Python tuples) may become less important.
>
> Regardless, this nogc stuff is an easy win restoring what we have before
> 279cd80059.

Yeah, as a stopgap it seems okay.

> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Jun Wu - May 24, 2017, 9:34 p.m.
Excerpts from Augie Fackler's message of 2017-05-24 17:32:09 -0400:
> On Wed, May 24, 2017 at 02:07:25PM -0700, Jun Wu wrote:
> > Excerpts from Gregory Szorc's message of 2017-05-23 18:03:53 -0700:
> > > Since this patch sounds like it has more to do with PyPy, then
> > > implementation should check for =pypy, not !=cpython. Other than that, I'm
> > > fine keeping the GC in place on PyPy, as its JIT should mitigate impact
> > > from garbage spewing code.
> >
> > I'll change it to PyPy.
> 
> Please change it to not-cpython, rather than pypy specifically: I'd
> expect our code to be fine in Jython's GC as well.

The current patch is not-cpython already.

> [...]
Augie Fackler - May 24, 2017, 9:35 p.m.
> On May 24, 2017, at 17:34, Jun Wu <quark@fb.com> wrote:
> 
> Excerpts from Augie Fackler's message of 2017-05-24 17:32:09 -0400:
>> On Wed, May 24, 2017 at 02:07:25PM -0700, Jun Wu wrote:
>>> Excerpts from Gregory Szorc's message of 2017-05-23 18:03:53 -0700:
>>>> Since this patch sounds like it has more to do with PyPy, then
>>>> implementation should check for =pypy, not !=cpython. Other than that, I'm
>>>> fine keeping the GC in place on PyPy, as its JIT should mitigate impact
>>>> from garbage spewing code.
>>> 
>>> I'll change it to PyPy.
>> 
>> Please change it to not-cpython, rather than pypy specifically: I'd
>> expect our code to be fine in Jython's GC as well.
> 
> The current patch is not-cpython already.

Hm, then I'm confused what this subthread is about. :/

Patch

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -910,9 +910,5 @@  def nogc(func):
     into. As a workaround, disable GC while building complex (huge)
     containers.
-
-    This garbage collector issue have been fixed in 2.7.
     """
-    if sys.version_info >= (2, 7):
-        return func
     def wrapper(*args, **kwargs):
         gcenabled = gc.isenabled()
@@ -925,4 +921,9 @@  def nogc(func):
     return wrapper
 
+if pyplatform.python_implementation() != 'CPython':
+    # PyPy becomes slower with gc disabled
+    def nogc(func):
+        return func
+
 def pathto(root, n1, n2):
     '''return the relative path from one place to another.