176 const json& model = root.contains(
"model") ? root.at(
"model") : root;
177 const std::string mtype = model.value(
"type", std::string(
"LayeredNetwork"));
178 if (mtype !=
"LayeredNetwork")
180 "' is not a LayeredNetwork; a Network model is read by "
188 const json empty = json::array();
189 const json& hosts = model.contains(
"hosts")
191 : (model.contains(
"processors") ? model.at(
"processors") : empty);
192 std::vector<std::pair<double, double>> quantum_speed;
193 std::vector<std::pair<std::string, const json*>> host_rows;
194 std::vector<std::pair<std::string, const json*>> host_pools, task_pools;
195 for (
const json& h : hosts) {
196 const std::string name = h.at(
"name").get<std::string>();
198 detail::lqn_sched_from_json(h.value(
"scheduling", std::string(
"PS")));
199 const double mult = h.contains(
"multiplicity")
200 ? detail::lqn_mult_from_json(h.at(
"multiplicity"))
202 b.processor(name, mult, sched, h.value(
"replication", 1.0));
203 quantum_speed.push_back(
204 std::make_pair(h.value(
"quantum", 0.001), h.value(
"speedFactor", 1.0)));
205 if (h.contains(
"admissionConstraints"))
206 host_rows.push_back(std::make_pair(name, &h.at(
"admissionConstraints")));
207 if (h.contains(
"serverTypes")) host_pools.push_back(std::make_pair(name, &h.at(
"serverTypes")));
211 std::vector<std::vector<std::pair<std::string, double>>> fan_in, fan_out;
212 std::vector<std::pair<std::string, const json*>> task_rows;
213 for (
const json& t : model.at(
"tasks")) {
214 const std::string name = t.at(
"name").get<std::string>();
215 fan_in.push_back(t.contains(
"fanIn") ? detail::lqn_fan_from_json(t.at(
"fanIn"))
216 : std::vector<std::pair<std::string, double>>());
217 fan_out.push_back(t.contains(
"fanOut") ? detail::lqn_fan_from_json(t.at(
"fanOut"))
218 : std::vector<std::pair<std::string, double>>());
219 if (t.contains(
"admissionConstraints"))
220 task_rows.push_back(std::make_pair(name, &t.at(
"admissionConstraints")));
221 if (t.contains(
"serverTypes")) task_pools.push_back(std::make_pair(name, &t.at(
"serverTypes")));
222 const std::string on = t.at(
"host").get<std::string>();
224 detail::lqn_sched_from_json(t.value(
"scheduling", std::string(
"FCFS")));
225 const double mult = t.contains(
"multiplicity")
226 ? detail::lqn_mult_from_json(t.at(
"multiplicity"))
228 const double repl = t.value(
"replication", 1.0);
229 const std::string kind = t.value(
"taskType", std::string());
230 if (kind ==
"CacheTask") {
231 std::vector<int> cap;
232 if (t.at(
"cacheCapacity").is_array())
233 cap = t.at(
"cacheCapacity").get<std::vector<int> >();
235 cap.push_back(t.at(
"cacheCapacity").get<
int>());
236 b.cache_task(name, mult, sched, on, t.at(
"totalItems").get<std::size_t>(), cap,
237 detail::replacement_from_json(
238 t.value(
"replacementStrategy", std::string(
"FIFO"))),
241 b.task(name, mult, sched, on, repl);
244 if (t.contains(
"priority")) b.task_priority(name,
static_cast<int>(t.at(
"priority").get<
double>()));
247 if (t.contains(
"thinkTime"))
248 b.think_time(name, detail::dist_from_json<T>(t.at(
"thinkTime")));
249 else if (t.contains(
"thinkTimeMean") && t.at(
"thinkTimeMean").get<
double>() > 0)
251 t.at(
"thinkTimeMean").get<
double>())));
261 const bool has_setup_obj = t.contains(
"setupTime");
262 const bool has_setup_mean =
263 t.contains(
"setupTimeMean") && t.at(
"setupTimeMean").get<
double>() > 0;
264 if (has_setup_obj || has_setup_mean) {
265 const bool has_off_obj = t.contains(
"delayOffTime");
266 const bool has_off_mean =
267 t.contains(
"delayOffTimeMean") && t.at(
"delayOffTimeMean").get<
double>() > 0;
268 if (!has_off_obj && !has_off_mean)
270 "' declares a setup time with no delay-off time; a server that "
271 "never shuts down pays the setup at most once");
273 has_setup_obj ? detail::dist_from_json<T>(t.at(
"setupTime"))
275 t.at(
"setupTimeMean").get<
double>()));
277 has_off_obj ? detail::dist_from_json<T>(t.at(
"delayOffTime"))
279 t.at(
"delayOffTimeMean").get<
double>()));
280 b.setup_time(name, su, doff);
285 for (
const json& e : model.at(
"entries")) {
286 const std::string name = e.at(
"name").get<std::string>();
287 const std::string on = e.at(
"task").get<std::string>();
288 if (e.value(
"entryType", std::string()) ==
"ItemEntry") {
289 const std::size_t card = e.at(
"totalItems").get<std::size_t>();
294 if (e.contains(
"accessProb"))
295 pop = detail::pmf_from_json<T>(e.at(
"accessProb"), card);
298 b.item_entry(name, on, card, pop);
302 if (e.contains(
"arrival"))
303 b.open_arrival(name, detail::dist_from_json<T>(e.at(
"arrival")));
307 for (
const json& a : model.at(
"activities")) {
308 const std::string name = a.at(
"name").get<std::string>();
309 const std::string on = a.at(
"task").get<std::string>();
313 ? detail::dist_from_json<T>(a.at(
"hostDemand"))
315 b.activity(name, dem, on);
316 if (a.contains(
"thinkTime")) b.act_think_time(name, detail::dist_from_json<T>(a.at(
"thinkTime")));
317 if (a.contains(
"phase")) b.activity_phase(name, a.at(
"phase").get<
int>());
318 if (a.contains(
"callOrder")) b.call_order(name, a.at(
"callOrder").get<std::string>());
319 if (a.contains(
"boundToEntry"))
320 b.bound_to(name, a.at(
"boundToEntry").get<std::string>());
321 else if (a.contains(
"boundTo"))
322 b.bound_to(name, a.at(
"boundTo").get<std::string>());
323 if (a.contains(
"repliesTo")) b.replies_to(name, a.at(
"repliesTo").get<std::string>());
324 const char* kCallKey[2] = {
"synchCalls",
"asynchCalls"};
325 for (
int which = 0; which < 2; ++which) {
326 if (!a.contains(kCallKey[which]))
continue;
327 for (
const json& c : a.at(kCallKey[which])) {
329 const std::string dest = c.contains(
"dest")
330 ? c.at(
"dest").get<std::string>()
331 : c.at(
"entry").get<std::string>();
333 if (which == 0) b.sync_call(name, dest, mean);
334 else b.async_call(name, dest, mean);
339 if (a.contains(
"callGroups")) {
340 for (
const json& g : a.at(
"callGroups")) {
342 g.value(
"strategy", std::string()), name);
343 std::vector<std::string> dests;
344 for (
const json& d : g.at(
"dests")) dests.push_back(d.get<std::string>());
345 b.record_call_group(name, dests, rs);
352 for (
const json& e : model.at(
"entries")) {
353 if (!e.contains(
"forwarding"))
continue;
354 const std::string name = e.at(
"name").get<std::string>();
355 for (
const json& f : e.at(
"forwarding"))
356 b.forward(name, f.at(
"dest").get<std::string>(),
366 if (model.contains(
"precedences")) {
367 for (
const json& p : model.at(
"precedences")) {
368 const std::string kind = p.value(
"type", std::string());
372 const P pre = detail::lqn_prectype_from_json(p.value(
"preType", std::string(
"pre")),
true);
374 detail::lqn_prectype_from_json(p.value(
"postType", std::string(
"post")),
false);
375 std::vector<std::string> pres, posts;
376 if (p.contains(
"preActs"))
377 for (
const json& x : p.at(
"preActs")) pres.push_back(x.get<std::string>());
378 if (p.contains(
"postActs"))
379 for (
const json& x : p.at(
"postActs")) posts.push_back(x.get<std::string>());
380 const std::vector<T> post_params = p.contains(
"postParams")
381 ? detail::num_vec_from_json<T>(p.at(
"postParams"))
383 if (pre == P::PRE_SEQ && post == P::POST_SEQ) {
384 b.serial(pres.at(0), posts.at(0));
385 }
else if (pre == P::PRE_SEQ && post == P::POST_AND) {
386 b.and_fork(pres.at(0), posts);
387 }
else if (pre == P::PRE_AND && post == P::POST_SEQ) {
388 b.and_join(pres, posts.at(0), detail::lqn_quorum_from_json<T>(p, pres.size()));
389 }
else if (pre == P::PRE_OR && post == P::POST_SEQ) {
390 b.or_join(pres, posts.at(0));
391 }
else if (pre == P::PRE_SEQ && post == P::POST_OR) {
393 std::vector<T> probs;
394 if (p.contains(
"probabilities"))
395 probs = detail::num_vec_from_json<T>(p.at(
"probabilities"));
396 if (probs.empty()) probs = post_params;
399 b.or_fork(pres.at(0), posts, probs);
400 }
else if (pre == P::PRE_SEQ && post == P::POST_LOOP) {
404 if (posts.size() < 2)
406 "lqn_json_reader: a loop's postActs is the body followed by the "
407 "activity it exits to, so it holds at least two entries");
409 if (!p.contains(
"loopCount") && !post_params.empty()) count = post_params[0];
410 b.loop(pres.at(0), std::vector<std::string>(posts.begin(), posts.end() - 1),
411 posts.back(), count);
412 }
else if (pre == P::PRE_SEQ && post == P::POST_CACHE) {
413 if (posts.size() < 2)
414 throw InputError(
ErrorKind{
"Format"},
"lqn_json_reader: a post-CACHE precedence lists the hit and miss branches");
415 b.cache_access(pres.at(0), posts.at(0), posts.at(1));
418 " -> " + p.value(
"postType", std::string(
"post")) +
419 " has no builder counterpart");
423 std::vector<std::string> acts;
424 for (
const json& x : p.at(
"activities")) acts.push_back(x.get<std::string>());
425 if (kind ==
"Serial") {
428 for (std::size_t i = 0; i + 1 < acts.size(); ++i) b.serial(acts[i], acts[i + 1]);
429 }
else if (kind ==
"AndFork") {
430 b.and_fork(acts.at(0), std::vector<std::string>(acts.begin() + 1, acts.end()));
431 }
else if (kind ==
"AndJoin") {
432 b.and_join(std::vector<std::string>(acts.begin(), acts.end() - 1), acts.back(),
433 detail::lqn_quorum_from_json<T>(p, acts.size() - 1));
434 }
else if (kind ==
"OrFork") {
435 std::vector<T> probs;
436 if (p.contains(
"probabilities"))
437 probs = detail::num_vec_from_json<T>(p.at(
"probabilities"));
438 b.or_fork(acts.at(0), std::vector<std::string>(acts.begin() + 1, acts.end()),
440 }
else if (kind ==
"OrJoin") {
441 b.or_join(std::vector<std::string>(acts.begin(), acts.end() - 1), acts.back());
442 }
else if (kind ==
"Loop") {
445 if (!p.contains(
"preActivity"))
447 "lqn_json_reader: a Loop precedence carries its trigger as 'preActivity'");
450 "lqn_json_reader: a Loop precedence lists the body followed by the "
451 "activity it exits to, so it holds at least two entries");
452 b.loop(p.at(
"preActivity").get<std::string>(),
453 std::vector<std::string>(acts.begin(), acts.end() - 1), acts.back(),
455 }
else if (kind ==
"CacheAccess") {
458 "lqn_json_reader: a CacheAccess precedence names the read activity plus "
459 "its hit and miss branches");
460 b.cache_access(acts.at(0), acts.at(1), acts.at(2));
463 "' has no builder counterpart");
467 for (
const auto& r : host_rows) detail::lqn_apply_lincon(b, r.first, *r.second);
468 for (
const auto& r : task_rows) detail::lqn_apply_lincon(b, r.first, *r.second);
469 for (
const auto& r : host_pools) detail::lqn_apply_pools(b, r.first, *r.second);
470 for (
const auto& r : task_pools) detail::lqn_apply_pools(b, r.first, *r.second);
472 for (std::size_t i = 0; i < quantum_speed.size() && i < m.
procs.size(); ++i) {
473 m.
procs[i].quantum = quantum_speed[i].first;
474 m.
procs[i].speed_factor = quantum_speed[i].second;
476 for (std::size_t i = 0; i < m.
tasks.size() && i < fan_in.size(); ++i) {
477 m.
tasks[i].fanin = fan_in[i];
478 m.
tasks[i].fanout = fan_out[i];
480 if (model.contains(
"name") && model.at(
"name").is_string()) m.
name = model.at(
"name").get<std::string>();