5#ifndef LINE_SOLVERS_LDES_LDES_STATION_H
6#define LINE_SOLVERS_LDES_LDES_STATION_H
81 double deadline = std::numeric_limits<double>::infinity();
249 const double ma = mean_of(a), mb = mean_of(b);
250 if (ma != mb)
return ma > mb;
254 const double ma = mean_of(a), mb = mean_of(b);
255 if (ma != mb)
return ma < mb;
293 double mean_of(
const Job& j)
const {
333 double c,
const std::vector<double>& weight,
334 std::size_t nclasses) {
335 const std::size_t n = jobs.size();
336 std::vector<double> rates(n, 0.0);
337 if (n == 0)
return rates;
348 if (weighted_by_job) {
350 for (
const PsJob& j : jobs) tot += weight[j.
cls];
352 for (std::size_t i = 0; i < n; ++i)
353 rates[i] = std::min(1.0, weight[jobs[i].cls] * c / tot);
356 }
else if (weighted_by_class) {
357 std::vector<int> per_class(nclasses, 0);
358 for (
const PsJob& j : jobs) ++per_class[j.
cls];
360 for (std::size_t k = 0; k < nclasses; ++k)
361 if (per_class[k] > 0) tot += weight[k];
363 for (std::size_t i = 0; i < n; ++i) {
364 const std::size_t k = jobs[i].cls;
365 rates[i] = std::min(1.0, (weight[k] / tot / per_class[k]) * c);
371 const double share = std::min(1.0, c /
static_cast<double>(n));
372 for (std::size_t i = 0; i < n; ++i) rates[i] = share;
379 if (
static_cast<double>(n) <= c) {
380 for (std::size_t i = 0; i < n; ++i) rates[i] = 1.0;
385 double remaining = c;
386 for (std::set<int>::const_iterator it = prios.begin(); it != prios.end(); ++it) {
387 if (remaining <= 0.0)
break;
390 double tot_job_weight = 0.0;
391 std::vector<int> per_class(nclasses, 0);
392 for (
const PsJob& j : jobs)
395 tot_job_weight += weight[j.
cls];
398 const double allocated = std::min(remaining,
static_cast<double>(count));
399 double tot_class_weight = 0.0;
400 for (std::size_t k = 0; k < nclasses; ++k)
401 if (per_class[k] > 0) tot_class_weight += weight[k];
403 for (std::size_t i = 0; i < n; ++i) {
404 if (jobs[i].priority != p)
continue;
405 const std::size_t k = jobs[i].cls;
407 rates[i] = std::min(1.0, weight[k] * allocated / tot_job_weight);
409 rates[i] = std::min(1.0, (weight[k] / tot_class_weight / per_class[k]) * allocated);
411 rates[i] = allocated / count;
413 remaining -= allocated;
429 double c,
double now) {
430 std::vector<double> works = residuals;
431 std::sort(works.begin(), works.end());
432 const std::size_t n = works.size();
433 double cumulative = 0.0, prev = 0.0;
434 for (std::size_t rank = 0; rank < n; ++rank) {
435 const double w = works[rank];
436 const double rate = std::min(1.0, c /
static_cast<double>(n - rank));
437 if (rate > 0.0) cumulative += (w - prev) / rate;
438 if (w >= target_work)
return now + cumulative;
441 return now + cumulative;
473 const Job& arriving,
double c,
double now) {
474 const std::size_t none = in_service.size();
475 if (in_service.empty())
return none;
482 std::size_t best = none;
483 double oldest = std::numeric_limits<double>::infinity();
484 for (std::size_t j = 0; j < in_service.size(); ++j)
485 if (in_service[j].t_arr < oldest) {
486 oldest = in_service[j].t_arr;
493 std::size_t best = none;
494 double oldest = std::numeric_limits<double>::infinity();
495 for (std::size_t j = 0; j < in_service.size(); ++j)
496 if (in_service[j].priority >= arriving.
priority && in_service[j].t_arr < oldest) {
497 oldest = in_service[j].t_arr;
512 std::size_t best = none;
513 for (std::size_t j = 0; j < in_service.size(); ++j) {
514 if (in_service[j].priority <= arriving.
priority)
continue;
515 if (best == none || in_service[j].priority > in_service[best].priority ||
516 (in_service[j].priority == in_service[best].priority &&
517 in_service[j].t_arr > in_service[best].t_arr))
524 std::size_t worst = 0;
525 for (std::size_t j = 1; j < in_service.size(); ++j)
526 if (in_service[j].remaining > in_service[worst].remaining) worst = j;
528 in_service[worst].priority < arriving.
priority)
530 return (arriving.
remaining < in_service[worst].remaining) ? worst : none;
533 std::size_t largest = 0;
534 for (std::size_t j = 1; j < in_service.size(); ++j)
535 if (in_service[j].service > in_service[largest].service) largest = j;
536 return (arriving.
service < in_service[largest].service) ? largest : none;
542 std::size_t most = 0;
543 for (std::size_t j = 1; j < in_service.size(); ++j)
544 if (in_service[j].elapsed > in_service[most].elapsed) most = j;
545 return (in_service[most].elapsed > arriving.
elapsed) ? most : none;
548 std::size_t least = 0;
549 for (std::size_t j = 1; j < in_service.size(); ++j)
550 if (in_service[j].remaining < in_service[least].remaining) least = j;
551 return (arriving.
remaining > in_service[least].remaining) ? least : none;
554 std::vector<double> works;
555 for (
const Job& j : in_service) works.push_back(j.
remaining);
558 std::size_t worst = 0;
559 double worst_vft = -std::numeric_limits<double>::infinity();
560 for (std::size_t j = 0; j < in_service.size(); ++j) {
567 return (arrival_vft < worst_vft) ? worst : none;
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
SchedStrategy
Scheduling disciplines, with the values of MATLAB SchedStrategy.
bool is_preemptive(lang::SchedStrategy s)
True for the disciplines that interrupt a job already in service.
double fsp_virtual_finish(const std::vector< double > &residuals, double target_work, double c, double now)
FSP's virtual finish time: when target would finish if the station ran processor sharing from now on.
std::vector< double > ps_shares(lang::SchedStrategy sched, const std::vector< PsJob > &jobs, double c, const std::vector< double > &weight, std::size_t nclasses)
The per-job shares of a sharing discipline, in units of one server.
bool is_preemptive_resume(lang::SchedStrategy s)
PREEMPTIVE RESUME, as against preemptive restart.
bool is_ps_family(lang::SchedStrategy s)
True for the disciplines that share the server instead of ordering a queue.
bool is_size_based(lang::SchedStrategy s)
True for the orders whose key is the job's size, residual or attained work.
std::size_t preemption_victim(lang::SchedStrategy sched, const std::vector< Job > &in_service, const Job &arriving, double c, double now)
Which job in service arriving displaces, or in_service.size() for none.
Conservation laws of a layered queueing network, enumerated from its structure.
double deadline
EDD/EDF key.
double region_wait
Time spent parked outside a WAITQ region before entering this station.
double t_arr
arrival instant at this station
std::uint64_t call
The SYNCHRONOUS CALL this job belongs to, 0 when it belongs to none.
double rank
SIRO's random key, drawn at arrival.
double vft
FSP's virtual finish time, recomputed on demand.
int attempts
How many times this job has already retried from an orbit.
double t_sys
instant the current passage started
std::uint64_t tag
The generation its currently scheduled completion was pushed under.
double elapsed
attained service across all its service intervals
double service
the sampled requirement, drawn at arrival
double remaining
residual work; equals service before any preemption
std::uint64_t parent
The fork synchronization this job is a sibling of, 0 when it is not one.
A job being served by a sharing discipline, with the work it still owes.
double total
the sampled requirement
std::uint64_t tag
identifies the departure event scheduled for it
double region_wait
Job::region_wait, carried across the sharing station.
double remaining
residual work, in service-time units
std::uint64_t parent
The fork the job belongs to, carried across the sharing station.
The waiting-room order of a buffered discipline.
lang::SchedStrategy sched
bool operator()(const Job &a, const Job &b) const
const std::vector< double > * class_mean
mean service per class, for SEPT/LEPT