Commit b8bdfff3 authored by Augustin Degomme's avatar Augustin Degomme

Features :

- add a second thread to separate OTF file operations and trace operations : not as much parallelism as in Paje as file operations are more efficient for OTF (as for Paje parsing, flag MT_PARSING)

- multithreaded loading of serialized files : moves loading from the main thread to multiple threads, as for serialization.

- beginning of the work with MPI : work can now be distributed and several intervals loaded from several machines and displayed there. 

How to use: the flag USE_MPI must be set, links  -lboost_mpi -lmpi -lmpi_cxx must be added in src.pro

mpicc and mpic++ have to be used instead of gcc and g++. This can be set manually in src/makefile, but will be reseted by the global makefile. Another solution is to add

unix{
QMAKESPEC = mpicc
QMAKE_CXX = mpic++
}

to the src.pro file.

To launch on a single machine :
mpirun -np nprocess vite path/to/file.vite2/configure

on several machines with separated screens and a machinefile to list them :
- allow ssh authentification without password (by key)
- allow display on each distant machine with "xhost +"
- have a split folder in a folder accessible with the same path for each machine (nfs or local)
- have vite in the path for each machine
- use mpirun -np nprocess -hostfile machinefile -mca orte_rsh_agent "ssh -X" -xDISPLAY=:0.0 vite -tInterval path/to/file.vite

