From 93f368c8832089ec38783e4a9fbcc2b1e6189670 Mon Sep 17 00:00:00 2001 From: Brett Langdon Date: Tue, 16 Feb 2021 18:02:50 -0500 Subject: [PATCH] add benchmark and cython improvements (#11) * add benchmark and cython improvements * raise exceptions * mypy ignore pytest module * Update sysaudit/_csysaudit.pyx --- .mypy.ini | 4 ++++ poetry.lock | 50 ++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + sysaudit/_csysaudit.pyx | 29 +++++++++++++++--------- tests/test_benchmark.py | 31 +++++++++++++++++++++++++ 5 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 .mypy.ini create mode 100644 tests/test_benchmark.py diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 0000000..c8b86c7 --- /dev/null +++ b/.mypy.ini @@ -0,0 +1,4 @@ +[mypy] + +[mypy-pytest] +ignore_missing_imports = True diff --git a/poetry.lock b/poetry.lock index 83e520f..621c67a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -409,6 +409,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "py-cpuinfo" +version = "7.0.0" +description = "Get CPU info with pure Python 2 & 3" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "pygments" version = "2.5.2" @@ -469,6 +477,25 @@ wcwidth = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "nose", "requests", "mock"] +[[package]] +name = "pytest-benchmark" +version = "3.2.3" +description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer. See calibration_ and FAQ_." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.dependencies] +pathlib2 = {version = "*", markers = "python_version < \"3.4\""} +py-cpuinfo = "*" +pytest = ">=3.8" +statistics = {version = "*", markers = "python_version < \"3.4\""} + +[package.extras] +aspect = ["aspectlib"] +elasticsearch = ["elasticsearch"] +histogram = ["pygal", "pygaljs"] + [[package]] name = "pytz" version = "2021.1" @@ -659,6 +686,17 @@ python-versions = ">=3.5" lint = ["flake8", "mypy", "docutils-stubs"] test = ["pytest"] +[[package]] +name = "statistics" +version = "1.0.3.5" +description = "A Python 2.* port of 3.4 Statistics Module" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +docutils = ">=0.3" + [[package]] name = "stevedore" version = "3.3.0" @@ -764,7 +802,7 @@ testing = ["pathlib2", "unittest2", "jaraco.itertools", "func-timeout"] [metadata] lock-version = "1.1" python-versions = "~2.7 || ~=3.5" -content-hash = "66b3b619f735c9504ddf521624a8f902b6fb71e0d577c662e943087d0a2d66b7" +content-hash = "57946bea81d199e225e949dee5fce80d7777c2c688a0f0af4d4852f5014d827e" [metadata.files] alabaster = [ @@ -1000,6 +1038,9 @@ py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] +py-cpuinfo = [ + {file = "py-cpuinfo-7.0.0.tar.gz", hash = "sha256:9aa2e49675114959697d25cf57fec41c29b55887bff3bc4809b44ac6f5730097"}, +] pygments = [ {file = "Pygments-2.5.2-py2.py3-none-any.whl", hash = "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b"}, {file = "Pygments-2.5.2.tar.gz", hash = "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"}, @@ -1020,6 +1061,10 @@ pytest = [ {file = "pytest-4.6.11-py2.py3-none-any.whl", hash = "sha256:a00a7d79cbbdfa9d21e7d0298392a8dd4123316bfac545075e6f8f24c94d8c97"}, {file = "pytest-4.6.11.tar.gz", hash = "sha256:50fa82392f2120cc3ec2ca0a75ee615be4c479e66669789771f1758332be4353"}, ] +pytest-benchmark = [ + {file = "pytest-benchmark-3.2.3.tar.gz", hash = "sha256:ad4314d093a3089701b24c80a05121994c7765ce373478c8f4ba8d23c9ba9528"}, + {file = "pytest_benchmark-3.2.3-py2.py3-none-any.whl", hash = "sha256:01f79d38d506f5a3a0a9ada22ded714537bbdfc8147a881a35c1655db07289d9"}, +] pytz = [ {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, @@ -1151,6 +1196,9 @@ sphinxcontrib-serializinghtml = [ {file = "sphinxcontrib-serializinghtml-1.1.4.tar.gz", hash = "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc"}, {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, ] +statistics = [ + {file = "statistics-1.0.3.5.tar.gz", hash = "sha256:2dc379b80b07bf2ddd5488cad06b2b9531da4dd31edb04dc9ec0dc226486c138"}, +] stevedore = [ {file = "stevedore-3.3.0-py3-none-any.whl", hash = "sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"}, {file = "stevedore-3.3.0.tar.gz", hash = "sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee"}, diff --git a/pyproject.toml b/pyproject.toml index fdcf2ce..a313737 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ sphinx-rtd-theme = {version = "~=0.5.1", python = "~=3.5"} vulture = {version = "~=2.3", python = "~=3.6"} bandit = {version = "~=1.7.0", python = "~=3.6"} pdbpp = "^0.10.2" +pytest-benchmark = "^3.2.3" [build-system] requires = ["poetry-core>=1.0.0", "Cython", "setuptools"] diff --git a/sysaudit/_csysaudit.pyx b/sysaudit/_csysaudit.pyx index 8a74c06..5ef0ef6 100644 --- a/sysaudit/_csysaudit.pyx +++ b/sysaudit/_csysaudit.pyx @@ -1,15 +1,24 @@ -_hooks = list() +cdef list hooks = [] +cdef int has_hooks = 0 -def audit(event, *args): - global _hooks - # Grab a copy of hooks so we don't need to lock here - for hook in _hooks[:]: +cdef void _audit(str event, tuple args) except *: + global hooks + for hook in hooks: hook(event, args) -def addaudithook(callback): - global _hooks +def audit(event, *args): + global has_hooks + + if has_hooks == 0: + return + _audit(event, args) + + +cpdef void addaudithook(callback) except *: + global hooks + global has_hooks # https://docs.python.org/3.8/library/sys.html#sys.addaudithook # Raise an auditing event `sys.addaudithook` with no arguments. @@ -18,9 +27,9 @@ def addaudithook(callback): # As a result, callers cannot assume that their hook has been added # unless they control all existing hooks. try: - audit("sys.addaudithook") + _audit("sys.addaudithook", tuple()) except RuntimeError: return - if callback not in _hooks: - _hooks.append(callback) + has_hooks = 1 + hooks.append(callback) diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py new file mode 100644 index 0000000..5f3646b --- /dev/null +++ b/tests/test_benchmark.py @@ -0,0 +1,31 @@ +import unittest + +import pytest + +import sysaudit + + +def hook(event, args): + pass + + +@pytest.mark.benchmark(group="audit") +def test_csysaudit_audit(benchmark): + sysaudit.csysaudit_addaudithook(hook) + + benchmark(sysaudit.csysaudit_audit, "event", 1, 2, 3) + + +@pytest.mark.benchmark(group="audit") +def test_std_audit(benchmark): + if not sysaudit.std_audit: + raise unittest.SkipTest("stdlib version not available") + + sysaudit.std_addaudithook(hook) + benchmark(sysaudit.std_audit, "event", 1, 2, 3) + + +@pytest.mark.benchmark(group="audit") +def test_py_audit(benchmark): + sysaudit.py_addaudithook(hook) + benchmark(sysaudit.py_audit, "event", 1, 2, 3)