.. _collectors-overview:

Collectors Overview
===================

.. automodule:: perun.collect

.. _collectors-list:

Supported Collectors
--------------------

Perun's tool suite currently contains the following three collectors:

  1. :ref:`collectors-trace` (authored by **Jirka Pavela**), collects running times of C/C++
     functions along with the size of the structures they were executed on. E.g. this collects
     resources such that function ``search`` over the class ``SingleLinkedList`` took 100ms on
     single linked list with one million elements. :ref:`collectors-trace-examples` shows
     concrete examples of profiles generated by :ref:`collectors-trace`

  2. :ref:`collectors-memory` (authored by **Radima Podola**), collects specifications of
     allocations in C/C++ programs, such as the type of allocation or the full call trace.
     :ref:`collectors-memory-examples` shows concrete generated profiles by
     :ref:`collectors-memory`.

  3. :ref:`collectors-time`, collects overall running times of arbitrary commands. Internally
     implemented as a simple wrapper over ``time`` utility

  4. :ref:`collectors-bounds`, collects bounds of integer and, to some extent, heap-manipulating
     loops represented as so called ranking function. The collectors works as a wrapper over
     the Loopus_ tool. The collection is limited to source codes only, written in subset of C
     language, i.e. for some construction it might return wrong bounds (e.g. for `switch`
     statement). Moreover, the runtime of `bounds` depends on Z3 library.

All of the listed collectors can be run from command line. For more information about command line
interface for individual collectors refer to :ref:`cli-collect-units-ref`.

Collector modules are implementation independent (hence, can be written in any language) and only
requires simple python interface registered within Perun. For brief tutorial how to create and
register new collectors in Perun refer to :ref:`collectors-custom`.

.. _collectors-trace:

Trace Collector
~~~~~~~~~~~~~~~

.. automodule:: perun.collect.trace

.. _collectors-trace-cli:

Overview and Command Line Interface
"""""""""""""""""""""""""""""""""""

.. click:: perun.collect.trace.run:trace
   :prog: perun collect trace

.. _collectors-trace-examples:

Examples
""""""""

.. literalinclude:: /../examples/complexity-sll-short.perf
    :language: json
    :linenos:
    :emphasize-lines: 2,7,12,43,47-51

The above is an example of profiled data for the simple manipulation with program with single
linked list. Profile captured running times of three functions---``SLList_init`` (an
initialization of single linked list), ``SLList_destroy`` (a destruction of single linked list) and
``SLList_search`` (search over the single linked list).

Highlighted lines show important keys and regions in the profile, e.g. the :preg:`origin`,
:preg:`collector_info` or :pkey:`resources`.

.. image:: /../examples/complexity-scatter-with-models.*

The :ref:`views-scatter` above shows the example of visualization of trace profile. Each
points corresponds to the running time of the ``SLList_search`` function over the single linked
list with ``structure-unit-size`` elements. Elements are further interleaved with set of models
obtained by :ref:`postprocessors-regression-analysis`. The light green line corresponds to `linear`
model, which seems to be the most fitting to model the performance of given function.

.. image:: /../examples/complexity-bars.*

The :ref:`views-bars` above shows the overall sum of the running times for each
``structure-unit-size`` for the ``SLList_search`` function. The interpretation highlights that the
most of the consumed running time were over the single linked lists with 41 elements.

.. image:: /../examples/complexity-flow.*

The :ref:`views-flow` above shows the trend of the average running time of the ``SLList_search``
function depending on the size of the structure we execute the search on.

.. _collectors-memory:

Memory Collector
~~~~~~~~~~~~~~~~

.. automodule:: perun.collect.memory

Overview and Command Line Interface
"""""""""""""""""""""""""""""""""""

.. click:: perun.collect.memory.run:memory
   :prog: perun collect memory

.. _collectors-memory-examples:

Examples
""""""""

.. literalinclude:: /../examples/memory-short.perf
    :language: json
    :linenos:
    :emphasize-lines: 2,7,12,22,26-56

The above is an example of profiled data on a simple binary, which makes several minor allocations.
Profile shows a simple allocation followed by deallocation and highlights important keys and
regions in the `memory` profiles, e.g. the :preg:`origin`, :preg:`collector_info` or
:pkey:`resources`

.. image:: /../examples/memory-flow.*

The :ref:`views-flow` above shows the mean of allocated amounts per each allocation site (i.e.
``uid``) in stacked mode. The stacking of the means clearly shows, where the biggest allocations
where made during the program run.

.. image:: /../examples/memory-flamegraph.*

The :ref:`views-flame-graph` is an efficient visualization of inclusive consumption of resources.
The width of the base of one flame shows the bottleneck and hotspots of profiled binaries.

