Skip to content
This repository was archived by the owner on Jun 9, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 8 additions & 5 deletions .hgignore → .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
syntax: glob
.gdb_history
# Swap files.
.*.swp
.*.swo
*~

*.pyc
*.pyo
*.pyclbr
*.so
.*.swp
.*.swo
*.o
*.a

build/
dist/
_line_profiler.c
Expand Down
14 changes: 14 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
language: python
python:
- "3.4"
- "3.3"
- "3.2"
- "2.7"
install:
- pip install --install-option='--no-cython-compile' -r dev_requirements.txt
- python setup.py develop
script:
- python -m unittest discover -v tests
notifications:
email:
- [email protected]
3 changes: 2 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
include LICENSE.txt
include LICENSE_Python.txt
include README.txt
include README.rst
include python25.pxd
include timers.h
include _line_profiler.c
include unset_trace.h
recursive-include tests *.py
116 changes: 53 additions & 63 deletions README.txt → README.rst
Original file line number Diff line number Diff line change
@@ -1,58 +1,53 @@
line_profiler and kernprof
--------------------------

line_profiler is a module for doing line-by-line profiling of functions.
kernprof is a convenient script for running either line_profiler or the Python
`line_profiler` is a module for doing line-by-line profiling of functions.
kernprof is a convenient script for running either `line_profiler` or the Python
standard library's cProfile or profile modules, depending on what is available.

They are available under a `BSD license`_.

.. _BSD license: http://packages.python.org/line_profiler/LICENSE.txt
.. _BSD license: https://raw.githubusercontent.com/rkern/line_profiler/master/LICENSE.txt

.. contents::


Installation
============

Source releases and any binaries can be downloaded from the PyPI link.
Releases of `line_profiler` can be installed using pip_::

http://pypi.python.org/pypi/line_profiler
$ pip install line_profiler

The current release of the kernprof.py script may be downloaded separately here:
Source releases and any binaries can be downloaded from the PyPI link.

http://packages.python.org/line_profiler/kernprof.py
http://pypi.python.org/pypi/line_profiler

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

$ hg clone https://bitbucket.org/robertkern/line_profiler
$ git clone https://github.com/rkern/line_profiler.git

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

Source releases will require a C compiler in order to build line_profiler. In
addition, Mercurial checkouts will also require Cython_ >= 0.10. Source releases
Source releases will require a C compiler in order to build `line_profiler`.
In addition, git checkouts will also require Cython_ >= 0.10. Source releases
on PyPI should contain the pregenerated C sources, so Cython should not be
required in that case.

kernprof.py is a single-file pure Python script and does not require a compiler.
If you wish to use it to run cProfile and not line-by-line profiling, you may
copy it to a directory on your PATH manually and avoid trying to build any
C extensions.
`kernprof` is a single-file pure Python script and does not require
a compiler. If you wish to use it to run cProfile and not line-by-line
profiling, you may copy it to a directory on your `PATH` manually and avoid
trying to build any C extensions.

In order to build and install line_profiler, you will simply use the standard
`build and install`_ for most Python packages::

$ python setup.py install

.. _Mercurial: http://www.selenic.com/mercurial/wiki/
.. _git: http://git-scm.com/
.. _Cython: http://www.cython.org
.. _build and install: http://docs.python.org/install/index.html


line_profiler
=============

The current profiling tools supported in Python 2.5 and later only time
The current profiling tools supported in Python 2.7 and later only time
function calls. This is a good first step for locating hotspots in one's program
and is frequently all one needs to do to optimize the program. However,
sometimes the cause of the hotspot is actually a single line in the function,
Expand All @@ -75,27 +70,29 @@ of each individual line inside those functions. In a typical workflow, one only
cares about line timings of a few functions because wading through the results
of timing every single line of code would be overwhelming. However, LineProfiler
does need to be explicitly told what functions to profile. The easiest way to
get started is to use the kernprof.py script.
get started is to use the `kernprof` script. ::

$ kernprof -l script_to_profile.py

