diff options
| author | Federico Caselli <cfederico87@gmail.com> | 2023-04-19 18:39:18 -0400 |
|---|---|---|
| committer | mike bayer <mike_mp@zzzcomputing.com> | 2023-04-26 19:48:00 +0000 |
| commit | 105f18be353965b064750726597b63334fc0716b (patch) | |
| tree | 29ee8a339ea86dbb37fc07b2e654d11c5922a419 /test/perf/compiled_extensions.py | |
| parent | ff198e35f0e04b8d38df25df234e72259069b4d1 (diff) | |
| download | sqlalchemy-105f18be353965b064750726597b63334fc0716b.tar.gz | |
Performance improvement in Row
Various performance improvements to Row instanciation
- avoid passing processors if they are all None
- improve processor logic in cython
- improve tuplegetter using slices when contiguous indexes are used
Some timing follow.
In particular [base_]row_new_proc that tests using processors has
a 25% improvement compared to before in cython.
Looking at the [b]row_new_proc_none that test a list of processors
all None, this has 50% improvement in cython when passing the none list,
but in this patch it would usually be disabled by passing None, so the
performance gain is actually 90%, since it would run the case
[base_]row_new.
Tuplegetter is a bit faster in the single item get and when getting
sequential indexes (like indexes 1,2,3,4) at the cost of a bit
longer creation time in python, cython is mostly the same.
Current times
| python | cython | cy / py |
base_row_new | 0.639817400 | 0.118265500 | 0.184842582 |
row_new | 0.680355100 | 0.129714600 | 0.190657202 |
base_row_new_proc | 3.076538900 | 1.488428600 | 0.483799701 |
row_new_proc | 3.119700100 | 1.532197500 | 0.491136151 |
brow_new_proc_none | 1.917702300 | 0.475511500 | 0.247958977 |
row_new_proc_none | 1.956253300 | 0.497803100 | 0.254467609 |
tuplegetter_one | 0.152512600 | 0.148523900 | 0.973846751 |
tuplegetter_many | 0.184394100 | 0.184511500 | 1.000636680 |
tuplegetter_seq | 0.154832800 | 0.156270100 | 1.009282917 |
tuplegetter_new_one | 0.523730000 | 0.343402200 | 0.655685563 |
tuplegetter_new_many| 0.738924400 | 0.420961400 | 0.569694816 |
tuplegetter_new_seq | 1.062036900 | 0.495462000 | 0.466520514 |
Parent commit times
| python | cython | cy / py |
base_row_new | 0.643890800 | 0.113548300 | 0.176347138 |
row_new | 0.674885900 | 0.124391800 | 0.184315304 |
base_row_new_proc | 3.072020400 | 2.017367000 | 0.656690626 |
row_new_proc | 3.109943400 | 2.048359400 | 0.658648450 |
brow_new_proc_none | 1.967133700 | 1.006326000 | 0.511569702 |
row_new_proc_none | 1.960814900 | 1.025217800 | 0.522852922 |
tuplegetter_one | 0.197359900 | 0.205999000 | 1.043773330 |
tuplegetter_many | 0.196575900 | 0.194888500 | 0.991416038 |
tuplegetter_seq | 0.192723900 | 0.205635000 | 1.066992729 |
tuplegetter_new_one | 0.534644500 | 0.414311700 | 0.774929322 |
tuplegetter_new_many| 0.479376500 | 0.417448100 | 0.870814694 |
tuplegetter_new_seq | 0.481580200 | 0.412697900 | 0.856966088 |
Change-Id: I2ca1f49dca2beff625c283f1363c29c8ccc0c3f7
Diffstat (limited to 'test/perf/compiled_extensions.py')
| -rw-r--r-- | test/perf/compiled_extensions.py | 65 |
1 files changed, 51 insertions, 14 deletions
diff --git a/test/perf/compiled_extensions.py b/test/perf/compiled_extensions.py index 14bb4e4ab..872165d07 100644 --- a/test/perf/compiled_extensions.py +++ b/test/perf/compiled_extensions.py @@ -787,6 +787,8 @@ class OrderedSet(IdentitySet): class TupleGetter(Case): + NUMBER = 2_000_000 + @staticmethod def python(): from sqlalchemy.engine._py_row import tuplegetter @@ -817,20 +819,7 @@ class TupleGetter(Case): self.tuple = tuple(range(1000)) self.tg_inst = self.impl_tg(42) self.tg_inst_m = self.impl_tg(42, 420, 99, 9, 1) - - class MockRow: - def __init__(self, data): - self.data = data - - def __getitem__(self, index): - # called by python - return self.data[index] - - def _get_by_key_impl_mapping(self, index): - # called by c - return self.data[index] - - self.row = MockRow(self.tuple) + self.tg_inst_seq = self.impl_tg(*range(70, 75)) @classmethod def update_results(cls, results): @@ -847,6 +836,10 @@ class TupleGetter(Case): self.tg_inst_m(self.tuple) @test_case + def tuplegetter_seq(self): + self.tg_inst_seq(self.tuple) + + @test_case def tuplegetter_new_one(self): self.impl_tg(42)(self.tuple) @@ -854,6 +847,10 @@ class TupleGetter(Case): def tuplegetter_new_many(self): self.impl_tg(42, 420, 99, 9, 1)(self.tuple) + @test_case + def tuplegetter_new_seq(self): + self.impl_tg(40, 41, 42, 43, 44)(self.tuple) + class BaseRow(Case): @staticmethod @@ -911,6 +908,30 @@ class BaseRow(Case): self.row_state = self.row.__getstate__() self.row_long_state = self.row_long.__getstate__() + assert len(ascii_letters) == 52 + self.parent_proc = SimpleResultMetaData( + tuple(ascii_letters), + _processors=[None, int, float, None, str] * 10, # cut the last 2 + ) + self.row_proc_args = ( + self.parent_proc, + self.parent_proc._processors, + self.parent_proc._key_to_index, + tuple(range(len(ascii_letters))), + ) + + self.parent_proc_none = SimpleResultMetaData( + tuple(ascii_letters), _processors=[None] * 52 + ) + self.row_proc_none_args = ( + self.parent_proc_none, + # NOTE: usually the code calls _effective_processors that returns + # None for this case of all None. + self.parent_proc_none._processors, + self.parent_proc_none._key_to_index, + tuple(range(len(ascii_letters))), + ) + @classmethod def update_results(cls, results): cls._divide_results(results, "c", "python", "c / py") @@ -928,6 +949,22 @@ class BaseRow(Case): self.Row(*self.row_long_args) @test_case + def base_row_new_proc(self): + self.impl(*self.row_proc_args) + + @test_case + def row_new_proc(self): + self.Row(*self.row_proc_args) + + @test_case + def brow_new_proc_none(self): + self.impl(*self.row_proc_none_args) + + @test_case + def row_new_proc_none(self): + self.Row(*self.row_proc_none_args) + + @test_case def row_dumps(self): self.row.__getstate__() self.row_long.__getstate__() |
