Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f3254b0
Add threading
Theelx Apr 20, 2021
39eb7d6
fix erroneous variable name
Theelx Apr 24, 2021
5a38626
add -i option
Theelx Jul 14, 2022
04df6fc
Update build process & massively decrease profiling overhead
Theelx Jul 17, 2022
f7d5ec1
Remove testing file
Theelx Jul 17, 2022
d138c40
Expose python interface
Theelx Jul 17, 2022
00aabd5
Improve python interface & update gitignore
Theelx Jul 17, 2022
c4bb3fc
Remove unused scikit stuff and update changelog/version
Theelx Jul 17, 2022
71851bf
Update README.rst
Theelx Jul 17, 2022
d9ff50a
Remove unnecssary build requirements
Theelx Jul 18, 2022
f91c1e0
Fix formatting
Theelx Jul 18, 2022
d701729
Fix bytecode hashing failing to display identical functions
Theelx Jul 20, 2022
62f7657
Misc code cleanup
Theelx Aug 12, 2022
001cedf
More misc code cleanups
Theelx Aug 12, 2022
5e65833
Remove useless comments
Theelx Aug 12, 2022
ba57c29
Move around external declaration for better 3.11 compatability
Theelx Aug 19, 2022
6f7d098
Add python 3.11 support
Theelx Aug 22, 2022
a9448ec
Drop unused build-time dependencies
Theelx Aug 22, 2022
873535f
Update kernprof version in sync
Theelx Aug 23, 2022
50df07a
Fix tests
Theelx Aug 23, 2022
5a0e3cf
Update changelog
Theelx Aug 23, 2022
e47c57d
Fix accidental cpdef
Theelx Sep 12, 2022
8218f55
Fix cython submodule and relative imports
Theelx Sep 12, 2022
b25c875
Fix relative imports in order to remove redundant file
Theelx Sep 12, 2022
d418abe
Extract xor into a specialized function
Theelx Sep 14, 2022
380f049
Rebase on main branch
Erotemic Sep 12, 2022
796a26d
Fix merge conflicts
Erotemic Sep 11, 2022
2f4888e
Fix a whoopsie
Theelx Sep 14, 2022
7cc13f4
Use ns resolution for times on non-windows platforms
Theelx Sep 16, 2022
5c51546
Remove duplicate function in setup
Erotemic Oct 2, 2022
db76206
Refactor test to use pytest intead of unittest
Erotemic Oct 2, 2022
ed3c667
Make code_map and last_time backwards compatible
Erotemic Oct 2, 2022
699f0d4
refactor code_replace
Erotemic Oct 2, 2022
ba4ad39
Merge pull request #1 from Erotemic/tweaks
Theelx Oct 3, 2022
d2ae5f9
Fix mistake
Erotemic Nov 2, 2022
8dc3721
Enable 311 in CI
Erotemic Nov 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Checkout source
uses: actions/checkout@v3
- name: Set up Python 3.8
uses: actions/setup-python@v4.2.0
uses: actions/setup-python@v4.3.0
with:
python-version: 3.8
- name: Install dependencies
Expand All @@ -40,15 +40,14 @@ jobs:
- name: Checkout source
uses: actions/checkout@v3
- name: Set up Python 3.8
uses: actions/setup-python@v4.2.0
uses: actions/setup-python@v4.3.0
with:
python-version: 3.8
- name: Upgrade pip
run: |-
python -m pip install --upgrade pip
python -m pip install -r requirements/tests.txt
python -m pip install -r requirements/runtime.txt
true
- name: Build sdist
shell: bash
run: |-
Expand Down Expand Up @@ -99,9 +98,9 @@ jobs:
strategy:
matrix:
os:
- windows-latest
- ubuntu-latest
- macOS-latest
- windows-latest
cibw_skip:
- '*-win32'
arch:
Expand All @@ -127,7 +126,7 @@ jobs:
with:
platforms: all
- name: Build binary wheels
uses: pypa/cibuildwheel@v2.9.0
uses: pypa/cibuildwheel@v2.10.0
with:
output-dir: wheelhouse
config-file: pyproject.toml
Expand All @@ -138,7 +137,7 @@ jobs:
shell: bash
run: ls -la wheelhouse
- name: Set up Python 3.8 to combine coverage Linux
uses: actions/setup-python@v4.2.0
uses: actions/setup-python@v4.3.0
if: runner.os == 'Linux'
with:
python-version: 3.8
Expand Down Expand Up @@ -204,7 +203,8 @@ jobs:
$GPG_EXECUTABLE --list-keys || echo "first invocation of gpg creates directories and returns 1"
$GPG_EXECUTABLE --list-keys
VERSION=$(python -c "import setup; print(setup.VERSION)")
pip install urllib3 requests[security] twine -U
pip install twine
pip install urllib3 requests[security] twine
GPG_KEYID=$(cat dev/public_gpg_key)
echo "GPG_KEYID = '$GPG_KEYID'"
DO_GPG=True GPG_KEYID=$GPG_KEYID TWINE_REPOSITORY_URL=${TWINE_REPOSITORY_URL} TWINE_PASSWORD=$TWINE_PASSWORD TWINE_USERNAME=$TWINE_USERNAME GPG_EXECUTABLE=$GPG_EXECUTABLE DO_UPLOAD=True DO_TAG=False ./publish.sh
Expand Down Expand Up @@ -246,7 +246,8 @@ jobs:
$GPG_EXECUTABLE --list-keys || echo "first invocation of gpg creates directories and returns 1"
$GPG_EXECUTABLE --list-keys
VERSION=$(python -c "import setup; print(setup.VERSION)")
pip install urllib3 requests[security] twine -U
pip install twine
pip install urllib3 requests[security] twine
GPG_KEYID=$(cat dev/public_gpg_key)
echo "GPG_KEYID = '$GPG_KEYID'"
DO_GPG=True GPG_KEYID=$GPG_KEYID TWINE_REPOSITORY_URL=${TWINE_REPOSITORY_URL} TWINE_PASSWORD=$TWINE_PASSWORD TWINE_USERNAME=$TWINE_USERNAME GPG_EXECUTABLE=$GPG_EXECUTABLE DO_UPLOAD=True DO_TAG=False ./publish.sh
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*.so
*.o
*.a
*.cpp