If you use "kernprof.py [-l/--line-by-line] script_to_profile.py", an instance
of LineProfiler will be created and inserted into the __builtins__ namespace
with the name "profile". It has been written to be used as a decorator, so in
your script, you can decorate any function you want to profile with @profile. ::
`kernprof` will create an instance of LineProfiler and insert it into the
`__builtins__` namespace with the name `profile`. It has been written to be
used as a decorator, so in your script, you can decorate any function you want
to profile with @profile. ::

@profile
def slow_function(a, b, c):
...

The default behavior of kernprof is to put the results into a binary file
script_to_profile.py.lprof . You can tell kernprof to immediately view the
The default behavior of `kernprof` is to put the results into a binary file
script_to_profile.py.lprof . You can tell `kernprof` to immediately view the
formatted results at the terminal with the [-v/--view] option. Otherwise, you
can view the results later like so::

$ python -m line_profiler script_to_profile.py.lprof

For example, here are the results of profiling a single function from
a decorated version of the pystone.py benchmark (the first two lines are output
from pystone.py, not kernprof)::
from `pystone.py`, not `kernprof`)::

Pystone(1.1) time for 50000 passes = 2.48
This machine benchmarks at 20161.3 pystones/second
Expand Down Expand Up @@ -148,21 +145,11 @@ line. There are six columns of information.
If you are using IPython, there is an implementation of an %lprun magic command
which will let you specify functions to profile and a statement to execute. It
will also add its LineProfiler instance into the __builtins__, but typically,
you would not use it like that. For IPython 0.10, you can install it by editing
the IPython configuration file ~/.ipython/ipy_user_conf.py to add the following
lines::

# These two lines are standard and probably already there.
import IPython.ipapi
ip = IPython.ipapi.get()

# These two are the important ones.
import line_profiler
ip.expose_magic('lprun', line_profiler.magic_lprun)
you would not use it like that.

For IPython 0.11+, you can install it by editing the IPython configuration file
~/.ipython/profile_default/ipython_config.py to add the `'line_profiler'` item
to the extensions list::
`~/.ipython/profile_default/ipython_config.py` to add the `'line_profiler'`
item to the extensions list::

