Compiling Configuration
=======================

.. _configuration:

.. contents:: Table of Contents

Each SPBench benchmark has a configuration file that includes its parameters and build dependencies.
Also, SPBEnch provides a global configuration file, that enables adding extra compiling parameters or override the benchmark-specific ones.
SPBench reads these files and generates a makefile specific to the respective benchmark. 
Some triggers activate the generation of a new makefile. 
It happens whenever one of the following situations occurs:

- When the ``./spbench compile`` command is executed and there is no makefile yet.
- When the user runs the ``./spbench configure`` command and modifies the JSON file (if nothing is changed, a new makefile will not be generated).
- When the user runs the ``./spbench update`` command.
- When the user runs the ``./spbench global-config`` command and modifies the JSON file.

Run ``./spbench -h`` for more info about the commands.

.. warning:: 
   In the ``./spbench configure`` command, the trigger for generating a new makefile is to exit the text editor. 
   So realize that if you use a text editor that will not exit or was not opened via the ``./spbench configure ... -editor <my_text_editor>`` command, the new makefile will not be generated automatically every time you change the file. 
   You will always need to run the 'update' command if you want to generate an updated makefile in these cases.

JSON Configuration File
-----------------------

Each benchmark has a local and exclusive compiling configuration file.
This is the structure of a local JSON configuration:

.. code-block:: JSON

   {
      "CXX"          : "<compiler>",
      "CXX_FLAGS"    : "<compiler flags>",
      "PPI_CXX"      : "<custom PPI compiler>",
      "PPI_CXX_FLAGS": "<custom PPI compiler flags>",
      "PRE_SRC_CMD"  : "<specific commands added right before the benchmark source file>",
      "POST_SRC_CMD" : "<specific commands added right after the benchmark source file>",
      "MACROS"       : "<compiling macros>",
      "PKG-CONFIG":{
         "myPKG_1"   : "<package-config command>",
         "myPKG_2"   : "...",
         "myPKG_N"   : "..."
      },
      "INCLUDES":{
         "myINC_1"   : "-I <my includes>",
         "myINC_2"   : "...",
         "myINC_N"   : "..."
      },
      "LIBS":{
         "myLIB_1"   : "-L <my libs>",
         "myLIB_2"   : "...",
         "myLIB_N"   : "..."
      },
      "LDFLAGS"      : "-my_lib1 -my_lib2 ..."
   }

The compiler defined in CXX is the compiler used to compile the SPBench source code and the backend applications. 
PPI_CXX is the compiler that will be used to compile the code that the user has access to. 
If no custom compiler is defined for PPI_CXX, the CXX compiler will be used by default.

.. warning:: 
   SPBench recognizes all these keywords, but will not recognize others. 
   So be careful not to change the keys. 
   The exception are the subkeys from PKG-CONFIG, INCLUDES, and LIBS.

Example
-------

The example below shows the configuration file of a benchmark implemented with the SPar PPI. 
Note that SPar has its custom compiler and its flags.
For SPar it is also necessary to add a flag in front of the source code to be compiled. 
It is a case where PRE_SRC_CMD needs to be used. Also, note the syntax used to add pkg-config. 
You must not add the encapsulation of the command, only the parameters.

.. code-block:: JSON

   {
      "CXX"          : "g++",
      "CXX_FLAGS"    : "-std=c++1y -O3",
      "PPI_CXX"      : "$BENCH_DIR/ppis/SPar/bin/spar",
      "PPI_CXX_FLAGS": "-O3 -spar_ordered -spar_ondemand -spar_blocking",
      "PRE_SRC_CMD"  : "-spar_file",
      "POST_SRC_CMD" : "",
      "MACROS"       : "-DNO_DEFAULT_MAPPING",
      "PKG-CONFIG":{
         "opencv"    : "pkg-config --cflags --libs opencv"
      },
      "INCLUDES":{
         "opencv"    : "-I $BENCH_DIR/libs/opencv/opencv-2.4.13.6/include/",
         "UPL"       : "-I $BENCH_DIR/libs/upl/include/upl/"
      },
      "LIBS":{
         "UPL"       : "-L $BENCH_DIR/libs/upl/lib/x86 -lupl"
      },
      "LDFLAGS"      : "-lpthread"
   }

