blob: 0639f567de713df0a32d70be2da39b579fd2558c [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2022 Dortmund University of Applied Sciences and Arts and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dortmund University of Applied Sciences and Arts - initial API and implementation
********************************************************************************
*/
package org.eclipse.app4mc.amalthea.model.util.stimuli;
import java.math.BigInteger;
import org.eclipse.app4mc.amalthea.model.ModeLabel;
import org.eclipse.app4mc.amalthea.model.PeriodicStimulus;
import org.eclipse.app4mc.amalthea.model.Process;
import org.eclipse.app4mc.amalthea.model.Time;
import org.eclipse.app4mc.amalthea.model.util.FactoryUtil;
import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil;
import org.eclipse.app4mc.amalthea.model.util.RuntimeUtil.TimeType;
import org.eclipse.emf.common.util.EMap;
/**
* Event Model functions for APP4MC's {@link PeriodicStimulus}.
* <p>
* For a full documentation of the underlying functions, please refer to the
* <a href="https://doi.org/10.1016/j.sysarc.2021.102343">related
* publication</a>, Section 3.1.
*/
public class EMPeriodic implements IEventModel {
/**
* The actual period of this trigger pattern
*/
private Time tOuterPeriod;
/**
* Minimum distance between two subsequent activation events
*/
private Time tMinDistance;
/**
* Maximum jitter by which an activation event can be delayed
*/
private Time tJitter;
public EMPeriodic() {
// Empty on purpose
}
@Override
public long etaPlus(final Time dt) {
// Return 0 on dt=0
if (dt.getValue().compareTo(BigInteger.ZERO) == 0) {
return 0;
}
// LHS: ceil(dt+J/T)
final Time num = dt.add(this.tJitter);
final double eta_plus_p = Math.ceil(num.divide(this.tOuterPeriod));
// RHS: ceil(dt/d)
final double eta_plus;
if (this.tMinDistance.getValue().compareTo(BigInteger.ZERO) != 0) {
final double eta_plus_d = Math.ceil(dt.divide(this.tMinDistance));
eta_plus = Math.min(eta_plus_p, eta_plus_d);
} else {
eta_plus = eta_plus_p;
}
return (long) eta_plus;
}
@Override
public long etaMinus(final Time dt) {
// Return 0 on dt=0
if (dt.getValue().compareTo(BigInteger.ZERO) == 0) {
return 0;
}
// LHS: floor(dt-J/T)
final Time num = dt.subtract(this.tJitter);
final double eta_min_p = Math.floor(num.divide(this.tOuterPeriod));
// RHS: floor(dt/d)
final double eta_min;
if (this.tMinDistance.getValue().compareTo(BigInteger.ZERO) != 0) {
final double eta_min_d = Math.floor(dt.divide(this.tMinDistance));
eta_min = Math.max(eta_min_p, eta_min_d);
} else {
eta_min = eta_min_p;
}
return (long) Math.max(0, eta_min);
}
@Override
public Time deltaPlus(final long n) {
// Function is only valid for n >= 2, return null on invalid parameter
if (n < 2) {
return null;
}
// Compare recurrence and minDistance, use the *highest* of both for
// further calculation
final Time tMinDistanceCalc = EventModelFactory.max(this.tOuterPeriod, this.tMinDistance);
// Multiply this distance with the number of events (minus one)
final Time tDistance = tMinDistanceCalc.multiply(n - 1);
return tDistance.add(this.tJitter);
}
@Override
public Time deltaMinus(final long n) {
// Function is only valid for n >= 2, return 0 on invalid parameter
if (n < 2) {
return FactoryUtil.createTime("0ms");
}
// Compare recurrence and minDistance, use the *highest* of both for
// further calculation
final Time tMinDistanceCalc = EventModelFactory.max(this.tOuterPeriod, this.tMinDistance);
// Multiply this distance with the number of events (minus one)
final Time tDistance = tMinDistanceCalc.multiply(n - 1);
/*
* Subtract jitter if and only if it does not decrease the distance between two
* activation events to less than tMinDistance. Cap it otherwise to the max.
* permitted value that does not violate tMinDistance.
*/
// Check if tRecurrence > tMinDistance (Prerequisite, otherwise jitter
// is capped at 0)
if (this.tOuterPeriod.compareTo(this.tMinDistance) > 0) {
final Time tMaxJitter;
final Time tDiffRecMinDistance = this.tOuterPeriod.subtract(this.tMinDistance);
// Check if Jitter exceeds (tRecurrence - tMinDistane)
if (this.tJitter.compareTo(tDiffRecMinDistance) > 0) {
// Yes, so max. Jitter must be capped at tRecurrence -
// tMinDistane
tMaxJitter = tDiffRecMinDistance;
} else {
// No, so max. Jitter can be taken as specified
tMaxJitter = this.tJitter;
}
return tDistance.subtract(tMaxJitter);
}
return tDistance;
}
@Override
public double getUtilization(Process process, TimeType tt, EMap<ModeLabel, String> modes) {
final Time time = RuntimeUtil.getExecutionTimeForProcess(process, modes, tt);
return time.divide(this.tOuterPeriod);
}
public Time getRecurrence() {
return this.tOuterPeriod;
}
public void setRecurrence(Time recurrence) {
this.tOuterPeriod = recurrence;
}
public Time getMinDistance() {
return this.tMinDistance;
}
public void setMinDistance(Time minDistance) {
this.tMinDistance = minDistance;
}
public Time getJitter() {
return this.tJitter;
}
public void setJitter(Time jitter) {
this.tJitter = jitter;
}
}