.. _collectors-time:

Time Collector
~~~~~~~~~~~~~~

.. automodule:: perun.collect.time

Overview and Command Line Interface
"""""""""""""""""""""""""""""""""""

.. click:: perun.collect.time.run:time
   :prog: perun collect time

.. _collectors-time-examples:

Examples
""""""""

.. literalinclude:: /../examples/time-short.perf
    :language: json
    :linenos:
    :emphasize-lines: 2,7,12-18,24-28

The above is an example of profiled data using the `time` wrapper with important regions and keys
highlighted. The given command was profiled two times.

.. _collectors-bounds:

Bounds Collector
~~~~~~~~~~~~~~~~

.. automodule:: perun.collect.bounds

Overview and Command Line Interface
"""""""""""""""""""""""""""""""""""

.. click:: perun.collect.bounds.run:bounds
   :prog: perun collect bounds

.. _collectors-bounds-examples:

Examples
""""""""

.. literalinclude:: /../examples/bounds-short.perf
    :language: json
    :linenos:
    :emphasize-lines: 42,43,45,78-79

The above is an example of profiled data using the `bounds` with important regions and keys
highlighted. The bounds corresponds to the program listed below, which contains four highlighted
loops. For each loop we have a local bound that is represented as a ranking function based on input
function parameters. For each bound, we also list its class, i.e. the highest polynom of the ranking
function, or Big-O complexity. In case, the complexity cannot be inferred, the Loopus returns failure
and we report infinite bound, which is safe approximation. Each function then gets a cummulative total
bound, that represents the whole complexity of the function.

.. literalinclude:: /../examples/bounds.c
    :language: c
    :linenos:
    :emphasize-lines: 16,31,37,46

.. _collectors-custom:

Creating your own Collector
---------------------------

.. currentmodule:: perun.utils.common.cli_kit

New collectors can be registered within Perun in several steps. Internally they can be implemented
in any programming language and in order to work with Perun requires three phases to be specified
as given in :ref:`collectors-overview`---``before()``, ``collect()`` and ``after()``. Each new
collector requires a interface module ``run.py``, which contains the three functions and, moreover,
a cli API for Click_.

You can register your new collector as follows:

    1. Run ``perun utils create collect mycollector`` to generate a new modules in
       ``perun/collect`` directory with the following structure. The command takes a predefined
       templates for new collectors and creates ``__init__.py`` and ``run.py`` according to the
       supplied command line arguments (see :ref:`cli-utils-ref` for more information about
       interface of ``perun utils create`` command)::

        /perun
        |-- /collect
            |-- /mycollector
                |-- __init__.py
                |-- run.py
            |-- /trace
            |-- /memory
            |-- /time
            |-- __init__.py

    2. First, implement the ``__init__.py`` file, including the module docstring with brief
       collector descriptions and definitions of constants that are used for automatic setting of
       profiles (namely the :preg:`collector_info`) which has the following structure:

    .. literalinclude:: /_static/templates/collectors_init.py
        :language: python
        :linenos:

    3. Next, implement the ``run.py`` module with ``collect()`` function, (optionally with
       ``before()`` and ``after()``). The ``collect()`` function should do the actual collection of
       the profiling data over the given configuration. Each function should return the integer
       status of the phase, the status message (used in case of error) and dictionary including
       params passed to additional phases and 'profile' with dictionary w.r.t :ref:`profile-spec`.

    .. literalinclude:: /_static/templates/collectors_run.py
        :language: python
        :linenos:

    4. Additionally implement the command line interface function in ``run.py``, named the same as
       your collector. This function will is called from command line as ``perun collect
       mycollector`` and is based on Click_ library.

    .. literalinclude:: _static/templates/collectors_run_api.py
        :language: python
        :linenos:
        :diff: _static/templates/collectors_run.py

    5. Finally register your newly created module in function ``get_supported_module_names`` located in
       ``perun.utils.common.cli_kit.py``:

    .. literalinclude:: _static/templates/supported_module_names_collectors.py
        :language: python
        :linenos:
        :diff: _static/templates/supported_module_names.py

    6. Preferably, verify that registering did not break anything in the Perun and if you are not
       using the developer installation, then reinstall Perun::

        make test
        make install

    7. At this point you can start using your collector either using ``perun collect`` or using the
       following to set the job matrix and run the batch collection of profiles::

        perun config --edit
        perun run matrix

    8. If you think your collector could help others, please, consider making `Pull Request`_.

.. _Pull Request: https://github.com/Perfexionists/perun/pull/new/develop
.. _Click: https://click.palletsprojects.com/en/latest/
.. _Loopus: https://forsyte.at/software/loopus/