This will split the given interval in nprocess parts and send them for display to the various nodes described, displaying on their local display
parent 7be547a8
......@@ -283,8 +283,8 @@ if [ $with_otf -ge 1 ]; then
exit;
else
defines="$defines WITH_OTF"
sources="$sources parser/ParserOTF.cpp parser/ParserEventOTF.cpp parser/ParserDefinitionOTF.cpp"
headers="$headers parser/ParserOTF.hpp parser/ParserEventOTF.hpp parser/ParserDefinitionOTF.hpp"
sources="$sources parser/ParserOTF.cpp parser/ParserEventOTF.cpp parser/OTFTraceBuilderThread.cpp parser/ParserDefinitionOTF.cpp parser/mt_ParserOTF.cpp parser/mt_ParserEventOTF.cpp"
headers="$headers parser/ParserOTF.hpp parser/ParserEventOTF.hpp parser/OTFTraceBuilderThread.hpp parser/ParserDefinitionOTF.hpp parser/mt_ParserOTF.hpp parser/mt_ParserEventOTF.hpp"
includepath="$includepath $otfincdir"
libs="$libs -L$otflibdir $otflibdir/libotf.a"
fi
......
......@@ -282,6 +282,8 @@ IF(VITE_ENABLE_OTF)
parser/ParserDefinitionOTF.hpp
parser/ParserEventOTF.hpp
parser/ParserOTF.hpp
parser/mt_ParserEventOTF.hpp
parser/mt_ParserOTF.hpp
)
SET(VITE_SRCS
......@@ -289,6 +291,8 @@ IF(VITE_ENABLE_OTF)
parser/ParserDefinitionOTF.cpp
parser/ParserEventOTF.cpp
parser/ParserOTF.cpp
parser/mt_ParserEventOTF.cpp
parser/mt_ParserOTF.cpp
)
INCLUDE_DIRECTORIES(${OTF_INCLUDE_DIR})
......
......@@ -86,6 +86,7 @@ bool Info::Splitter::load_splitted = false;
bool Info::Splitter::preview = false;
std::string Info::Splitter::path ;
std::string Info::Splitter::filename ;
std::string Info::Splitter::xml_filename ;
Element_pos Info::Splitter::_x_min = 0.0;
Element_pos Info::Splitter::_x_max = 0.0;
......
......@@ -305,6 +305,10 @@ public:
*/
static std::string filename;
/*!
* \brief filename of the node selection file, used to select nodes to display in PArserSplitted
*/
static std::string xml_filename;
/*!
* \brief min time we want to load
*/
static Element_pos _x_min;
......
......@@ -131,6 +131,11 @@
#endif
#ifdef USE_MPI
#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#endif
using namespace std;
#define message *Message::get_instance() << "(" << __FILE__ << " l." << __LINE__ << "): "
......@@ -170,6 +175,10 @@ Core::Core(int &argc, char ** argv){
Message::set_interface(this);/* define which interface will receive messages */
_state = get_state(argc, argv);
#ifdef USE_MPI
boost::mpi::environment env(argc, argv);
#endif
if (_state!= _STATE_EXPORT_FILE)
app = new QApplication(argc, argv);/* create the Qt application */
......@@ -298,8 +307,10 @@ bool Core::draw_trace(const string & filename, const int format) {
}
#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
Info::Splitter::path=QFileInfo(_file_opened.c_str()).dir().path().toStdString();
Info::Splitter::filename=QFileInfo(_file_opened.c_str()).baseName().toStdString();
if(Info::Splitter::path.empty())Info::Splitter::path=QFileInfo(_file_opened.c_str()).dir().path().toStdString();
if(Info::Splitter::filename.empty())Info::Splitter::filename=QFileInfo(_file_opened.c_str()).baseName().toStdString();
if(Info::Splitter::xml_filename.empty() && !_xml_config_file.empty())Info::Splitter::xml_filename=_xml_config_file;
if(Info::Splitter::split==true){
std::stringstream str;
str<<Info::Splitter::path<<"/"<<Info::Splitter::filename;
......@@ -310,13 +321,56 @@ bool Core::draw_trace(const string & filename, const int format) {
#endif
}
Info::Splitter::_x_min = _time_start;
if((Info::Splitter::_x_max==0.0)&&(Info::Splitter::_x_min==0.0)){
#ifdef USE_MPI
if (_world.rank() == 0) {
double min = _time_start;
double max = 0;
if(_time_end == 0.) {
max = _trace->get_max_date().get_value();
}
else {
max =_time_end;
}
double interval = (max-min)/ _world.size();
for(int i=1;i<_world.size(); i++){
//send the new working interval for each node
// double out_msg[2]={min+i*interval,min+(i+1)*interval};
_world.send(i, 0,min+i*interval );
_world.send(i, 1,min+(i+1)*interval );
}
//0 displays the first interval
_time_start=min;
_time_end=min+interval;
if(_time_end == 0.) {
Info::Splitter::_x_max = _trace->get_max_date().get_value();
}
else {
Info::Splitter::_x_max =_time_end;
} else {
double msg[2];
_world.recv(0, 0, msg[0]);
_world.recv(0, 1, msg[1]);
_time_start=msg[0];
_time_end=msg[1];
}
#endif
Info::Splitter::_x_min = _time_start;
if(_time_end == 0.) {
Info::Splitter::_x_max = _trace->get_max_date().get_value();
}
else {
Info::Splitter::_x_max =_time_end;
}
}
#endif
......@@ -353,16 +407,7 @@ bool Core::draw_trace(const string & filename, const int format) {
// if(finish_trace_after_parse) {
// unsigned long long before = getCurrentTime();
#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
if(Info::Splitter::load_splitted==true){
if(Info::Splitter::_x_max == 0)Info::Splitter::preview = true; //we are in the preview mode
if(Info::Splitter::preview==true)_trace->loadPreview();
else {
Interval* i= new Interval(Info::Splitter::_x_min,Info::Splitter::_x_max);
_trace->updateTrace(i);
}
}else{
#endif
......@@ -387,12 +432,12 @@ bool Core::draw_trace(const string & filename, const int format) {
*Message::get_instance() << QObject::tr("Splitting was asked but neither USE_ITC nor BOOST_SERIALIZE flags were set ").toStdString() << Message::ende;
#endif
}
#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
//#if defined(USE_ITC) && defined(BOOST_SERIALIZE)
finished.wait(&mutex);
}
#endif
// }
// #endif
parsing_finished=true;
}
cout << QObject::tr("Loading of the trace : ").toStdString() << loaded << "%" ;
......
......@@ -67,6 +67,10 @@ class QCoreApplication;
class QString;
#include <interface/Interface_graphic.hpp>
#include <QObject>
#ifdef USE_MPI
#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#endif
//#include "render/Render.hpp"
//#include "interface/Interface.hpp"
......@@ -286,6 +290,11 @@ protected:
#endif
//Render<Render_opengl>* _render_opengl;
#ifdef USE_MPI
boost::mpi::communicator _world;
#endif
/*!
* \brief Contains the SVG render instance.
*/
......
......@@ -616,9 +616,15 @@ void Interface_graphic::on_export_file_triggered(){
void Interface_graphic::on_reload_triggered() {
if(_is_rendering_trace) {
Element_pos zoom[2]={Info::Splitter::_x_min,Info::Splitter::_x_max};
_core->launch_action(Core::_STATE_RELEASE_RENDER_AREA);
_core->draw_trace(_trace_path, Core::_DRAW_OPENGL);
if(Info::Splitter::_x_max!=0.0)_core->launch_action(Core:: _STATE_ZOOM_IN_AN_INTERVAL, &zoom);
_core->launch_action(Core:: _STATE_RENDER_UPDATE);
//update the interval selection display
if(_ui_interval_selection!=NULL)_ui_interval_selection->update_values();
}
......
/*
** This file is part of the ViTE project.
**
** This software is governed by the CeCILL-A license under French law
** and abiding by the rules of distribution of free software. You can
** use, modify and/or redistribute the software under the terms of the
** CeCILL-A license as circulated by CEA, CNRS and INRIA at the following
** URL: "http://www.cecill.info".
**
** As a counterpart to the access to the source code and rights to copy,
** modify and redistribute granted by the license, users are provided
** only with a limited warranty and the software's author, the holder of
** the economic rights, and the successive licensors have only limited
** liability.
**
** In this respect, the user's attention is drawn to the risks associated
** with loading, using, modifying and/or developing or reproducing the
** software by the user in light of its specific status of free software,
** that may mean that it is complicated to manipulate, and that also
** therefore means that it is reserved for developers and experienced
** professionals having in-depth computer knowledge. Users are therefore
** encouraged to load and test the software's suitability as regards
** their requirements in conditions enabling the security of their
** systems and/or data to be ensured and, more generally, to use and
** operate it in the same conditions as regards security.
**
** The fact that you are presently reading this means that you have had
** knowledge of the CeCILL-A license and that you accept its terms.
**
**
** ViTE developers are (for version 0.* to 1.0):
**
** - COULOMB Kevin
** - FAVERGE Mathieu
** - JAZEIX Johnny
** - LAGRASSE Olivier
** - MARCOUEILLE Jule
** - NOISETTE Pascal
** - REDONDY Arthur
** - VUCHENER Clément
**
*/
#include <sstream>
#include <string>
#include <map>
#include <queue>
#include <list>
/* -- */
#include <otf.h>
/* -- */
#include "common/Errors.hpp"
/* -- */
#include "trace/values/Values.hpp"
#include "trace/EntityValue.hpp"
#include "trace/EntityTypes.hpp"
#include "trace/Entitys.hpp"
#include "trace/Trace.hpp"
#include <QWaitCondition>
#include <QSemaphore>
#include <QObject>
#include <QMutex>
/* -- */
#include "parser/ParserDefinitionOTF.hpp"
#include "parser/mt_ParserEventOTF.hpp"
#include "parser/OTFTraceBuilderThread.hpp"
/* -- */
using namespace std;
map <const String, Container *, String::less_than> OTFTraceBuilderThread::_containers;
std::map<uint32_t, Marker > OTFTraceBuilderThread::_marker;
OTFTraceBuilderThread::OTFTraceBuilderThread(QWaitCondition* cond, QSemaphore * freeSlots, QMutex* mutex):_cond(cond), _freeSlots(freeSlots), _mutex(mutex){
}
OTFTraceBuilderThread::~OTFTraceBuilderThread() {
_containers.clear();
}
void OTFTraceBuilderThread::build_trace(int n_structs, OTF_Trace_builder_struct* tb_struct){
for(int i=0; i<n_structs; i++){
tb_struct[i].func(&tb_struct[i]);
}
_freeSlots->release();
delete[] tb_struct;
}
void OTFTraceBuilderThread::build_finished(){
//locks the mutex and automatically unlocks it when going out of scope
QMutexLocker locker(_mutex);
_is_finished=true;
_cond->wakeAll();
}
int OTFTraceBuilderThread::handler_begin_process(OTF_Trace_builder_struct* tb_struct) {
Trace *t = (Trace *)tb_struct->trace;
Process current_process = ParserDefinitionOTF::get_process_by_id(tb_struct->process);
Process process_parent = ParserDefinitionOTF::get_process_by_id(current_process._parent);
ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(tb_struct->process);
map<string, Value *> extra_fields;
Date d = (double)tb_struct->time/(double)ParserDefinitionOTF::get_ticks_per_second();
Name n = Name(current_process._name, "");
ContainerType *process_container_type = t->search_container_type(String(process_group._name));
Container *parent_container = t->search_container(String(process_parent._name));
if(t->search_container(String(current_process._name))) {
return OTF_RETURN_OK; // Already created so we quit the function
}
if(process_container_type == 0) {
Error::set(Error::_UNKNOWN_CONTAINER_TYPE + process_group._name, Error::_ERROR);
}
if(parent_container == 0 && process_parent._name != "0") {
// Create the parent process
tb_struct->process=current_process._parent;
handler_begin_process(tb_struct);
parent_container = t->search_container(String(process_parent._name));
}
t->create_container(d, n, process_container_type, parent_container, extra_fields);
// We store the container in the map
_containers[n.to_string()] = t->search_container(n.to_string());
return OTF_RETURN_OK;
}
int OTFTraceBuilderThread::handler_end_process (OTF_Trace_builder_struct* tb_struct) {
Trace *t = (Trace *)tb_struct->trace;
Process process = ParserDefinitionOTF::get_process_by_id(tb_struct->process);
ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(tb_struct->process);
map<string, Value *> extra_fields;
Date d = (double)tb_struct->time/(double)ParserDefinitionOTF::get_ticks_per_second();
Container *temp_container = NULL;
ContainerType *temp_container_type = t->search_container_type(String(process_group._name));
const String process_name = String(process._name);
if(_containers.find(process_name) != _containers.end()) {
temp_container = _containers[process_name];
}
else {
temp_container = t->search_container(process_name);
_containers[process_name] = temp_container;
}
if(temp_container_type == 0) {
Error::set(Error::_UNKNOWN_CONTAINER_TYPE + process_group._name, Error::_ERROR);
}
else if(temp_container == 0 && process._name != "0") {
Error::set(Error::_UNKNOWN_CONTAINER + process._name, Error::_ERROR);
}
t->destroy_container(d, temp_container, temp_container_type, extra_fields);
return OTF_RETURN_OK;
}
int OTFTraceBuilderThread::handler_enter (OTF_Trace_builder_struct* tb_struct) {
Trace *t = (Trace *)tb_struct->trace;
Date d = (double)tb_struct->time/(double)ParserDefinitionOTF::get_ticks_per_second();
Function &temp_function = ParserDefinitionOTF::get_function_by_id(tb_struct->process);
const FunctionGroup temp_function_group = ParserDefinitionOTF::get_function_group_by_id(temp_function._func_group);
Process temp_proc = ParserDefinitionOTF::get_process_by_id(tb_struct->process2);
const ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(tb_struct->process2);
const String function_name = String(temp_function._name);
const String function_group_name = String(temp_function_group._name);
const String proc_name = String(temp_proc._name);
Container *temp_container = NULL;
ContainerType *temp_container_type = t->search_container_type(String(process_group._name));
StateType *temp_state_type = t->search_state_type(function_group_name);
EntityValue *temp_value = NULL;
map<string, Value *> extra_fields;
if(_containers.find(proc_name) != _containers.end()) {
temp_container = _containers[proc_name];
}
else {
temp_container = t->search_container(proc_name);
_containers[proc_name] = temp_container;
}
if(temp_state_type == 0) {
Name name_temp(temp_function_group._name, "");
t->define_state_type(name_temp, temp_container_type, extra_fields);
temp_state_type = t->search_state_type(function_group_name);
}
if(!temp_function._is_defined) {
temp_function._is_defined = true;
Name name_temp(temp_function._name, "");
map<string, Value *> opt;
/* Optional fields */
FileLine source_file_locator;
FileSource source_file;
if(temp_function._file_source != 0) {
source_file_locator = ParserDefinitionOTF::get_fileline_by_id(temp_function._file_source);
source_file = ParserDefinitionOTF::get_filesource_by_id(source_file_locator._file_id);
}
if(source_file._name != "") {
opt["File name"] = new String(source_file._name);
opt["Line"] = new Integer(source_file_locator._line_number);
}
opt["Color"] = ParserDefinitionOTF::get_color(tb_struct->process);
t->define_entity_value(name_temp, t->search_entity_type(function_group_name), opt);
}
temp_value = t->search_entity_value(function_name, temp_state_type);
if(temp_container == NULL && temp_proc._name != "0") {
// Creation of the container if not already done with beginProcess
tb_struct->process=tb_struct->process2;
handler_begin_process(tb_struct);
temp_proc = ParserDefinitionOTF::get_process_by_id(tb_struct->process2);
temp_container = t->search_container(proc_name);
temp_container_type = t->search_container_type(proc_name);
}
// Check if nothing is empty
if(temp_state_type == 0 && temp_function_group._name != "0") {
Error::set(Error::_UNKNOWN_STATE_TYPE + temp_function_group._name, Error::_ERROR);
}
if(temp_container == 0 && temp_proc._name != "0") {
Error::set(Error::_UNKNOWN_CONTAINER + temp_function_group._name, Error::_ERROR);
}
if(temp_value == 0 && temp_proc._name != "0") {
Error::set(Error::_UNKNOWN_ENTITY_VALUE + temp_proc._name, Error::_ERROR);
}
t->set_state(d, temp_state_type, temp_container, temp_value, extra_fields);
return OTF_RETURN_OK;
}
int OTFTraceBuilderThread::handler_leave (OTF_Trace_builder_struct*) {
//Trace *t = (Trace *)trace;
//Date d = (double)time/(double)ParserDefinitionOTF::get_ticks_per_second();
//Function temp_function = ParserDefinitionOTF::get_function_by_id(func_id);
//Process temp_proc = ParserDefinitionOTF::get_process_by_id(proc_id);
//StateType *temp_type = t->search_state_type(String(temp_function._name));
//Container *temp_container = t->search_container(String(temp_proc._name));
//EventType *temp_event_type = t->search_event_type(String(temp_function._name));
//EntityValue *temp_value = t->search_entity_value(String(temp_function._name), temp_event_type);
//map<string, Value *> extra_fields;
//t->set_state(d, temp_type, temp_container, temp_value, extra_fields);
//t->pop_state(d, temp_type, temp_container, extra_fields);
return OTF_RETURN_OK;
}
int OTFTraceBuilderThread::handler_counter(OTF_Trace_builder_struct* tb_struct) {
Trace *t = (Trace *)tb_struct->trace;
Date d = (double)tb_struct->time/(double)ParserDefinitionOTF::get_ticks_per_second();
Counter temp_counter = ParserDefinitionOTF::get_counter_by_id(tb_struct->process2);
Process temp_proc = ParserDefinitionOTF::get_process_by_id(tb_struct->process);
CounterGroup temp_counter_group = ParserDefinitionOTF::get_counter_group_by_id(temp_counter._counter_group);
Container *temp_container = NULL;
map<string, Value *> extra_fields;
String counter_group_name = String(temp_counter_group._name);
VariableType *temp_variable_type = t->search_variable_type(counter_group_name);
ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(tb_struct->process);
ContainerType *temp_container_type = t->search_container_type(String(process_group._name));
const String temp_proc_name = String(temp_proc._name);
if(_containers.find(temp_proc_name) != _containers.end()) {
temp_container = _containers[temp_proc_name];
}
else {
temp_container = t->search_container(temp_proc_name);
_containers[temp_proc_name] = temp_container;
}
if(temp_variable_type == 0) {
Name name_temp(temp_counter_group._name, "");
t->define_variable_type(name_temp, temp_container_type, extra_fields);
temp_variable_type = t->search_variable_type(counter_group_name);
}
if(temp_container == NULL && temp_proc._name != "0") {
// Creation of the container if not already done with beginProcess
handler_begin_process(tb_struct);
temp_proc = ParserDefinitionOTF::get_process_by_id(tb_struct->process);
temp_container = t->search_container(temp_proc_name);
}
// Check if nothing is empty
if(temp_variable_type == 0 && temp_counter_group._name != "0") {
Error::set(Error::_UNKNOWN_VARIABLE_TYPE + temp_counter_group._name, Error::_ERROR);
}
if(temp_container == 0 && temp_proc._name != "0") {
Error::set(Error::_UNKNOWN_CONTAINER + temp_counter_group._name, Error::_ERROR);
}
t->set_variable(d, temp_variable_type, temp_container, tb_struct->value, extra_fields);
return OTF_RETURN_OK;
}
int OTFTraceBuilderThread::handler_defmarker(OTF_Trace_builder_struct* tb_struct) {
Marker temp = {tb_struct->text, tb_struct->process, tb_struct->type};
OTFTraceBuilderThread::_marker[tb_struct->process2] = temp;
return OTF_RETURN_OK;
}
int OTFTraceBuilderThread::handler_marker(OTF_Trace_builder_struct* tb_struct) {
Trace *t = (Trace *)tb_struct->trace;
Date d = (double)tb_struct->time/(double)ParserDefinitionOTF::get_ticks_per_second();
Marker temp_marker = _marker[tb_struct->process2];
Process temp_proc = ParserDefinitionOTF::get_process_by_id(tb_struct->process);
Container *temp_container = NULL;
map<string, Value *> extra_fields;
String str_eventType(temp_marker._name);
String str_event(tb_struct->text);
Name n(tb_struct->text, "");
EventType *event_type = t->search_event_type(str_eventType);
ProcessGroup process_group = ParserDefinitionOTF::get_processgroup_by_process(tb_struct->process);
ContainerType *temp_container_type = t->search_container_type(String(process_group._name));
EntityValue *value = NULL;
const String temp_proc_name = String(temp_proc._name);
if(_containers.find(temp_proc_name) != _containers.end()) {
temp_container = _containers[temp_proc_name];
}
else {
temp_container = t->search_container(temp_proc_name);
_containers[temp_proc_name] = temp_container;
}
if(event_type == 0) {
Name name_temp(temp_marker._name, "");
t->define_event_type(name_temp, temp_container_type, extra_fields);
event_type = t->search_event_type(str_eventType);
}
value = t->search_entity_value(str_event, event_type);
if(temp_container == NULL && temp_proc._name != "0") {
// Creation of the container if not already done with beginProcess
handler_begin_process(tb_struct);
temp_proc = ParserDefinitionOTF::get_process_by_id(tb_struct->process);
temp_container = t->search_container(temp_proc_name);
}
// Check if nothing is empty
if(event_type == 0) {
Error::set(Error::_UNKNOWN_EVENT_TYPE + n.to_string(), Error::_ERROR);
}
if(temp_container == 0 && temp_proc._name != "0") {
//Error::set(Error::_UNKNOWN_CONTAINER + temp_counter_group._name, Error::_ERROR);
}
t->new_event(d, event_type, temp_container, value, extra_fields);
return OTF_RETURN_OK;
}
int OTFTraceBuilderThread::handler_send_message (OTF_Trace_builder_struct* tb_struct ) {
// We define the LinkType if not exist and we store the time and other fields
Trace *t = (Trace *)tb_struct->trace;
Date d = (double)tb_struct->time/(double)ParserDefinitionOTF::get_ticks_per_second();
Process temp_sender = ParserDefinitionOTF::get_process_by_id(tb_struct->process);
Process temp_receiver = ParserDefinitionOTF::get_process_by_id(tb_struct->process2);
// The sender process may have no ancestor, so let's say that his ancestor is himself
Process temp_ancestor = temp_sender;
ProcessGroup sender_group = ParserDefinitionOTF::get_processgroup_by_process(tb_struct->process);
ProcessGroup receiver_group = ParserDefinitionOTF::get_processgroup_by_process(tb_struct->process2);
ProcessGroup ancestor_group = ParserDefinitionOTF::get_processgroup_by_process(temp_sender._parent);
String sender_string = String(temp_sender._name);
String ancestor_string = String(temp_ancestor._name);
String receiver_string = String(temp_receiver._name);
String sender_group_string = String(sender_group._name);
String ancestor_group_string = String(ancestor_group._name);
String receiver_group_string = String(receiver_group._name);
/* Value */
string name = temp_sender._name + " to " + temp_receiver._name;
String name_string = String(name);
ostringstream link_type_oss;
link_type_oss << tb_struct->type;
String link_type_string = String(link_type_oss.str());
Name name_temp = Name(name, "");
LinkType *link_type = t->search_link_type(link_type_string);
Container *source_container = NULL;
Container *ancestor_container = NULL;
ContainerType *source_type = t->search_container_type(sender_group_string);
ContainerType *destination_type = t->search_container_type(receiver_group_string);
ContainerType *ancestor_type = t->search_container_type(ancestor_group_string);
EntityValue *value;
map<string, Value *> opt;
if(_containers.find(sender_string) != _containers.end()) {
source_container = _containers[sender_string];
}
else {
source_container = t->search_container(sender_string);
_containers[sender_string] = source_container;
}
if(_containers.find(ancestor_string) != _containers.end() && !_containers.empty()) {
// found
ancestor_container = _containers[ancestor_string];
}
else {
// receiver not found
ancestor_container = t->search_container(ancestor_string);
if(ancestor_container) {
_containers[ancestor_string] = ancestor_container;
}
}
if(ancestor_type == 0) {
// No ancestor
ancestor_type = source_type;
}
if(ancestor_container == 0) {
// No ancestor
ancestor_container = source_container;
}
if(link_type == 0) {
Name link_name = Name(link_type_oss.str(), "");
t->define_link_type(link_name, ancestor_type, destination_type, destination_type, opt);
link_type = t->search_link_type(link_type_string);
}
value = t->search_entity_value(name_string, link_type);
// Check if nothing is empty
if(source_type == 0) {
Error::set(Error::_UNKNOWN_CONTAINER_TYPE + temp_sender._name, Error::_ERROR);
}
if(destination_type == 0) {
Error::set(Error::_UNKNOWN_CONTAINER_TYPE + temp_receiver._name, Error::_ERROR);
}
if(ancestor_type == 0) {
Error::set(Error::_UNKNOWN_CONTAINER_TYPE + temp_ancestor._name, Error::_ERROR);
}
if(link_type == 0) {
Error::set(Error::_UNKNOWN_LINK_TYPE + link_type_oss.str(), Error::_ERROR);
}
/* Creation of the optional fields */
if(tb_struct->group != 0) {
ProcessGroup proc_group = ParserDefinitionOTF::get_processgroup_by_id(tb_struct->group);
String *proc_group_string = new String(proc_group._name)