build/
dist/
Expand All @@ -18,6 +19,9 @@ line_profiler.egg-info/
MANIFEST
pypi-site-docs.zip
index.html
CMake*
!line_profiler/CMakeLists.txt
Makefile

.coverage
tests/coverage.xml
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Changes
=======

4.0.0
~~~~~
* ENH: Python 3.11 is now supported.
* ENH: Profiling overhead is now drastically smaller, thanks to reimplementing almost all of the tracing callback in C++. You can expect to see reductions of between 0.3 and 1 microseconds per line hit, resulting in a speedup of up to 4x for codebases with many lines of Python that only do a little work per line.
* ENH: Added the ``-i <# of seconds>`` option to the ``kernprof`` script. This uses the threading module to output profiling data to the output file every n seconds, and is useful for long-running tasks that shouldn't be stopped in the middle of processing.
* CHANGE: Cython's native cythonize function is now used to compile the project, instead of scikit-build's convoluted process.
* CHANGE: Due to optimizations done while reimplementing the callback in C++, the profiler's code_map and last_time attributes now are indexed by a hash of the code block's bytecode and its line number. Any code that directly reads (and processes) or edits the code_map and/or last_time attributes will likely break.

3.5.2
~~~~~
* FIX: filepath test in is_ipython_kernel_cell for Windows #161
Expand Down
45 changes: 0 additions & 45 deletions CMakeLists.txt

This file was deleted.

22 changes: 9 additions & 13 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ line_profiler and kernprof
|Pypi| |Downloads| |CircleCI| |GithubActions| |Codecov|


NOTICE: This is the official `line_profiler` repository. The most recent
NOTICE: This is **not** the official `line_profiler` repository. The most recent
version of `line-profiler <https://pypi.org/project/line_profiler/>`_ on pypi
points to this repo. The the original
`line_profiler <https://github.com/rkern/line_profiler/>`_ package by
`@rkern <https://github.com/rkern/>`_ is currently unmaintained. This fork
seeks to simply maintain the original code so it continues to work in new
versions of Python.
points to the repo this was forked from. This fork makes a few ABI changes for
the sake of massively decreased overhead. You can install this fork with
``pip install git+https://github.com/Theelx/line_profiler.git``
Eventually this fork may be uploaded to PyPi, or upstreamed to pyutils, but not
for now.

----

Expand All @@ -31,19 +31,15 @@ Installation

Releases of `line_profiler` can be installed using pip::

$ pip install line_profiler
$ pip install git+https://github.com/Theelx/line_profiler.git

Installation while ensuring a compatible IPython version can also be installed using pip::

$ pip install line_profiler[ipython]

Source releases and any binaries can be downloaded from the PyPI link.