c.TerminalIPythonApp.extensions = [
'line_profiler',
Expand Down Expand Up @@ -200,7 +187,7 @@ the timer unit.
kernprof
========

kernprof also works with cProfile, its third-party incarnation lsprof, or the
`kernprof` also works with cProfile, its third-party incarnation lsprof, or the
pure-Python profile module depending on what is available. It has a few main
features:

Expand All @@ -224,8 +211,7 @@ features:
Profiler will be instantiated and inserted into your __builtins__ with the
name "profile". Like LineProfiler, it may be used as a decorator, or
enabled/disabled with `enable_by_count()` and `disable_by_count()`, or
even as a context manager with the "with profile:" statement in Python 2.5
and 2.6.
even as a context manager with the "with profile:" statement.

* Pre-profiling setup. With the [-s/--setup] option, you can provide
a script which will be executed without profiling before executing the
Expand Down Expand Up @@ -324,32 +310,26 @@ Frequently Asked Questions
projects for modules as small as these. However, kernprof.py is
a standalone, pure Python script that can be used to do function profiling
with just the Python standard library. You may grab it and install it by
itself without line_profiler.
itself without `line_profiler`.

* Do I need a C compiler to build line_profiler? kernprof.py?
* Do I need a C compiler to build `line_profiler`? kernprof.py?

You do need a C compiler for line_profiler. kernprof.py is a pure Python
script and can be installed separately, though.

* Do I need Cython to build line_profiler?
* Do I need Cython to build `line_profiler`?

You should not have to if you are building from a released source tarball.
It should contain the generated C sources already. If you are running into
problems, that may be a bug; let me know. If you are building from
a Mercurial checkout or snapshot, you will need Cython to generate the
a git checkout or snapshot, you will need Cython to generate the
C sources. You will probably need version 0.10 or higher. There is a bug in
some earlier versions in how it handles NULL PyObject* pointers.

* What version of Python do I need?

Both line_profiler and kernprof have been tested with Python 2.4-2.7.
It might work with Python 2.3, but does not currently work with Python 3.x.

* I get negative line timings! What's going on?

There was a bug in 1.0b1 on Windows that resulted in this. It should be
fixed in 1.0b2. If you are still seeing negative numbers, please let me
know.
Both `line_profiler` and `kernprof` have been tested with Python 2.7, and
3.2-3.4.


To Do
Expand All @@ -367,16 +347,27 @@ now. Maybe later. Contributions accepted!
Bugs and Such
=============

If you find a bug, or a missing feature you really want added, please post to
the enthought-dev_ mailing list or email the author at
<[email protected]>.
Bugs and pull requested can be submitted on GitHub_.

.. _enthought-dev : https://mail.enthought.com/mailman/listinfo/enthought-dev
.. _GitHub: https://github.com/rkern/line_profiler


Changes
=======

1.0
~~~
* ENH: `kernprof.py` is now installed as `kernprof`.
* ENH: Python 3 support. Thanks to the long-suffering Mikhail Korobov for being
patient.
* Dropped 2.6 as it was too annoying.
* ENH: The `stripzeros` and `add_module` options. Thanks to Erik Tollerud for
contributing it.
* ENH: Support for IPython cell blocks. Thanks to Michael Forbes for adding
this feature.
* ENH: Better warnings when building without Cython. Thanks to David Cournapeau
for spotting this.

1.0b3
~~~~~

Expand All @@ -396,4 +387,3 @@ Changes
~~~~~

* Initial release.

33 changes: 19 additions & 14 deletions _line_profiler.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,8 @@ cdef class LineTiming:
"""
cdef public object code
cdef public int lineno
# Note: leave at least total_time private. This should help compile under
# Python 2.4.
cdef PY_LONG_LONG total_time
cdef long nhits
cdef public PY_LONG_LONG total_time
cdef public long nhits

def __init__(self, object code, int lineno):
self.code = code
Expand Down Expand Up @@ -106,9 +104,9 @@ class LineStats(object):
cdef class LineProfiler:
""" Time the execution of lines of Python code.
"""
cdef public object functions
cdef public object code_map
cdef public object last_time
cdef public list functions
cdef public dict code_map
cdef public dict last_time
cdef public double timer_unit
cdef public long enable_count

Expand Down Expand Up @@ -186,21 +184,26 @@ cdef class LastTime:
self.time = time


cdef int python_trace_callback(object self, PyFrameObject *py_frame, int what,
cdef int python_trace_callback(object self_, PyFrameObject *py_frame, int what,
PyObject *arg):
""" The PyEval_SetTrace() callback.
"""
cdef object code, line_entries, key
cdef LineProfiler self
cdef object code, key
cdef dict line_entries, last_time
cdef LineTiming entry
cdef LastTime old
cdef PY_LONG_LONG time

self = <LineProfiler>self_
last_time = self.last_time

if what == PyTrace_LINE or what == PyTrace_RETURN:
code = <object>py_frame.f_code
if code in self.code_map:
time = hpTimer()
if code in self.last_time:
old = self.last_time[code]
if code in last_time:
old = last_time[code]
line_entries = self.code_map[code]
key = old.f_lineno
if key not in line_entries:
Expand All @@ -212,11 +215,13 @@ cdef int python_trace_callback(object self, PyFrameObject *py_frame, int what,
if what == PyTrace_LINE:
# Get the time again. This way, we don't record much time wasted
# in this function.
self.last_time[code] = LastTime(py_frame.f_lineno, hpTimer())
last_time[code] = LastTime(py_frame.f_lineno, hpTimer())
else:
# We are returning from a function, not executing a line. Delete
# the last_time record.
del self.last_time[code]
# the last_time record. It may have already been deleted if we
# are profiling a generator that is being pumped past its end.
if code in last_time:
del last_time[code]

return 0

Expand Down
1 change: 1 addition & 0 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Cython
Loading