2

I would like to use statprof.py for profiling code in PyPy. Unfortunately, it does not seem to work, the line numbers it points to are off. Does anyone know how to make it work or know of an alternative?

Ecir Hana
  • 10,864
  • 13
  • 67
  • 117

1 Answers1

5

It's likely that "the line numbers are off" because PyPy, in JITted code, will inline many functions and will only deliver signals (here from the timer) at the end of the loops. Compare this with CPython, which delivers the signals between two random bytecodes -- occasionally at the end of the loops too, but generally anywhere. So what you get on PyPy is the same as what you'd get on CPython if you constrained the signal handlers to run only at the "end of loop" bytecode.

This is why this kind of profiling will seem to always miss a lot of functions, like most functions with no loop in them.

You can try to use the built-in cProfile module. It comes of course with a bigger performance hit than statistical profiling, but try it anyway --- it doesn't prevent JITting, for example, so the performance hit should still be reasonable.

More generally, I don't see an easy way to implement the equivalent of statistical profiling in PyPy. It's quite hard to give it sense in the presence of functions that are inlined into each other and then optimized globally... I'd be interested if you can find that a tool actually exists, for some other high-level language, doing statistical profiling, on a VM with a tracing JIT.

We could record enough information to track each small group of assembler instructions back to the real Python function it comes from, and then use hacks to inspect the current Instruction Pointer (IP) at the machine level. Not impossible, but serious work :-)

Armin Rigo
  • 12,048
  • 37
  • 48
  • 1
    Thanks for the detailed response. I tried cProfile before but it records only the function calls, i.e. it is not possible to tell which part (line) of a function consumes time. I don't really have to use statistical profiling as long as I could find out where the bottleneck is with higher precision than "some function". I know there is also lineprofiler/kernproof but I think it would report the line numbers off, too. So my question really is, how to profile/optimize code for PyPy in general? – Ecir Hana Jun 27 '13 at 17:40
  • That is slightly different question than the one above though, so I'm asking again here: http://stackoverflow.com/questions/17349822/optimizing-for-pypy – Ecir Hana Jun 27 '13 at 17:40
  • 2
    If you really need more precision than the function level, you might have a coding problem --- don't make your functions so large that they contain a lot of unrelated loops. Split them so that each one does ideally just one thing... – Armin Rigo Jun 28 '13 at 07:51
  • 1
    if a function contains more than one line I have the same problem again. And I don't think I should split code into functions just to please the profiler - I mean, there are legitimate functions which span over few lines and I would like to know which lines are the problematic ones. – Ecir Hana Jun 28 '13 at 08:16
  • 3
    Sorry, I meant: cProfile gives you "overall" results for whole functions, yes; but I'm not sure line-by-line results would easily make sense with PyPy, because PyPy is like a C compiler: it optimizes the code so that half of line 2 is run in the middle of line 4, line 3 turns into no code at all, etc. Basic C profilers also report per-function results only; to get more details you'd split a large C function containing two loops into two parts. (Note that it's not the case of more advanced profilers, but it's work to build them --- and for PyPy, sorry, nobody did the work so far...) – Armin Rigo Jun 28 '13 at 12:33
  • I'm sure you already noticed but LuaJIT just got a profiler which claims to also work line by line. Just saying that it seems to be possible to do this... more here: http://www.freelists.org/post/luajit/LuaJIT-21-Profiler-released – Ecir Hana Sep 11 '13 at 03:33