https://github.com/sueszli/nogil
performance optimizations with GIL free cpython
https://github.com/sueszli/nogil
global-interpreter-lock pep-703 performance-engineering
Last synced: 6 months ago
JSON representation
performance optimizations with GIL free cpython
- Host: GitHub
- URL: https://github.com/sueszli/nogil
- Owner: sueszli
- License: agpl-3.0
- Created: 2024-11-18T16:51:23.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2024-12-17T07:03:12.000Z (about 1 year ago)
- Last Synced: 2025-01-22T21:32:47.878Z (about 1 year ago)
- Topics: global-interpreter-lock, pep-703, performance-engineering
- Language: Python
- Homepage:
- Size: 7.78 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README
- License: LICENSE
Awesome Lists containing this project
README
Check out the:
- report: https://sueszli.github.io/nogil/docs/report.pdf
- slides: https://sueszli.github.io/nogil/docs/slides.pdf
Y
.-^-.
/ \ .- ~ ~ -. pssssss...
() () / _ _ `. _ _ _
\_ _/ / / \ \ . ~ _ _ ~ .
| | / / \ \ .' .~ ~-. `.
| | / / ) ) / / `.`.
\ \_ _/ / / / / / `'
\_ _ _.' / / ( (
/ / \ \
/ / \ \ psssss.....
/ / ) )
( ( / /
`. `. .' /
`. ~ - - - - ~ .'
~ . _ _ _ _ . ~
File tree:
- `src/0_plain`: plain python implementations of hashcat
- `src/1_multiprocessing`: multiprocessing implementations
- `src/2_multithreading`: multithreading implementations with the GIL enabled/disabled
- `src/3_ctypes`: ctypes implementations, some using OpenMP
- `src/4_cpython`: cpython implementations, based on the C API of CPython
- `benchmark.sh`: non-portable benchmarking script using `perf`
Evaluation:
```bash
#
# prepare environment
#
# compile cpython
make docker-up # takes 20min
docker compose exec main python3 -c 'import sys; assert sys.version_info >= (3, 13); assert not sys._is_gil_enabled(); print("it works!")'
# get dependencies for hyperfine, openssl
docker compose exec main apt update
docker compose exec main apt install -y build-essential apt-utils curl libssl-dev openssl
docker compose exec main sh -c 'curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh'
docker compose exec main /root/.cargo/bin/cargo --version
docker compose exec main /root/.cargo/bin/cargo install --locked hyperfine
docker compose exec main /root/.cargo/bin/hyperfine --version
# get target hash to crack
python -c "import hashlib; print(hashlib.sha1('aaa'.encode()).hexdigest())"
#
# runtime benchmark
#
# plain
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/0_plain/itertools.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +1 tmp.csv >> results.csv
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/0_plain/lib.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/0_plain/plain.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
# multiprocessing
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/1_multiprocessing/imap_unordered.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/1_multiprocessing/imap.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/1_multiprocessing/map_async.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/1_multiprocessing/map.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
# multithreading
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "PYTHON_GIL=1 python ./src/2_multithreading/executor.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "PYTHON_GIL=0 python ./src/2_multithreading/executor.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "PYTHON_GIL=1 python ./src/2_multithreading/workers.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "PYTHON_GIL=0 python ./src/2_multithreading/workers.py 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
# ctypes
docker compose exec main gcc -fopenmp -fPIC -shared -o ./src/3_ctypes/libhashcat.so ./src/3_ctypes/hashcat.c -lcrypto -lssl
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/3_ctypes/invoke_hashcat.py ./src/3_ctypes/libhashcat.so 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
docker compose exec main gcc -fopenmp -fPIC -shared -o ./src/3_ctypes/libhashcat_openmp.so ./src/3_ctypes/hashcat_openmp.c -lcrypto -lssl
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/3_ctypes/invoke_hashcat.py ./src/3_ctypes/libhashcat_openmp.so 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
# cpython
docker compose exec main gcc -shared -fopenmp -o ./src/4_cpython/hashcatmodule.so -fPIC -I/usr/local/include/python3.13t ./src/4_cpython/hashcat.c -lcrypto -lssl
docker compose exec main /root/.cargo/bin/hyperfine --warmup 3 --export-csv tmp.csv "python ./src/4_cpython/invoke_hashcat.py ./src/3_ctypes/libhashcat_openmp.so 7e240de74fb1ed08fa08d38063f6a6a91462a815" && tail -n +2 tmp.csv >> results.csv
```
# Advanced Evaluation
We also measure cycles, instructions and runtime in the `benchmark.sh` script. However, it isn't portable and requires an amd64 architecture for execution.
- 1) update the python binary path in the script at the variable `PYTHON_BIN`. for example: `PYTHON_BIN="python3.13-nogil"`
- 2) compile the cpython extension binaries:
```bash
docker compose exec main gcc -shared -fopenmp -o ./src/4_cpython/hashcatmodule.so -fPIC -I/usr/local/include/python3.13t ./src/4_cpython/hashcat.c -lcrypto -lssl
docker compose exec main gcc -fopenmp -fPIC -shared -o ./src/3_ctypes/libhashcat_openmp.so ./src/3_ctypes/hashcat_openmp.c -lcrypto -lssl
docker compose exec main gcc -fopenmp -fPIC -shared -o ./src/3_ctypes/libhashcat.so ./src/3_ctypes/hashcat.c -lcrypto -lssl
```
- 3) run `./benchmark.sh`.