211 mol_detail::lqn_mol_assert(
lsn);
214 const std::size_t nidx =
lsn.nidx, ncalls =
lsn.ncalls;
215 const std::size_t e0 =
lsn.eshift + 1, e1 =
lsn.eshift +
lsn.nentries;
216 const std::size_t t0 =
lsn.tshift + 1, t1 =
lsn.tshift +
lsn.ntasks;
217 const double om = options.relax_factor;
220 std::vector<std::size_t> actof(nidx + 1, 0), taskof(nidx + 1, 0), hostof(nidx + 1, 0);
221 std::vector<T> dem(nidx + 1, zero);
222 for (std::size_t tidx = t0; tidx <= t1; ++tidx) hostof[tidx] =
lsn.parent[tidx];
223 for (std::size_t eidx = e0; eidx <= e1; ++eidx) {
224 actof[eidx] =
lsn.actsof[eidx][0];
225 const T d =
lsn.hostdem[actof[eidx]].mean;
227 taskof[eidx] =
lsn.parent[eidx];
231 std::vector<std::size_t> callsrc(ncalls + 1, 0), calldst(ncalls + 1, 0);
232 std::vector<T> cally(ncalls + 1, zero);
233 std::vector<std::size_t> entryOfAct(nidx + 1, 0);
234 for (std::size_t eidx = e0; eidx <= e1; ++eidx) entryOfAct[actof[eidx]] = eidx;
235 std::vector<std::vector<std::size_t>> callsFrom(nidx + 1), callsTo(nidx + 1);
236 for (std::size_t c = 1; c <= ncalls; ++c) {
237 callsrc[c] = entryOfAct[
lsn.callpair_src[c]];
238 calldst[c] =
lsn.callpair_dst[c];
239 const T y =
lsn.callproc_mean[c];
241 callsFrom[callsrc[c]].push_back(c);
242 callsTo[calldst[c]].push_back(c);
246 std::vector<double> npop(nidx + 1, 1.0);
247 for (std::size_t idx = 1; idx <= t1; ++idx) {
248 double m = (idx <
lsn.maxmult.size()) ?
lsn.maxmult[idx] : 1.0;
249 if (!std::isfinite(m) || m < 1.0) m = 1.0;
256 std::vector<std::size_t> hostLayers, taskLayers;
257 for (std::size_t hidx = 1; hidx <=
lsn.nhosts; ++hidx)
258 if (!
lsn.tasksof[hidx].empty()) hostLayers.push_back(hidx);
259 std::vector<bool> isCalled(nidx + 1,
false);
260 for (std::size_t c = 1; c <= ncalls; ++c) isCalled[taskof[calldst[c]]] =
true;
261 for (std::size_t tidx = t0; tidx <= t1; ++tidx)
262 if (!
lsn.isref[tidx] && isCalled[tidx]) taskLayers.push_back(tidx);
265 std::vector<T> residt = dem, servt(nidx + 1, zero), thinkt(nidx + 1, zero),
266 share(nidx + 1, zero), Xtask(nidx + 1, zero), Xentry(nidx + 1, zero),
267 busyth(nidx + 1, zero), zref(nidx + 1, zero);
268 std::vector<T> callservt(ncalls + 1, zero);
269 for (std::size_t tidx = t0; tidx <= t1; ++tidx) {
273 if (
lsn.isref[tidx] && tidx <
lsn.think.size() && !
lsn.think[tidx].disabled) {
274 z =
lsn.think[tidx].mean;
276 if (!std::isfinite(zd) || zd < 0.0) z = zero;
280 const std::vector<std::size_t>& es =
lsn.entriesof[tidx];
282 for (std::size_t k = 0; k < es.size(); ++k)
287 for (std::size_t eidx = e0; eidx <= e1; ++eidx) servt[eidx] = dem[eidx];
288 for (std::size_t pass = 0; pass < std::max<std::size_t>(1,
lsn.nentries); ++pass)
289 for (std::size_t eidx = e0; eidx <= e1; ++eidx) {
291 for (std::size_t k = 0; k < callsFrom[eidx].size(); ++k) {
292 const std::size_t c = callsFrom[eidx][k];
293 s += T(cally[c] * servt[calldst[c]]);
297 for (std::size_t c = 1; c <= ncalls; ++c) callservt[c] = servt[calldst[c]];
304 auto cycle_outside = [&](std::size_t tidx, std::size_t excl) -> T {
306 for (std::size_t j = 0; j <
lsn.entriesof[tidx].size(); ++j) {
307 const std::size_t eidx =
lsn.entriesof[tidx][j];
308 T w = T(share[eidx] * residt[eidx]);
309 for (std::size_t k = 0; k < callsFrom[eidx].size(); ++k) {
310 const std::size_t c = callsFrom[eidx][k];
311 if (taskof[calldst[c]] != excl) w += T(share[eidx] * cally[c] * callservt[c]);
320 auto host_servers = [&](std::size_t hidx) ->
double {
321 return (
lsn.sched[hidx] == SchedStrategy::INF) ? 1.0 : npop[hidx];
326 auto throughputs = [&]() {
327 for (std::size_t t = t0; t <= t1; ++t) {
330 for (std::size_t j = 0; j <
lsn.entriesof[t].size(); ++j) {
331 const std::size_t eidx =
lsn.entriesof[t][j];
332 cyc += T(share[eidx] * servt[eidx]);
337 for (std::size_t j = 0; j <
lsn.entriesof[t].size(); ++j) {
338 const std::size_t eidx =
lsn.entriesof[t][j];
339 Xentry[eidx] = T(Xtask[t] * share[eidx]);
343 for (std::size_t j = 0; j <
lsn.entriesof[t].size(); ++j)
344 Xentry[
lsn.entriesof[t][j]] = zero;
347 for (std::size_t pass = 0; pass < std::max<std::size_t>(1,
lsn.ntasks); ++pass) {
348 for (std::size_t eidx = e0; eidx <= e1; ++eidx) {
349 if (
lsn.isref[taskof[eidx]])
continue;
351 for (std::size_t k = 0; k < callsTo[eidx].size(); ++k) {
352 const std::size_t c = callsTo[eidx][k];
353 x += T(cally[c] * Xentry[callsrc[c]]);
357 for (std::size_t t = t0; t <= t1; ++t) {
358 if (
lsn.isref[t])
continue;
359 const std::vector<std::size_t>& es =
lsn.entriesof[t];
361 for (std::size_t j = 0; j < es.size(); ++j)
sum += Xentry[es[j]];
364 for (std::size_t j = 0; j < es.size(); ++j)
365 share[es[j]] = T(Xentry[es[j]] /
sum);
372 for (std::size_t t = t0; t <= t1; ++t) {
374 for (std::size_t j = 0; j <
lsn.entriesof[t].size(); ++j) {
375 const std::size_t eidx =
lsn.entriesof[t][j];
376 u += T(Xentry[eidx] * servt[eidx]);
382 std::size_t iter = 0;
383 double resid = std::numeric_limits<double>::infinity();
384 while (iter < options.iter_max) {
386 const std::vector<T> servt_prev = servt, thinkt_prev = thinkt;
389 for (std::size_t li = 0; li < taskLayers.size(); ++li) {
390 const std::size_t tidx = taskLayers[li];
392 std::set<std::size_t> callerset;
393 for (std::size_t j = 0; j <
lsn.entriesof[tidx].size(); ++j)
394 for (std::size_t k = 0; k < callsTo[
lsn.entriesof[tidx][j]].size(); ++k)
395 callerset.insert(taskof[callsrc[callsTo[
lsn.entriesof[tidx][j]][k]]]);
396 const std::vector<std::size_t> callers(callerset.begin(), callerset.end());
397 const std::size_t Kc = callers.size();
398 if (Kc == 0)
continue;
400 if (
lsn.sched[tidx] != SchedStrategy::INF) {
403 std::vector<T> N(Kc, zero), Z(Kc, zero);
404 for (std::size_t k = 0; k < Kc; ++k) {
405 const std::size_t ctask = callers[k];
408 for (std::size_t j = 0; j <
lsn.entriesof[ctask].size(); ++j) {
409 const std::size_t eidx =
lsn.entriesof[ctask][j];
410 for (std::size_t m = 0; m < callsFrom[eidx].size(); ++m) {
411 const std::size_t c = callsFrom[eidx][m];
412 if (taskof[calldst[c]] == tidx)
413 d += T(share[eidx] * cally[c] * servt[calldst[c]]);
417 Z[k] = cycle_outside(ctask, tidx);
421 for (std::size_t k = 0; k < Kc; ++k)
423 gcl[k] = T(r.
R(0, k) / L(0, k));
425 for (std::size_t k = 0; k < Kc; ++k) {
426 const std::size_t ctask = callers[k];
427 for (std::size_t j = 0; j <
lsn.entriesof[ctask].size(); ++j) {
428 const std::size_t eidx =
lsn.entriesof[ctask][j];
429 for (std::size_t m = 0; m < callsFrom[eidx].size(); ++m) {
430 const std::size_t c = callsFrom[eidx][m];
431 if (taskof[calldst[c]] != tidx)
continue;
432 const T newv = T(gcl[k] * servt[calldst[c]]);
441 for (std::size_t li = 0; li < hostLayers.size(); ++li) {
442 const std::size_t hidx = hostLayers[li];
444 const std::vector<std::size_t>& tsks =
lsn.tasksof[hidx];
445 const std::size_t Kt = tsks.size();
447 if (
lsn.sched[hidx] != SchedStrategy::INF) {
450 std::vector<T> N(Kt, zero), Z(Kt, zero);
451 for (std::size_t k = 0; k < Kt; ++k) {
452 const std::size_t tidx = tsks[k];
454 T d = zero, z = thinkt[tidx];
455 for (std::size_t j = 0; j <
lsn.entriesof[tidx].size(); ++j) {
456 const std::size_t eidx =
lsn.entriesof[tidx][j];
457 d += T(share[eidx] * dem[eidx]);
458 for (std::size_t m = 0; m < callsFrom[eidx].size(); ++m) {
459 const std::size_t c = callsFrom[eidx][m];
460 z += T(share[eidx] * cally[c] * callservt[c]);
468 for (std::size_t k = 0; k < Kt; ++k)
470 f[k] = T(r.
R(0, k) / L(0, k));
472 for (std::size_t k = 0; k < Kt; ++k)
473 for (std::size_t j = 0; j <
lsn.entriesof[tsks[k]].size(); ++j) {
474 const std::size_t eidx =
lsn.entriesof[tsks[k]][j];
475 residt[eidx] = T(f[k] * dem[eidx]);
480 for (std::size_t eidx = e0; eidx <= e1; ++eidx) {
482 for (std::size_t k = 0; k < callsFrom[eidx].size(); ++k) {
483 const std::size_t c = callsFrom[eidx][k];
484 s += T(cally[c] * callservt[c]);
492 for (std::size_t tidx = t0; tidx <= t1; ++tidx) {
493 if (
lsn.isref[tidx]) {
494 thinkt[tidx] = zref[tidx];
514 for (std::size_t eidx = e0; eidx <= e1; ++eidx) {
517 resid = std::max(resid, std::fabs(a - b) / std::max(1.0, std::fabs(a)));
519 for (std::size_t tidx = t0; tidx <= t1; ++tidx) {
522 resid = std::max(resid, std::fabs(a - b) / std::max(1.0, std::fabs(a)));
524 if (resid < options.iter_tol)
break;
529 const double nan = std::numeric_limits<double>::quiet_NaN();
533 for (std::size_t eidx = e0; eidx <= e1; ++eidx) {
534 const std::size_t hidx = hostof[taskof[eidx]];
537 out.
QN[eidx] = T(Xentry[eidx] * servt[eidx]);
538 out.
UN[eidx] = procutil;
539 out.
RN[eidx] = servt[eidx];
540 out.
TN[eidx] = Xentry[eidx];
541 const std::size_t aidx = actof[eidx];
542 out.
QN[aidx] = out.
QN[eidx];
543 out.
UN[aidx] = out.
UN[eidx];
544 out.
RN[aidx] = out.
RN[eidx];
545 out.
TN[aidx] = out.
TN[eidx];
547 for (std::size_t tidx = t0; tidx <= t1; ++tidx) {
548 T q = zero, u = zero;
549 for (std::size_t j = 0; j <
lsn.entriesof[tidx].size(); ++j) {
550 q += out.
QN[
lsn.entriesof[tidx][j]];
551 u += out.
UN[
lsn.entriesof[tidx][j]];
556 out.
TN[tidx] = Xtask[tidx];
558 for (std::size_t hidx = 1; hidx <=
lsn.nhosts; ++hidx) {
560 for (std::size_t j = 0; j <
lsn.tasksof[hidx].size(); ++j)
561 u += out.
UN[
lsn.tasksof[hidx][j]];
569 out.
info.iter = iter;
570 out.
info.resid = resid;
571 out.
info.servt = servt;
572 out.
info.residt = residt;
573 out.
info.callservt = callservt;
574 out.
info.thinkt = thinkt;
575 out.
info.share = share;
576 out.
info.hostLayers = hostLayers;
577 out.
info.taskLayers = taskLayers;