http://pypi.python.org/pypi/line_profiler
$ pip install git+https://github.com/Theelx/line_profiler.git[ipython]

To check out the development sources, you can use Git_::

$ git clone https://github.com/pyutils/line_profiler.git
$ git clone https://github.com/Theelx/line_profiler.git

You may also download source tarballs of any snapshot from that URL.

Expand Down
4 changes: 4 additions & 0 deletions clean.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ rm -rf wheelhouse
rm -rf pip-wheel-metadata
rm -rf htmlcov
rm -rf tests/htmlcov
rm -rf CMakeCache.txt
rm -rf CMakeTmp
rm -rf CMakeFiles
rm -rf tests/htmlcov


if [ -f "distutils.errors" ]; then
Expand Down
29 changes: 29 additions & 0 deletions comp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import multiprocessing
import os
import sys
from setuptools import Extension, setup

from Cython.Build import cythonize

def run_cythonize(force=False):
return cythonize(
Extension(
name="line_profiler._line_profiler",
sources=[f"line_profiler/_line_profiler.pyx", "line_profiler/timers.c", "line_profiler/unset_trace.c"],
language="c++",
define_macros=[("CYTHON_TRACE", (1 if os.getenv("DEV") == "true" else 0))],
),
compiler_directives={"language_level": 3, "infer_types": True, "linetrace": (True if os.getenv("DEV") == "true" else False)},
include_path=["line_profiler/python25.pxd"],
force=force,
nthreads=multiprocessing.cpu_count(),
)

def run_setup(force=False):
setup(
ext_modules=run_cythonize()
)


if __name__ == "__main__":
run_setup(force=True)
50 changes: 48 additions & 2 deletions kernprof.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import functools
import os
import sys
import threading
import asyncio
import concurrent.futures
import time
from argparse import ArgumentError, ArgumentParser

# NOTE: This version needs to be manually maintained with the line_profiler
# __version__ for now.
__version__ = '3.5.2'
__version__ = '4.0.0'

# Guard the import of cProfile such that 3.x people
# without lsprof can still use this script.
Expand Down Expand Up @@ -125,6 +129,38 @@ def __exit__(self, exc_type, exc_val, exc_tb):
self.disable_by_count()


class RepeatedTimer(object):
"""
Background timer for outputting file every n seconds.

Adapted from
https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds/40965385#40965385
"""
def __init__(self, interval, dump_func, outfile):
self._timer = None
self.interval = interval
self.dump_func = dump_func
self.outfile = outfile
self.is_running = False
self.next_call = time.time()
self.start()

def _run(self):
self.is_running = False
self.start()
self.dump_func(self.outfile)

def start(self):
if not self.is_running:
self.next_call += self.interval
self._timer = threading.Timer(self.next_call - time.time(), self._run)
self._timer.start()
self.is_running = True

def stop(self):
self._timer.cancel()
self.is_running = False

def find_script(script_name):
""" Find the script.

Expand Down Expand Up @@ -171,7 +207,10 @@ def positive_float(value):
help='Output unit (in seconds) in which the timing info is '
'displayed (default: 1e-6)')
parser.add_argument('-z', '--skip-zero', action='store_true',
help='Hide functions which have not been called')
help="Hide functions which have not been called")
parser.add_argument('-i', '--output-interval', type=int, default=0, const=0, nargs='?',
help="Enables outputting of cumulative profiling results to file every n seconds. Uses the threading module."
"Minimum value is 1 (second). Defaults to disabled.")

parser.add_argument('script', help='The python script file to run')
parser.add_argument('args', nargs='...', help='Optional script arguments')
Expand Down Expand Up @@ -211,7 +250,12 @@ def positive_float(value):
# kernprof.py's.
sys.path.insert(0, os.path.dirname(script_file))


if options.output_interval:
rt = RepeatedTimer(max(options.output_interval, 1), prof.dump_stats, options.outfile)
original_stdout = sys.stdout
if options.output_interval:
rt = RepeatedTimer(max(options.output_interval, 1), prof.dump_stats, options.outfile)
try:
try:
execfile_ = execfile
Expand All @@ -223,6 +267,8 @@ def positive_float(value):
except (KeyboardInterrupt, SystemExit):
pass
finally:
if options.output_interval:
rt.stop()
prof.dump_stats(options.outfile)
print('Wrote profile results to %s' % options.outfile)
if options.view:
Expand Down
36 changes: 0 additions & 36 deletions line_profiler/CMakeLists.txt

This file was deleted.

Loading