-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8e5fa8b
commit 1f49ebb
Showing
4 changed files
with
233 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,101 @@ | ||
/target | ||
flaco/*.so | ||
flaco/*.c | ||
*.html | ||
*.dat | ||
heaptrack.* | ||
.idea/ | ||
__pycache__/ | ||
|
||
# Distribution / packaging | ||
wheelhouse/ | ||
.Python | ||
env/ | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
.hypothesis/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
*.cpp | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
prof/ | ||
# pyenv | ||
.python-version | ||
|
||
# celery beat schedule file | ||
celerybeat-schedule | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# dotenv | ||
.env | ||
|
||
# virtualenv | ||
.venv | ||
venv/ | ||
ENV/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,70 @@ | ||
from concurrent.futures import ThreadPoolExecutor, wait | ||
from gilknocker import KnockKnock, lock_and_release_gil | ||
import numpy as np | ||
import threading | ||
import time | ||
from gilknocker import KnockKnock | ||
|
||
|
||
def test_knockknock(): | ||
knocker = KnockKnock(5) | ||
assert knocker.time_locked_ms() is None | ||
N_THREADS = 4 | ||
N_PTS = 4096 | ||
|
||
n = 10 | ||
|
||
def flaky(n_tries=5): | ||
def wrapper(func): | ||
def _wrapper(*args, **kwargs): | ||
for _ in range(n_tries - 1): | ||
try: | ||
return func(*args, **kwargs) | ||
except: | ||
pass | ||
return func(*args, **kwargs) | ||
|
||
return _wrapper | ||
|
||
return wrapper | ||
|
||
|
||
def a_lotta_gil(): | ||
"""Keep the GIL busy""" | ||
for i in range(100_000_000): | ||
pass | ||
|
||
|
||
def a_little_gil(): | ||
"""Work which releases the GIL""" | ||
for i in range(2): | ||
x = np.random.randn(N_PTS, N_PTS) | ||
x[:] = np.fft.fft2(x).real | ||
|
||
|
||
def _run(target): | ||
knocker = KnockKnock(interval_micros=1000, timeout_secs=1) | ||
knocker.start() | ||
jobs = [] | ||
with ThreadPoolExecutor(10) as executor: | ||
for _ in range(n): | ||
jobs.append(executor.submit(lock_and_release_gil, 0, 5000)) | ||
wait(jobs) | ||
threads = [] | ||
for i in range(N_THREADS): | ||
thread = threading.Thread(target=target, daemon=True) | ||
threads.append(thread) | ||
thread.start() | ||
|
||
for thread in threads: | ||
thread.join() | ||
knocker.stop() | ||
assert knocker.time_unlocked_ms() > 0 | ||
breakpoint() | ||
print(f"Metric: {knocker.contention_metric}") | ||
return knocker | ||
|
||
|
||
@flaky() | ||
def test_knockknock_busy(): | ||
knocker = _run(a_lotta_gil) | ||
assert knocker.contention_metric > 0.9 | ||
|
||
|
||
@flaky() | ||
def test_knockknock_available_gil(): | ||
knocker = _run(a_little_gil) | ||
assert knocker.contention_metric < 0.01 | ||
|
||
|
||
# Manual verification with py-spy | ||
# busy should give high GIL % | ||
if __name__ == "__main__": | ||
test_knockknock_busy() |