Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cythonize some hotspots #55

Merged
merged 21 commits into from Jul 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cf871af
Basic cythonization of datastructures, externalization, internalizati…
jamadden Jun 26, 2018
fa77efa
Add cython to travis.
jamadden Jun 26, 2018
5ced9a2
Workaround broken test on Python 3 with cython.
jamadden Jun 26, 2018
fe925a8
cython optimize singleton.py
jamadden Jun 26, 2018
06dbfdb
Checkpoint on cython declarations. About a 3-5% improvement over the …
jamadden Jun 26, 2018
7750157
More externalization work: declare attributes for state management
jamadden Jun 26, 2018
4c62daf
More declarations: another 3-6% faster on externalization.
jamadden Jun 26, 2018
0290392
Our thread-local data is simple enough (and read/written in only one …
jamadden Jun 26, 2018
e1f69e1
Fix build when no old .pycs are around. Also some more typing for ano…
jamadden Jun 27, 2018
232b089
Update comment.
jamadden Jun 27, 2018
f9a9592
Now that I understand that it's *types* that cause the problem with l…
jamadden Jun 27, 2018
b20aed4
More typing in datastructures.py
jamadden Jun 27, 2018
bed7e65
Learn how to do enumerated constants as class bodies in cython
jamadden Jun 27, 2018
1627cb6
First part of typing internalization.py. Roughly 3-5% further improve…
jamadden Jun 28, 2018
5a57ae8
More tpying for internalization.py
jamadden Jun 28, 2018
b979de0
More internalization typing.
jamadden Jun 28, 2018
78c71b5
Tweak function for readability.
jamadden Jun 28, 2018
45d5d81
Typing and optimizations for notifyModified, one of the biggest remai…
jamadden Jun 28, 2018
50e55c3
More static names.
jamadden Jun 28, 2018
02d5792
test coverage
jamadden Jun 28, 2018
a4946ec
Officially deprecate arbitrary kwargs for to_standard_external_dictio…
jamadden Jun 28, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
@@ -1,4 +1,12 @@
*.py[cod]
*.so
# artifacts from cythonize
*.c
src/nti/externalization/*.html


__pycache__/*
benchmark_results/

/.project
/.pydevproject
Expand Down
22 changes: 20 additions & 2 deletions .travis.yml
Expand Up @@ -5,6 +5,20 @@ python:
- 3.6
- pypy
- pypy3
matrix:
include:
- python: 2.7
env: PURE_PYTHON=1
- python: 3.6
env: PURE_PYTHON=1
env:
global:
- CC="ccache gcc"
- CCACHE_SLOPPINESS=file_macro,time_macros,include_file_ctime,include_file_mtime
- CCACHE_NOHASHDIR=true
- CFLAGS="-Ofast -pipe -fomit-frame-pointer -march=native"
- PYTHONHASHSEED=random
- PIP_UPGRADE_STRATEGY=eager
script:
- coverage run -m zope.testrunner --test-path=src
after_success:
Expand All @@ -14,11 +28,15 @@ notifications:

install:
- pip install -U pip
- pip install -U setuptools
- pip install -U setuptools cython
- pip install -U coveralls coverage
- pip install -U -e ".[test]"

cache: pip

cache:
pip: true
directories:
- $HOME/.ccache

before_cache:
- rm -f $HOME/.cache/pip/log/debug.log
18 changes: 18 additions & 0 deletions CHANGES.rst
Expand Up @@ -10,6 +10,24 @@
``update_from_external_object``. See
https://github.com/NextThought/nti.externalization/issues/29.

- A number of deprecated aliases for moved functions have been
removed.

- On CPython, some of the modules are compiled as extension modules
using Cython for a 10-30% increase in speed. Set the ``PURE_PYTHON``
environment variable to disable this at runtime.

- The unused, undocumented method
``stripSyntheticKeysFromExternalDictionary`` was removed from
instances of ``ExternalizableDictionaryMixin``. Use the import instead.

- Unused keyword arguments for ``to_standard_external_dictionary``
and ``to_minimal_standard_external_dictionary`` now produce a warning.
In the future, extra keyword arguments will be an error.

- ``notifyModified`` no longer accepts the ``eventFactory`` argument.

- The ``notify_modified`` alias for ``notifyModified`` has been removed.

1.0.0a1 (2017-09-29)
====================
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Expand Up @@ -17,3 +17,4 @@ recursive-include docs *.rst
recursive-include docs Makefile

recursive-include src *.zcml
recursive-include src *.c
2 changes: 1 addition & 1 deletion setup.cfg
Expand Up @@ -5,4 +5,4 @@ cover-package=nti.externalization
dev = develop easy_install nti.externalization[test]

[bdist_wheel]
universal = 1
universal = 0
85 changes: 82 additions & 3 deletions setup.py
@@ -1,5 +1,12 @@
import os
import sys
import codecs
from setuptools import setup, find_packages

from setuptools import setup
from setuptools import find_packages
from setuptools import Extension

PYPY = hasattr(sys, 'pypy_version_info')

entry_points = {
'console_scripts': [
Expand All @@ -17,6 +24,79 @@ def _read(fname):
with codecs.open(fname, encoding='utf-8') as f:
return f.read()

# Cython

try:
from Cython.Build import cythonize
except ImportError:
# The .c files had better already exist, as they should in
# an sdist. Based on code from
# http://cython.readthedocs.io/en/latest/src/reference/compilation.html#distributing-cython-modules
def cythonize(extensions, **_kwargs):
for extension in extensions:
sources = []
for sfile in extension.sources:
path, ext = os.path.splitext(sfile)
if ext in ('.pyx', '.py'):
ext = '.c'
sfile = path + ext
sources.append(sfile)
extension.sources[:] = sources
return extensions


ext_modules = []

# Modules we want to compile with Cython. These *should* have a parallel
# .pxd file (with a leading _) defining cython attributes.
# They should also have a cython comment at the top giving options,
# and mention that they are compiled with cython on CPython.
# The bottom of the file must call import_c_accel.
# We use the support from Cython 28 to be able to parallel compile
# and cythonize modules to a different name with a leading _.
# This list is derived from the profile of bm_simple_iface
# https://github.com/NextThought/nti.externalization/commit/0bc4733aa8158acd0d23c14de2f9347fb698c040
if not PYPY:
def _source(m, ext):
return 'src/nti/externalization/' + m + '.' + ext
def _py_source(m):
return _source(m, 'py')
def _pxd(m):
return _source(m, 'pxd')
def _c(m):
return _source(m, 'c')
# Each module should list the python name of the
# modules it cimports from as deps. We'll generate the rest.
# (Not that this actually appears to do anything right now.)

for mod_name, deps in (
('singleton', ()),
('_base_interfaces', ()),
('internalization', ()),
('externalization', ('_base_interfaces',)),
('datastructures', ('_base_interfaces', 'externalization',
'internalization')),
):
deps = ([_py_source(mod) for mod in deps]
+ [_pxd(mod) for mod in deps]
+ [_c(mod) for mod in deps])

ext_modules.append(
Extension(
'nti.externalization._' + mod_name,
sources=[_py_source(mod_name)],
depends=deps,
define_macros=[('CYTHON_TRACE', '1')],
))

ext_modules = cythonize(
ext_modules,
annotate=True,
compiler_directives={
#'linetrace': True,
'infer_types': True,
},
)

setup(
name='nti.externalization',
Expand Down Expand Up @@ -45,6 +125,7 @@ def _read(fname):
package_dir={'': 'src'},
include_package_data=True,
namespace_packages=['nti'],
ext_modules=ext_modules,
tests_require=TESTS_REQUIRE,
install_requires=[
'setuptools',
Expand All @@ -60,8 +141,6 @@ def _read(fname):
'zope.component',
'zope.configuration',
'zope.container',
'zope.deferredimport',
'zope.deprecation >= 4.3.0',
'zope.dottedname',
'zope.dublincore',
'zope.event',
Expand Down
54 changes: 54 additions & 0 deletions src/nti/externalization/__base_interfaces.pxd
@@ -0,0 +1,54 @@
# declarations for _base_interfaces.py

import cython

@cython.final
@cython.internal
cdef class _NotGiven(object):
pass


cdef class LocatedExternalDict(dict):
cdef public __name__
cdef public __parent__
cdef public __acl__
cdef readonly mimeType

cpdef LocatedExternalDict make_external_dict()

cdef class StandardExternalFields(object):

cdef readonly unicode ID
cdef readonly unicode OID
cdef readonly unicode HREF
cdef readonly unicode INTID
cdef readonly unicode NTIID
cdef readonly unicode CREATOR
cdef readonly unicode CONTAINER_ID
cdef readonly unicode CREATED_TIME
cdef readonly unicode LAST_MODIFIED
cdef readonly unicode CLASS
cdef readonly unicode LINKS
cdef readonly unicode MIMETYPE
cdef readonly unicode ITEMS
cdef readonly unicode TOTAL
cdef readonly unicode ITEM_COUNT
cdef readonly frozenset ALL

cdef StandardExternalFields _standard_external_fields

cpdef StandardExternalFields get_standard_external_fields()

cdef class StandardInternalFields(object):

cdef readonly str ID
cdef readonly str NTIID
cdef readonly str CREATOR
cdef readonly str CREATED_TIME
cdef readonly str CONTAINER_ID
cdef readonly str LAST_MODIFIED
cdef readonly str LAST_MODIFIEDU

cdef StandardInternalFields _standard_internal_fields

cpdef StandardInternalFields get_standard_internal_fields()