Package: py-pal
ThePython Performance Analysis Library(py-pal) is a profiling tool for the Python programming language. Withpy-palone can approximate the time complexity (big O notation) of Python functions in an empirical way. The arguments
of the function and the executed opcodes serve as a basis for the analysis.To thedocs.InstallationRequirementsAn installation of the CPython implementation of the Python programming language of version greater or equal to 3.7For instance:https://www.python.org/ftp/python/3.7.9/python-3.7.9-amd64.exeA compiler for the C/C++ programming language:On Microsoft Windows, we use theBuildtools für Visual Studio 2019:https://visualstudio.microsoft.com/de/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16On Linux, any C compiler supported by Cython e.g. g++Install py-pal via pip by running:This project requires CPython and a C compiler to run. Install CPython >= 3.7, then install py-pal by running:pip install py-palorpython -m pip install py-palCommand line usage of the py-pal modulepython -m py_pal <target-module/file>orpy-pal <target-module/file>There are multiple aliases to the same command:py-pal,py_palandpypal. If py-pal is executed this way, all
functions called in the code are captured and analyzed. The output is in the form of a pandas data frame.See the help message:py-pal -hpy-pal can perform cost analysis on a line-by-line basis:py-pal <file> -l/–lineThe –separate flag can be used to examine the cost function of individual arguments (caution: this function assumes
the independence of the arguments):py-pal <file> -s/–separateThe output of the results can be noisy, to limit this you can use –filter-function to filter the desired functions from
the result. Regular expressions are supported:py-pal <file> -ff/–filter-function .*_sortSimilarly, the result can also be filtered by modules with –filter-module, e.g. to exclude importlib modulespy-pal <file> -fm/–filter-module “^(?!<frozen.*>).*”To save the results in a specified folder use –out:py-pal <file> -o/–out resultsThe output format can be changed with –format:py-pal <file> -o/–out results –format jsonWith the additional specification of the –plot flag, the cost functions of the result set are stored as images:py-pal <file> -o/–out results -p/–plotFor the –log-level flag see thedevelopmentdocs.Example, creating plots for selected functions:py-pal tests/examples/sort.py -o results -p -f sortProgrammatic usage of the py-pal moduleTo profile a single function and get the complexity estimate there isprofile_function.frompy_pal.coreimportprofile_functionfrompy_pal.data_collection.opcode_metricimportOpcodeMetricfrompy_pal.datagenimportgen_random_growing_listsfromalgorithms.sortimportbubble_sortprofile_function(OpcodeMetric(),gen_random_growing_lists(),bubble_sort)Theprofiledecorator:frompy_pal.coreimportprofile,DecoratorStore@profiledeftest():pass# Must be called at some pointtest()estimator=AllArgumentEstimator(DecoratorStore.get_call_stats(),DecoratorStore.get_opcode_stats())res=estimator.export()By using theprofiledecorator, it is possible to annotate Python functions such that only the annotated Python
functions will be profiled. It acts similar to a whitelist filter.Another possibility is to use the context-manager protocol:frompy_pal.analysis.estimatorimportAllArgumentEstimatorfrompy_pal.data_collection.tracerimportTracerwithTracer()ast:passestimator=AllArgumentEstimator(t.get_call_stats(),t.get_opcode_stats())res=estimator.export()# Do something with the resulting DataFrameprint(res)The most verbose way to use thepy-palAPI:frompy_pal.analysis.estimatorimportAllArgumentEstimatorfrompy_pal.data_collection.tracerimportTracert=Tracer()t.trace()# Your functionpasst.stop()estimator=AllArgumentEstimator(t.get_call_stats(),t.get_opcode_stats())res=estimator.export()# Do something with the resulting DataFrameprint(res)All examples instantiate a tracer object that is responsible for collecting the data. After execution, the collected
data is passed to the analysis module. Finally, an estimate of the asymptotic runtime of the functions contained in the
code is obtained.ModesIn the current version py-pal offers only theprofiling mode. Althoughpy_pal.datagenoffers some functions for
generating inputs, py-pal must be combined with appropriate test cases to realize aperformance testing mode. An
automatic detection and generation of appropriate test inputs does not exist at the moment.LimitationsThe profiling approach implemented by the py-pal modules does not distinguish between different threads executing a
Python function. Actually it is a major problem to profile a Python script which makes use of threads. The bytecode
counting strategy will increase all counters of Python functions on the current call stack no matter what threads is
executing it. Thus, the data points will not be accurate to what really happened during the profiled execution of the
script.Licensing NotesThis work integrates some code from thebig_Oproject. More specifically, most
code inpy_pal.analysis.complexity,py_pal.datagenandpy_pal.analysis.estimator.Estimator.infer_complexityis adapted from bigO.ChangelogWhat’s New in Py-PAL 1.3.0Command line interface changes:Renamed -f/–function to -ff/–filter-functionAdded -fm/–filter-module functionality to filter results by modulePy-PAL 1.2.0Improved the statistics and plotting outputCommand line interface changes:Deprecated–saveflag in favor of-o/–outRenamed-V/–visualizeto-p/–plotChange functionality of-f/–functionfrom executing and profiling a specific function inside a python file to applying the analysis to a selected function. Regular expressions are suported.Py-PAL 1.1.0Improved Data Collection: The heuristic for determining the size of function arguments has been improved.More testsMore documentationMore argument generation functions inpy_pal.datagenReplaced command line option –debug with –log-level for more configurable log outputRefactoringProject structure changes, overall CLI interface is unchanged.
API changes:py_pal.tracermoved topy_pal.data_collection.tracerpy_pal.complexityandpy_pal.estimatormoved to thepy_pal.analysispackage.py_pal.analysis.estimator.Estimatornow takes call and opcode stats as arguments.Py-PAL 1.0.0More thorough testing from different combinations of requirements and Python versions.Bug fixesPy-PAL 0.2.1RefactoringTheestimatormodule was refactored which introduces a slight change to the API.
Classes inheriting fromEstimatornow only specify how to transform the collected data with respect to the arguments
of the function.Instead ofComplexityEstimatoryou should use theAllArgumentEstimatorclass. Additionally there is theSeparateArgumentEstimatorwhich is experimental.Py-PAL 0.1.6More accurate Data CollectionTheTraceris enhanced by measuring builtin function calls withAdvancedOpcodeMetric.Opcodes resembling a function call .e.gFUNCTION_CALLare filtered for built in function calls.
If the called function is found in the complexity mapping a synthetic Opcode weight gets assigned.
A builtin function call is evaluated using its argument and a pre-defined runtime complexity e.g. O(n log n) forsort().The feature is enabled by defaultThe calculation produces a performance overhead and can be disabled by providing aOpcodeMetricinstance to theTracerTheAdvancedOpcodeMetricinstance assigned to theTracerprovides statistics about how many builtin function calls were observed and how many were found in the complexity mapBugfixesCleaning data after normalization introduced wrong data points