.. _reference-engine-label:
Installing & using available engines
====================================
Requirements
------------
The reference engine does not require any special software aside from a standard
C++ compiler and the `STL `_ (usually installed
along with the C++ compiler). In addition, a support for
`C++0x `_ is required when working with the
optimized engine, and `C++11 `_ for the
multithread engine. We are currently working with the GNU compiler g++ version
4.8.2, and for ABI compatibility issues we recommend to use g++ version 4.8 or
higher when compiling the generated code.
Downloading & installing
------------------------
Getting latest version
^^^^^^^^^^^^^^^^^^^^^^
Go to the `download page `_ for the
BIP tools. As for the compiler, you may install the engines separately using
specific archives, or you can install everything at once (compiler & engines).
Only the first installation procedure is presented here. For the *one archive*
installation, read the :ref:`installing-compiler-label`.
.. _engine-installation-label:
Installation of the engine
^^^^^^^^^^^^^^^^^^^^^^^^^^
The archive is a self-contained. You need to extract it in a dedicated
directory, for example ``/home/a_user/local/bip2``::
$ mkdir /home/a_user/local/bip2
$ cd /home/a_user/local/bip2
$ tar zxvf /path/to/the/BIP-reference-engine_2012.01.tar.gz
BIP-reference-engine-2012.01/
...
...
For easier use, set the following environment variables:
* ``BIP2_ENGINE_GENERIC_DIR`` : *absolute* path to *generic* header files.
* ``BIP2_ENGINE_SPECIFIC_DIR`` : *absolute* path to *specific* header files.
* ``BIP2_ENGINE_LIB_DIR`` : *absolute* path to library containing engine
library.
This can be done adding the following in your ``~/.bashrc`` (if you are using
bash)::
export BIP2_ENGINE_SPECIFIC_DIR=/path/to/BIP-reference-engine-2012.01/include/specific
export BIP2_ENGINE_GENERIC_DIR=/path/to/BIP-reference-engine-2012.01/include/generic
export BIP2_ENGINE_LIB_DIR=/path/to/BIP-reference-engine-2012.01/lib/static
Quick-tour of installation
^^^^^^^^^^^^^^^^^^^^^^^^^^
After extracting the archive, you should have a similar setup::
.
÷── generic/
│ `── include
│ ÷── AtomExportPortItf.hpp
│ ÷── AtomInternalPortItf.hpp
│ ÷── AtomItf.hpp
│ ÷── bip-engineiface-config.hpp
│ ÷── BipErrorItf.hpp
│
÷── specific/
│ `── include
│ ÷── AtomExportPort.hpp
│ ÷── Atom.hpp
│ ÷── AtomInternalPort.hpp
│ ...
`── lib/
`── libengine.a
* the ``generic`` directory contains the header files that should be common to
all engines following the standard API (see
:ref:`dev-doc-engine_std_API-label` ).
* the ``specific`` directory contains the header files specific to the engine
being installed (here, the reference engine).
* the ``lib`` directory contains the compiled code of the engine being
installed.
Using the reference engine
--------------------------
Compiling & linking with generated code
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You need to generate code from your BIP source as explained in
:ref:`cpp-backend-label`.
Quick-start : follow regular *cmake* procedure
""""""""""""""""""""""""""""""""""""""""""""""
* create a ``build`` directory, for example within the generated code. This
directory will host all files created during the compilation and the linking
of the generated code. This directory can be wiped clean if needed without the
need to run again the BIP compiler.
* from this new directory, invoke ``cmake`` by pointing to the directory
containing the generated code.
* still from this new directory, invoke ``make`` to actually compile and link
everything together
Step-by-step guide
""""""""""""""""""
You need to create a *build* subdirectory where all the compiled code will be
located. Usually, this directory is a sub-directory within the generated code
tree. For example, if the ``output`` directory contains all our generated code::
/home/a_user/output $ mkdir build && cd build
Then you need to invoke ``cmake`` from within this new *build* directory by
pointing to the directory containing the generated code (in our example,
``..``). If you did not set environment variables as detailed in the
:ref:`engine-installation-label`, then you need to provide cmake with
*absolutes* paths to engine files: ``BIP2_ENGINE_GENERIC_DIR`` and
``BIP2_ENGINE_SPECIFIC_DIR`` for the engine interface code (*ie.* *header*
files), and ``BIP2_ENGINE_LIB_DIR`` for the compiled engine code.
Example cmake invocation *with* environment variables set::
$ cmake ..
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/a_user/output/build
Example cmake invocation *without* environment variables set::
$ cmake \
-DBIP2_ENGINE_GENERIC_DIR=/absolute/path/to/engines/BIP-reference-engine-2012.01/include/generic/ \
-DBIP2_ENGINE_SPECIFIC_DIR=/absolute/path/to/engines/BIP-reference-engine-2012.01/include/specific/ \
-DBIP2_ENGINE_LIB_DIR=/absolute/path/to/engines/BIP-reference-engine-2012.01/lib/static \
..
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/a_user/output/build
If your output matches the examples, you can proceed to the actual C++
compilation & linking by simply invoking ``make``::
$ make
The result will be a single executable file called ``system``.
Running the resulting executable
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The resulting executable is called **system** and is created in the build
directory created previously (see previous section).
It includes both the code generated specifically for the considered BIP2 model
and the reference engine. Engines are runtime used for scheduling execution
sequences of BIP models.
Once the executable is built, help information is provided when executing
**system** with option ``--help``::
./system --help
Usage: ./system [options]
BIP Engine general options:
-d, --debug allows debug of the system, i.e. diplays the state of the system
--execute execute a single sequence of interactions (default)
--explore compute all possible sequences of interactions
-h, --help display this help and exit
-i, --interactive interactive mode of execution
-l, --limit LIMIT limits the execution to LIMIT interactions
--seed SEED set the seed for random to SEED
-s, --silent disables the display of the sequence of enabled/chosen interactions
-v, --verbose enables the display of the sequence of enabled/chosen interactions (default)
-V, --version displays engine version and exits
BIP Engine semantics options (WARNING: modify the official semantics of BIP!):
--disable-maximal-progress disable the application of maximal progress priorities
Executing a single sequence
"""""""""""""""""""""""""""
An execution sequence can be scheduled simply by running directly **system**
without any option (execution of a single sequence is a default mode)::
$ ./system
Notice that the reference engine is in verbose mode by default. At each state,
it displays the enabled interactions and internal ports, and the chosen sequence
, *e.g.*::
...
[BIP ENGINE]: initialize components...
[BIP ENGINE]: random scheduling based on seed=6
[BIP ENGINE]: state #0: 14 interactions:
[BIP ENGINE]: [0] ROOT.f1take1: ROOT.f1.take() ROOT.p1.take_left()
[BIP ENGINE]: [1] ROOT.f1take2: ROOT.f1.take() ROOT.p7.take_right()
[BIP ENGINE]: [2] ROOT.f2take1: ROOT.f2.take() ROOT.p2.take_left()
[BIP ENGINE]: [3] ROOT.f2take2: ROOT.f2.take() ROOT.p1.take_right()
[BIP ENGINE]: [4] ROOT.f3take1: ROOT.f3.take() ROOT.p3.take_left()
[BIP ENGINE]: [5] ROOT.f3take2: ROOT.f3.take() ROOT.p2.take_right()
[BIP ENGINE]: [6] ROOT.f4take1: ROOT.f4.take() ROOT.p4.take_left()
[BIP ENGINE]: [7] ROOT.f4take2: ROOT.f4.take() ROOT.p3.take_right()
[BIP ENGINE]: [8] ROOT.f5take1: ROOT.f5.take() ROOT.p5.take_left()
[BIP ENGINE]: [9] ROOT.f5take2: ROOT.f5.take() ROOT.p4.take_right()
[BIP ENGINE]: [10] ROOT.f6take1: ROOT.f6.take() ROOT.p6.take_left()
[BIP ENGINE]: [11] ROOT.f6take2: ROOT.f6.take() ROOT.p5.take_right()
[BIP ENGINE]: [12] ROOT.f7take1: ROOT.f7.take() ROOT.p7.take_left()
[BIP ENGINE]: [13] ROOT.f7take2: ROOT.f7.take() ROOT.p6.take_right()
[BIP ENGINE]: -> choose [1] ROOT.f1take2: ROOT.f1.take() ROOT.p7.take_right()
[BIP ENGINE]: state #1: 12 interactions:
[BIP ENGINE]: [0] ROOT.f2take1: ROOT.f2.take() ROOT.p2.take_left()
[BIP ENGINE]: [1] ROOT.f2take2: ROOT.f2.take() ROOT.p1.take_right()
[BIP ENGINE]: [2] ROOT.f3take1: ROOT.f3.take() ROOT.p3.take_left()
[BIP ENGINE]: [3] ROOT.f3take2: ROOT.f3.take() ROOT.p2.take_right()
[BIP ENGINE]: [4] ROOT.f4take1: ROOT.f4.take() ROOT.p4.take_left()
[BIP ENGINE]: [5] ROOT.f4take2: ROOT.f4.take() ROOT.p3.take_right()
[BIP ENGINE]: [6] ROOT.f5take1: ROOT.f5.take() ROOT.p5.take_left()
[BIP ENGINE]: [7] ROOT.f5take2: ROOT.f5.take() ROOT.p4.take_right()
[BIP ENGINE]: [8] ROOT.f6take1: ROOT.f6.take() ROOT.p6.take_left()
[BIP ENGINE]: [9] ROOT.f6take2: ROOT.f6.take() ROOT.p5.take_right()
[BIP ENGINE]: [10] ROOT.f7take1: ROOT.f7.take() ROOT.p7.take_left()
[BIP ENGINE]: [11] ROOT.f7take2: ROOT.f7.take() ROOT.p6.take_right()
[BIP ENGINE]: -> choose [11] ROOT.f7take2: ROOT.f7.take() ROOT.p6.take_right()
...
[BIP ENGINE]: state #26: 2 interactions:
[BIP ENGINE]: [0] ROOT.f7take1: ROOT.f7.take() ROOT.p7.take_left()
[BIP ENGINE]: [1] ROOT.f7take2: ROOT.f7.take() ROOT.p6.take_right()
[BIP ENGINE]: -> choose [1] ROOT.f7take2: ROOT.f7.take() ROOT.p6.take_right()
[BIP ENGINE]: state #27: deadlock!
Interactions or internal ports are chosen randomly amongst the enabled ones.
The reference engine is based on a uniform distribution of probability for
the choice of the interactions or internal ports. By default, the seed
used to initialize randomize choices is computed from the current value of time,
but it can be set to a given value using option ``--seed``. The execution is
stopped if no interaction and no internal port is enabled, or if ctrl-D is hit.
Exhaustive execution
""""""""""""""""""""
Option ``--explore`` allows the exhaustive execution of the sequences defined by
a model. In order to perform back-tracking, this mode of execution requires the
generation of additional code, which is enforced using option
``--gencpp-enable-marshalling`` when compiling the model.
.. IMPORTANT::
Enabling option ``--gencpp-enable-marshalling`` generates code for storing and
retrieving states of atomic components, which requires storing / retrieving
their variables. For custom types, such code has to be provided by the user
(as the definition of the type). For a custom type ``custom_t``, the generated
code expect the presence of an implementation for following methods:
* ``size_t custom_t_sizeof(const custom_t &v)``: returns the number of bytes
necessary to allocate for storing the current value of variable ``v`` of
type ``custom_t`` provided as a parameter. Notice that it can return non
constant numbers of bytes that depend on the value of ``v`` (e.g. useful for
a ``string``, a list, etc.).
* ``void custom_t_toBytes(char *b, const custom_t *ptr_v)`` encode the value
of a variable of type ``custom_t`` pointed by ``ptr_v`` into a sequence of
``n`` bytes which are stored in a location starting from ``b``. The number
of bytes ``n`` must satisfy ``n = custom_t_sizeof(*ptr_v)``.
* ``void custom_t_fromBytes(custom_t *ptr_v, const char *b)``: decode a
sequence of bytes stored at ``b`` and assign the corresponding value to
the variable of type ``custom_t`` pointed by ``ptr_v``. Notice that this
method must be able to guess the number of bytes to read from the sequence
itself, i.e. it is the user responsibility to provide a way for kwowing when
to stop reading bytes from ``b``.
Notice that the exploration mode requires comparison of states. It assumes
deterministic execution of the above methods, that is, they must provide the
same results for the same input values. Obviously, the application of
``fromBytes`` to the sequence of bytes computed by ``toBytes`` for a variable
``v`` must assign to ``v`` the value it had when calling ``toBytes``.
The current version of the engine displays dots each time an interaction or an
internal port is executed. Moreover, the number of reachable states, deadlocks,
and errors is displayed, *e.g.*::
$ ./system --explore
...
[BIP ENGINE]: initialize components...
[BIP ENGINE]: computing reachable states:..............................................
.......................................................................................
.......................................................................................
.......................................................................................
.......................................................................................
...
.................... found 27303 reachable states, 2 deadlocks, and 0 error in 0 state
Using the optimized engine
--------------------------
Since the reference engine (presented in the previous section) can be very, very
slow, we recommend to use the optimized engine whenever performance is an issue.
The optimized engine implements minimal optimizations required for reasonable
runtime performances in terms of both execution time and memory usage. It
currently passes the same tests as the reference engine, and it accepts the same
general options.
For installing and using the optimized engine, proceeds as explained above for
the reference engine (see :ref:`engine-installation-label`), after downloading
the optimized engine instead of the reference engine from
`download page `_. Performances
can be again improved when combining the use of the optimized engine and the
activation of optimizations in the code generator (see
:ref:`cpp-optimizations-label`).
To allow maximal optimization, combine the following:
* pass ``--gencpp-optim 3`` to the C++ back-end when compiling your BIP model
* use the optimized engine
* pass ``-DCMAKE_BUILD_TYPE=Release`` to ``cmake`` when compiling the generated C++ code (i.e. use ``cmake -DCMAKE_BUILD_TYPE=Release ..``).
Using the multithread engine (beta version)
-------------------------------------------
The multithread engine is proposed for increasing further the performance when
running on multicore platforms. It is available in a beta version that is
experimental is and should not be considered as mature as the reference and the
optimized engine. It relies on the latest standard C++11 of C++, requiring
version 4.8 or higher of GCC for compiling the generated C++ code.
Moreover, it may require additional library implementing threads, e.g. to use
``pthread`` add the option ``--gencpp-ld-l pthread`` when invoking the BIP
compiler.
The options proposed by the multithread engine are listed
below::
BIP Engine general options:
(i.e. executes interactions in parallel, if obs. equivalent)
-d, --debug allows debug of the system, i.e. diplays the state of the system
-h, --help display this help and exit
-i, --interactive interactive mode of execution
-l, --limit LIMIT limits the execution to LIMIT interactions
--seed SEED set the seed for random to SEED
--threads NB set the number of threads (by default, use the maximal HW
parallelism or 8)
-s, --silent disables the display of the sequence of enabled/chosen interactions
-v, --verbose enables the display of the sequence of enabled/chosen interactions
(default)
-V, --version displays engine version and exits
The multithread engine does not support any exploration mode and can only
execute sequences of interactions. It executes components involved in
interactions is parallel, based on the notion of partial state: interactions can
start from partial states, that is, even if some components are still running.
The multithread engine guarantees that interactions are always started in an
order meeting the global state semantics which is implemented in the reference
and the optimized engine.
Option ``--threads`` can be used to control the total number of threads used for
executing the model. Notice that these threads are used not only for executing
the atomic components, but also for computing the enabled interactions:
connectors evaluate enabled interactions in a parallel and concurrent way.
.. IMPORTANT::
* The partial state semantics execution implemented by the multithread
engine is equivalent to the one of the global state semantics if the
execution of components is side-effect free (i.e. the external code
executed by a component modifies only its local variables).
* Due to the partial state semantics and the concurrent execution of
connectors, the multithread engine cannot guarantee fairness of the
execution of interactions and internal ports.
Notice that performances obtained when using the multithread engine depend on
many factors, and may be worse than the ones obtained when using the optimized
engine. This is due to the overhead introduced by the use of threads and threads
synchronizations, which is inherent to the concurrent design implemented by the
multithread engine.
Troubleshooting
---------------
``libengine_path`` error when running cmake
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you get the following error::
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
libengine_path
linked by target "system" in directory ..../output
It's probably because you are trying to use a relative path for the
``BIP2_ENGINE_LIB_DIR``. Always use *absolute* paths!
``Atom.hpp: No such file or directory`` error
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you get::
In file included from .../src/simple/AT_At1.cpp:3:
.../include/simple/AT_At1.hpp:6:20: error: Atom.hpp: No such file or directory
It's probably because you are trying to use a relative path for one or both
``BIP2_ENGINE_GENERIC_DIR`` and ``BIP2_ENGINE_SPECIFIC_DIR``. Always use
*absolute* paths !