blob: d3683da8eb550d8ab5543410f3ec3db05fd108c1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr
* - Initial API and Implementation
*******************************************************************************/
package org.eclipse.efm.modeling.codegen.xlia.sdf.polygraph.mocc.ast.feature;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.stream.IntStream;
import org.eclipse.efm.modeling.codegen.xlia.sdf.polygraph.mocc.ast.MoccActor;
import org.eclipse.efm.modeling.codegen.xlia.sdf.polygraph.mocc.ast.MoccChannel;
import org.eclipse.efm.modeling.codegen.xlia.sdf.polygraph.mocc.ast.MoccPort;
import org.eclipse.efm.modeling.codegen.xlia.sdf.polygraph.mocc.ast.MoccSystem;
import org.eclipse.efm.modeling.codegen.xlia.sdf.polygraph.util.Rational;
public class MoccSystemFeature {
public final MoccSystem system;
public final boolean hasModeSelector;
public final boolean hasModeProcessor;
public final boolean hasRegular;
public final boolean hasRationalInput;
public final boolean hasRationalOutput;
public final boolean isPureInteger;
public final int timedActorCount;
public final int phaseActorCount;
public final int executableActorCount;
public final boolean hasTimed;
public final boolean hasUntimed;
public int[] repetitions;
public int firings;
public final int[] allFrequencies;
public final int[] exeFrequencies;
public final int time_interval;
public final int time_period;
public final int tick_period;
private int scheduledStageCount;
public final boolean consistency;
public final List< MoccActor > rootActor;
public final List< MoccActor > leafActor;
public MoccSystemFeature(
final MoccSystem system, final boolean isStrict) {
super();
assert (system != null) : "Unexpected a null MoccSystem";
this.system = system;
this.rootActor = new ArrayList<MoccActor>();
this.leafActor = new ArrayList<MoccActor>();
boolean hasModeSelector = false;
boolean hasModeProcessor = false;
boolean hasRegular = false;
boolean hasRationalInput = false;
boolean hasRationalOutput = false;
int timedActorCount = 0;
int phaseActorCount = 0;
int executableActorCount = 0;
final Set< Integer > allFrequencies = new HashSet<Integer>();
final Set< Integer > exeFrequencies = new HashSet<Integer>();
assert (! system.getActor().isEmpty()) :
"Unexpected a MoccSystem without actor";
// Basic static analysis feature
for( final MoccActor actor : system.getActor() ) {
if( isStrict ) {
if( actor.phase < 0 ) {
actor.phase = 0;
}
}
if( actor.phase > 0 ) {
phaseActorCount = phaseActorCount + 1;
}
actor.computeFeature();
if( actor.FEATURE.hasInteraction ) {
executableActorCount = executableActorCount + 1;
}
// Basic static analysis feature
hasModeSelector = hasModeSelector || actor.FEATURE.isModeSelector;
hasModeProcessor = hasModeProcessor || actor.FEATURE.isModeProcessor;
if( actor.FEATURE.isTimed ) {
timedActorCount = timedActorCount + 1;
}
if( actor.FEATURE.isTimed ) {
allFrequencies.add(actor.getFrequency());
if( actor.FEATURE.hasInteraction ) {
exeFrequencies.add(actor.getFrequency());
}
}
hasRegular = hasRegular || actor.FEATURE.isRegular;
hasRationalInput =
hasRationalInput || actor.FEATURE.hasRationalInput;
hasRationalOutput =
hasRationalOutput || actor.FEATURE.hasRationalOutput;
if( ! actor.FEATURE.hasInput ) {
rootActor.add(actor);
}
else if( actor.getPhase() == 0 ) {
boolean isRoot = true;
for( final MoccPort port : actor.getInputPort() ) {
if( ! port.hasEnoughInitialRate() ) {
isRoot = false;
break;
}
}
if( isRoot ) {
rootActor.add(actor);
}
}
if( ! actor.FEATURE.hasOutput ) {
leafActor.add(actor);
}
}
this.hasModeSelector = hasModeSelector;
this.hasModeProcessor = hasModeProcessor;
this.hasRegular = hasRegular;
this.hasRationalInput = hasRationalInput;
this.hasRationalOutput = hasRationalOutput;
this.isPureInteger = ! (this.hasRationalInput || this.hasRationalOutput);
this.timedActorCount = timedActorCount;
this.phaseActorCount = phaseActorCount;
this.executableActorCount = executableActorCount;
this.hasTimed = (timedActorCount > 0);
this.hasUntimed = (timedActorCount < system.getActor().size());
// Order Actor by causality
this.scheduledStageCount = 0;
computeScheduleOrder();
Collections.sort(this.system.getActor(), new Comparator<MoccActor>() {
@Override
public int compare(final MoccActor actorA, final MoccActor actorB)
{
final int scheduleA = actorA.schedule;
final int scheduleB = actorB.schedule;
return (scheduleA < scheduleB) ? -1 :
((scheduleA == scheduleB) ? 0 : 1);
}
});
int index = 0;
for( final MoccActor actor : system.getActor() ) {
actor.index = index++;
}
// computeReptetition2();
this.repetitions = computeReptetition();
this.firings = IntStream.of( this.repetitions ).sum();
this.allFrequencies = new int[allFrequencies.size()];
int offset = 0;
for( final Integer frequency : allFrequencies ) {
this.allFrequencies[offset++] = frequency;
}
if( (phaseActorCount == 0) && (this.allFrequencies.length > 0) ) {
this.exeFrequencies = new int[exeFrequencies.size()];
offset = 0;
for( final Integer frequency : exeFrequencies ) {
this.exeFrequencies[offset++] = frequency;
}
}
else {
this.exeFrequencies = this.allFrequencies;
}
if( this.exeFrequencies.length > 1 ) {
this.time_interval = gcd( this.exeFrequencies );
this.time_period = lcm( this.exeFrequencies );
this.tick_period = time_period / time_interval;
}
else if( this.exeFrequencies.length == 1 ) {
this.time_interval = this.exeFrequencies[0];
this.time_period = this.exeFrequencies[0];
this.tick_period = 1;
}
else {
this.time_interval = 1;
this.time_period = 1;
this.tick_period = this.scheduledStageCount + 1;
// IntStream.of( this.repetitions ).sum() + 1 - system.getActor().size();
}
// For non-conex graph
for( final MoccActor actor : system.getActor() ) {
if( this.repetitions[actor.index] == 0 ) {
this.repetitions[actor.index] = actor.FEATURE.repetition = -1;
}
}
this.consistency = checkConsistency();
for( final MoccActor actor : system.getActor() ) {
actor.FEATURE.computeCycloStaticRate();
actor.FEATURE.computeActivation(this);
}
}
public String strFrequencies() {
final StringBuilder sout = new StringBuilder(
Arrays.toString(exeFrequencies));
if( this.exeFrequencies != this.allFrequencies ) {
final HashSet<Integer> execFreq = new HashSet<Integer>();
for (final Integer freq : this.exeFrequencies) {
execFreq.add(freq);
}
sout.append(" -- [");
for (final Integer freq : this.allFrequencies) {
if( ! execFreq.contains(freq) ) {
sout.append(" ").append(freq);
}
}
sout.append(" ]");
}
return sout.toString();
}
private static int gcd(final int x, final int y) {
return (y == 0) ? x : gcd(y, x % y);
}
public static int gcd(final int... numbers) {
return Arrays.stream(numbers).reduce(0, (x, y) -> gcd(x, y));
}
public static int lcm(final int... numbers) {
return Arrays.stream(numbers).reduce(1, (x, y) -> x * (y / gcd(x, y)));
}
private void computeScheduleOrder() {
for( final MoccActor actor : this.rootActor ) {
actor.schedule = 0;
}
for( final MoccActor actor : this.rootActor ) {
propagateScheduleOrder(actor);
}
}
private final static int PENDING_SCHEDULE_MARK = -42;
private void computeScheduleOrder(final MoccActor actor) {
actor.schedule = PENDING_SCHEDULE_MARK;
int schedule = 0;
for( final MoccActor sourceActor : actor.getPredecessor() ) {
if( (sourceActor.schedule
== MoccActorFeature.DEFAULT_INITIAL_SCHEDULE)
&& (sourceActor.getPhase() <= actor.getPhase())
&& (! actor.hasEnoughInitialRate(sourceActor)) )
{
computeScheduleOrder(sourceActor);
}
schedule = Math.max(schedule, sourceActor.schedule);
}
this.scheduledStageCount = actor.schedule = schedule + 1;
}
private void propagateScheduleOrder(final MoccActor actor) {
for( final MoccActor targetActor : actor.getSuccessor() ) {
if( targetActor.schedule < 0 ) {
computeScheduleOrder(targetActor);
propagateScheduleOrder(targetActor);
}
}
}
public void computeReptetition2() {
boolean isOK = true;
final Vector<Integer> repetitionVector =
new Vector<Integer>(system.getActor().size());
for( int index = 0 ; index < system.getActor().size() ; index++ ) {
repetitionVector.add(1);
}
for (final MoccChannel channel : this.system.getChannel()) {
System.out.println( channel );
final MoccPort portA = channel.getOutputPort();
final int indexActorA = portA.getActor().index;
final int repeatA = repetitionVector.get(indexActorA);
final MoccPort portB = channel.getInputPort();
final int indexActorB = portB.getActor().index;
final int repeatB = repetitionVector.get(indexActorB);
final int rateA = portA.getRate() * portB.getRateDenominator();
final int rateB = portB.getRate() * portA.getRateDenominator();
boolean consistency = (rateA * repeatA == rateB * repeatB);
int newRepeatA;
int newRepeatB;
// if( ! vectorA.equals(vectorB) )
{
if( ! consistency ) {
final int multiple = lcm(rateA, rateB);
int divisor = gcd(repeatA, repeatB);
newRepeatA = (multiple/rateA)*(repeatB /divisor);
newRepeatB = (multiple/rateB )*(repeatA/divisor);
divisor = gcd(newRepeatA, newRepeatB);
newRepeatA /= divisor;
newRepeatB /= divisor;
}
else {
newRepeatA = newRepeatB = 1;
}
repetitionVector.set(indexActorA,
newRepeatA * repetitionVector.get(indexActorA));
repetitionVector.set(indexActorB,
newRepeatB * repetitionVector.get(indexActorB));
System.out.print("Repetition Vector : ");
System.out.println( repetitionVector );
consistency = true;
}
isOK &= consistency;
}
if( isOK ) {
System.out.print("Final Repetition Vector: ");
System.out.println( repetitionVector );
}
}
private final Map<MoccActor, Rational> rationals = new HashMap<MoccActor, Rational>();
private int[] computeReptetition() {
for( final MoccActor actor : system.getActor() ) {
if( actor.FEATURE.hasInteraction )
{
if( ! rationals.containsKey(actor) ) {
calculateRate(actor, new Rational(1, 1));
}
}
else {
rationals.put(actor, new Rational(0, 1));
}
}
// get least common denominator
int lcm = 1;
for( final Rational rat : rationals.values() ) {
lcm = Rational.lcm(lcm, rat.getDenominator());
}
final int[] repetions = new int[system.getActor().size()];
for( final MoccActor actor : rationals.keySet() ) {
final Rational rat = rationals.get(actor);
repetions[actor.index] = actor.FEATURE.repetition
= rat.getNumerator() * (lcm / rat.getDenominator());
}
return( repetions );
}
private void calculateRate(final MoccActor actor, final Rational rate) {
rationals.put(actor, rate);
for( final MoccPort outputPort : actor.getOutputPort() ) {
final MoccPort inputPort = outputPort.getChannel().getInputPort();
final MoccActor inputActor = inputPort.getActor();
if( ! rationals.containsKey(inputActor) ) {
final int prod = outputPort.getRate() * inputPort.getRateDenominator();
final int conso = inputPort.getRate() * outputPort.getRateDenominator();
calculateRate(inputActor, rate.mul(new Rational(prod, conso)));
}
}
for( final MoccPort inputPort : actor.getInputPort() ) {
final MoccPort outputPort = inputPort.getChannel().getOutputPort();
final MoccActor outputActor = outputPort.getActor();
if( ! rationals.containsKey(outputActor) ) {
final int prod = outputPort.getRate() * inputPort.getRateDenominator();
final int conso = inputPort.getRate() * outputPort.getRateDenominator();
calculateRate(outputActor, rate.mul(new Rational(conso, prod)));
}
}
}
private boolean checkConsistency() {
boolean consistency = true;
for( final MoccActor actor : rationals.keySet() ) {
actor.FEATURE.consistency = (! actor.FEATURE.isTimed)
|| (! actor.FEATURE.hasInteraction)
|| ((actor.FEATURE.repetition ==
(actor.getFrequency() / this.time_interval))
&& (actor.getPhase() < (this.time_period / actor.getFrequency())));
consistency &= actor.FEATURE.consistency;
}
for( final MoccChannel channel : system.getChannel() ) {
final MoccPort outputPort = channel.getOutputPort();
final MoccPort inputPort = channel.getInputPort();
final int outputRate = outputPort.getActor().FEATURE.repetition;
final int inputRate = inputPort.getActor().FEATURE.repetition;
final int prod = outputPort.getRate() * inputPort.getRateDenominator();
final int conso = inputPort.getRate() * outputPort.getRateDenominator();
if (outputRate * prod != inputRate * conso) {
consistency = false;
outputPort.actor.FEATURE.consistency = false;
inputPort.actor.FEATURE.consistency = false;
}
}
return consistency;
}
}