Une MAJ de sécurité est nécessaire sur notre version actuelle. Elle sera effectuée lundi 02/08 entre 12h30 et 13h. L'interruption de service devrait durer quelques minutes (probablement moins de 5 minutes).

Commit e8d4f5c2 authored by Millian Poquet's avatar Millian Poquet
Browse files

Towards dynamic jobs: memory management.

Dynamic jobs are now added into Batsim data structures when the server
received a JOB_SUBMITTED message if needed.

To do so, methods have been added in the data structures (Jobs, Profiles,
Workloads...).

Furthermore, the JSON parsing is a bit cleaner now to avoid code redundancy.
parent b0a3b6a9
...@@ -164,6 +164,13 @@ IPMessage::~IPMessage() ...@@ -164,6 +164,13 @@ IPMessage::~IPMessage()
data = nullptr; data = nullptr;
} }
JobIdentifier::JobIdentifier(const string &workload_name, int job_number) :
workload_name(workload_name),
job_number(job_number)
{
}
string JobIdentifier::to_string() const string JobIdentifier::to_string() const
{ {
return workload_name + '!' + std::to_string(job_number); return workload_name + '!' + std::to_string(job_number);
......
...@@ -19,6 +19,13 @@ struct BatsimContext; ...@@ -19,6 +19,13 @@ struct BatsimContext;
*/ */
struct JobIdentifier struct JobIdentifier
{ {
/**
* @brief Creates a JobIdentifier
* @param[in] workload_name The workload name
* @param[in] job_number The job number
*/
JobIdentifier(const std::string & workload_name = "", int job_number = -1);
std::string workload_name; //!< The name of the workload the job belongs to std::string workload_name; //!< The name of the workload the job belongs to
int job_number; //!< The job unique number inside its workload int job_number; //!< The job unique number inside its workload
......
...@@ -78,9 +78,9 @@ int static_job_submitter_process(int argc, char *argv[]) ...@@ -78,9 +78,9 @@ int static_job_submitter_process(int argc, char *argv[])
MSG_process_sleep(job->submission_time - previousSubmissionDate); MSG_process_sleep(job->submission_time - previousSubmissionDate);
// Let's put the metadata about the job into the data storage // Let's put the metadata about the job into the data storage
string job_id_string = args->workload_name + "!" + to_string(job->number); JobIdentifier job_id(workload->name, job->number);
string job_key = "job_" + job_id_string; string job_key = RedisStorage::job_key(job_id);
string profile_key = "profile_" + job_id_string; string profile_key = RedisStorage::profile_key(workload->name, job->profile);
context->storage.set(job_key, job->json_description); context->storage.set(job_key, job->json_description);
context->storage.set(profile_key, workload->profiles->at(job->profile)->json_description); context->storage.set(profile_key, workload->profiles->at(job->profile)->json_description);
......
...@@ -59,74 +59,51 @@ void Jobs::load_from_json(const Document &doc, const string &filename) ...@@ -59,74 +59,51 @@ void Jobs::load_from_json(const Document &doc, const string &filename)
for (SizeType i = 0; i < jobs.Size(); i++) // Uses SizeType instead of size_t for (SizeType i = 0; i < jobs.Size(); i++) // Uses SizeType instead of size_t
{ {
Job * j = new Job; const Value & job_json_description = jobs[i];
j->workload = _workload;
j->starting_time = -1; Job * j = Job::from_json(job_json_description, _workload);
j->runtime = -1;
j->state = JobState::JOB_STATE_NOT_SUBMITTED;
j->consumed_energy = -1;
const Value & job = jobs[i];
xbt_assert(job.IsObject(), "Invalid JSON file '%s': one job is not an object", filename.c_str());
xbt_assert(job.HasMember("id"), "Invalid JSON file '%s': one job has no 'id' field", filename.c_str());
xbt_assert(job["id"].IsInt(), "Invalid JSON file '%s': one job has a non-integral 'id' field ('%s')", filename.c_str(), job["id"].GetString());
j->number = job["id"].GetInt();
xbt_assert(job.HasMember("subtime"), "Invalid JSON file '%s': job %d has no 'subtime' field", filename.c_str(), j->number);
xbt_assert(job["subtime"].IsNumber(), "Invalid JSON file '%s': job %d has a non-number 'subtime' field", filename.c_str(), j->number);
j->submission_time = job["subtime"].GetDouble();
xbt_assert(job.HasMember("walltime"), "Invalid JSON file '%s': job %d has no 'walltime' field", filename.c_str(), j->number);
xbt_assert(job["walltime"].IsNumber(), "Invalid JSON file '%s': job %d has a non-number 'walltime' field", filename.c_str(), j->number);
j->walltime = job["walltime"].GetDouble();
xbt_assert(job.HasMember("res"), "Invalid JSON file '%s': job %d has no 'res' field", filename.c_str(), j->number);
xbt_assert(job["res"].IsInt(), "Invalid JSON file '%s': job %d has a non-number 'res' field", filename.c_str(), j->number);
j->required_nb_res = job["res"].GetInt();
xbt_assert(job.HasMember("profile"), "Invalid JSON file '%s': job %d has no 'profile' field", filename.c_str(), j->number);
xbt_assert(job["profile"].IsString(), "Invalid JSON file '%s': job %d has a non-string 'profile' field", filename.c_str(), j->number);
j->profile = job["profile"].GetString();
// Let's get the JSON string which describes the job
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
job.Accept(writer);
j->json_description = buffer.GetString();
xbt_assert(!exists(j->number), "Invalid JSON file '%s': duplication of job id %d", filename.c_str(), j->number); xbt_assert(!exists(j->number), "Invalid JSON file '%s': duplication of job id %d", filename.c_str(), j->number);
_jobs[j->number] = j; _jobs[j->number] = j;
} }
} }
Job *Jobs::operator[](int job_id) Job *Jobs::operator[](int job_number)
{ {
auto it = _jobs.find(job_id); auto it = _jobs.find(job_number);
xbt_assert(it != _jobs.end(), "Cannot get job %d: it does not exist", job_id); xbt_assert(it != _jobs.end(), "Cannot get job %d: it does not exist", job_number);
return it->second; return it->second;
} }
const Job *Jobs::operator[](int job_id) const const Job *Jobs::operator[](int job_number) const
{ {
auto it = _jobs.find(job_id); auto it = _jobs.find(job_number);
xbt_assert(it != _jobs.end(), "Cannot get job %d: it does not exist", job_id); xbt_assert(it != _jobs.end(), "Cannot get job %d: it does not exist", job_number);
return it->second; return it->second;
} }
Job *Jobs::at(int job_id) Job *Jobs::at(int job_number)
{
return operator[](job_number);
}
const Job *Jobs::at(int job_number) const
{ {
return operator[](job_id); return operator[](job_number);
} }
const Job *Jobs::at(int job_id) const void Jobs::add_job(Job *job)
{ {
return operator[](job_id); xbt_assert(!exists(job->number),
"Bad Jobs::add_job call: A job with number=%d already exists.",
job->number);
_jobs[job->number] = job;
} }
bool Jobs::exists(int job_id) const bool Jobs::exists(int job_number) const
{ {
auto it = _jobs.find(job_id); auto it = _jobs.find(job_number);
return it != _jobs.end(); return it != _jobs.end();
} }
...@@ -170,3 +147,51 @@ bool job_comparator_subtime(const Job *a, const Job *b) ...@@ -170,3 +147,51 @@ bool job_comparator_subtime(const Job *a, const Job *b)
{ {
return a->submission_time < b->submission_time; return a->submission_time < b->submission_time;
} }
Job * Job::from_json(const rapidjson::Value & json_desc, Workload * workload)
{
Job * j = new Job;
j->workload = workload;
j->starting_time = -1;
j->runtime = -1;
j->state = JobState::JOB_STATE_NOT_SUBMITTED;
j->consumed_energy = -1;
xbt_assert(json_desc.IsObject(), "Invalid JSON: one job is not an object");
xbt_assert(json_desc.HasMember("id"), "Invalid JSON: one job has no 'id' field");
xbt_assert(json_desc["id"].IsInt(), "Invalid JSON: one job has a non-integral 'id' field ('%s')", json_desc["id"].GetString());
j->number = json_desc["id"].GetInt();
xbt_assert(json_desc.HasMember("subtime"), "Invalid JSON: job %d has no 'subtime' field", j->number);
xbt_assert(json_desc["subtime"].IsNumber(), "Invalid JSON: job %d has a non-number 'subtime' field", j->number);
j->submission_time = json_desc["subtime"].GetDouble();
xbt_assert(json_desc.HasMember("walltime"), "Invalid JSON: job %d has no 'walltime' field", j->number);
xbt_assert(json_desc["walltime"].IsNumber(), "Invalid JSON: job %d has a non-number 'walltime' field", j->number);
j->walltime = json_desc["walltime"].GetDouble();
xbt_assert(json_desc.HasMember("res"), "Invalid JSON: job %d has no 'res' field", j->number);
xbt_assert(json_desc["res"].IsInt(), "Invalid JSON: job %d has a non-number 'res' field", j->number);
j->required_nb_res = json_desc["res"].GetInt();
xbt_assert(json_desc.HasMember("profile"), "Invalid JSON: job %d has no 'profile' field", j->number);
xbt_assert(json_desc["profile"].IsString(), "Invalid JSON: job %d has a non-string 'profile' field", j->number);
j->profile = json_desc["profile"].GetString();
// Let's get the JSON string which describes the job (to conserve potential fields unused by Batsim)
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json_desc.Accept(writer);
j->json_description = buffer.GetString();
return j;
}
Job * Job::from_json(const std::string & json_str, Workload *workload)
{
Document doc;
doc.Parse(json_str.c_str());
return Job::from_json(doc, workload);
}
...@@ -48,6 +48,26 @@ struct Job ...@@ -48,6 +48,26 @@ struct Job
double runtime; //!< The amount of time during which the job has been executed double runtime; //!< The amount of time during which the job has been executed
MachineRange allocation; //!< The machines on which the job has been executed. MachineRange allocation; //!< The machines on which the job has been executed.
JobState state; //!< The current state of the job JobState state; //!< The current state of the job
/**
* @brief Creates a new-allocated Job from a JSON description
* @param[in] json_desc The JSON description of the job
* @param[in] workload The Workload the job is in
* @return The newly allocated Job
* @pre The JSON description of the job is valid
*/
static Job * from_json(const rapidjson::Value & json_desc,
Workload * workload);
/**
* @brief Creates a new-allocated Job from a JSON description
* @param[in] json_str The JSON description of the job (as a string)
* @param[in] workload The Workload the job is in
* @return The newly allocated Job
* @pre The JSON description of the job is valid
*/
static Job * from_json(const std::string & json_str,
Workload * workload);
}; };
/** /**
...@@ -70,6 +90,7 @@ public: ...@@ -70,6 +90,7 @@ public:
Jobs(); Jobs();
/** /**
* @brief Destroys a Jobs * @brief Destroys a Jobs
* @details All Job instances will be deleted
*/ */
~Jobs(); ~Jobs();
...@@ -94,38 +115,45 @@ public: ...@@ -94,38 +115,45 @@ public:
/** /**
* @brief Accesses one job thanks to its unique number * @brief Accesses one job thanks to its unique number
* @param[in] job_id The job unique number * @param[in] job_number The job unique number
* @return A pointer to the job associated to the given job number * @return A pointer to the job associated to the given job number
*/ */
Job * operator[](int job_id); Job * operator[](int job_number);
/** /**
* @brief Accesses one job thanks to its unique number (const version) * @brief Accesses one job thanks to its unique number (const version)
* @param[in] job_id The job unique number * @param[in] job_number The job unique number
* @return A (const) pointer to the job associated to the given job number * @return A (const) pointer to the job associated to the given job number
*/ */
const Job * operator[](int job_id) const; const Job * operator[](int job_number) const;
/** /**
* @brief Accesses one job thanks to its unique number * @brief Accesses one job thanks to its unique number
* @param[in] job_id The job unique number * @param[in] job_number The job unique number
* @return A pointer to the job associated to the given job number * @return A pointer to the job associated to the given job number
*/ */
Job * at(int job_id); Job * at(int job_number);
/** /**
* @brief Accesses one job thanks to its unique number (const version) * @brief Accesses one job thanks to its unique number (const version)
* @param[in] job_id The job unique number * @param[in] job_number The job unique number
* @return A (const) pointer to the job associated to the given job number * @return A (const) pointer to the job associated to the given job number
*/ */
const Job * at(int job_id) const; const Job * at(int job_number) const;
/**
* @brief Adds a job into a Jobs instance
* @param[in] job The job to add
* @pre No job with the same number exist in the Jobs instance
*/
void add_job(Job * job);
/** /**
* @brief Allows to know whether a job exists * @brief Allows to know whether a job exists
* @param[in] job_id The unique job number * @param[in] job_number The unique job number
* @return True if and only if a job with the given job number exists * @return True if and only if a job with the given job number exists
*/ */
bool exists(int job_id) const; bool exists(int job_number) const;
/** /**
* @brief Allows to know whether the Jobs contains any SMPI job * @brief Allows to know whether the Jobs contains any SMPI job
......
...@@ -47,135 +47,16 @@ void Profiles::load_from_json(const Document &doc, const string & filename) ...@@ -47,135 +47,16 @@ void Profiles::load_from_json(const Document &doc, const string & filename)
const Value & key = it->name; const Value & key = it->name;
const Value & value = it->value; const Value & value = it->value;
xbt_assert(key.IsString(), "Invalid JSON file '%s': all children of the 'profiles' object must have a string key", filename.c_str()); xbt_assert(key.IsString(),
xbt_assert(value.IsObject(), "Invalid JSON file '%s': profile '%s' value must be an object", filename.c_str(), key.GetString()); "Invalid JSON file '%s': all children of the 'profiles' object must have a string key",
xbt_assert(value.HasMember("type"), "Invalid JSON file '%s': profile '%s' has no 'type' field", filename.c_str(), key.GetString()); filename.c_str());
xbt_assert(value["type"].IsString(), "Invalid JSON file '%s': profile '%s' has a non-string 'type' field", filename.c_str(), key.GetString()); string profile_name = key.GetString();
Profile * profile = new Profile; Profile * profile = Profile::from_json(profile_name, value);
string profileType = value["type"].GetString(); xbt_assert(!exists(string(key.GetString())),
if (profileType == "delay") "Invalid JSON file '%s': duplication of profile name '%s'",
{ filename.c_str(), key.GetString());
profile->type = ProfileType::DELAY;
DelayProfileData * data = new DelayProfileData;
xbt_assert(value.HasMember("delay"), "Invalid JSON file '%s': profile '%s' has no 'delay' field", filename.c_str(), key.GetString());
xbt_assert(value["delay"].IsNumber(), "Invalid JSON file '%s': profile '%s' has a non-number 'delay' field", filename.c_str(), key.GetString());
data->delay = value["delay"].GetDouble();
profile->data = data;
}
else if (profileType == "msg_par")
{
profile->type = ProfileType::MSG_PARALLEL;
MsgParallelProfileData * data = new MsgParallelProfileData;
xbt_assert(value.HasMember("cpu"), "Invalid JSON file '%s': profile '%s' has no 'cpu' field", filename.c_str(), key.GetString());
const Value & cpu = value["cpu"];
xbt_assert(cpu.IsArray(), "Invalid JSON file '%s': profile '%s' has a non-array 'cpu' field", filename.c_str(), key.GetString());
data->nb_res = cpu.Size();
xbt_assert(data->nb_res > 0, "Invalid JSON file '%s': profile '%s' has an invalid-sized array 'cpu' (size=%d): must be strictly positive", filename.c_str(), key.GetString(), (int)cpu.Size());
xbt_assert((int)cpu.Size() == data->nb_res, "Invalid JSON file '%s' : profile '%s' is incoherent: cpu array has size %d whereas nb_res is %d", filename.c_str(), key.GetString(), cpu.Size(), data->nb_res);
data->cpu = new double[data->nb_res];
for (unsigned int i = 0; i < cpu.Size(); ++i)
{
xbt_assert(cpu[i].IsNumber(), "Invalid JSON file '%s': profile '%s' computation array is invalid: all elements must be numbers", filename.c_str(), key.GetString());
data->cpu[i] = cpu[i].GetDouble();
}
xbt_assert(value.HasMember("com"), "Invalid JSON file '%s': profile '%s' has no 'com' field", filename.c_str(), key.GetString());
const Value & com = value["com"];
xbt_assert(com.IsArray(), "Invalid JSON file '%s': profile '%s' has a non-array 'com' field", filename.c_str(), key.GetString());
xbt_assert((int)com.Size() == data->nb_res * data->nb_res, "Invalid JSON file '%s' : profile '%s' is incoherent: com array has size %d whereas nb_res is %d", filename.c_str(), key.GetString(), com.Size(), data->nb_res);
data->com = new double[data->nb_res * data->nb_res];
for (unsigned int i = 0; i < com.Size(); ++i)
{
xbt_assert(com[i].IsNumber(), "Invalid JSON file '%s': profile '%s' communication array is invalid: all elements must be numbers", filename.c_str(), key.GetString());
data->com[i] = com[i].GetDouble();
xbt_assert(data->com[i] >= 0, "Invalid JSON file '%s': profile '%s' communication array is invalid: all elements must be non-negative", filename.c_str(), key.GetString());
}
profile->data = data;
}
else if (profileType == "msg_par_hg")
{
profile->type = ProfileType::MSG_PARALLEL_HOMOGENEOUS;
MsgParallelHomogeneousProfileData * data = new MsgParallelHomogeneousProfileData;
xbt_assert(value.HasMember("cpu"), "Invalid JSON file '%s': profile '%s' has no 'cpu' field", filename.c_str(), key.GetString());
xbt_assert(value["cpu"].IsNumber(), "Invalid JSON file '%s': profile '%s' has a non-number 'cpu' field", filename.c_str(), key.GetString());
data->cpu = value["cpu"].GetDouble();
xbt_assert(value.HasMember("com"), "Invalid JSON file '%s': profile '%s' has no 'com' field", filename.c_str(), key.GetString());
xbt_assert(value["com"].IsNumber(), "Invalid JSON file '%s': profile '%s' has a non-number 'com' field", filename.c_str(), key.GetString());
data->com = value["com"].GetDouble();
profile->data = data;
}
else if (profileType == "composed")
{
profile->type = ProfileType::SEQUENCE;
SequenceProfileData * data = new SequenceProfileData;
xbt_assert(value.HasMember("nb"), "Invalid JSON file '%s': profile '%s' has no 'nb' field", filename.c_str(), key.GetString());
xbt_assert(value["nb"].IsInt(), "Invalid JSON file '%s': profile '%s' has a non-integral 'nb' field", filename.c_str(), key.GetString());
data->repeat = value["nb"].GetInt();
xbt_assert(data->repeat > 0, "Invalid JSON file '%s': profile '%s' has a non-strictly-positive 'nb' field (%d)", filename.c_str(), key.GetString(), data->repeat);
xbt_assert(value.HasMember("seq"), "Invalid JSON file '%s': profile '%s' has no 'seq' field", filename.c_str(), key.GetString());
xbt_assert(value["seq"].IsArray(), "Invalid JSON file '%s': profile '%s' has a non-array 'seq' field", filename.c_str(), key.GetString());
const Value & seq = value["seq"];
xbt_assert(seq.Size() > 0, "Invalid JSON file '%s': profile '%s' has an invalid array 'seq': its size must be strictly positive", filename.c_str(), key.GetString());
for (unsigned int i = 0; i < seq.Size(); ++i)
profile->data = data;
}
else if (profileType == "smpi")
{
profile->type = ProfileType::SMPI;
SmpiProfileData * data = new SmpiProfileData;
xbt_assert(value.HasMember("trace"), "Invalid JSON file '%s': profile '%s' has no 'trace' field", filename.c_str(), key.GetString());
xbt_assert(value["trace"].IsString(), "Invalid JSON file '%s': profile '%s' has a non-string 'trace' field", filename.c_str(), key.GetString());
const string trace = value["trace"].GetString();
filesystem::path baseDir(filename);
baseDir = baseDir.parent_path();
xbt_assert(filesystem::exists(baseDir) && filesystem::is_directory(baseDir));
//XBT_DEBUG("baseDir = '%s'", baseDir.string().c_str());
//XBT_DEBUG("trace = '%s'", trace.c_str());
filesystem::path tracePath(baseDir.string() + "/" + trace);
xbt_assert(filesystem::exists(tracePath) && filesystem::is_regular_file(tracePath),
"Invalid JSON file '%s': profile '%s' has an invalid 'trace' field ('%s'), which lead to a non-existent file ('%s')",
filename.c_str(), key.GetString(), trace.c_str(), string(filename + "/" + trace).c_str());
ifstream traceFile(tracePath.string());
xbt_assert(traceFile.is_open(), "Cannot open file '%s'", tracePath.string().c_str());
string line;
while (std::getline(traceFile, line))
{
trim_right(line);
filesystem::path rank_trace_path(tracePath.parent_path().string() + "/" + line);
data->trace_filenames.push_back("./" + rank_trace_path.string());
}
string filenames = boost::algorithm::join(data->trace_filenames, ", ");
XBT_DEBUG("Filenames of profile '%s': [%s]", key.GetString(), filenames.c_str());
profile->data = data;
}
// Let's get the JSON string which describes the profile
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
value.Accept(writer);
profile->json_description = buffer.GetString();
xbt_assert(!exists(string(key.GetString())), "Invalid JSON file '%s': duplication of profile name '%s'", filename.c_str(), key.GetString());
_profiles[string(key.GetString())] = profile; _profiles[string(key.GetString())] = profile;
} }
} }
...@@ -210,6 +91,16 @@ bool Profiles::exists(const std::string &profile_name) const ...@@ -210,6 +91,16 @@ bool Profiles::exists(const std::string &profile_name) const
return mit != _profiles.end(); return mit != _profiles.end();
} }
void Profiles::add_profile(const std::string & profile_name,
Profile *profile)
{
xbt_assert(!exists(profile_name),
"Bad Profiles::add_profile call: A profile with name='%s' already exists.",
profile_name.c_str());
_profiles[profile_name] = profile;
}
const std::map<std::string, Profile *> Profiles::profiles() const const std::map<std::string, Profile *> Profiles::profiles() const
{ {
return _profiles; return _profiles;
...@@ -280,3 +171,146 @@ Profile::~Profile() ...@@ -280,3 +171,146 @@ Profile::~Profile()
else else
XBT_ERROR("Deletion of an unknown profile type (%d)", type); XBT_ERROR("Deletion of an unknown profile type (%d)", type);
} }
Profile *Profile::from_json(const std::string &profile_name, const rapidjson::Value &json_desc)
{
Profile * profile = new Profile;
xbt_assert(json_desc.IsObject(), "Invalid JSON: profile '%s' value must be an object", profile_name.c_str());
xbt_assert(json_desc.HasMember("type"), "Invalid JSON: profile '%s' has no 'type' field", profile_name.c_str());
xbt_assert(json_desc["type"].IsString(), "Invalid JSON: profile '%s' has a non-string 'type' field", profile_name.c_str());
string profile_type = json_desc["type"].GetString();
if (profile_type == "delay")
{
profile->type = ProfileType::DELAY;
DelayProfileData * data = new DelayProfileData;
xbt_assert(json_desc.HasMember("delay"), "Invalid JSON: profile '%s' has no 'delay' field", profile_name.c_str());
xbt_assert(json_desc["delay"].IsNumber(), "Invalid JSON: profile '%s' has a non-number 'delay' field", profile_name.c_str());
data->delay = json_desc["delay"].GetDouble();
profile->data = data;
}
else if (profile_type == "msg_par")
{
profile->type = ProfileType::MSG_PARALLEL;
MsgParallelProfileData * data = new MsgParallelProfileData;
xbt_assert(json_desc.HasMember("cpu"), "Invalid JSON: profile '%s' has no 'cpu' field", profile_name.c_str());
const Value & cpu = json_desc["cpu"];
xbt_assert(cpu.IsArray(), "Invalid JSON: profile '%s' has a non-array 'cpu' field", profile_name.c_str());
data->nb_res = cpu.Size();
xbt_assert(data->nb_res > 0, "Invalid JSON: profile '%s' has an invalid-sized array 'cpu' (size=%d): must be strictly positive", profile_name.c_str(), (int)cpu.Size());
xbt_assert((int)cpu.Size() == data->nb_res, "Invalid JSON : profile '%s' is incoherent: cpu array has size %d whereas nb_res is %d", profile_name.c_str(), cpu.Size(), data->nb_res);
data->cpu = new double[data->nb_res];
for (unsigned int i = 0; i < cpu.Size(); ++i)
{
xbt_assert(cpu[i].IsNumber(), "Invalid JSON: profile '%s' computation array is invalid: all elements must be numbers", profile_name.c_str());
data->cpu[i] = cpu[i].GetDouble();
}
xbt_assert(json_desc.HasMember("com"), "Invalid JSON: profile '%s' has no 'com' field", profile_name.c_str());
const Value & com = json_desc["com"];
xbt_assert(com.IsArray(), "Invalid JSON: profile '%s' has a non-array 'com' field", profile_name.c_str());
xbt_assert((int)com.Size() == data->nb_res * data->nb_res, "Invalid JSON : profile '%s' is incoherent: com array has size %d whereas nb_res is %d", profile_name.c_str(), com.Size(), data->nb_res);
data->com = new double[data->nb_res * data->nb_res];
for (unsigned int i = 0; i < com.Size(); ++i)
{
xbt_assert(com[i].IsNumber(), "Invalid JSON: profile '%s' communication array is invalid: all elements must be numbers", profile_name.c_str());
data->com[i] = com[i].GetDouble();
xbt_assert(data->com[i] >= 0, "Invalid JSON: profile '%s' communication array is invalid: all elements must be non-negative", profile_name.c_str());
}
profile->data = data;
}
else if (profile_type == "msg_par_hg")
{
profile->type = ProfileType::MSG_PARALLEL_HOMOGENEOUS;
MsgParallelHomogeneousProfileData * data = new MsgParallelHomogeneousProfileData;
xbt_assert(json_desc.HasMember("cpu"), "Invalid JSON: profile '%s' has no 'cpu' field", profile_name.c_str());
xbt_assert(json_desc["cpu"].IsNumber(), "Invalid JSON: profile '%s' has a non-number 'cpu' field", profile_name.c_str());
data->cpu = json_desc["cpu"].GetDouble();
xbt_assert(json_desc.HasMember("com"), "Invalid JSON: profile '%s' has no 'com' field", profile_name.c_str());
xbt_assert(json_desc["com"].IsNumber(), "Invalid JSON: profile '%s' has a non-number 'com' field", profile_name.c_str());
data->com = json_desc["com"].GetDouble();
profile->data = data;
}
else if (profile_type == "composed")
{
profile->type = ProfileType::SEQUENCE;
SequenceProfileData * data = new SequenceProfileData;
xbt_assert(json_desc.HasMember("nb"), "Invalid JSON: profile '%s' has no 'nb' field", profile_name.c_str());
xbt_assert(json_desc["nb"].IsInt(), "Invalid JSON: profile '%s' has a non-integral 'nb' field", profile_name.c_str());
data->repeat = json_desc["nb"].GetInt();
xbt_assert(data->repeat > 0, "Invalid JSON: profile '%s' has a non-strictly-positive 'nb' field (%d)", profile_name.c_str(),