diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-11-26 23:24:13 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-11-26 23:24:13 -0500 |
commit | 30a50cc46aa836e24ebcbb889cbee583c511af82 (patch) | |
tree | 053c2af8e82434c1e7a616e1a1c55b819aad244b | |
parent | 6029496bd3fb78caeab349ef8df5b58f058db16e (diff) | |
download | sqlalchemy-30a50cc46aa836e24ebcbb889cbee583c511af82.tar.gz |
- the wrapped memoized_property here was not working, as the attribute name
didn't match. use straight memoized_props here for now, add a perf test to check it
-rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 28 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/dynamic.py | 9 | ||||
-rw-r--r-- | test/aaa_profiling/test_orm.py | 60 | ||||
-rw-r--r-- | test/perf/orm2010.py | 8 | ||||
-rw-r--r-- | test/profiles.txt | 8 |
5 files changed, 97 insertions, 16 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index e3c6a3512..ce6200e71 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -355,12 +355,6 @@ class Event(object): self.op = op self.parent_token = self.impl.parent_token - @classmethod - def _token_gen(self, op): - @util.memoized_property - def gen(self): - return Event(self, op) - return gen @property def key(self): @@ -687,8 +681,17 @@ class ScalarAttributeImpl(AttributeImpl): state._modified_event(dict_, self, old) dict_[self.key] = value - _replace_token = _append_token = Event._token_gen(OP_REPLACE) - _remove_token = Event._token_gen(OP_REMOVE) + @util.memoized_property + def _replace_token(self): + return Event(self, OP_REPLACE) + + @util.memoized_property + def _append_token(self): + return Event(self, OP_REPLACE) + + @util.memoized_property + def _remove_token(self): + return Event(self, OP_REMOVE) def fire_replace_event(self, state, dict_, value, previous, initiator): for fn in self.dispatch.set: @@ -879,8 +882,13 @@ class CollectionAttributeImpl(AttributeImpl): return [(instance_state(o), o) for o in current] - _append_token = Event._token_gen(OP_APPEND) - _remove_token = Event._token_gen(OP_REMOVE) + @util.memoized_property + def _append_token(self): + return Event(self, OP_APPEND) + + @util.memoized_property + def _remove_token(self): + return Event(self, OP_REMOVE) def fire_append_event(self, state, dict_, value, initiator): for fn in self.dispatch.append: diff --git a/lib/sqlalchemy/orm/dynamic.py b/lib/sqlalchemy/orm/dynamic.py index b419d2a07..829cda554 100644 --- a/lib/sqlalchemy/orm/dynamic.py +++ b/lib/sqlalchemy/orm/dynamic.py @@ -76,8 +76,13 @@ class DynamicAttributeImpl(attributes.AttributeImpl): history = self._get_collection_history(state, passive) return history.added_plus_unchanged - _append_token = attributes.Event._token_gen(attributes.OP_APPEND) - _remove_token = attributes.Event._token_gen(attributes.OP_REMOVE) + @util.memoized_property + def _append_token(self): + return attributes.Event(self, attributes.OP_APPEND) + + @util.memoized_property + def _remove_token(self): + return attributes.Event(self, attributes.OP_REMOVE) def fire_append_event(self, state, dict_, value, initiator, collection_history=None): diff --git a/test/aaa_profiling/test_orm.py b/test/aaa_profiling/test_orm.py index 6d71468b7..2c1e84afb 100644 --- a/test/aaa_profiling/test_orm.py +++ b/test/aaa_profiling/test_orm.py @@ -310,3 +310,63 @@ class DeferOptionsTest(fixtures.MappedTest): *[defer(letter) for letter in ['x', 'y', 'z', 'p', 'q', 'r']]).\ all() + +class AttributeOverheadTest(fixtures.MappedTest): + @classmethod + def define_tables(cls, metadata): + Table('parent', metadata, Column('id', Integer, + primary_key=True, + test_needs_autoincrement=True), Column('data', + String(20))) + Table('child', metadata, Column('id', Integer, + primary_key=True, test_needs_autoincrement=True), + Column('data', String(20)), Column('parent_id', + Integer, ForeignKey('parent.id'), nullable=False)) + + @classmethod + def setup_classes(cls): + class Parent(cls.Basic): + pass + + class Child(cls.Basic): + pass + + @classmethod + def setup_mappers(cls): + Child, Parent, parent, child = (cls.classes.Child, + cls.classes.Parent, + cls.tables.parent, + cls.tables.child) + + mapper(Parent, parent, properties={'children': + relationship(Child, backref='parent')}) + mapper(Child, child) + + + def test_attribute_set(self): + Parent, Child = self.classes.Parent, self.classes.Child + p1 = Parent() + c1 = Child() + + @profiling.function_call_count() + def go(): + for i in range(30): + c1.parent = p1 + c1.parent = None + c1.parent = p1 + del c1.parent + go() + + def test_collection_append_remove(self): + Parent, Child = self.classes.Parent, self.classes.Child + p1 = Parent() + children = [Child() for i in range(100)] + + @profiling.function_call_count() + def go(): + for child in children: + p1.children.append(child) + for child in children: + p1.children.remove(child) + go() + diff --git a/test/perf/orm2010.py b/test/perf/orm2010.py index 088563e94..0213458b6 100644 --- a/test/perf/orm2010.py +++ b/test/perf/orm2010.py @@ -103,9 +103,8 @@ def runit(status, factor=1): sess.commit() status("Associated grunts w/ bosses and committed") - # do some heavier reading - for i in range(5): + for i in range(int(round(factor / 2.0))): status("Heavy query run #%d" % (i + 1)) report = [] @@ -147,7 +146,7 @@ def run_with_profile(): #stats.sort_stats('time', 'calls') #stats.print_stats() - #os.system("runsnake %s" % filename) +# os.system("runsnake %s" % filename) # SQLA Version: 0.7b1 # Total calls 4956750 @@ -174,4 +173,5 @@ def run_with_time(): runit(status, 10) print("Total time: %d" % (time.time() - now)) -run_with_time() +run_with_profile() +#run_with_time() diff --git a/test/profiles.txt b/test/profiles.txt index 5b17ee8ec..282bc5f4f 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -99,6 +99,14 @@ test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_postgre test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_postgresql_psycopg2_nocextensions 151 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_sqlite_pysqlite_cextensions 151 +# TEST: test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set + +test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_sqlite_pysqlite_cextensions 4265 + +# TEST: test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove + +test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_sqlite_pysqlite_cextensions 6525 + # TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_mysql_mysqldb_cextensions 30052 |