summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-11-26 23:24:13 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2013-11-26 23:24:13 -0500
commit30a50cc46aa836e24ebcbb889cbee583c511af82 (patch)
tree053c2af8e82434c1e7a616e1a1c55b819aad244b
parent6029496bd3fb78caeab349ef8df5b58f058db16e (diff)
downloadsqlalchemy-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.py28
-rw-r--r--lib/sqlalchemy/orm/dynamic.py9
-rw-r--r--test/aaa_profiling/test_orm.py60
-rw-r--r--test/perf/orm2010.py8
-rw-r--r--test/profiles.txt8
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