Skip to content

Instantly share code, notes, and snippets.

@jmuhlich
Created June 3, 2015 15:56
Show Gist options
  • Save jmuhlich/b6e349c5d80ec3897a77 to your computer and use it in GitHub Desktop.
Save jmuhlich/b6e349c5d80ec3897a77 to your computer and use it in GitHub Desktop.
profile top-level code with line_profiler
# Hacks to get line_profiler to profile top-level code in a script/module.
# 1. The interface only allows profiling functions, but the core profiling logic
# actually works directly with code objects. We create a new function object
# from the code at the top level of the script to profile, and call
# profile.add_function on it. This is enough to trick the bookkeeping code in
# line_profiler to include the top-level code.
# 2. Even though the entirety of the top-level code is profiled in full, the
# results printer will stop at the first function definition, class definition,
# or lambda due to its use of inspect.getblock to retrieve the code (should it
# use inspect.getsource?). The quick workaround is to patch up the profiler's
# internal accounting data structure to lie about what line number the code
# begins on, using a line number that is after any function and class
# definitions (hopefully they are all above the code you want to profile). You
# will need to adjust this number in the second code block below (search for
# "12345"). Lambdas are still a problem, though, and I'm not sure this can be
# worked around easily without a patch to line_profiler itself.
# Note that this code assumes you are running under kernprof -l or have
# explicitly created your own LineProfiler object named "profile".
# Put this at the top of your file:
import inspect, types
__code = inspect.currentframe().f_code
profile.add_function(types.FunctionType(__code, globals()))
profile.enable()
# Put this at the bottom of your file (and patch up the line number on the
# commented line):
profile.disable()
__code_patched = types.CodeType(
__code.co_argcount, __code.co_nlocals, __code.co_stacksize, __code.co_flags,
__code.co_code, __code.co_consts, __code.co_names, __code.co_varnames,
__code.co_filename, __code.co_name,
12345, # Change this to the first line of the desired block (see 2. above)
__code.co_lnotab, __code.co_freevars, __code.co_cellvars)
profile.code_map[__code_patched] = profile.code_map[__code]
del profile.code_map[__code]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment