profiling.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!/usr/bin/env python3
  2. # Contest Management System - http://cms-dev.github.io/
  3. # Copyright © 2018 Stefano Maggiolo <s.maggiolo@gmail.com>
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU Affero General Public License as
  7. # published by the Free Software Foundation, either version 3 of the
  8. # License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Affero General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. """Profiling utils for the testsuites.
  18. There are several Python profilers out there, but many of them have problems,
  19. are not maintained, or are not greenlet-aware. We selected two that work
  20. reasonably well: yappi (`pip install yappi`,
  21. https://bitbucket.org/sumerc/yappi/) and kernprof (`pip install line_profiler`,
  22. https://github.com/rkern/line_profiler).
  23. Yappi was developed exactly due to the missing multithreading support of the
  24. official profilers, and is designed for long-running applications (as are CMS'
  25. services). After running a test with yappi enabled, .prof files will be
  26. generated for each service, and they can be inspected with pstats or the handy
  27. cprofilev, or with kcachegrind using `pip install pyprof2calltree` and
  28. `pyprof2calltree -i output.prof -k`.
  29. Kernprof offers instead a greenlet-aware line profiler whose output might be
  30. easier to understand than yappi's, but requires @profile annotations on
  31. functions or methods. The output will be in .lprof files, that can be inspected
  32. using `python -m line_profile output.lprof`
  33. """
  34. from cmstestsuite import CONFIG
  35. PROFILER_NONE = ""
  36. PROFILER_YAPPI = "yappi"
  37. PROFILER_KERNPROF = "kernprof"
  38. _YAPPI_CMDLINE = ["yappi", "-o", "%(output_basename)s.prof"]
  39. _KERNPROF_CMDLINE = [
  40. "kernprof", "-l", "-o", "%(output_basename)s.lprof"]
  41. def _format_cmdline(profiler_cmdline, cmdline, output_basename):
  42. return [
  43. token % {"output_basename": output_basename}
  44. for token in profiler_cmdline
  45. ] + cmdline
  46. def profiling_cmdline(cmdline, output_basename):
  47. """Return a cmdline possibly decorated to record profiling information."""
  48. profiler = CONFIG.get("PROFILER", PROFILER_NONE)
  49. if profiler == PROFILER_NONE:
  50. return cmdline
  51. elif profiler == PROFILER_YAPPI:
  52. return _format_cmdline(_YAPPI_CMDLINE, cmdline, output_basename)
  53. elif profiler == PROFILER_KERNPROF:
  54. return _format_cmdline(_KERNPROF_CMDLINE, cmdline, output_basename)
  55. else:
  56. raise ValueError("Unknown profiler %s" % profiler)