Global Compiling Configuration
------------------------------

.. _globalconfig:

The global JSON configuration file is similar to the benchmark-specific one, but it adds some extra keys.

The basic rule is that the JSON keys in the global configuration file override the local ones. 
The exception are keys starting with "EXTRA", which are recognized only in the global JSON.
These keys do not override local keys but add to them instead. 
Let us see what would happen if a user used the global configuration file below.

.. code-block:: JSON

   {
      "CXX"                : "clang",
      "CXX_FLAGS"          : "",
      "EXTRA_CXX_FLAGS"    : "-g",
      "PPI_CXX"            : "",
      "PPI_CXX_FLAGS"      : "-O3",
      "EXTRA_PPI_CXX_FLAGS": "",
      "MACROS"             : "",
      "EXTRA_MACROS"       : "-DNO_UPL",
      "PKG-CONFIG":{
         "myPKG"           : ""
      },
      "INCLUDES":{
         "myINC"           : "-I /my/awesome/library/"
      },
      "LIBS":{
         "myLIB_N"         : ""
      },
      "LDFLAGS"            : "",
      "EXTRA_LDFLAGS"      : "-lpthread"
   }

First, the entire SPBench infrastructure would be compiled with the clang compiler since it would completely overwrite GCC. 
Then it would add '-g' to the existing compilation flags of each benchmark. 
Next, it would replace all the compile flags in the user code with '-O3'. 
It would add the 'NO_UPL' macro to the macros of each benchmark. 
It would do nothing concerning pkg-config since nothing was added. 
If the local configuration file of a benchmark had an include with the same key 'myINC', this include would be overwritten by the global JSON include. 
Otherwise, 'myINC' would be added to the local includes. 
Finally, all benchmarks would be compiled with '-lpthread', in addition to their original LDFLAGS.

.. Note::
   
   The contents of both global and local configuration files are converted directly into a Makefile. 
   The global JSON does not modify the local JSON at any time. 
   Nor is any resulting JSON created. 
   So you need not be afraid of losing the local build configurations.

UPL
---

You can see in the example above that the configuration file includes the UPL library.
UPL stands for Utility Performance Library.
It is a static library that provides a set of functions useful for measuring performance in C/C++ programs (`more info here <https://github.com/dalvangriebler/upl>`_).

In SPBench, we use UPL for measuring CPU and memory usage.

That is why it is included in the configuration file. However, this library is only available for **x86** and **arm** architectures. 
The benchmarks default include the x86 version, as seen in the configuration file above. 
However, you can change ``upl/lib/x86`` to ``upl/lib/arm`` if you want to run SPBench on an arm processor.

It may not be possible to use UPL on other architectures at the moment, so if this is the case, you can disable UPL by adding the macro ``-DNO_UPL`` in the configuration file. 
You will not be able to evaluate CPU and memory usage. 
However, the other metrics will be available.

.. Tip::
   ``$BENCH_DIR`` defines the root of the SPBench. 
   It is basically an SPBench keyword. 
   If you want, you can also use it to define the paths that you insert into configuration files.

.. Tip::
   The macro ``-DNO_DEFAULT_MAPPING`` is used to disable FastFlow/SPar thread pinning. 
   This macro is active by default in all benchmarks. 
   FastFlow developers recommend not using this pinning if running in a hyper-threading environment.
   This thread pinning serves to allocate the threads to the processor's physical cores first.
   But if you want to use it, to make FastFlow/SPar properly recognize and map the cores of the processor you must run at SPBench root ``bash ./ppis/SPar/libraries/ff/mapping_string.sh`` and ``bash ./ppis/fastflow/ff/mapping_string.sh``. 
   It is only required once. 
   However, this FastFlow feature may not be able to automatically set this value in the ``./ppis/.../ff/config.sh`` file. 
   In this case, you must manually update this ``config.hpp`` file with the execution result of the ``mapping_string.sh`` script.
