1. 18 Jun, 2019 4 commits
    • wendelin.core v0.13 · b26ba558
      Kirill Smelkov committed
    • tox -= Python3.5 · 76e8dc34
      Let's keep on test coverage for last 2 stable Python releases.
      Kirill Smelkov committed
    • Fix build for Python 3.7 · bca5f79e
      Starting from Python 3.7 the place to keep exception state was changed:
      https://github.com/python/cpython/commit/ae3087c638
      
      NOTE ZEO4 does not wok with Python3.7, because ZEO4 uses "async" for a
      variable and that breaks because starting from Python3.7 "async" became
      a keyword.
      
      After the fix wendelin.core tests pass under all python2.7, python3.6
      and python3.7.
      Kirill Smelkov committed
    • tox: ZODB5.test.util needs mock · 6b5384ae
      Dependency added here:
      
      	https://github.com/zopefoundation/ZODB/commit/e0bc8bd567
      
      If we don't provide mock, e.g. py27-ZODB5-*-zeo-* breaks:
      
      	    def setup_module():
      	        global testdb
      	>       testdb = getTestDB()
      
      	bigarray/tests/test_arrayzodb.py:38:
      	_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      	.tox/py27-ZODB5-zblk1-zeo-numpy115/lib/python2.7/site-packages/wendelin/lib/testing.py:342: in getTestDB
      	    testdb = testdb_factory(testdb_uri)
      	.tox/py27-ZODB5-zblk1-zeo-numpy115/lib/python2.7/site-packages/wendelin/lib/testing.py:245: in __init__
      	    from ZEO.tests import forker
      	.tox/py27-ZODB5-zblk1-zeo-numpy115/lib/python2.7/site-packages/ZEO/tests/forker.py:29: in <module>
      	    import ZODB.tests.util
      	_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
      	    """
      	    from ZODB.MappingStorage import DB
      
      	    import atexit
      	    import os
      	    import persistent
      	    import re
      	    import tempfile
      	    import time
      	    import transaction
      	    import unittest
      	    import warnings
      	    import ZODB.utils
      	    from ZODB.Connection import TransactionMetaData
      	    import zope.testing.setupstack
      	    from zope.testing import renormalizing
      
      	    try:
      	        from unittest import mock
      	    except ImportError:
      	>       import mock
      	E       ImportError: No module named mock
      
      	.tox/py27-ZODB5-zblk1-zeo-numpy115/lib/python2.7/site-packages/ZODB/tests/util.py:35: ImportError
      Kirill Smelkov committed
  2. 23 May, 2019 2 commits
    • tox: v↑ NumPy to 2 latest releases · 7fd83b61
      Kirill Smelkov committed
    • bigfile/zodb: Resync _ZBigFileH to Connection.transaction_manager on every connection reopen · d9d6adec
      This continues c7c01ce4 (bigfile/zodb: ZODB.Connection can migrate
      between threads on close/open and we have to care): Until now we were
      retrieving zconn.transaction_manager on _ZBigFileH init, and further using
      that transaction manager for every connection reopen. However that is
      not correct because on every reopen connection can be given new
      transaction manager.
      
      We were not practically hitting the bug because until recently ZODB was,
      by default, using the same ThreadTransactionManager manager instance as
      Connection.transaction_manager for all connections, and not doing all
      steps needed to keep _ZBigFileH.transaction_manager in sync to
      Connection was forgiven - a particular transaction manager that was used
      was TransactionManager instance implicitly associated with current
      thread by global threading.Local transaction.manager . However starting
      from ZODB 5.5.0 Connection code was changed to remember as
      .transaction_manager the particular TransactionManager instance without
      any threading.Local games:
      
          https://github.com/zopefoundation/ZODB/commit/b6ac40f153
          https://github.com/zopefoundation/ZODB/issues/208
          https://github.com/zopefoundation/ZODB/pull/226
      
      Given that we were not syncing properly that broke wendelin.core tests, for
      example:
      
          bigfile/tests/test_filezodb.py::test_bigfile_filezodb_vs_conn_migration Exception in thread Thread-1:
          Traceback (most recent call last):
            File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
              self.run()
            File "/usr/lib/python2.7/threading.py", line 754, in run
              self.__target(*self.__args, **self.__kwargs)
            File "/home/kirr/src/wendelin/wendelin.core/bigfile/tests/test_filezodb.py", line 401, in T11
              transaction.commit()    # should be nothing
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/transaction/_manager.py", line 252, in commit
              return self.manager.commit()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/transaction/_manager.py", line 131, in commit
              return self.get().commit()
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/transaction/_transaction.py", line 298, in commit
              self._synchronizers.map(lambda s: s.beforeCompletion(self))
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/transaction/weakset.py", line 61, in map
              f(elt)
            File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/transaction/_transaction.py", line 298, in <lambda>
              self._synchronizers.map(lambda s: s.beforeCompletion(self))
            File "/home/kirr/src/wendelin/wendelin.core/bigfile/file_zodb.py", line 671, in beforeCompletion
              assert txn is zconn.transaction_manager.get()
          AssertionError
      
      What is happening here is that one thread used the connection and
      ZBigFile/_ZBigFileH associated with it, then the connection was closed
      and released to DB pool. Then the connection was reopened but by another
      thread and thus with different TransactionManager instance and oops -
      _ZBigFileH.transaction_manager is different because it is
      TransactionManager instance that was used by the first thread.
      
      Fix it by resyncing _ZBigFileH.transaction_manager on every
      connection reopen. No new test as existing tests already cover the
      problem when run with ZODB >= 5.5.0 .
      Kirill Smelkov committed
  3. 03 May, 2019 1 commit
  4. 17 Mar, 2019 1 commit
    • t/qemu-runlinux: Kernel verbosity control via -v · 208aca62
      	0: ERROR+ on boot/run
      	1: INFO+  on      run
      	2: INFO+  on boot/run
      	3: DEBUG+ on boot/run
      
      It is convenient not to see large kernel boot log on every test run. "1"
      (single -v) is also convenient: one can skip the boot log but still see
      details of what is going on when test workload is run. -vv and -vvv are
      there to see full picture.
      Kirill Smelkov committed
  5. 27 Feb, 2019 3 commits
  6. 13 Feb, 2019 1 commit
    • t/qemu-runlinux: Update · fe541453
      Continuing 76d8f76d (Script to run compiled linux kernel with root fs
      mounted from host) update the script to run/debug linux inside QEMU:
      
      - teach it to run specified program + args, instead of hardcoded /bin/sh;
      - before tailing to user program, builtin init mounts /proc, /sys, ...
        inside - previously it was /proc, /sys from host seen on those
        mountpoints and it was very misleading - e.g. ps was showing processes
        from host, not inside, etc.
      - builtin init also cares to run specified program with the same current
        directory that was current on host, and environments such as $HOME,
        $PATH, $TERM, ... are also propagated.
      - allow to optionally run QEMU with graphics, instead of stdout only;
      - increase available RAM from 128M to 512M (with 128M running py.test
        inside is failing with fork: not enough memory).
      
      This updated version was useful to debug WCFS(*) & FUSE issues by running
      
      	kirr@deco:~/src/wendelin/wendelin.core/wcfs$ ../t/qemu-runlinux ~/src/linux/linux/arch/x86_64/boot/bzImage py.test -vsx -k test_wcfs
      
      See https://marc.info/?l=linux-fsdevel&m=155000277921155&w=2 for details.
      
      (*) WCFS is still being draft and worked on t branch.
      Kirill Smelkov committed
  7. 11 Jan, 2019 1 commit
    • bigfile/py: Properly untrack PyVMA from GC before dealloc · d97641d2
      On a testing instance we started to see segfaults in pyvma_dealloc()
      with inside calls to vma_unmap but with NULL pyvma->fileh. That was
      strange, becuse before calling vma_unmap(), the code explicitly checks
      whether pyvma->fileh is !NULL.
      
      That was, as it turned out, due to pyvma_dealloc being called twice at the
      same time from two python threads. Here is how that was possible:
      
      T1 decrefs pyvma and finds its reference count drops to zero. It calls
      pyvma_dealloc. From there vma_unmap() is called, which calls virt_lock()
      and that releases GIL first. Another thread T2 was waiting for GIL, it
      acquires it, does some work at python level and somehow triggers GC.
      Since PyVMA supports cyclic GC, it was on GC list and thus GC calls
      dealloc for the same vma again. Here is how it looks in the backtraces:
      
      T1:
      
      	#0  0x00007f6aefc57827 in futex_abstimed_wait_cancelable (private=0, abstime=0x0, expected=0, futex_word=0x1e011d0) at ../sysdeps/unix/sysv/linux/futex-internal.h:205
      	#1  do_futex_wait (sem=sem@entry=0x1e011d0, abstime=0x0) at sem_waitcommon.c:111
      	#2  0x00007f6aefc578d4 in __new_sem_wait_slow (sem=0x1e011d0, abstime=0x0) at sem_waitcommon.c:181
      	#3  0x00007f6aefc5797a in __new_sem_wait (sem=<optimized out>) at sem_wait.c:29
      	#4  0x00000000004ffbc4 in PyThread_acquire_lock ()
      	#5  0x00000000004dbe8a in PyEval_RestoreThread ()
      	#6  0x00007f6ac6d3b8fc in py_gil_retake_if_waslocked (arg=0x4f18f00) at bigfile/_bigfile.c:1048
      	#7  0x00007f6ac6d3dcfc in virt_gil_retake_if_waslocked (gilstate=0x4f18f00) at bigfile/virtmem.c:78
      	#8  0x00007f6ac6d3dd30 in virt_lock () at bigfile/virtmem.c:92
      	#9  0x00007f6ac6d3e724 in vma_unmap (vma=0x7f6a7e0c4100) at bigfile/virtmem.c:271
      	#10 0x00007f6ac6d3a0bc in pyvma_dealloc (pyvma0=0x7f6a7e0c40e0) at bigfile/_bigfile.c:284
      	...
      	#13 0x00000000004d76b0 in PyEval_EvalFrameEx ()
      
      T2:
      
      	#5  0x00007f6ac6d3a081 in pyvma_dealloc (pyvma0=0x7f6a7e0c40e0) at bigfile/_bigfile.c:276
      	#6  0x0000000000500450 in ?? ()
      	#7  0x00000000004ffd82 in _PyObject_GC_New ()
      	#8  0x0000000000485392 in PyList_New ()
      	#9  0x00000000004d3bff in PyEval_EvalFrameEx ()
      
      T2 does the work of vma_unmap and clears C-level vma. Then, when T1 wakes up and
      returns to vma_unmap, it sees vma->file and all other fields cleared -> oops
      segfault.
      
      Fix it by removing pyvma from GC list before going to do actual destruction.
      This way if a concurrent GC triggers, it won't see the vma object on its list,
      and thus won't have a chance to invoke its destructor the second time.
      
      The bug was introduced in 450ad804 (bigarray: ArrayRef support for BigArray)
      when PyVMA was changed to be cyclic-GC aware. However at that time, even Python
      documentation itself was not saying PyObject_GC_UnTrack is needed, as it was
      added only in 2.7.15 after finding that many types in CPython itself are
      vulnerable to similar segfaults:
      
      https://github.com/python/cpython/commit/4cde4bdcc86
      https://bugs.python.org/issue31095
      
      It is pity, that CPython took the approach to force all type authors to
      care to invoke PyObject_GC_UnTrack explicitly, instead of doing that
      automatically in Python runtime before calling tp_dealloc.
      
      /cc @Tyagov, @klaus
      /reviewed-on nexedi/wendelin.core!11
      Kirill Smelkov committed
  8. 29 Oct, 2018 2 commits
    • lib.xnumpy.structured: New utility to create structured view of an array · 32ca80e2
      Structured creates view of the array interpreting its minor axis as fully covered by a dtype.
      
      It is similar to arr.view(dtype) + corresponding reshape, but does
      not have limitations of ndarray.view(). For example:
      
        In [1]: a = np.arange(3*3, dtype=np.int32).reshape((3,3))
      
        In [2]: a
        Out[2]:
        array([[0, 1, 2],
               [3, 4, 5],
               [6, 7, 8]], dtype=int32)
      
        In [3]: b = a[:2,:2]
      
        In [4]: b
        Out[4]:
        array([[0, 1],
               [3, 4]], dtype=int32)
      
        In [5]: dtxy = np.dtype([('x', np.int32), ('y', np.int32)])
      
        In [6]: dtxy
        Out[6]: dtype([('x', '<i4'), ('y', '<i4')])
      
        In [7]: b.view(dtxy)
        ---------------------------------------------------------------------------
        ValueError                                Traceback (most recent call last)
        <ipython-input-66-af98529aa150> in <module>()
        ----> 1 b.view(dtxy)
      
        ValueError: To change to a dtype of a different size, the array must be C-contiguous
      
        In [8]: structured(b, dtxy)
        Out[8]: array([(0, 1), (3, 4)], dtype=[('x', '<i4'), ('y', '<i4')])
      
      Structured always creates view and never copies data.
      
      Here is original context where separately playing with .shape and .dtype
      was not enough, since it was creating array copy and OOM'ing the machine:
      
      klaus/wendelin@cbe4938b
      Kirill Smelkov committed
    • bigarray: Factor-out our custom numpy.lib.stride_tricks.as_strided-alike into lib/xnumpy.py · 6a5dfefa
      We are going to use this code in another place, so move this out to
      dommon place as a preparatory step first.
      
      On a related note: Since ArrayRef is generic and quite independent from
      BigArray (it only supports it, but equally it supports just other - e.g.
      plain arrays), the proper place for it might be also to be lib/xnumpy.py .
      We might get to this topic a bit later.
      Kirill Smelkov committed
  9. 12 Oct, 2018 2 commits
    • RAMArray · 99b91c84
      RAMArray is compatible to ZBigArray in API and semantic, but stores its
      data in RAM only. It is useful in situations where ZBigArray compatible
      data type is needed, but the amount of data is small and the data itself
      is needed only temporarily - e.g. in a simulation.
      
      Please see details in individual patches.
      
      Original merge request by @klaus (nexedi/wendelin.core!8).
      
      /cc @Tyagov
      /reviewed-on nexedi/wendelin.core!9
      Kirill Smelkov committed
    • bigarray: RAMArray · fc9b69d8
      RAMArray is compatible to ZBigArray in API and semantic, but stores its
      data in RAM only. It is useful in situations where ZBigArray compatible
      data type is needed, but the amount of data is small and the data itself
      is needed only temporarily - e.g. in a simulation.
      
      Implementation is based on mmapping temporary files from /dev/shm/... and
      passing them as file handles, similarly to how ZBigArray works, to BigArray.
      We don't use just numpy.ndarray because of append - for ZBigArray append
      works in O(1), but more importantly it does not copy data. This way
      mmapings previously created for ZBigArray views, continue to correctly
      alias array data. If we would be using ndarray directly, since
      ndarray.resize copies data, that property would not be preserved.
      
      Original patch by Klaus Wölfel <klaus@nexedi.com>
      (nexedi/wendelin.core!8)
      Kirill Smelkov committed
  10. 11 Oct, 2018 1 commit
  11. 04 Jul, 2018 1 commit
  12. 26 Jun, 2018 2 commits
  13. 17 Apr, 2018 3 commits
    • Wendelin.core v1 is used in production for several years now · e92f4f16
      Kirill Smelkov committed
    • tests: Explicitly close ZODB connections for places with warnings found by previous patch · 01b995a4
      bigfile/tests/test_filezodb.py ........W: testdb: teardown: <Connection at 7f8fe2b43b90> left not closed by test code; opened by:
        ...
        File "/home/kirr/src/wendelin/wendelin.core/bigfile/tests/test_filezodb.py", line 754, in test_bigfile_zblk1_zdata_reuse
          _test_bigfile_zblk1_zdata_reuse()
        File "/home/kirr/src/wendelin/wendelin.core/bigfile/tests/test_filezodb.py", line 759, in _test_bigfile_zblk1_zdata_reuse
          root = dbopen()
        File "/home/kirr/src/wendelin/wendelin.core/bigfile/tests/test_filezodb.py", line 47, in dbopen
          return testdb.dbopen()
        File "/home/kirr/src/wendelin/wendelin.core/lib/testing.py", line 188, in dbopen
          self.connv.append( (weakref.ref(conn), ''.join(traceback.format_stack())) )
      
      lib/tests/test_zodb.py .W: testdb: teardown: <Connection at 7f8fe26f13d0> left not closed by test code; opened by:
        ...
        File "/home/kirr/src/wendelin/wendelin.core/lib/tests/test_zodb.py", line 49, in test_deactivate_btree
          root = dbopen()
        File "/home/kirr/src/wendelin/wendelin.core/lib/tests/test_zodb.py", line 30, in dbopen
          return testdb.dbopen()
        File "/home/kirr/src/wendelin/wendelin.core/lib/testing.py", line 188, in dbopen
          self.connv.append( (weakref.ref(conn), ''.join(traceback.format_stack())) )
      Kirill Smelkov committed
    • tests: Force-close ZODB connections in teardown, that testing code forgot to explicitly close · 5a5ed2c7
      If a test forgets to explicitly close ZODB connection it was using, this
      connection stays alive in transaction synchronizers (it is a weakset),
      and continues to be used on e.g. transaction.commit() when all
      synchronizers are invoked. This could lead to crashes like below when
      underlying ZODB storage was closed by test module teardown and testing
      moved on to another test module:
      
          $ WENDELIN_CORE_TEST_DB="<neo>" py.test  bigfile/tests/test_filezodb.py::test_bigfile_zblk1_zdata_reuse lib/tests/test_zodb.py
          ======= test session starts ========
          platform linux2 -- Python 2.7.14+, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
          rootdir: /home/kirr/src/wendelin/wendelin.core, inifile:
          collected 2 items
      
          bigfile/tests/test_filezodb.py .                                     [ 50%]
          lib/tests/test_zodb.py F                                             [100%]
      
          ______ test_deactivate_btree _______
      
              def test_deactivate_btree():
                  root = dbopen()
                  # init btree with many leaf nodes
                  leafv = []
                  root['btree'] = B = IOBTree()
                  for i in range(10000):
                      B[i] = xi = XInt(i)
                      leafv.append(xi)
          >       transaction.commit()
      
          lib/tests/test_zodb.py:56:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
          ../venv/z5/local/lib/python2.7/site-packages/transaction/_manager.py:131: in commit
              return self.get().commit()
          ../venv/z5/local/lib/python2.7/site-packages/transaction/_transaction.py:316: in commit
              self._synchronizers.map(lambda s: s.afterCompletion(self))
          ../venv/z5/local/lib/python2.7/site-packages/transaction/weakset.py:62: in map
              f(elt)
          ../venv/z5/local/lib/python2.7/site-packages/transaction/_transaction.py:316: in <lambda>
              self._synchronizers.map(lambda s: s.afterCompletion(self))
          ../venv/z5/local/lib/python2.7/site-packages/ZODB/Connection.py:757: in afterCompletion
              self.newTransaction(transaction, False)
          ../venv/z5/local/lib/python2.7/site-packages/ZODB/Connection.py:737: in newTransaction
              invalidated = self._storage.poll_invalidations()
          ../venv/z5/local/lib/python2.7/site-packages/ZODB/mvccadapter.py:131: in poll_invalidations
              self._start = p64(u64(self._storage.lastTransaction()) + 1)
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          self = <neo.client.Storage.Storage object at 0x7ffa1be8d410>
      
              def lastTransaction(self):
                  # Used in ZODB unit tests
          >       return self.app.last_tid
          E       AttributeError: 'NoneType' object has no attribute 'last_tid'
      
          ../../neo/src/lab.nexedi.com/kirr/neo/neo/client/Storage.py:181: AttributeError
      
      where NEO's Storage.app is None because the storage was closed.
      
      ----
      
      To avoid such kind of failures make sure TestDB.teardown() always closes
      all ZODB connections that were ever opened via TestDB.dbopen().
      
      Add a warning about such force-closing with information about corresponding
      connection and code place that created it, so that it is easy to
      understand which test needs a fix.
      
      /suggested-by @jm
      Kirill Smelkov committed
  14. 16 Apr, 2018 4 commits
    • wendelin.core v0.12 · 72df6eb6
      Kirill Smelkov committed
    • tox: v↑ everything · 0dbf3c44
      - start testing NEO with ZODB4 and ZODB5. ZODB4-*-NEO works while
        ZODB5-*-NEO currently fails [1].
      - update NumPy to latest releases.
      - update Python 3 to latest releases.
      Kirill Smelkov committed
    • tests: Teach to run with ZEO5 · 808b59b7
      Since 7fc4ec66 (tests: Allow to test with ZEO & NEO ZODB storages) we
      can run the tests with either FileStorage, ZEO or NEO. But ZEO test
      adapter started to fail with ZEO5:
      
      	self = <wendelin.lib.testing.TestDB_ZEO object at 0x7f1feb5091d0>
      
      	    def setup(self):
      	        port  = self.zeo_forker.get_port()
      	        zconf = self.zeo_forker.ZEOConfig(('', port))
      	        self.addr, self.adminaddr, self.pid, self.path = \
      	>               self.zeo_forker.start_zeo_server(zeo_conf=zconf, port=port)
      	E       ValueError: need more than 2 values to unpack
      
      This is because in ZEO5 forker.start_zeo_server() was reworked to return only
      addr and stop closure instead of returning all details and relying on caller to
      implement stop itself.
      
      Adapt the test to detect ZEO5 and use new calling convention.
      Kirill Smelkov committed
    • tox/ZODB3: Limit ZConfig < 3.2.0 · c96daa2f
      With ZConfig==3.2.0 (released 2017-06-22) ZEO started to get file names
      as unicode, which eventually breaks on assert in ZODB3.FileStorage code:
      
          Traceback (most recent call last):
            File "/home/kirr/src/wendelin/r/work/venv/local/lib/python2.7/site-packages/ZEO/tests/zeoserver.py", line 215, in <module>
              main()
            File "/home/kirr/src/wendelin/r/work/venv/local/lib/python2.7/site-packages/ZEO/tests/zeoserver.py", line 188, in main
              server = ZEO.runzeo.create_server({"1": storage}, zo)
            File "/home/kirr/src/wendelin/r/work/venv/local/lib/python2.7/site-packages/ZEO/runzeo.py", line 366, in create_server
              auth_realm = options.auth_realm,
            File "/home/kirr/src/wendelin/r/work/venv/local/lib/python2.7/site-packages/ZEO/StorageServer.py", line 890, in __init__
              self._setup_invq(name, storage)
            File "/home/kirr/src/wendelin/r/work/venv/local/lib/python2.7/site-packages/ZEO/StorageServer.py", line 928, in _setup_invq
              self.invq[name] = list(lastInvalidations(self.invq_bound))
            File "/home/kirr/src/wendelin/r/work/venv/local/lib/python2.7/site-packages/ZODB/FileStorage/FileStorage.py", line 1238, in lastInvalidations
              for trans in FileIterator(self._file_name, pos=pos)]
            File "/home/kirr/src/wendelin/r/work/venv/local/lib/python2.7/site-packages/ZODB/FileStorage/FileStorage.py", line 1640, in __init__
              assert isinstance(filename, str), `filename`
          AssertionError: u'/home/kirr/src/wendelin/r/work/wendelin.core/Data.fs'
      
      -> So for ZODB3 pin ZConfig to ZConfig <3.2.0 which is known to work with ZODB3.
      Kirill Smelkov committed
  15. 12 Apr, 2018 1 commit
    • bigarray: ArrayRef utility · e9d61a89
      ArrayRef is a reference to NumPy array.
      
      The reference is represented by root array object and instructions how to
      create original array as some view of the root.
      
      Such reference could be useful in situations where one needs to pass arrays
      between processes and instead of copying array data, leverage the fact that
      top-level array, for example ZBigArray, is already persisted separately, and
      only send small amount of information referencing data in question.
      
      Use `ArrayRef(array)` to create reference to an ndarray.
      
      Use `.deref()` to convert ArrayRef to pointed array object.
      
      NOTE
      
      don't send ArrayRef unconditionally - for example when array object is
      small regular ndarray with also regular, but big, root ndarray, sending
      ArrayRef will send whole data for root object, not for small leaf.
      
      Sending ArrayRef only makes sense when root object is known to be already
      persisted by other means, for example something like below in ZODB context:
      
      ```python
        aref = ArrayRef(a)
        if isinstance(aref.root, Persistent):
            send aref
        else:
            send a 
      ```
      
      Please see individual patches for more details.
      
      /reviewed-on nexedi/wendelin.core!6
      Kirill Smelkov committed
  16. 02 Apr, 2018 2 commits
    • bigarray: ArrayRef support for BigArray · 450ad804
      Rationale
      ---------
      
      Array reference could be useful in situations where one needs to pass arrays
      between processes and instead of copying array data, leverage the fact that
      top-level array, for example ZBigArray, is already persisted separately, and
      only send small amount of information referencing data in question.
      
      Implementation
      --------------
      
      BigArray is not regular NumPy array and so needs explicit support in
      ArrayRef code to find root object and indices. This patch adds such
      support via the following way:
      
      - when BigArray.__getitem__ creates VMA, it remembers in the VMA
        the top-level BigArray object under which this VMA was created.
      
      - when ArrayRef is finding root, it can detect such VMAs, because it will
        be pointed to by the most top regular ndarray's .base, and in turn gets
        top-level BigArray object from the VMA.
      
      - further all indices computations are performed, similarly to complete regular
        ndarrays case, on ndarrays root and a. But in the end .lo and .hi are
        adjusted for the corresponding offset of where root is inside whole
        BigArray.
      
      - there is no need to adjust .deref() at all.
      
      For remembering information into a VMA and also to be able to get
      (readonly) its mapping addresses _bigfile.c extension has to be extended
      a bit. Since we are now storing arbitrary python object attached to
      PyVMA - it can create cycles - and so PyVMA accordingly adjusted to
      support cyclic garbage collector.
      
      Please see the patch itself for more details and comments.
      Kirill Smelkov committed
    • bigarray: Add ArrayRef utility · d53371b6
      ArrayRef is a tool to find out for a NumPy array its top-level root
      parent and remember instructions how to recreate original array from
      the root. For example if
      
      	root = arange(1E7)
      	z = root[1000:2000]
      	a = z[10:20]
      
      `ArrayRef(a)` will find out that the root array for `a` is `root` and
      that `a` occupies 1010:1020 bytes in it. The vice versa operation is
      also possible, for example given
      
      	aref = ArrayRef(a)
      
      it is possible to restore original `a` from `aref`:
      
      	a_ = aref.deref()
      	assert array_equal(a_, a)
      
      the restoration works without copying by creating appropriate view of
      root.
      
      ArrayRef should work reliably for arrays of arbitrary dimensions,
      strides etc - even fancy arrays created via stride tricks such as arrays
      whose elements overlap each other should be supported.
      
      This patch adds ArrayRef with support for regular ndarrays only.
      
      The next patch will add ArrayRef support for BigArray and description
      for ArrayRef rationale.
      Kirill Smelkov committed
  17. 21 Feb, 2018 1 commit
  18. 31 Jan, 2018 1 commit
    • bigfile/virtmem: Fix build with recent glibc · c3cc8a99
      It was
      
      	bigfile/pagefault.c:45:36: warning: ‘struct ucontext’ declared inside parameter list will not be visible outside of this definition or declaration
      	 static int faulted_by(const struct ucontext *uc);
      	                                    ^~~~~~~~
      	bigfile/pagefault.c: In function ‘on_pagefault’:
      	bigfile/pagefault.c:59:24: warning: passing argument 1 of ‘faulted_by’ from incompatible pointer type [-Wincompatible-pointer-types]
      	     write = faulted_by(uc);
      	                        ^~
      	bigfile/pagefault.c:45:12: note: expected ‘const struct ucontext *’ but argument is of type ‘struct ucontext *’
      	 static int faulted_by(const struct ucontext *uc);
      	            ^~~~~~~~~~
      	bigfile/pagefault.c: At top level:
      	bigfile/pagefault.c:208:36: warning: ‘struct ucontext’ declared inside parameter list will not be visible outside of this definition or declaration
      	 static int faulted_by(const struct ucontext *uc)
      	                                    ^~~~~~~~
      	bigfile/pagefault.c:208:12: error: conflicting types for ‘faulted_by’
      	 static int faulted_by(const struct ucontext *uc)
      	            ^~~~~~~~~~
      	bigfile/pagefault.c:45:12: note: previous declaration of ‘faulted_by’ was here
      	 static int faulted_by(const struct ucontext *uc);
      	            ^~~~~~~~~~
      	bigfile/pagefault.c: In function ‘faulted_by’:
      	bigfile/pagefault.c:217:15: error: dereferencing pointer to incomplete type ‘const struct ucontext’
      	     write = uc->uc_mcontext.gregs[REG_ERR] & 0x2;
      	               ^~
      	bigfile/pagefault.c: At top level:
      	bigfile/pagefault.c:45:12: warning: ‘faulted_by’ used but never defined
      	 static int faulted_by(const struct ucontext *uc);
      	            ^~~~~~~~~~
      	bigfile/pagefault.c:208:12: warning: ‘faulted_by’ defined but not used [-Wunused-function]
      	 static int faulted_by(const struct ucontext *uc)
      	            ^~~~~~~~~~
      
      Change to using ucontext_t because apparently there is no `struct
      ucontext` anymore (and man for sigaction says 3rd parameter to hander is
      of type `ucontext_t *` - not `struct ucontext *` - cast to `void *`)
      
      Explicitly include <ucontext.h> because we are dereferencing ucontext_t,
      even though today it appears to be included by <signal.h>.
      Kirill Smelkov committed
  19. 12 Dec, 2017 1 commit
    • virtmem: Benchmarks for pagefault handling · 3cfc2728
      Benchmark the time it takes for virtmem to handle pagefault with noop
      loadblk for loadblk both implemented in C and in Python.
      
      On my computer it is:
      
      	name          µs/op
      	PagefaultC    269 ± 0%
      	pagefault_py  291 ± 0%
      
      Quite a big time in other words.
      
      It turned out to be mostly spent in fallocate'ing pages on tmpfs from
      /dev/shm. Part of the above 269 µs/op is taken by freeing (reclaiming)
      pages back when benchmarking work size exceed /dev/shm size, and part to
      allocating.
      
      If I limit the work size (via npage in benchmem.c) to be less than whole
      /dev/shm it starts to be ~ 170 µs/op and with additional tracing it
      shows as something like this:
      
          	.. on_pagefault_start   0.954 µs
          	.. vma_on_pagefault_pre 0.954 µs
          	.. ramh_alloc_page_pre  0.954 µs
          	.. ramh_alloc_page      169.992 µs
          	.. vma_on_pagefault     172.853 µs
          	.. vma_on_pagefault_pre 172.853 µs
          	.. vma_on_pagefault     174.046 µs
          	.. on_pagefault_end     174.046 µs
          	.. whole:               171.900 µs
      
      so almost all time is spent in ramh_alloc_page which is doing the fallocate:
      
      	https://lab.nexedi.com/nexedi/wendelin.core/blob/f11386a4/bigfile/ram_shmfs.c#L125
      
      Simple benchmark[1] confirmed it is indeed the case for fallocate(tmpfs) to be
      relatively slow[2] (and that for recent kernels it regressed somewhat
      compared to Linux 3.16). Profile flamegraph for that benchmark[3] shows
      internal loading of shmem_fallocate which for 1 hardware page is not
      that too slow (e.g. <1µs) but when a request comes for a region
      internally performs it page by page and so accumulates that ~ 170µs for 2M.
      
      I've tried to briefly rerun the benchmark with huge pages activated on /dev/shm via
      
      	mount /dev/shm -o huge=always,remount
      
      as both regular user and as root but it was executing several times
      slower. Probably something to investigate more later.
      
      [1] https://lab.nexedi.com/kirr/misc/blob/4f84a06e/tmpfs/t_fallocate.c
      [2] https://lab.nexedi.com/kirr/misc/blob/4f84a06e/tmpfs/1.txt
      [3] https://lab.nexedi.com/kirr/misc/raw/4f84a06e/tmpfs/fallocate-2M-nohuge.svg
      Kirill Smelkov committed
  20. 06 Dec, 2017 1 commit
    • py.bench: Rework output to match Go benchmarking format · 51f252d4
      Rework py.bench output to match output of Go benchmarking[1] so that go
      tools like benchstat & friends could be used to analyze and compare the
      timings.
      
      Before patch:
      
      ============================= test session starts ==============================
      platform linux2 -- Python 2.7.14, pytest-3.3.2.dev2+g88f2cc9b.d20171206, py-1.5.2, pluggy-0.6.0
      rootdir: /home/kirr/src/wendelin/wendelin.core, inifile:
      collected 11 items
      
      pymod: bigfile/tests/bench_0virtmem.py
      bench_file_mmapread_hole	0.21  (0.39 0.22 0.21)
      bench_file_read_hole    	0.24  (0.24 0.24 0.24)
      bench_file_readbig_hole 	0.30  (0.30 0.31 0.31)
      bench_bigf_read_hole    	0.44  (0.44 0.45 0.44)
      bench_file_mmapwrite0   	0.13  (0.13 0.13 0.13)
      bench_file_write55      	0.08  (0.08 0.08 0.08)
      bench_bigf_writeff      	0.47  (0.47 0.48 0.47)
      bench_file_mmapread     	0.22  (0.22 0.22 0.22)
      bench_file_read         	0.25  (0.25 0.25 0.26)
      bench_file_readbig      	0.31  (0.31 0.31 0.31)
      bench_bigf_read         	0.44  (0.45 0.44 0.44)
      
      ========================== 11 passed in 12.92 seconds ==========================
      
      After patch:
      
      ============================= test session starts ==============================
      platform linux2 -- Python 2.7.14, pytest-3.3.2.dev2+g88f2cc9b.d20171206, py-1.5.2, pluggy-0.6.0
      rootdir: /home/kirr/src/wendelin/wendelin.core, inifile:
      collected 11 items
      
      pymod: bigfile/tests/bench_0virtmem.py
      Benchmarkfile_mmapread_hole	1	385839.939 µs/op
      Benchmarkfile_mmapread_hole	1	219214.916 µs/op
      Benchmarkfile_mmapread_hole	1	210209.131 µs/op
      Benchmarkfile_read_hole    	1	238974.094 µs/op
      Benchmarkfile_read_hole    	1	237294.197 µs/op
      Benchmarkfile_read_hole    	1	238043.070 µs/op
      Benchmarkfile_readbig_hole 	1	301330.090 µs/op
      Benchmarkfile_readbig_hole 	1	301767.111 µs/op
      Benchmarkfile_readbig_hole 	1	301135.063 µs/op
      Benchmarkbigf_read_hole    	1	434718.132 µs/op
      Benchmarkbigf_read_hole    	1	435019.970 µs/op
      Benchmarkbigf_read_hole    	1	434729.099 µs/op
      Benchmarkfile_mmapwrite0   	1	126471.996 µs/op
      Benchmarkfile_mmapwrite0   	1	125886.917 µs/op
      Benchmarkfile_mmapwrite0   	1	125730.038 µs/op
      Benchmarkfile_write55      	1	86760.044 µs/op
      Benchmarkfile_write55      	1	87507.010 µs/op
      Benchmarkfile_write55      	1	87735.891 µs/op
      Benchmarkbigf_writeff      	1	448369.980 µs/op
      Benchmarkbigf_writeff      	1	448238.850 µs/op
      Benchmarkbigf_writeff      	1	447322.845 µs/op
      Benchmarkfile_mmapread     	1	207049.131 µs/op
      Benchmarkfile_mmapread     	1	207813.978 µs/op
      Benchmarkfile_mmapread     	1	210857.868 µs/op
      Benchmarkfile_read         	1	238364.935 µs/op
      Benchmarkfile_read         	1	236908.913 µs/op
      Benchmarkfile_read         	1	238602.161 µs/op
      Benchmarkfile_readbig      	1	303429.842 µs/op
      Benchmarkfile_readbig      	1	302191.973 µs/op
      Benchmarkfile_readbig      	1	304115.057 µs/op
      Benchmarkbigf_read         	1	435079.098 µs/op
      Benchmarkbigf_read         	1	434193.850 µs/op
      Benchmarkbigf_read         	1	434813.976 µs/op
      
      ========================== 11 passed in 12.54 seconds ==========================
      
      benchstat of new output:
      
      	name                µs/op
      	file_mmapread_hole   272k ±42%
      	file_read_hole       238k ± 0%
      	file_readbig_hole    301k ± 0%
      	bigf_read_hole       435k ± 0%
      	file_mmapwrite0      126k ± 0%
      	file_write55        87.3k ± 1%
      	bigf_writeff         448k ± 0%
      	file_mmapread        209k ± 1%
      	file_read            238k ± 0%
      	file_readbig         303k ± 0%
      	bigf_read            435k ± 0%
      
      --------
      
      Not only the output format is reworked here, but also b fixture is added
      to BenchPlugin so that functions which accept it as arg, can run the
      benchmark b.N times, can stop/restart timer etc - similar to
      https://golang.org/pkg/testing/#B . If a bench_* func does not accept b,
      B is still created, but b.N is assumed to be always 1.
      
      The first benchmark which actually uses b will come in the next patch.
      
      [1] https://github.com/golang/proposal/blob/master/design/14313-benchmark-format.md
      Kirill Smelkov committed
  21. 05 Dec, 2017 1 commit
  22. 04 Dec, 2017 2 commits
    • py.bench: Less noisy output · 074ce24d
      For several benchmarks in a python module instead of always printing
      whole benchmark function path (nodeid in pytest speak), first print
      
      	pymod: modulename
      
      header, and then only function names.
      
      Before patch:
      
      ============================= test session starts ==============================
      platform linux2 -- Python 2.7.14, pytest-3.3.0, py-1.5.2, pluggy-0.6.0
      rootdir: /home/kirr/src/wendelin/wendelin.core, inifile:
      collected 14 items
      
      bigfile/tests/bench_0virtmem.py::bench_file_mmapread_hole 	0.22  (0.39 0.22 0.22)
      bigfile/tests/bench_0virtmem.py::bench_file_read_hole    	0.24  (0.24 0.24 0.24)
      bigfile/tests/bench_0virtmem.py::bench_file_readbig_hole 	0.30  (0.30 0.30 0.30)
      bigfile/tests/bench_0virtmem.py::bench_bigf_read_hole    	0.43  (0.43 0.43 0.43)
      bigfile/tests/bench_0virtmem.py::bench_file_mmapwrite0   	0.12  (0.13 0.12 0.13)
      bigfile/tests/bench_0virtmem.py::bench_file_write55      	0.08  (0.08 0.08 0.08)
      bigfile/tests/bench_0virtmem.py::bench_bigf_writeff      	0.45  (0.45 0.45 0.45)
      bigfile/tests/bench_0virtmem.py::bench_file_mmapread     	0.21  (0.21 0.21 0.22)
      bigfile/tests/bench_0virtmem.py::bench_file_read         	0.23  (0.23 0.24 0.24)
      bigfile/tests/bench_0virtmem.py::bench_file_readbig      	0.30  (0.30 0.30 0.30)
      bigfile/tests/bench_0virtmem.py::bench_bigf_read         	0.43  (0.44 0.43 0.44)
      bigfile/tests/bench_1filezodb.py::bench_bigz_readhole    	0.42  (0.42 0.43 0.43)
      bigfile/tests/bench_1filezodb.py::bench_bigz_writeff     	0.84  (0.84 1.25 1.25)
      bigfile/tests/bench_1filezodb.py::bench_bigz_read        	0.60  (0.64 0.60 0.60)
      ========================== 14 passed in 21.78 seconds ==========================
      
      After patch:
      
      ============================= test session starts ==============================
      platform linux2 -- Python 2.7.14, pytest-3.3.0, py-1.5.2, pluggy-0.6.0
      rootdir: /home/kirr/src/wendelin/wendelin.core, inifile:
      collected 14 items
      
      pymod: bigfile/tests/bench_0virtmem.py
      bench_file_mmapread_hole	0.21  (0.39 0.22 0.21)
      bench_file_read_hole    	0.24  (0.24 0.24 0.24)
      bench_file_readbig_hole 	0.30  (0.30 0.30 0.30)
      bench_bigf_read_hole    	0.43  (0.43 0.43 0.43)
      bench_file_mmapwrite0   	0.12  (0.13 0.12 0.13)
      bench_file_write55      	0.08  (0.08 0.08 0.08)
      bench_bigf_writeff      	0.45  (0.52 0.51 0.45)
      bench_file_mmapread     	0.21  (0.21 0.21 0.21)
      bench_file_read         	0.24  (0.24 0.24 0.24)
      bench_file_readbig      	0.30  (0.30 0.30 0.30)
      bench_bigf_read         	0.43  (0.43 0.43 0.43)
      
      pymod: bigfile/tests/bench_1filezodb.py
      bench_bigz_readhole     	0.43  (0.43 0.43 0.43)
      bench_bigz_writeff      	0.83  (0.83 1.20 1.21)
      bench_bigz_read         	0.60  (0.65 0.60 0.60)
      
      ========================== 14 passed in 21.80 seconds ==========================
      
      The `key: value` header is compatible with Go benchmark format[1] and
      further we'll be trying to teach py.bench to output results in that
      format so that Go benchmarking tools like benchstat and perf.golang.org
      could be used for free.
      
      [1] https://github.com/golang/proposal/blob/master/design/14313-benchmark-format.md
      Kirill Smelkov committed
    • py.bench: Fix output reporting · ed13c3f9
      Upstream pytest changed TerminalReporter._locationline() signature from
      
      	def _locationline(self, collect_fspath, fspath, lineno, domain):
      
      to
      
      	def _locationline(self, nodeid, fspath, lineno, domain):
      
      https://github.com/pytest-dev/pytest/commit/d73e6899 .
      
      This way without adjusting py.bench was reporting just filenames instead
      of benchmark names, e.g. this way:
      
      (z-dev) kirr@deco:~/src/wendelin/wendelin.core$ ./t/py.bench bigfile/tests/bench_0virtmem.py
      =============================================================== test session starts ===============================================================
      platform linux2 -- Python 2.7.14, pytest-3.3.0, py-1.5.2, pluggy-0.6.0
      rootdir: /home/kirr/src/wendelin/wendelin.core, inifile:
      collected 11 items
      
      bigfile/tests/bench_0virtmem.py                                 0.21  (0.38 0.22 0.21)
      bigfile/tests/bench_0virtmem.py                                 0.23  (0.23 0.24 0.23)
      bigfile/tests/bench_0virtmem.py                                 0.30  (0.30 0.30 0.30)
      bigfile/tests/bench_0virtmem.py                                 0.43  (0.43 0.43 0.43)
      bigfile/tests/bench_0virtmem.py                                 0.12  (0.12 0.12 0.12)
      bigfile/tests/bench_0virtmem.py                                 0.08  (0.08 0.08 0.08)
      bigfile/tests/bench_0virtmem.py                                 0.44  (0.44 0.44 0.44)
      bigfile/tests/bench_0virtmem.py                                 0.20  (0.20 0.20 0.21)
      bigfile/tests/bench_0virtmem.py                                 0.24  (0.24 0.24 0.24)
      bigfile/tests/bench_0virtmem.py                                 0.30  (0.30 0.30 0.30)
      bigfile/tests/bench_0virtmem.py                                 0.43  (0.43 0.43 0.43)
      
      =========================================================== 11 passed in 12.39 seconds ============================================================
      
      Fix it.
      Kirill Smelkov committed
  23. 02 Dec, 2017 1 commit
    • py.bench: Fix report.bench_time collect · fc08766d
      In pytest3 pytest_runtest_call hook is always run as multicall and there
      is no way to control to disable it and force e.g. 'firstresult'
      behaviour. This way call.result in pytest_runtest_makereport is always a
      list of returned results, not the first result itself.
      
      Adjust the code in pytest_runtest_makereport to emulate 'firstresult'
      behaviour manually.
      
      Without the patch with recent pytest py.bench was crashing like this:
      
      ---- 8< ----
      (z-dev) kirr@link:~/src/wendelin/wendelin.core$ make bench
      python setup.py ll_build_ext --inplace
      running ll_build_ext
      copying build/lib.linux-x86_64-2.7/wendelin/bigfile/_bigfile.so -> bigfile
      python t/py.bench --ignore=3rdparty --ignore=build --ignore=t
      ============================================================= test session starts ==============================================================
      platform linux2 -- Python 2.7.14, pytest-3.3.0, py-1.5.2, pluggy-0.6.0
      rootdir: /home/kirr/src/wendelin/wendelin.core, inifile:
      collected 14 items
      
      bigfile/tests/bench_0virtmem.py                          	INTERNALERROR> Traceback (most recent call last):
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/_pytest/main.py", line 103, in wrap_session
      INTERNALERROR>     session.exitstatus = doit(config, session) or 0
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/_pytest/main.py", line 141, in _main
      INTERNALERROR>     config.hook.pytest_runtestloop(session=session)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 617, in __call__
      INTERNALERROR>     return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 222, in _hookexec
      INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 216, in <lambda>
      INTERNALERROR>     firstresult=hook.spec_opts.get('firstresult'),
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 201, in _multicall
      INTERNALERROR>     return outcome.get_result()
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 77, in get_result
      INTERNALERROR>     _reraise(*ex)  # noqa
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 180, in _multicall
      INTERNALERROR>     res = hook_impl.function(*args)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/_pytest/main.py", line 164, in pytest_runtestloop
      INTERNALERROR>     item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 617, in __call__
      INTERNALERROR>     return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 222, in _hookexec
      INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 216, in <lambda>
      INTERNALERROR>     firstresult=hook.spec_opts.get('firstresult'),
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 201, in _multicall
      INTERNALERROR>     return outcome.get_result()
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 77, in get_result
      INTERNALERROR>     _reraise(*ex)  # noqa
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 180, in _multicall
      INTERNALERROR>     res = hook_impl.function(*args)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/_pytest/runner.py", line 63, in pytest_runtest_protocol
      INTERNALERROR>     runtestprotocol(item, nextitem=nextitem)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/_pytest/runner.py", line 77, in runtestprotocol
      INTERNALERROR>     reports.append(call_and_report(item, "call", log))
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/_pytest/runner.py", line 161, in call_and_report
      INTERNALERROR>     hook.pytest_runtest_logreport(report=report)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 617, in __call__
      INTERNALERROR>     return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 222, in _hookexec
      INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/__init__.py", line 216, in <lambda>
      INTERNALERROR>     firstresult=hook.spec_opts.get('firstresult'),
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 201, in _multicall
      INTERNALERROR>     return outcome.get_result()
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 77, in get_result
      INTERNALERROR>     _reraise(*ex)  # noqa
      INTERNALERROR>   File "/home/kirr/src/wendelin/venv/z-dev/local/lib/python2.7/site-packages/pluggy/callers.py", line 180, in _multicall
      INTERNALERROR>     res = hook_impl.function(*args)
      INTERNALERROR>   File "t/py.bench", line 165, in pytest_runtest_logreport
      INTERNALERROR>     self._tw.write('%.2f' % min(report.bench_times))
      INTERNALERROR> TypeError: float argument required, not list
      Kirill Smelkov committed
  24. 01 Dec, 2017 1 commit
    • py.bench: Don't forget to clear config's inicache after tweaking config.inicfg · 5a1ed45a
      If py.test machinery access any of the keys we change before we tweak
      them - their values will be put to config._inicache and our tweaking
      won't essentially have the effect.
      
      It used to be working without explicit cache invalidation with older
      pytests, but as of e.g. py.test 3.2.1 it does not work without explicit
      cache clearing because e.g. 'python_files' is somehow accessed before
      and is set to std 'test_*.py' + friends in the cache and this way
      py.bench then does not collect benchmarks from bench_*.py files.
      
      Fix it by making sure inicache is invalidated after our inicfg tweak.
      Kirill Smelkov committed