#35270: Optimize Model._meta._property_names
-------------------------------------+-------------------------------------
     Reporter:  Adam Johnson         |                    Owner:  Adam
         Type:                       |  Johnson
  Cleanup/optimization               |                   Status:  assigned
    Component:  Database layer       |                  Version:  dev
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  1                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Description changed by Adam Johnson:

Old description:

> Optimize Model._meta._property_names
>
> Continuing my project to optimize the system checks, I found some
> optimizations for `Options._meta._property_names`, which I found to take
> ~4% of the total runtime for checks.
>
> Most of this function’s runtime was being spent running
> `inspect.getattr_static()`. This is not surprising as it
> [https://github.com/python/cpython/blob/9b9e819b5116302cb4e471763feb2764eb17dde8/Lib/inspect.py#L1852
> jumps through many hoops] in order to avoid triggering attribute access.
>
> I added use of `getattr_static()` back in #28269 /
> ed244199c72f5bbf33ab4547e06e69873d7271d0 to fix a bug with instance
> descriptors. But I think it’s overly cautious, and we can assume that
> accessing the `__dict__` of the model class will work fine.
>
> Two optimizations make the function run in negligible time:
>
> 1. Changing the function to use  `__dict__` directly
> 2. Caching on a per-class basis. This requires using a weak-reference to
> classes, as we shouldn’t mutate base classes in the MRO, some of which
> can be non-model subclasses, like `Model` itself for the `pk` property,
> `object`, or any mixins.
>
> Before optimization stats:
>
> 106 calls to `_property_names` took 26ms, or ~4% of the total runtime of
> system checks.
>
> After optimization:
>
> The same calls take 1ms, or ~0.2% of the total runtime. (The real runtime
> may be <1ms, but shows as 1 due to rounding up by cProfile.)

New description:

 Continuing my project to optimize the system checks, I found some
 optimizations for `Options._meta._property_names`, which I found to take
 ~4% of the total runtime for checks.

 Most of this function’s runtime was being spent running
 `inspect.getattr_static()`. This is not surprising as it
 
[https://github.com/python/cpython/blob/9b9e819b5116302cb4e471763feb2764eb17dde8/Lib/inspect.py#L1852
 jumps through many hoops] in order to avoid triggering attribute access.

 I added use of `getattr_static()` back in #28269 /
 ed244199c72f5bbf33ab4547e06e69873d7271d0 to fix a bug with instance
 descriptors. But I think it’s overly cautious, and we can assume that
 accessing the `__dict__` of the model class will work fine.

 Two optimizations make the function run in negligible time:

 1. Changing the function to use  `__dict__` directly
 2. Caching on a per-class basis. This requires using a weak-reference to
 classes, as we shouldn’t mutate base classes in the MRO, some of which can
 be non-model subclasses, like `Model` itself for the `pk` property,
 `object`, or any mixins.

 Before optimization stats:

 106 calls to `_property_names` took 26ms, or ~4% of the total runtime of
 system checks.

 After optimization:

 The same calls take 1ms, or ~0.2% of the total runtime. (The real runtime
 may be <1ms, but shows as 1 due to rounding up by cProfile.)

--
-- 
Ticket URL: <https://code.djangoproject.com/ticket/35270#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018e0abd41aa-c526e3e0-e913-4303-ab80-956d41476c87-000000%40eu-central-1.amazonses.com.

Reply via email to