~ubuntu-branches/debian/jessie/sqlalchemy/jessie

« back to all changes in this revision

Viewing changes to test/aaa_profiling/test_memusage.py

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski, Jakub Wilk, Piotr Ożarowski
  • Date: 2013-07-06 20:53:52 UTC
  • mfrom: (1.4.23) (16.1.17 experimental)
  • Revision ID: package-import@ubuntu.com-20130706205352-ryppl1eto3illd79
Tags: 0.8.2-1
[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

[ Piotr Ożarowski ]
* New upstream release
* Upload to unstable
* Build depend on python3-all instead of -dev, extensions are not built for
  Python 3.X 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
from test.lib.testing import eq_
 
1
from sqlalchemy.testing import eq_
2
2
from sqlalchemy.orm import mapper, relationship, create_session, \
3
 
    clear_mappers, sessionmaker, class_mapper
 
3
    clear_mappers, sessionmaker, aliased,\
 
4
    Session, subqueryload
4
5
from sqlalchemy.orm.mapper import _mapper_registry
5
6
from sqlalchemy.orm.session import _sessions
6
 
import operator
7
 
from test.lib import testing, engines
 
7
from sqlalchemy import testing
 
8
from sqlalchemy.testing import engines
8
9
from sqlalchemy import MetaData, Integer, String, ForeignKey, \
9
 
    PickleType, create_engine, Unicode
10
 
from test.lib.schema import Table, Column
 
10
    Unicode, select
11
11
import sqlalchemy as sa
 
12
from sqlalchemy.testing.schema import Table, Column
12
13
from sqlalchemy.sql import column
13
14
from sqlalchemy.processors import to_decimal_processor_factory, \
14
15
    to_unicode_processor_factory
15
 
from test.lib.util import gc_collect
16
 
from sqlalchemy.util.compat import decimal
 
16
from sqlalchemy.testing.util import gc_collect
 
17
import decimal
17
18
import gc
 
19
from sqlalchemy.testing import fixtures
18
20
import weakref
19
 
from test.lib import fixtures
20
21
 
21
22
class A(fixtures.ComparableEntity):
22
23
    pass
23
24
class B(fixtures.ComparableEntity):
24
25
    pass
25
 
 
26
 
def profile_memory(func):
27
 
    # run the test 50 times.  if length of gc.get_objects()
28
 
    # keeps growing, assert false
29
 
 
30
 
    def profile(*args):
31
 
        gc_collect()
32
 
        samples = [0 for x in range(0, 50)]
33
 
        for x in range(0, 50):
34
 
            func(*args)
 
26
class ASub(A):
 
27
    pass
 
28
 
 
29
def profile_memory(times=50):
 
30
    def decorate(func):
 
31
        # run the test 50 times.  if length of gc.get_objects()
 
32
        # keeps growing, assert false
 
33
 
 
34
        def get_objects_skipping_sqlite_issue():
 
35
            # pysqlite keeps adding weakref objects which only
 
36
            # get reset after 220 iterations, which is too long
 
37
            # to run lots of these tests, so just filter them
 
38
            # out.
 
39
            return [o for o in gc.get_objects()
 
40
                    if not isinstance(o, weakref.ref)]
 
41
 
 
42
        def profile(*args):
35
43
            gc_collect()
36
 
            samples[x] = len(gc.get_objects())
37
 
 
38
 
        print "sample gc sizes:", samples
39
 
 
40
 
        assert len(_sessions) == 0
41
 
 
42
 
        for x in samples[-4:]:
43
 
            if x != samples[-5]:
44
 
                flatline = False
45
 
                break
46
 
        else:
47
 
            flatline = True
48
 
 
49
 
        # object count is bigger than when it started
50
 
        if not flatline and samples[-1] > samples[0]:
51
 
            for x in samples[1:-2]:
52
 
                # see if a spike bigger than the endpoint exists
53
 
                if x > samples[-1]:
 
44
            samples = [0 for x in range(0, times)]
 
45
            for x in range(0, times):
 
46
                func(*args)
 
47
                gc_collect()
 
48
                samples[x] = len(get_objects_skipping_sqlite_issue())
 
49
 
 
50
            print "sample gc sizes:", samples
 
51
 
 
52
            assert len(_sessions) == 0
 
53
 
 
54
            for x in samples[-4:]:
 
55
                if x != samples[-5]:
 
56
                    flatline = False
54
57
                    break
55
58
            else:
56
 
                assert False, repr(samples) + " " + repr(flatline)
57
 
 
58
 
    return profile
 
59
                flatline = True
 
60
 
 
61
            # object count is bigger than when it started
 
62
            if not flatline and samples[-1] > samples[0]:
 
63
                for x in samples[1:-2]:
 
64
                    # see if a spike bigger than the endpoint exists
 
65
                    if x > samples[-1]:
 
66
                        break
 
67
                else:
 
68
                    assert False, repr(samples) + " " + repr(flatline)
 
69
 
 
70
        return profile
 
71
    return decorate
59
72
 
60
73
def assert_no_mappers():
61
74
    clear_mappers()
78
91
            pass
79
92
 
80
93
        x = []
81
 
        @profile_memory
 
94
        @profile_memory()
82
95
        def go():
83
96
            x[-1:] = [Foo(), Foo(), Foo(), Foo(), Foo(), Foo()]
84
97
        go()
107
120
 
108
121
        m3 = mapper(A, table1, non_primary=True)
109
122
 
110
 
        @profile_memory
 
123
        @profile_memory()
111
124
        def go():
112
125
            sess = create_session()
113
126
            a1 = A(col2="a1")
139
152
        del m1, m2, m3
140
153
        assert_no_mappers()
141
154
 
 
155
    def test_sessionmaker(self):
 
156
        @profile_memory()
 
157
        def go():
 
158
            sessmaker = sessionmaker(bind=testing.db)
 
159
            sess = sessmaker()
 
160
            r = sess.execute(select([1]))
 
161
            r.close()
 
162
            sess.close()
 
163
            del sess
 
164
            del sessmaker
 
165
        go()
 
166
 
142
167
    @testing.crashes('sqlite', ':memory: connection not suitable here')
143
168
    def test_orm_many_engines(self):
144
169
        metadata = MetaData(testing.db)
168
193
 
169
194
        m3 = mapper(A, table1, non_primary=True)
170
195
 
171
 
        @profile_memory
 
196
        @profile_memory()
172
197
        def go():
173
198
            engine = engines.testing_engine(
174
199
                                options={'logging_name':'FOO',
227
252
            (postgresql.INTERVAL, ),
228
253
            (mysql.VARCHAR, ),
229
254
        ):
230
 
            @profile_memory
 
255
            @profile_memory()
231
256
            def go():
232
257
                type_ = args[0](*args[1:])
233
258
                bp = type_._cached_bind_processor(eng.dialect)
260
285
        del session
261
286
        counter = [1]
262
287
 
263
 
        @profile_memory
 
288
        @profile_memory()
264
289
        def go():
265
290
            session = create_session()
266
291
            w1 = session.query(Wide).first()
282
307
        finally:
283
308
            metadata.drop_all()
284
309
 
285
 
    @testing.fails_if(lambda : testing.db.dialect.name == 'sqlite' \
286
 
                      and testing.db.dialect.dbapi.version_info >= (2,
287
 
                      5),
288
 
                      'Newer pysqlites generate warnings here too and '
289
 
                      'have similar issues.')
 
310
    @testing.crashes('mysql+cymysql', 'blocking with cymysql >= 0.6')
290
311
    def test_unicode_warnings(self):
291
312
        metadata = MetaData(testing.db)
292
313
        table1 = Table('mytable', metadata, Column('col1', Integer,
296
317
        metadata.create_all()
297
318
        i = [1]
298
319
 
 
320
        # the times here is cranked way up so that we can see
 
321
        # pysqlite clearing out it's internal buffer and allow
 
322
        # the test to pass
299
323
        @testing.emits_warning()
300
 
        @profile_memory
 
324
        @profile_memory()
301
325
        def go():
302
326
 
303
327
            # execute with a non-unicode object. a warning is emitted,
325
349
            Column('col2', String(30)),
326
350
            Column('col3', Integer, ForeignKey("mytable.col1")))
327
351
 
328
 
        @profile_memory
 
352
        @profile_memory()
329
353
        def go():
330
354
            m1 = mapper(A, table1, properties={
331
355
                "bs":relationship(B, order_by=table2.c.col1)
368
392
            metadata.drop_all()
369
393
        assert_no_mappers()
370
394
 
 
395
    def test_alias_pathing(self):
 
396
        metadata = MetaData(testing.db)
 
397
 
 
398
        a = Table("a", metadata,
 
399
            Column('id', Integer, primary_key=True,
 
400
                                test_needs_autoincrement=True),
 
401
            Column('bid', Integer, ForeignKey('b.id')),
 
402
            Column('type', String(30))
 
403
        )
 
404
 
 
405
        asub = Table("asub", metadata,
 
406
            Column('id', Integer, ForeignKey('a.id'),
 
407
                                primary_key=True),
 
408
            Column('data', String(30)))
 
409
 
 
410
        b = Table("b", metadata,
 
411
            Column('id', Integer, primary_key=True,
 
412
                                test_needs_autoincrement=True),
 
413
        )
 
414
        mapper(A, a, polymorphic_identity='a',
 
415
            polymorphic_on=a.c.type)
 
416
        mapper(ASub, asub, inherits=A,polymorphic_identity='asub')
 
417
        m1 = mapper(B, b, properties={
 
418
            'as_':relationship(A)
 
419
        })
 
420
 
 
421
        metadata.create_all()
 
422
        sess = Session()
 
423
        a1 = ASub(data="a1")
 
424
        a2 = ASub(data="a2")
 
425
        a3 = ASub(data="a3")
 
426
        b1 = B(as_=[a1, a2, a3])
 
427
        sess.add(b1)
 
428
        sess.commit()
 
429
        del sess
 
430
 
 
431
        # sqlite has a slow enough growth here
 
432
        # that we have to run it more times to see the
 
433
        # "dip" again
 
434
        @profile_memory(times=120)
 
435
        def go():
 
436
            sess = Session()
 
437
            sess.query(B).options(subqueryload(B.as_.of_type(ASub))).all()
 
438
            sess.close()
 
439
        try:
 
440
            go()
 
441
        finally:
 
442
            metadata.drop_all()
 
443
        clear_mappers()
 
444
 
 
445
    def test_path_registry(self):
 
446
        metadata = MetaData()
 
447
        a = Table("a", metadata,
 
448
            Column('id', Integer, primary_key=True),
 
449
            Column('foo', Integer),
 
450
            Column('bar', Integer)
 
451
        )
 
452
        m1 = mapper(A, a)
 
453
        @profile_memory()
 
454
        def go():
 
455
            ma = sa.inspect(aliased(A))
 
456
            m1._path_registry[m1.attrs.foo][ma][m1.attrs.bar]
 
457
        go()
 
458
        clear_mappers()
 
459
 
371
460
    def test_with_inheritance(self):
372
461
        metadata = MetaData(testing.db)
373
462
 
383
472
            Column('col3', String(30)),
384
473
            )
385
474
 
386
 
        @profile_memory
 
475
        @profile_memory()
387
476
        def go():
388
477
            class A(fixtures.ComparableEntity):
389
478
                pass
449
538
            Column('t2', Integer, ForeignKey('mytable2.col1')),
450
539
            )
451
540
 
452
 
        @profile_memory
 
541
        @profile_memory()
453
542
        def go():
454
543
            class A(fixtures.ComparableEntity):
455
544
                pass
496
585
            metadata.drop_all()
497
586
        assert_no_mappers()
498
587
 
499
 
    @testing.fails_if(lambda : testing.db.dialect.name == 'sqlite' \
500
 
                      and testing.db.dialect.dbapi.version > '2.5')
501
588
    @testing.provide_metadata
502
589
    def test_key_fallback_result(self):
503
590
        e = testing.db
505
592
        t = Table('t', m, Column('x', Integer), Column('y', Integer))
506
593
        m.create_all(e)
507
594
        e.execute(t.insert(), {"x":1, "y":1})
508
 
        @profile_memory
 
595
        @profile_memory()
509
596
        def go():
510
597
            r = e.execute(t.alias().select())
511
598
            for row in r:
516
603
    # in pysqlite itself. background at:
517
604
    # http://thread.gmane.org/gmane.comp.python.db.pysqlite.user/2290
518
605
 
519
 
    @testing.fails_if(lambda : testing.db.dialect.name == 'sqlite' \
520
 
                      and testing.db.dialect.dbapi.version > '2.5')
521
606
    def test_join_cache(self):
522
607
        metadata = MetaData(testing.db)
523
608
        table1 = Table('table1', metadata, Column('id', Integer,
541
626
        metadata.create_all()
542
627
        session = sessionmaker()
543
628
 
544
 
        @profile_memory
 
629
        @profile_memory()
545
630
        def go():
546
631
            s = table2.select()
547
632
            sess = session()
553
638
            metadata.drop_all()
554
639
 
555
640
 
556
 
    def test_mutable_identity(self):
557
 
        metadata = MetaData(testing.db)
558
 
 
559
 
        table1 = Table("mytable", metadata,
560
 
            Column('col1', Integer, primary_key=True,
561
 
                                test_needs_autoincrement=True),
562
 
            Column('col2', PickleType(comparator=operator.eq, mutable=True))
563
 
            )
564
 
 
565
 
        class Foo(object):
566
 
            def __init__(self, col2):
567
 
                self.col2 = col2
568
 
 
569
 
        mapper(Foo, table1)
570
 
        metadata.create_all()
571
 
 
572
 
        session = sessionmaker()()
573
 
 
574
 
        def go():
575
 
            obj = [
576
 
                Foo({'a':1}),
577
 
                Foo({'b':1}),
578
 
                Foo({'c':1}),
579
 
                Foo({'d':1}),
580
 
                Foo({'e':1}),
581
 
                Foo({'f':1}),
582
 
                Foo({'g':1}),
583
 
                Foo({'h':1}),
584
 
                Foo({'i':1}),
585
 
                Foo({'j':1}),
586
 
                Foo({'k':1}),
587
 
                Foo({'l':1}),
588
 
            ]
589
 
 
590
 
            session.add_all(obj)
591
 
            session.commit()
592
 
 
593
 
            testing.eq_(len(session.identity_map._mutable_attrs), 12)
594
 
            testing.eq_(len(session.identity_map), 12)
595
 
            obj = None
596
 
            gc_collect()
597
 
            testing.eq_(len(session.identity_map._mutable_attrs), 0)
598
 
            testing.eq_(len(session.identity_map), 0)
599
 
 
600
 
        try:
601
 
            go()
602
 
        finally:
603
 
            metadata.drop_all()
604
641
 
605
642
    def test_type_compile(self):
606
643
        from sqlalchemy.dialects.sqlite.base import dialect as SQLiteDialect
607
644
        cast = sa.cast(column('x'), sa.Integer)
608
 
        @profile_memory
 
645
        @profile_memory()
609
646
        def go():
610
647
            dialect = SQLiteDialect()
611
648
            cast.compile(dialect=dialect)
613
650
 
614
651
    @testing.requires.cextensions
615
652
    def test_DecimalResultProcessor_init(self):
616
 
        @profile_memory
 
653
        @profile_memory()
617
654
        def go():
618
655
            to_decimal_processor_factory({}, 10)
619
656
        go()
620
657
 
621
658
    @testing.requires.cextensions
622
659
    def test_DecimalResultProcessor_process(self):
623
 
        @profile_memory
 
660
        @profile_memory()
624
661
        def go():
625
662
            to_decimal_processor_factory(decimal.Decimal, 10)(1.2)
626
663
        go()
627
664
 
628
665
    @testing.requires.cextensions
629
666
    def test_UnicodeResultProcessor_init(self):
630
 
        @profile_memory
 
667
        @profile_memory()
631
668
        def go():
632
669
            to_unicode_processor_factory('utf8')
633
670
        go()